Skip to content

Instantly share code, notes, and snippets.

@avih
Created April 18, 2021 03:23
Show Gist options
  • Save avih/d4765c2d39d487737134682dbb08cf70 to your computer and use it in GitHub Desktop.
Save avih/d4765c2d39d487737134682dbb08cf70 to your computer and use it in GitHub Desktop.
mujs test-262 patchset - on top of mujs dcb3f03 (after 1.0.4 and before 1.0.5)
From 7297871b882483e748946cb7156244be2da9e752 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <[email protected]>
Date: Thu, 30 Aug 2018 16:24:24 +0300
Subject: [PATCH 1/4] mujs shell: Add compile function.
The new compile function compiles a source code string as a script and
returns a callable object. The optional 'filename' argument is used to
format error messages and stack traces.
---
main.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/main.c b/main.c
index cbc7edc..ef343a7 100644
--- a/main.c
+++ b/main.c
@@ -98,6 +98,13 @@ static void jsB_load(js_State *J)
js_pushboolean(J, !rv);
}
+static void jsB_compile(js_State *J)
+{
+ const char *source = js_tostring(J, 1);
+ const char *filename = js_isdefined(J, 2) ? js_tostring(J, 2) : "[string]";
+ js_loadstring(J, filename, source);
+}
+
static void jsB_print(js_State *J)
{
int i, top = js_gettop(J);
@@ -288,6 +295,9 @@ main(int argc, char **argv)
js_newcfunction(J, jsB_load, "load", 1);
js_setglobal(J, "load");
+ js_newcfunction(J, jsB_compile, "compile", 2);
+ js_setglobal(J, "compile");
+
js_newcfunction(J, jsB_print, "print", 0);
js_setglobal(J, "print");
--
2.25.1
From ac4b326b45c4fa36dbad4ebbc5d2da485b908006 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <[email protected]>
Date: Sun, 2 Sep 2018 23:41:06 +0300
Subject: [PATCH 2/4] tools: add test262-harness.js to run a single test
Usage: mujs <this-file> -- [-f] [-l file1.js -l ...] suit-root test-file
-f: print full paths/stacktraces if possible
-l: load a js file after the harness and before the test (to override things)
---
tools/test262-harness.js | 135 +++++++++++++++++++++++++++++++++++++++
1 file changed, 135 insertions(+)
create mode 100644 tools/test262-harness.js
diff --git a/tools/test262-harness.js b/tools/test262-harness.js
new file mode 100644
index 0000000..3722634
--- /dev/null
+++ b/tools/test262-harness.js
@@ -0,0 +1,135 @@
+/*
+ * Runs one test file from the ES5 test suite test-262
+ * Usage: mujs <this-file> [-f] [-l file1.js -l ...] suit-root test-file
+ * -f: print full paths/stacktraces if possible
+ * -l: load a js file after the harness and before the test (to override things)
+ *
+ * If there are errors, print them and exits with code 1, else exit code is 0.
+ *
+ * The test suite is at: https://github.com/tc39/test262.git
+ * The ES5 suite is at branch "es5-tests"
+ *
+ * - The test suite throws on any error, possibly with info at ex.message .
+ * - Some tests make irreversible changes to global attrubutes, therefore it's
+ * required to run each test file in a new mujs instance.
+ */
+
+(function(global) {
+ "use strict";
+
+ // clean the global environment
+ var mujs = {};
+
+ ["gc", "load", "compile", "print", "write", "read", "readline", "quit", "scriptArgs"]
+ .forEach(function(a) {
+ mujs[a] = global[a];
+ delete global[a];
+ });
+
+ // restore the original Error.toString behavior - it's being tested too
+ Error.prototype.toString = function() {
+ return this.name + ': ' + this.message;
+ }
+
+ function die_usage(str) {
+ if (str)
+ mujs.print(str);
+ mujs.print("Usage: mujs <this-file> [-f] [-l file1.js -l ...] suit-root test-file");
+ mujs.quit(1);
+ }
+
+ // our file loader
+ function load(str, as_filename) {
+ try {
+ var runtime_err = false;
+ var compiled = mujs.compile(str, as_filename);
+ runtime_err = true;
+ compiled();
+ return false;
+ } catch (e) {
+ return {err: e, runtime: runtime_err};
+ }
+ }
+
+ var args = mujs.scriptArgs;
+ var full_mode = false;
+ var overrides = [];
+ while ((""+args[0])[0] == "-") {
+ switch (args[0]) {
+ case "-f": full_mode = true;
+ break;
+ case "-l": args.shift();
+ overrides.push(args[0]);
+ break;
+ default: die_usage("Unknown option " + args[0]);
+ }
+ args.shift();
+ }
+ if (args.length != 2)
+ die_usage("Exactly 2 paths are expected");
+ var root_path = args[0];
+ var test_path = args[1];
+
+ // load suite utils
+ ["sta.js", "testBuiltInObject.js", "testIntl.js"]
+ .forEach(function(u) {
+ var path = root_path + "/test/harness/" + u;
+ var as_file = full_mode ? path : "test/harness/" + u;
+ var err = load(mujs.read(path), as_file);
+ if (err) throw (err.err);
+ });
+
+ // load user overrides (e.g. reduced getPrecision), with a global mujs
+ if (overrides.length) {
+ global.mujs = mujs
+ overrides.forEach(function(f) {
+ var err = load(mujs.read(f), f);
+ if (err) throw (err.err);
+ });
+ delete global.mujs;
+ }
+
+ // the actual test
+ var source = mujs.read(test_path);
+ var negative = !!source.match(/@negative/);
+ var as_file = test_path;
+ if (!full_mode) {
+ as_file = test_path.replace(/\\/g, "/");
+ var sub = as_file.indexOf("/suite/");
+ if (sub >= 0)
+ as_file = "test" + as_file.substring(sub);
+ }
+
+ var result = load(mujs.read(test_path), as_file);
+ if (!!result == negative)
+ mujs.quit(0);
+
+ // failed
+ var desc = source.match(/@description (.*)/);
+ var info = "[File] " + as_file +
+ (desc ? "\n[Desc] " + desc[1] : "") +
+ "\n";
+
+ if (result) {
+ var err = result.err;
+ info += (result.runtime ? "[run] " : "[load] ") + err;
+ if (err && err.stackTrace && (result.runtime || full_mode)) {
+ if (full_mode) {
+ info += err.stackTrace;
+ } else {
+ // trim the internal loader from the trace
+ var internal = err.stackTrace.indexOf("\n" + load("mujs_blahblah()").err.stackTrace.trim().split("\n")[1]);
+ if (internal >= 0)
+ info += err.stackTrace.substring(0, internal);
+ else
+ info += err.stackTrace;
+ }
+ }
+ } else {
+ info += "[run] [Error expected but none thrown]";
+ }
+
+ mujs.print(info);
+ mujs.quit(1);
+
+})(this)
--
2.25.1
From f57fe789d7b89916fc5c6d5935ec391b6feba026 Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <[email protected]>
Date: Sun, 2 Sep 2018 23:42:06 +0300
Subject: [PATCH 3/4] tools: add test-262 launcher
It can run the entire suite or just a sub-folder or one file, and by
default it skips tests which are known to crash/hang.
---
tools/test262 | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100755 tools/test262
diff --git a/tools/test262 b/tools/test262
new file mode 100755
index 0000000..6f5d6dc
--- /dev/null
+++ b/tools/test262
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+usage() {
+ [ "${1-}" ] && { to=2; >&$to printf "Error: %s\n" "$1"; } || to=1
+ >&$to echo "Usage: $(basename "$0") [+s] [-p] [-f] [-l f1.js -l ..] test-file | test-dir"
+ >&$to echo "Run test-262 ES5 test file[s]."
+ >&$to echo " +s : Don't skip known crashing/hanging tests"
+ >&$to echo " -p : Print every test name before running it"
+ >&$to echo " -f : Display full paths and full stack trace when possible"
+ >&$to echo " -l file.js : load file.js after the harness and before the test"
+ exit $((to-1))
+}
+
+KNOWN_BAD="
+ --hang-with-sta.js:
+ S15.1.3.2_A2.5_T1.js
+ S15.1.3.1_A2.5_T1.js
+
+ --Hang-(or-taking-more-than-few-seconds):
+ 15.4.4.18-3-14.js
+ 15.4.4.20-3-14.js
+ S15.4.4.10_A3_T2.js
+ S15.4.4.10_A3_T1.js
+ 15.4.4.19-3-29.js
+ 15.4.4.19-3-28.js
+ 15.4.4.19-3-8.js
+ 15.4.4.19-3-14.js
+ S15.4.4.8_A3_T3.js
+ 15.4.4.22-3-9.js
+ 15.4.4.22-3-12.js
+ 15.4.4.22-3-7.js
+ 15.4.4.22-3-25.js
+ 15.4.4.22-3-14.js
+ 15.4.4.21-3-14.js
+ 15.4.4.15-3-28.js
+ 15.4.4.15-3-12.js
+ 15.4.4.15-3-14.js
+ 15.4.4.15-3-7.js
+ 15.4.4.15-3-25.js
+ 15.4.4.15-3-9.js
+
+ --Buffer-overflow/abort:
+ S15.7.4.5_A1.4_T01.js
+
+ --Segfault:
+ S15.4.4.5_A2_T2.js
+ S15.4.4.5_A4_T3.js
+"
+
+SKIP_KNOWN=yes
+PRINT_ALL=
+EXTRA_ARGS=
+while [ "${1-}" ] && [ -z "${1##-*}" ]; do
+ case $1 in
+ -h|--help) usage ;;
+ +s) SKIP_KNOWN= ;;
+ -p) PRINT_ALL=yes ;;
+ -f) EXTRA_ARGS="$EXTRA_ARGS -f" ;;
+ -l) EXTRA_ARGS="$EXTRA_ARGS -l $2"; shift ;;
+ *) usage "unknown option $1" ;;
+ esac
+ shift
+done
+[ $# = 1 ] || usage "expecting one file/dir"
+
+BAD=
+if [ "$SKIP_KNOWN" ]; then
+ for b in $KNOWN_BAD; do
+ BAD="$BAD $b "
+ done
+fi
+
+find_root() {
+ ROOT=$1
+ n=0
+ while ! [ -e "$ROOT"/test/harness/sta.js ]; do
+ ROOT=$ROOT/..
+ n=$((n+1))
+ [ $n -lt 10 ] || usage "can't find test-suite root"
+ done
+}
+
+if [ -d "$1" ]; then
+ find_root "$1"
+
+ if [ "$ROOT" = "$1" ]; then
+ FILES_CMD='find "$1/test/suite" -name "*.js" | sort -V'
+ else
+ FILES_CMD='find "$1" -name "*.js" | sort -V'
+ fi
+else
+ find_root "$(dirname "$1")"
+ FILES_CMD='printf "%s\n" "$1"'
+fi
+
+# try to use a recently built mujs rather than a global one
+mujs=$(dirname "$0")/../build/release/mujs
+[ -e "$mujs" ] || mujs=mujs
+jsharness=$(dirname "$0")/test262-harness.js
+
+total=0
+skipped=0
+failed=0
+
+eval "$FILES_CMD" | (
+ while read f && [ "$f" ]; do
+ total=$((total+1))
+ base=${f##*/}
+ [ "$PRINT_ALL" ] && echo "Testing: $f"
+
+ case $BAD in
+ *" $base "*)
+ skipped=$((skipped+1))
+ printf "[Skipping: $base]\n\n"
+ ;;
+ *)
+ if ! $mujs $jsharness $EXTRA_ARGS "$ROOT" $f; then
+ failed=$((failed+1))
+ echo
+ fi
+ esac
+ done
+
+ if [ $total -gt 1 ]; then
+ printf "Total: $total\n"
+ printf "Pass: %${#total}s\n" $((total - skipped - failed))
+ printf "Skip: %${#total}s\n" $skipped
+ printf "Fail: %${#total}s\n" $failed
+ fi
+) 2>&1
--
2.25.1
From 263dafed5787d50bb1ba7cc1918c65070fa5584b Mon Sep 17 00:00:00 2001
From: "Avi Halachmi (:avih)" <[email protected]>
Date: Tue, 4 Sep 2018 15:36:05 +0300
Subject: [PATCH 4/4] test262-harness: @negative: match regex if exists
Some @negative tests add a regex which needs to match the error.
This wasn't tested, and now it is. This results in few more failures.
The actual string to compare is not documented, but it appears to be
err.message for plain Error(..) where the message is always compared
to "NotEarlyError" (equals/different), and err.name for anything else.
---
tools/test262-harness.js | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/tools/test262-harness.js b/tools/test262-harness.js
index 3722634..0a0f765 100644
--- a/tools/test262-harness.js
+++ b/tools/test262-harness.js
@@ -92,6 +92,8 @@
// the actual test
var source = mujs.read(test_path);
var negative = !!source.match(/@negative/);
+ if (negative)
+ var neg_str = (source.match(/@negative (.*)/) || [])[1];
var as_file = test_path;
if (!full_mode) {
as_file = test_path.replace(/\\/g, "/");
@@ -101,8 +103,13 @@
}
var result = load(mujs.read(test_path), as_file);
- if (!!result == negative)
- mujs.quit(0);
+ if (!!result == negative) {
+ // The docs don't really help about matching str, but this covers all cases
+ if (neg_str)
+ var err_for_match = /NotEarlyError/.test(neg_str) ? result.err.message : result.err.name;
+ if (!negative || !neg_str || RegExp(neg_str).exec(err_for_match))
+ mujs.quit(0);
+ }
// failed
var desc = source.match(/@description (.*)/);
@@ -112,7 +119,9 @@
if (result) {
var err = result.err;
- info += (result.runtime ? "[run] " : "[load] ") + err;
+ var msg = !neg_str ? err : "[Mismatch @negative " + neg_str + "]" + "\n " + err;
+
+ info += (result.runtime ? "[run] " : "[load] ") + msg;
if (err && err.stackTrace && (result.runtime || full_mode)) {
if (full_mode) {
info += err.stackTrace;
--
2.25.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment