summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-05-30 10:35:44 +0430
committerLinus Groh <mail@linusgroh.de>2021-05-30 10:34:44 +0100
commitf387da4a901e637b4bb0e8a2c4245f6dc0f31974 (patch)
treeb5aed9bbd6c60dc12b8b63191b88ff66e7508f55
parent724b89f90c859d45ebd66998465549bc99cd313f (diff)
downloadserenity-f387da4a901e637b4bb0e8a2c4245f6dc0f31974.zip
LibTest+test-js: Add back the lost test262 parser test option
Fixes #7566.
-rw-r--r--Tests/LibJS/test-js.cpp62
-rw-r--r--Userland/Libraries/LibTest/JavaScriptTestRunner.h63
-rw-r--r--Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp7
3 files changed, 132 insertions, 0 deletions
diff --git a/Tests/LibJS/test-js.cpp b/Tests/LibJS/test-js.cpp
index 129c2149e4..1927b67a39 100644
--- a/Tests/LibJS/test-js.cpp
+++ b/Tests/LibJS/test-js.cpp
@@ -9,6 +9,8 @@
TEST_ROOT("Userland/Libraries/LibJS/Tests");
+TESTJS_PROGRAM_FLAG(test262_parser_tests, "Run test262 parser tests", "test262-parser-tests", 0);
+
TESTJS_GLOBAL_FUNCTION(is_strict_mode, isStrictMode, 0)
{
return JS::Value(vm.in_strict_mode());
@@ -29,3 +31,63 @@ TESTJS_GLOBAL_FUNCTION(run_queued_promise_jobs, runQueuedPromiseJobs)
vm.run_queued_promise_jobs();
return JS::js_undefined();
}
+
+TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&)
+{
+ if (!test262_parser_tests)
+ return Test::JS::RunFileHookResult::RunAsNormal;
+
+ auto start_time = Test::JS::get_time_in_ms();
+
+ LexicalPath path(test_file);
+ auto& dirname = path.dirname();
+ enum {
+ Early,
+ Fail,
+ Pass,
+ ExplicitPass,
+ } expectation { Pass };
+
+ if (dirname.ends_with("early"))
+ expectation = Early;
+ else if (dirname.ends_with("fail"))
+ expectation = Fail;
+ else if (dirname.ends_with("pass-explicit"))
+ expectation = ExplicitPass;
+ else if (dirname.ends_with("pass"))
+ expectation = Pass;
+ else
+ return Test::JS::RunFileHookResult::SkipFile;
+
+ auto parse_result = Test::JS::parse_file(test_file);
+ bool test_passed = true;
+ String message;
+ String expectation_string;
+
+ switch (expectation) {
+ case Early:
+ case Fail:
+ expectation_string = "File should not parse";
+ test_passed = parse_result.is_error();
+ if (!test_passed)
+ message = "Expected the file to fail parsing, but it did not";
+ break;
+ case Pass:
+ case ExplicitPass:
+ expectation_string = "File should parse";
+ test_passed = !parse_result.is_error();
+ if (!test_passed)
+ message = "Expected the file to parse, but it did not";
+ break;
+ }
+
+ auto test_result = test_passed ? Test::Result::Pass : Test::Result::Fail;
+
+ return Test::JS::JSFileResult {
+ LexicalPath::relative_path(test_file, Test::JS::g_test_root),
+ {},
+ Test::JS::get_time_in_ms() - start_time,
+ test_result,
+ { Test::Suite { "Parse file", test_result, { { expectation_string, test_result, message } } } }
+ };
+}
diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunner.h b/Userland/Libraries/LibTest/JavaScriptTestRunner.h
index 07fcf31f96..de72d809b7 100644
--- a/Userland/Libraries/LibTest/JavaScriptTestRunner.h
+++ b/Userland/Libraries/LibTest/JavaScriptTestRunner.h
@@ -68,9 +68,28 @@
} __testjs_common_register_##name {}; \
void __TestJS_main_hook::hook()
+#define TESTJS_PROGRAM_FLAG(flag, help_string, long_name, short_name) \
+ bool flag { false }; \
+ struct __TestJS_flag_hook_##flag { \
+ __TestJS_flag_hook_##flag() \
+ { \
+ ::Test::JS::g_extra_args.set(&(flag), { help_string, long_name, short_name }); \
+ }; \
+ } __testjs_flag_hook_##flag;
+
#define TEST_ROOT(path) \
String Test::JS::g_test_root_fragment = path
+#define TESTJS_RUN_FILE_FUNCTION(...) \
+ struct __TestJS_run_file { \
+ __TestJS_run_file() \
+ { \
+ ::Test::JS::g_run_file = hook; \
+ } \
+ static ::Test::JS::IntermediateRunFileResult hook(const String&, JS::Interpreter&); \
+ } __testjs_common_run_file {}; \
+ ::Test::JS::IntermediateRunFileResult __TestJS_run_file::hook(__VA_ARGS__)
+
namespace Test::JS {
namespace JS = ::JS;
@@ -96,6 +115,7 @@ extern String g_test_root;
extern int g_test_argc;
extern char** g_test_argv;
extern Function<void()> g_main_hook;
+extern HashMap<bool*, Tuple<String, String, char>> g_extra_args;
struct ParserError {
JS::Parser::Error error;
@@ -113,6 +133,14 @@ struct JSFileResult {
Vector<String> logged_messages {};
};
+enum class RunFileHookResult {
+ RunAsNormal,
+ SkipFile,
+};
+
+using IntermediateRunFileResult = AK::Result<JSFileResult, RunFileHookResult>;
+extern IntermediateRunFileResult (*g_run_file)(const String&, JS::Interpreter&);
+
class TestRunner {
public:
static TestRunner* the()
@@ -302,6 +330,41 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
interpreter->heap().set_should_collect_on_every_allocation(g_collect_on_every_allocation);
+ if (g_run_file) {
+ auto result = g_run_file(test_path, *interpreter);
+ if (result.is_error() && result.error() == RunFileHookResult::SkipFile) {
+ return {
+ test_path,
+ {},
+ 0,
+ Test::Result::Skip,
+ {},
+ {}
+ };
+ }
+ if (!result.is_error()) {
+ auto value = result.release_value();
+ for (auto& suite : value.suites) {
+ if (suite.most_severe_test_result == Result::Pass)
+ m_counts.suites_passed++;
+ else if (suite.most_severe_test_result == Result::Fail)
+ m_counts.suites_failed++;
+ for (auto& test : suite.tests) {
+ if (test.result == Result::Pass)
+ m_counts.tests_passed++;
+ else if (test.result == Result::Fail)
+ m_counts.tests_failed++;
+ else if (test.result == Result::Skip)
+ m_counts.tests_skipped++;
+ }
+ }
+ ++m_counts.files_total;
+ m_total_elapsed_time_in_ms += value.time_taken;
+
+ return value;
+ }
+ }
+
if (!m_test_program) {
auto result = parse_file(m_common_path);
if (result.is_error()) {
diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp b/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp
index 64d3c19e0b..604327bb6e 100644
--- a/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp
+++ b/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp
@@ -18,6 +18,8 @@ String g_currently_running_test;
String g_test_glob;
HashMap<String, FunctionWithLength> s_exposed_global_functions;
Function<void()> g_main_hook;
+HashMap<bool*, Tuple<String, String, char>> g_extra_args;
+IntermediateRunFileResult (*g_run_file)(const String&, JS::Interpreter&) = nullptr;
TestRunner* TestRunner::s_the = nullptr;
String g_test_root;
int g_test_argc;
@@ -100,6 +102,8 @@ int main(int argc, char** argv)
});
args_parser.add_option(g_collect_on_every_allocation, "Collect garbage after every allocation", "collect-often", 'g');
args_parser.add_option(g_test_glob, "Only run tests matching the given glob", "filter", 'f', "glob");
+ for (auto& entry : g_extra_args)
+ args_parser.add_option(*entry.key, entry.value.get<0>().characters(), entry.value.get<1>().characters(), entry.value.get<2>());
args_parser.add_positional_argument(specified_test_root, "Tests root directory", "path", Core::ArgsParser::Required::No);
args_parser.add_positional_argument(common_path, "Path to tests-common.js", "common-path", Core::ArgsParser::Required::No);
args_parser.parse(argc, argv);
@@ -145,6 +149,9 @@ int main(int argc, char** argv)
#endif
}
+ test_root = Core::File::real_path_for(test_root);
+ common_path = Core::File::real_path_for(common_path);
+
if (chdir(test_root.characters()) < 0) {
auto saved_errno = errno;
warnln("chdir failed: {}", strerror(saved_errno));