Files
js-maker/testing/jsmaker-test-framework.rkt

99 lines
4.6 KiB
Racket

#lang racket/base
(require racket/format
racket/string
"jsmaker-executors.rkt")
(provide js-expression-test
js-program-test
write-js-test-file
run-jsmaker-regression
notice-line
warning-line)
(define (notice-line who fmt . args)
(displayln (string-append "NOTE: " (apply format fmt args))))
(define (warning-line who fmt . args)
(displayln (string-append "WARNING: " (apply format fmt args))
(current-error-port)))
(define (js-expression-test name expr expected)
(list name expr expected))
(define (js-program-test name program check-expr expected #:preamble [preamble ""])
(list name
(format "(() => {~a~a~areturn (~a); })()"
(if (string=? preamble "") "" (string-append "\n" preamble "\n"))
program
(if (regexp-match? #rx"\n$" program) "" "\n")
check-expr)
expected))
(define (write-js-test-file js-path tests)
(call-with-output-file js-path
#:exists 'replace
(lambda (out)
(displayln "const tests = [];" out)
(displayln "const __normalize = (v) => v === undefined ? 'undefined' : JSON.stringify(v);" out)
(displayln "const __print = (...xs) => {" out)
(displayln " if (typeof console !== 'undefined' && console.log) console.log(...xs);" out)
(displayln " else if (typeof print === 'function') print(xs.join(' '));" out)
(displayln "};" out)
(for ([t tests])
(define name (symbol->string (car t)))
(define expr (cadr t))
(define expected (caddr t))
(fprintf out "tests.push([~s, () => (~a), ~s]);\n" name expr expected))
(displayln "(async () => {" out)
(displayln " let failed = 0;" out)
(displayln " for (const [name, thunk, expected] of tests) {" out)
(displayln " let value;" out)
(displayln " try { value = await Promise.resolve(thunk()); }" out)
(displayln " catch (e) { value = { __thrown: String(e && e.message !== undefined ? e.message : e) }; }" out)
(displayln " const actual = __normalize(value);" out)
(displayln " const ok = actual === expected;" out)
(displayln " __print((ok ? 'ok' : 'FAIL') + '\\t' + name + '\\t' + actual);" out)
(displayln " if (!ok) failed++;" out)
(displayln " }" out)
(displayln " if (failed !== 0) throw new Error(failed + ' jsmaker test(s) failed');" out)
(displayln "})().catch((e) => {" out)
(displayln " __print(e && e.stack ? e.stack : String(e));" out)
(displayln " if (typeof process !== 'undefined' && process.exit) process.exit(1);" out)
(displayln " throw e;" out)
(displayln "});" out))))
(define (describe-engine engine)
(define version (or (js-engine-version engine) "unknown version"))
(format "~a at ~a (~a)"
(js-engine-name engine)
(path->string (js-engine-path engine))
version))
(define (run-jsmaker-regression who tests js-path #:engine [engine (find-js-engine)])
(write-js-test-file js-path tests)
(cond
[engine
(printf "~a: using JavaScript engine ~a\n" who (describe-engine engine))
(define result (run-js-file engine js-path))
(display (js-run-result-stdout result))
(unless (string=? (js-run-result-stderr result) "")
(display (js-run-result-stderr result) (current-error-port)))
(unless (js-run-result-success? result)
(error who "JavaScript regression failed with ~a; see ~a"
(js-engine-name engine) js-path))]
[else
(if (or (getenv "JSMAKER_REQUIRE_ENGINE") (getenv "JSMAKER_REQUIRE_NODE"))
(begin
(warning-line who "No JavaScript engine was found; regression tests were generated but not executed.")
(warning-line who "Generated JavaScript test file: ~a" js-path)
(warning-line who "Tried engines: ~a" (string-join (map symbol->string (known-js-engine-names)) ", "))
(warning-line who "Set JSMAKER_ENGINE to auto/node/deno/bun/qjs/d8/jsc/js/chromium or set JSMAKER_ENGINE_PATH.")
(warning-line who "For backwards compatibility, JSMAKER_NODE can point to a Node executable.")
(error who "JavaScript engine required by environment setting"))
(begin
(notice-line who "No JavaScript engine was found; using non-failing-javascript-stub.")
(notice-line who "Generated JavaScript test file: ~a" js-path)
(notice-line who "Generated tests were not executed by a JavaScript runtime.")
(notice-line who "Set JSMAKER_REQUIRE_ENGINE=1 to make a missing JavaScript engine fail.")))]))