[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Scheme-reports] programs and cond-expand

I looked through all of my R7RS tests and I don't think I have any that matter if interaction-environment is different on each call or different than load. I have some where I test import and define-library that do matter, but I don't think those tests are portable anyway.

In Foment, you can define a library using eval: (eval '(define-library (foo bar) ...)) and (foo bar) will be available for importing. That means as you are developing a program and libraries, you can just put them all into the same file to begin with and use load to try it out. Does chibi do something similar?

;;; Put all the code into a single file, for example, program.scm
;;; foment -i -l program.scm
;;; will define the library, run the program, and leave you at a repl.
(define-library (hello)
    (import (scheme base))
    (import (scheme write))
    (export hello)
        (define (hello) (write '|hello, world!|))))

(import (scheme write))
(import (hello))
(hello) (newline)

On 10/24/2013 9:09 PM, Michael Montague wrote:
I used a different approach. I use a procedure very like load, but that handles (must-equal <result> <expr>) and (must-raise <exception> <expr>) specially. Using this approach, I could start testing before I had syntax-rules working, and even before I had all that much of a scheme system working.

Right now, that procedure is written in C, but I am in the process of making it a scheme program, and making my tests compatible with (chibi test).

The specification for (interaction-environment) says that it "returns a specifier for a mutable environment..." Does it return the same environment every time that it is called? Does it return the same environment as
that used by load? must-raise can easily be transformed to (test-error (eval '(lambda () expr) (interaction-environment))) but the following example will not work if interaction-environment does not return the same environment as load -- assuming the tests are run by load. And I don't think the following example will work at all if the tests are run as a program, assuming the must-raise to test-error transformation.

(define (l x y) x)
(must-raise (assertion-violation l) (l 3))
(must-raise (assertion-violation l) (l 3 4 5))

Here is an R7RS program which will handle testing with must-equal and must-raise. It does not check for a specific exception being raised because that is implementation specific.
;; A program to run the tests.
;; <scheme> runtests.scm <test> ...

(import (scheme base))
(import (scheme cxr))
(import (scheme eval))
(import (scheme file))
(import (scheme process-context))
(import (scheme read))
(import (scheme repl))
(import (scheme write))

(define pass-count 0)
(define fail-count 0)

(define (run-tests lst)
    (define (fail obj ret)
        (set! fail-count (+ fail-count 1))
        (display "failed: ")
        (write obj)
        (display ": ")
        (write ret)
    (let ((env (interaction-environment)))
        (define (test-must-equal obj)
            (let ((ret (eval (caddr obj) env)))
                (if (equal? (cadr obj) ret)
                    (set! pass-count (+ pass-count 1))
                    (fail obj ret))))
        (define (test-must-raise obj)
            (guard (exc
                ((error-object? exc) (set! pass-count (+ pass-count 1)))
                (else (fail obj exc)))
                (eval (caddr obj) env)
                (fail obj "no exception raised")))
        (define (test port)
            (let ((obj (read port)))
                (if (not (eof-object? obj))
                            ((and (pair? obj) (eq? (car obj) 'must-equal))
                                (test-must-equal obj))
                            ((and (pair? obj) (eq? (car obj) 'must-raise))
                                (test-must-raise obj))
                            (else (eval obj env)))
                        (test port)))))
        (if (not (null? lst))
                (display (car lst))
                (call-with-port (open-input-file (car lst)) test)
                (run-tests (cdr lst))))))

(run-tests (cdr (command-line)))
(display "pass: ") (display pass-count) (display " fail: ") (display fail-count) (newline)

On 10/24/2013 5:48 PM, Alex Shinn wrote:
On Fri, Oct 25, 2013 at 12:53 AM, Michael Montague <mikemon@x> wrote:
My reader includes location information when it reads identifiers and
quote strips all that out. I want that to be part of the tests and I
want to be able to test for specific errors. I will put more thought
into it and figure out a way to make my tests work in (chibi test).

It's not really possible without implementation-specific
extensions, because the error is happening at compile
time, and there's no standard way to catch compile-time

You could write a low-level macro that evaluates it's body:

(define-syntax test-syntax
    (lambda (expr rename compare)
      (guard (else (exn '(test-assert "syntax bad" #f)))
        (eval expr)
        '(test-assert "syntax ok" #t)))))

and maybe preserve the source info there, but it's still
just falling back on eval.

As an implementation-specific extension you could provide
a syntax-guard form which can catch macro errors, which
would be a cleaner solution.


Scheme-reports mailing list