diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-05-30 10:35:44 +0430 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-05-30 10:34:44 +0100 |
commit | f387da4a901e637b4bb0e8a2c4245f6dc0f31974 (patch) | |
tree | b5aed9bbd6c60dc12b8b63191b88ff66e7508f55 | |
parent | 724b89f90c859d45ebd66998465549bc99cd313f (diff) | |
download | serenity-f387da4a901e637b4bb0e8a2c4245f6dc0f31974.zip |
LibTest+test-js: Add back the lost test262 parser test option
Fixes #7566.
-rw-r--r-- | Tests/LibJS/test-js.cpp | 62 | ||||
-rw-r--r-- | Userland/Libraries/LibTest/JavaScriptTestRunner.h | 63 | ||||
-rw-r--r-- | Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp | 7 |
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)); |