1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-24 21:45:08 +00:00

LibJS+LibTest: Use JS::Script and JS::SourceTextModule in test-js

Instead of creating a Parser and Lexer manually in test-js, we now
use either JS::Script::parse() or JS::SourceTextModule::parse()
to load tests.
This commit is contained in:
Andreas Kling 2021-09-14 20:58:33 +02:00
parent 10c489713d
commit 0a09eaf3a1
2 changed files with 49 additions and 29 deletions

View file

@ -94,7 +94,7 @@ TESTJS_GLOBAL_FUNCTION(mark_as_garbage, markAsGarbage)
return JS::js_undefined(); return JS::js_undefined();
} }
TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&) TESTJS_RUN_FILE_FUNCTION(String const& test_file, JS::Interpreter& interpreter)
{ {
if (!test262_parser_tests) if (!test262_parser_tests)
return Test::JS::RunFileHookResult::RunAsNormal; return Test::JS::RunFileHookResult::RunAsNormal;
@ -122,8 +122,12 @@ TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&)
return Test::JS::RunFileHookResult::SkipFile; return Test::JS::RunFileHookResult::SkipFile;
auto program_type = path.basename().ends_with(".module.js") ? JS::Program::Type::Module : JS::Program::Type::Script; auto program_type = path.basename().ends_with(".module.js") ? JS::Program::Type::Module : JS::Program::Type::Script;
bool parse_succeeded = false;
if (program_type == JS::Program::Type::Module)
parse_succeeded = !Test::JS::parse_module(test_file, interpreter.realm()).is_error();
else
parse_succeeded = !Test::JS::parse_script(test_file, interpreter.realm()).is_error();
auto parse_result = Test::JS::parse_file(test_file, program_type);
bool test_passed = true; bool test_passed = true;
String message; String message;
String expectation_string; String expectation_string;
@ -132,14 +136,14 @@ TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&)
case Early: case Early:
case Fail: case Fail:
expectation_string = "File should not parse"; expectation_string = "File should not parse";
test_passed = parse_result.is_error(); test_passed = !parse_succeeded;
if (!test_passed) if (!test_passed)
message = "Expected the file to fail parsing, but it did not"; message = "Expected the file to fail parsing, but it did not";
break; break;
case Pass: case Pass:
case ExplicitPass: case ExplicitPass:
expectation_string = "File should parse"; expectation_string = "File should parse";
test_passed = !parse_result.is_error(); test_passed = parse_succeeded;
if (!test_passed) if (!test_passed)
message = "Expected the file to parse, but it did not"; message = "Expected the file to parse, but it did not";
break; break;

View file

