#lang racket
(require
rackunit
racket/require
(path-up "self/require.rkt")
(path-up "self/module-path.rkt")
"../proof/proof.rkt"
"../proof/syntax.rkt"
"program-tests.rkt"
(cce-in main))
(provide test-language)
(define loc (make-loc #f #f #f))
(define program
(papply make-module-program/mred module-path:acl2))
(define (proof . args)
(make-proof (make-part 'Dracula loc (map sexp->term args))))
(define (sexp->term sexp)
(make-term sexp loc))
(define (check-prove program proof)
(check-equal? (get-proof (car (check-expand-success program))) proof))
(define check-run
(case-lambda
[(program) (check-eval-success program)]
[(program result)
(check-equal? (check-eval-success program) result)]))
(define (check-run/prove program result proof)
(check-run program result)
(check-prove program proof))
(define (check-syntax-equal? a b)
(check-equal? (datum a) (datum b)))
(define (datum v) (syntax->datum (datum->syntax #f v)))
(define (expr-term stx) (make-term stx #f))
(define (event-term stx) (make-term stx #t))
(define test-language
(test-suite "ACL2"
(test-suite "defun"
(test-case "bad function name"
(check-expand-failure
(program '[(defun t () 1)])))
(test-case "bad argument name"
(check-expand-failure
(program '[(defun f (nil) 1)])))
(test-case "recursion arity error"
(check-expand-failure
(program '[(defun f (x) (f x x))])))
(test-case "arity error"
(check-expand-failure
(program '[(defun f (x) x)] '[(f 1 2)])))
(test-case "redefinition"
(check-expand-failure
(program '[(defun f () 1) (defun f () 2)])))
(test-case "forward reference"
(check-expand-failure
(program '[(defun a () (b)) (defun b () 1)])))
(test-case "identity"
(check-run/prove
(program '[(defun id (x) x)] '[(id 2)])
2
(proof '(defun id (x) x))))
(test-case "backward reference"
(check-run/prove
(program '[(defun a () 1) (defun b () (a))] '[(b)])
1
(proof '(defun a () 1) '(defun b () (a)))))
(test-case "recursion"
(check-run/prove
(program '[(defun depth (v)
(if (atom v) 0 (1+ (max (depth (car v))
(depth (cdr v))))))]
'[(depth '((1 . 2) . ((3 . 4) . 5)))])
3
(proof
'(defun depth (v)
(if (atom v) 0 (1+ (max (depth (car v))
(depth (cdr v))))))))))
(test-suite "defstub"
(test-case "invalid name"
(check-expand-failure
(program '[(defstub nil () t)])))
(test-case "valid stub"
(check-eval-success
(program '[(defstub s (x y) t)])))
(test-case "direct call"
(check-eval-failure
(program '[(defstub s () t)] '[(s)])))
(test-case "indirect call"
(check-eval-failure
(program '[(defstub s () t) (defun f () (s))] '[(f)]))))
(test-suite "mutual recursion"
(test-case "two functions"
(check-run/prove
(program '[(mutual-recursion
(defun even-p (x)
(if (zp x) t (odd-p (1- x))))
(defun odd-p (x)
(if (zp x) nil (even-p (1- x)))))]
'[(even-p 4)])
't
(proof
'(mutual-recursion
(defun even-p (x)
(if (zp x) t (odd-p (1- x))))
(defun odd-p (x)
(if (zp x) nil (even-p (1- x))))))))
(test-case "arity error"
(check-expand-failure
(program '[(mutual-recursion
(defun a (x y) (b x y))
(defun b (x) (a x x)))]))))
(test-suite "defconst"
(test-case "reference"
(check-run/prove
(program '[(defconst *five* 5)] '[*five*])
5
(proof '(defconst *five* 5))))
(test-case "bad name"
(check-expand-failure
(program '[(defconst five 5)]))))
(test-suite "#%app"
(test-case "function"
(check-run/prove
(program '[] '[(max 1 2)])
2
(proof)))
(test-case "variable arity"
(check-run/prove
(program '[] '[(list (+ 1) (+ 1 2) (+ 1 2 3))])
'(1 3 6)
(proof))))
(test-suite "defstructure"
(test-case "defined functions"
(check-run/prove
(program '[(defstructure point x y)]
'[(list (point-x (point 1 2))
(point-y (point 1 2))
(point-p (point 1 2))
(weak-point-p (point 1 2)))])
'(1 2 t t)
(proof '(defstructure point x y))))
(test-case "forward reference"
(check-expand-failure
(program '[(defun origin () (point 0 0))
(defstructure point x y)]))))
))