Alles aangepast.

This commit is contained in:
2026-06-08 12:55:08 +02:00
parent a9610e6e0c
commit 823130e3ac
24 changed files with 418 additions and 2621 deletions
+48 -89
View File
@@ -1,98 +1,57 @@
#lang racket/base
(require racket/format
(require rackunit
racket/string
"jsmaker-executors.rkt")
racket/file
racket/system)
(provide js-expression-test
js-program-test
write-js-test-file
run-jsmaker-regression
notice-line
warning-line)
(provide check-js-equal?
check-js-contains?
check-js-matches?
node-available?
run-js/trimmed)
(define (notice-line who fmt . args)
(displayln (string-append "NOTE: " (apply format fmt args))))
(define-check (check-js-equal? actual expected)
(check-equal? actual expected))
(define (warning-line who fmt . args)
(displayln (string-append "WARNING: " (apply format fmt args))
(current-error-port)))
(define-check (check-js-contains? actual needle)
(check-true (string-contains? actual needle)
(format "expected generated JavaScript to contain ~s, got:\n~a" needle actual)))
(define (js-expression-test name expr expected)
(list name expr expected))
(define-check (check-js-matches? actual pattern)
(check-true (regexp-match? pattern actual)
(format "expected generated JavaScript to match ~s, got:\n~a" pattern actual)))
(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 (node-available?)
(and (find-executable-path "node") #t))
(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.")))]))
(define (run-js/trimmed program)
(define node (find-executable-path "node"))
(unless node
(error 'run-js/trimmed "node is not available"))
(define source-path (make-temporary-file "js-maker-test-~a.js"))
(define out-path (make-temporary-file "js-maker-test-out-~a.txt"))
(define err-path (make-temporary-file "js-maker-test-err-~a.txt"))
(dynamic-wind
void
(lambda ()
(call-with-output-file source-path #:exists 'truncate
(lambda (out) (display program out)))
(define exit-code
(call-with-output-file out-path #:exists 'truncate
(lambda (out)
(call-with-output-file err-path #:exists 'truncate
(lambda (err)
(parameterize ([current-output-port out]
[current-error-port err])
(system*/exit-code node source-path)))))))
(define stdout (file->string out-path))
(define stderr (file->string err-path))
(unless (zero? exit-code)
(error 'run-js/trimmed
"node failed with exit code ~a\nstdout:\n~a\nstderr:\n~a\nprogram:\n~a"
exit-code stdout stderr program))
(string-trim stdout))
(lambda ()
(for ([path (list source-path out-path err-path)])
(with-handlers ([exn:fail? void]) (delete-file path))))))