@ -29,6 +29,8 @@
#include <LibJS/Runtime/TypedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/WeakMap.h> #include <LibJS/Runtime/WeakMap.h>
#include <LibJS/Runtime/WeakSet.h> #include <LibJS/Runtime/WeakSet.h>
#include <LibJS/Script.h>
#include <LibJS/SourceTextModule.h>
#include <LibTest/Results.h> #include <LibTest/Results.h>
#include <LibTest/TestRunner.h> #include <LibTest/TestRunner.h>
#include <fcntl.h> #include <fcntl.h>
@ -169,7 +171,7 @@ protected:
void print_file_result(const JSFileResult& file_result) const; void print_file_result(const JSFileResult& file_result) const;
String m_common_path; String m_common_path;
RefPtr<JS::Program> m_test_program; RefPtr<JS::Script> m_test_script;
}; };
class TestRunnerGlobalObject final : public JS::GlobalObject { class TestRunnerGlobalObject final : public JS::GlobalObject {
@ -195,28 +197,42 @@ inline void TestRunnerGlobalObject::initialize_global_object()
} }
} }
inline AK::Result<NonnullRefPtr<JS::Program>, ParserError> parse_file(const String& file_path, JS::Program::Type program_type = JS::Program::Type::Script) inline ByteBuffer load_entire_file(StringView path)
{ {
auto file = Core::File::construct(file_path); auto file_or_error = Core::File::open(path, Core::OpenMode::ReadOnly);
auto result = file->open(Core::OpenMode::ReadOnly); if (file_or_error.is_error()) {
if (!result) { warnln("Failed to open the following file: \"{}\"", path);
warnln("Failed to open the following file: \"{}\"", file_path);
cleanup_and_exit(); cleanup_and_exit();
} }
auto contents = file->read_all(); auto file = file_or_error.release_value();
String test_file_string(reinterpret_cast<const char*>(contents.data()), contents.size()); return file->read_all();
file->close(); }
auto parser = JS::Parser(JS::Lexer(test_file_string), program_type); inline AK::Result<NonnullRefPtr<JS::Script>, ParserError> parse_script(StringView path, JS::Realm& realm)
auto program = parser.parse_program(); {
auto contents = load_entire_file(path);
auto script_or_errors = JS::Script::parse(contents, realm, path);
if (parser.has_errors()) { if (script_or_errors.is_error()) {
auto error = parser.errors()[0]; auto errors = script_or_errors.release_error();
return AK::Result<NonnullRefPtr<JS::Program>, ParserError>(ParserError { error, error.source_location_hint(test_file_string) }); return ParserError { errors[0], errors[0].source_location_hint(contents) };
} }
return AK::Result<NonnullRefPtr<JS::Program>, ParserError>(program); return script_or_errors.release_value();
}
inline AK::Result<NonnullRefPtr<JS::SourceTextModule>, ParserError> parse_module(StringView path, JS::Realm& realm)
{
auto contents = load_entire_file(path);
auto script_or_errors = JS::SourceTextModule::parse(contents, realm, path);
if (script_or_errors.is_error()) {
auto errors = script_or_errors.release_error();
return ParserError { errors[0], errors[0].source_location_hint(contents) };
}
return script_or_errors.release_value();
} }
inline Optional<JsonValue> get_test_results(JS::Interpreter& interpreter) inline Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
@ -304,19 +320,19 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
} }
} }
if (!m_test_program) { if (!m_test_script) {
auto result = parse_file(m_common_path); auto result = parse_script(m_common_path, interpreter->realm());
if (result.is_error()) { if (result.is_error()) {
warnln("Unable to parse test-common.js"); warnln("Unable to parse test-common.js");
warnln("{}", result.error().error.to_string()); warnln("{}", result.error().error.to_string());
warnln("{}", result.error().hint); warnln("{}", result.error().hint);
cleanup_and_exit(); cleanup_and_exit();
} }
m_test_program = result.value(); m_test_script = result.release_value();
} }
if (g_run_bytecode) { if (g_run_bytecode) {
auto unit = JS::Bytecode::Generator::generate(*m_test_program); auto unit = JS::Bytecode::Generator::generate(m_test_script->parse_node());
if (g_dump_bytecode) { if (g_dump_bytecode) {
for (auto& block : unit.basic_blocks) for (auto& block : unit.basic_blocks)
block.dump(unit); block.dump(unit);
@ -329,16 +345,16 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm()); JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm());
bytecode_interpreter.run(unit); bytecode_interpreter.run(unit);
} else { } else {
interpreter->run(interpreter->global_object(), *m_test_program); interpreter->run(interpreter->global_object(), m_test_script->parse_node());
} }
VERIFY(!g_vm->exception()); VERIFY(!g_vm->exception());
auto file_program = parse_file(test_path); auto file_script = parse_script(test_path, interpreter->realm());
if (file_program.is_error()) if (file_script.is_error())
return { test_path, file_program.error() }; return { test_path, file_script.error() };
if (g_run_bytecode) { if (g_run_bytecode) {
auto unit = JS::Bytecode::Generator::generate(*file_program.value()); auto unit = JS::Bytecode::Generator::generate(file_script.value()->parse_node());
if (g_dump_bytecode) { if (g_dump_bytecode) {
for (auto& block : unit.basic_blocks) for (auto& block : unit.basic_blocks)
block.dump(unit); block.dump(unit);
@ -351,7 +367,7 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm()); JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm());
bytecode_interpreter.run(unit); bytecode_interpreter.run(unit);
} else { } else {
interpreter->run(interpreter->global_object(), *file_program.value()); interpreter->run(interpreter->global_object(), file_script.value()->parse_node());
} }
if (g_vm->exception()) if (g_vm->exception())