;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname expr-test-R0) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) (require "R0.rkt") (require "scanner.rkt") (require rackunit) ; use `check-equal?`, not `check-expect`. ; ; We use `check-equal?` because it can be passed as a function (e.g. to `map`). ; The one advantage of `check-expect` we lose, is that all check-expects are ; delayed until the end of the file (hence, you can have a `check-expect` ; *before* the function it tests -- not so, with `check-equal?`.) ;;;;;;;;;;;;;;;;;;; TEST CASES: R0 ;;;;;;;;;;;;;;;; ; Some expressions to test in a non-automated way: (define e0 "43") (define e1 "<43>") (define e2 "|4 3 ;)|") (define e3 "<< < |4 3 ;)|>>>") (define e4 "|<43> | 42 3 xD | ;) |") (check-equal? (parse! "39") 39) (check-equal? (eval (parse! e4)) 169) ;;; three types of test we want to make, for many different exprs: (check-equal? (parse! "|4 3 ;)|") (make-binop 4 3 ";)")) (check-equal? (eval (parse! "|4 3 ;)|")) 7) (check-equal? (expr->string (parse! "|4 3 ;)|")) "|4 3 ;)|") (define tests ; Each entry in the list is either ; [str val] (where val is the result of interpreting the string str), or ; [str val expr] (as above, but expr is the internal (struct) representation). `{["7" 7 7] ["|3 4 ;)|" 7 ,(make-binop 3 4 ";)")] ["|3 4 xD|" 12 ,(make-binop 3 4 "xD")] ["||3 4 ;)| | 3 4 xD | ;) |" 19] ["/ 0 1 2\\" 1 ,(make-parity 0 1 2)] ["/ 1 1 2\\" 2 ,(make-parity 1 1 2)] ["/ |3 -3 ;)| 1 2\\" 1 ,(make-parity (make-binop 3 -3 ";)") 1 2)] ["/ |/ / 0 1 2 \\ 3 4 \\ -3 ;) | 1 2 \\" 2 ,(make-parity (make-binop (make-parity (make-parity 0 1 2) 3 4) -3 ";)") 1 2)] #| Further tests, for R1: ["|3.0 4.0 ;% |" 3] ["|| 5.0 6.0 ;) | 3.0 ;%|" 2] ["|8.1 3.0 ;%|" 2.1] ["|8.0 3.1 ;%|" 1.8] ["|-8.1 3.0 ;%|" 0.9] ["|-8.0 3.1 ;%|" 1.3] ["|8.1 -3 ;%|" -0.9] ["|8.0 -3.1 ;%|" -1.3] ["|-8.1 -3.0 ;%|" -2.1] ["|-8.0 -3.1 ;%|" -1.8] ["|8.0 2.0 ;%|" 0] ["|-8.0 2.0 ;%|" 0] ["|8.0 -2.0 ;%|" 0] ["|-8.0 -2.0 ;%|" 0] ["|8.0 3.0 ;%|" 2] ["|-8.0 3.0 ;%|" 1] ["|8.0 -3.0 ;%|" -1] ["|-8.0 -3.0 ;%|" -2] |# }) ; ; For info on backquote, see documentations and/or: ; http://www.radford.edu/itec380/2016fall-ibarland/Lectures/backquote.html ; string->tokens : string -> (listof string) ; Given a string, return a list of tokens (for the scanner, as configured). ; (define (string->tokens str) ; Don't use scheme's built-in `read`, because our string might contain semicolons etc. ; Make a local helper-function named `convert : scanner -> string` (letrec {[convert (λ (scnr) (if (eof-object? (peek scnr)) empty (cons (pop! scnr) (convert scnr))))]} (convert (create-scanner str)))) ; N.B. We RELY on left-to-right eval here: ; the pop happens before looping back. ; test `eval`: (for-each (λ (t) (check-equal? (eval (parse! (first t))) (second t))) tests) ; Test that expr->string and parse! are inverses: (for-each (λ (t) (check-equal? (string->tokens (expr->string (parse! (first t)))) (string->tokens (first t)))) tests) ; Test the internal representations: (for-each (λ (t) (check-equal? (parse! (first t)) (third t))) (filter (λ(t) (>= (length t) 3)) tests))