Ver código fonte

LibTest+Spreadsheet: Add some basic spreadsheet runtime behaviour tests

As there's a somewhat active development going on, let's keep the
expected behaviour under tests to make sure nothing blows up :^)
Ali Mohammad Pur 3 anos atrás
pai
commit
bed129a69f

+ 3 - 0
Base/home/anon/.config/Tests.ini

@@ -6,3 +6,6 @@ NotTestsPattern=^.*(txt|frm|inc)$
 
 [test-js]
 Arguments=--show-progress=false
+
+[test-spreadsheet]
+Arguments=--show-progress=false

+ 13 - 0
Meta/Lagom/CMakeLists.txt

@@ -625,6 +625,19 @@ if (BUILD_LAGOM)
         lagom_test(../../Tests/LibJS/test-invalid-unicode-js.cpp LIBS LagomJS)
         lagom_test(../../Tests/LibJS/test-bytecode-js.cpp LIBS LagomJS)
 
+        # Spreadsheet
+        add_executable(test-spreadsheet_lagom
+                ../../Tests/Spreadsheet/test-spreadsheet.cpp
+                ../../Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp)
+        set_target_properties(test-spreadsheet_lagom PROPERTIES OUTPUT_NAME test-spreadsheet)
+        target_link_libraries(test-spreadsheet_lagom LagomCore LagomTest LagomJS)
+        add_test(
+                NAME Spreadsheet
+                COMMAND test-spreadsheet_lagom --show-progress=false
+        )
+        set_tests_properties(Spreadsheet PROPERTIES ENVIRONMENT SERENITY_SOURCE_DIR=${SERENITY_PROJECT_ROOT})
+
+
         # Markdown
         include(commonmark_spec)
         file(GLOB LIBMARKDOWN_TEST_SOURCES CONFIGURE_DEPENDS "../../Tests/LibMarkdown/*.cpp")

+ 1 - 0
Meta/build-root-filesystem.sh

@@ -165,6 +165,7 @@ cp -r "$SERENITY_SOURCE_DIR"/Userland/Libraries/LibCpp/Tests/parser mnt/home/ano
 cp -r "$SERENITY_SOURCE_DIR"/Userland/Libraries/LibCpp/Tests/preprocessor mnt/home/anon/cpp-tests/preprocessor
 cp -r "$SERENITY_SOURCE_DIR"/Userland/Libraries/LibWasm/Tests mnt/home/anon/wasm-tests
 cp -r "$SERENITY_SOURCE_DIR"/Userland/Libraries/LibJS/Tests/test-common.js mnt/home/anon/wasm-tests
+cp -r "$SERENITY_SOURCE_DIR"/Userland/Applications/Spreadsheet/Tests mnt/home/anon/spreadsheet-tests
 
 if [ -n "$SERENITY_COPY_SOURCE" ] ; then
   printf "\ncopying Serenity's source... "

+ 1 - 0
Tests/CMakeLists.txt

@@ -27,3 +27,4 @@ if (${SERENITY_ARCH} STREQUAL "i686")
 endif()
 add_subdirectory(LibCrypto)
 add_subdirectory(LibTLS)
+add_subdirectory(Spreadsheet)

+ 1 - 1
Tests/LibJS/test-js.cpp

@@ -76,7 +76,7 @@ TESTJS_GLOBAL_FUNCTION(mark_as_garbage, markAsGarbage)
     return JS::js_undefined();
 }
 
-TESTJS_RUN_FILE_FUNCTION(String const& test_file, JS::Interpreter& interpreter)
+TESTJS_RUN_FILE_FUNCTION(String const& test_file, JS::Interpreter& interpreter, JS::ExecutionContext&)
 {
     if (!test262_parser_tests)
         return Test::JS::RunFileHookResult::RunAsNormal;

+ 3 - 0
Tests/Spreadsheet/CMakeLists.txt

@@ -0,0 +1,3 @@
+serenity_testjs_test(test-spreadsheet.cpp test-spreadsheet)
+install(TARGETS test-spreadsheet RUNTIME DESTINATION bin OPTIONAL)
+link_with_unicode_data(test-spreadsheet)

+ 44 - 0
Tests/Spreadsheet/test-spreadsheet.cpp

@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Map.h>
+#include <LibTest/JavaScriptTestRunner.h>
+
+TEST_ROOT("Userland/Applications/Spreadsheet/Tests");
+
+#ifdef __serenity__
+static constexpr auto s_spreadsheet_runtime_path = "/res/js/Spreadsheet/runtime.js"sv;
+#else
+static constexpr auto s_spreadsheet_runtime_path = "../../../../Base/res/js/Spreadsheet/runtime.js"sv;
+#endif
+
+TESTJS_RUN_FILE_FUNCTION(String const&, JS::Interpreter& interpreter, JS::ExecutionContext& global_execution_context)
+{
+    auto run_file = [&](StringView name) {
+        auto result = Test::JS::parse_script(name, interpreter.realm());
+        if (result.is_error()) {
+            warnln("Unable to parse {}", name);
+            warnln("{}", result.error().error.to_string());
+            warnln("{}", result.error().hint);
+            Test::cleanup_and_exit();
+        }
+        auto script = result.release_value();
+
+        interpreter.vm().push_execution_context(global_execution_context, interpreter.realm().global_object());
+        MUST(interpreter.run(*script));
+        interpreter.vm().pop_execution_context();
+    };
+
+#ifdef __serenity__
+    run_file(s_spreadsheet_runtime_path);
+#else
+    run_file(LexicalPath::join(Test::JS::g_test_root, s_spreadsheet_runtime_path).string());
+#endif
+
+    run_file("mock.test-common.js");
+
+    return Test::JS::RunFileHookResult::RunAsNormal;
+}

+ 97 - 0
Userland/Applications/Spreadsheet/Tests/basic.js

@@ -0,0 +1,97 @@
+describe("Position", () => {
+    test("here", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "Sheet 1");
+        sheet.makeCurrent();
+
+        sheet.setCell("A", 0, "0");
+        sheet.focusCell("A", 0);
+
+        expect(here).toBeDefined();
+        let position = here();
+        expect(position).toBeDefined();
+
+        expect(position.column).toEqual("A");
+        expect(position.name).toEqual("A0");
+        expect(position.row).toEqual(0);
+        expect(position.sheet).toBe(sheet);
+
+        expect(position.contents).toEqual("0");
+        expect(position.value()).toEqual("0");
+        expect(position.toString()).toEqual("<Cell at A0>");
+
+        position.contents = "=1 + 1";
+        expect(position.contents).toEqual("=1 + 1");
+        expect(position.value()).toEqual(2);
+
+        expect(position.up().row).toEqual(0);
+        expect(position.down().row).toEqual(1);
+        expect(position.right().row).toEqual(0);
+        expect(position.left().row).toEqual(0);
+
+        sheet.addColumn("B");
+        expect(position.up().column).toEqual("A");
+        expect(position.down().column).toEqual("A");
+        expect(position.right().column).toEqual("B");
+        expect(position.left().column).toEqual("A");
+    });
+
+    test("Position.from_name", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "Sheet 1");
+        sheet.makeCurrent();
+
+        sheet.setCell("A", 0, "0");
+        sheet.focusCell("A", 0);
+
+        expect(Position.from_name).toBeDefined();
+        let position = Position.from_name("A0");
+        expect(position).toBeInstanceOf(Position);
+
+        position = Position.from_name("A123");
+        expect(position).toBeInstanceOf(Position);
+    });
+});
+
+describe("Range", () => {
+    test("simple", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "Sheet 1");
+        sheet.makeCurrent();
+
+        sheet.setCell("A", 0, "0");
+        sheet.setCell("A", 10, "0");
+        sheet.setCell("B", 1, "0");
+        sheet.focusCell("A", 0);
+
+        expect(R).toBeDefined();
+        let cellsVisited = 0;
+        R`A0:A10`.forEach(name => {
+            ++cellsVisited;
+        });
+        expect(cellsVisited).toEqual(11);
+
+        cellsVisited = 0;
+        R`A0:A10:1:2`.forEach(name => {
+            ++cellsVisited;
+        });
+        expect(cellsVisited).toEqual(6);
+    });
+
+    test("Ranges", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "Sheet 1");
+        sheet.makeCurrent();
+
+        sheet.setCell("A", 0, "0");
+        sheet.setCell("A", 10, "0");
+        sheet.setCell("B", 1, "0");
+        sheet.focusCell("A", 0);
+
+        let cellsVisited = 0;
+        R`A0:A5`.union(R`A6:A10`).forEach(name => {
+            ++cellsVisited;
+        });
+        expect(cellsVisited).toEqual(11);
+    });
+});

+ 166 - 0
Userland/Applications/Spreadsheet/Tests/free-functions.js

@@ -0,0 +1,166 @@
+describe("Basic functions", () => {
+    const workbook = createWorkbook();
+    const sheet = createSheet(workbook, "Sheet 1");
+    sheet.makeCurrent();
+
+    sheet.setCell("A", 0, "0");
+    sheet.setCell("A", 1, "1");
+    sheet.setCell("A", 2, "2");
+
+    test("select", () => {
+        expect(select).toBeDefined();
+        expect(select(true, 1, 2)).toBe(1);
+        expect(select(false, 1, 2)).toBe(2);
+    });
+
+    test("choose", () => {
+        expect(choose).toBeDefined();
+        expect(choose(0, 1, 2, 3)).toBe(1);
+        expect(choose(1, 1, 2, 3)).toBe(2);
+        expect(choose(3, 1, 2, 3)).toBeUndefined();
+        expect(choose(-1, 1, 2, 3)).toBeUndefined();
+    });
+
+    test("now", () => {
+        expect(now).toBeDefined();
+        expect(now()).toBeInstanceOf(Date);
+    });
+
+    test("randRange", () => {
+        expect(randRange).toBeDefined();
+    });
+
+    test("integer", () => {
+        expect(integer).toBeDefined();
+        expect(integer("0")).toEqual(0);
+        expect(integer("32")).toEqual(32);
+    });
+
+    test("sheet", () => {
+        expect(globalThis.sheet).toBeDefined();
+        expect(globalThis.sheet("Sheet 1")).toBe(sheet);
+        expect(globalThis.sheet("Not a sheet")).toBeUndefined();
+    });
+
+    test("reduce", () => {
+        expect(reduce).toBeDefined();
+        expect(reduce(acc => acc + 1, 0, [1, 2, 3, 4])).toEqual(4);
+        expect(reduce(acc => acc + 1, 0, [])).toEqual(0);
+    });
+
+    test("numericReduce", () => {
+        expect(numericReduce).toBeDefined();
+        expect(numericReduce(acc => acc + 1, 0, [1, 2, 3, 4])).toEqual(4);
+        expect(numericReduce(acc => acc + 1, 0, [])).toEqual(0);
+    });
+
+    test("numericResolve", () => {
+        expect(numericResolve).toBeDefined();
+        expect(numericResolve(["A0", "A1", "A2"])).toEqual([0, 1, 2]);
+        expect(numericResolve([])).toEqual([]);
+    });
+
+    test("resolve", () => {
+        expect(resolve).toBeDefined();
+        expect(resolve(["A0", "A1", "A2"])).toEqual(["0", "1", "2"]);
+        expect(resolve([])).toEqual([]);
+    });
+});
+
+describe("Statistics", () => {
+    const workbook = createWorkbook();
+    const sheet = createSheet(workbook, "Sheet 1");
+    sheet.makeCurrent();
+
+    for (let i = 0; i < 10; ++i) sheet.setCell("A", i, `${i}`);
+
+    test("sum", () => {
+        expect(sum).toBeDefined();
+        expect(sum(R`A0:A9`)).toEqual(45);
+    });
+
+    test("sumIf", () => {
+        expect(sumIf).toBeDefined();
+        expect(sumIf(x => !Number.isNaN(x), R`A0:A10`)).toEqual(45);
+    });
+
+    test("count", () => {
+        expect(count).toBeDefined();
+        expect(count(R`A0:A9`)).toEqual(10);
+    });
+
+    test("countIf", () => {
+        expect(countIf).toBeDefined();
+        expect(countIf(x => x, R`A0:A10`)).toEqual(10);
+    });
+
+    test("average", () => {
+        expect(average).toBeDefined();
+        expect(average(R`A0:A9`)).toEqual(4.5);
+    });
+
+    test("averageIf", () => {
+        expect(averageIf).toBeDefined();
+        expect(averageIf(x => !Number.isNaN(x), R`A0:A10`)).toEqual(4.5);
+    });
+
+    test("median", () => {
+        expect(median).toBeDefined();
+        expect(median(R`A0:A9`)).toEqual(4.5);
+        expect(median(R`A0:A2`)).toEqual(1);
+    });
+
+    test("variance", () => {
+        expect(variance).toBeDefined();
+        expect(variance(R`A0:A0`)).toEqual(0);
+        expect(variance(R`A0:A9`)).toEqual(82.5);
+    });
+
+    test("mode", () => {
+        expect(mode).toBeDefined();
+        expect(mode(R`A0:A0`.union(R`A0:A0`).union(R`A1:A9`))).toEqual(0);
+    });
+
+    test("stddev", () => {
+        expect(stddev).toBeDefined();
+        expect(stddev(R`A0:A0`)).toEqual(0);
+        expect(stddev(R`A0:A9`)).toEqual(Math.sqrt(82.5));
+    });
+});
+
+describe("Lookup", () => {
+    const workbook = createWorkbook();
+    const sheet = createSheet(workbook, "Sheet 1");
+    sheet.makeCurrent();
+
+    for (let i = 0; i < 10; ++i) {
+        sheet.setCell("A", i, `${i}`);
+        sheet.setCell("B", i, `B${i}`);
+    }
+
+    sheet.focusCell("A", 0);
+
+    test("row", () => {
+        expect(row()).toEqual(0);
+    });
+
+    test("column", () => {
+        expect(column()).toEqual("A");
+    });
+
+    test("lookup", () => {
+        expect(lookup).toBeDefined();
+        // Note: String ordering.
+        expect(lookup("2", R`A0:A9`, R`B0:B9`)).toEqual("B2");
+        expect(lookup("20", R`A0:A9`, R`B0:B9`)).toBeUndefined();
+        expect(lookup("80", R`A0:A9`, R`B0:B9`, undefined, "nextlargest")).toEqual("B9");
+    });
+
+    test("reflookup", () => {
+        expect(reflookup).toBeDefined();
+        // Note: String ordering.
+        expect(reflookup("2", R`A0:A9`, R`B0:B9`).name).toEqual("B2");
+        expect(reflookup("20", R`A0:A9`, R`B0:B9`)).toEqual(here());
+        expect(reflookup("80", R`A0:A9`, R`B0:B9`, undefined, "nextlargest").name).toEqual("B9");
+    });
+});

+ 192 - 0
Userland/Applications/Spreadsheet/Tests/mock.test-common.js

@@ -0,0 +1,192 @@
+var thisSheet;
+var workbook;
+
+var createWorkbook = () => {
+    return {
+        __sheets: new Map(),
+        sheet(nameOrIndex) {
+            if (typeof nameOrIndex !== "number") return this.__sheets.get(nameOrIndex);
+            for (const entry of this.__sheets) {
+                if (nameOrIndex === 0) return entry[1];
+                nameOrIndex--;
+            }
+            return undefined;
+        },
+    };
+};
+
+function toBijectiveBase(number) {
+    const alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    number += 1;
+    let c = 0;
+    let x = 1;
+    while (number >= x) {
+        ++c;
+        number -= x;
+        x *= 26;
+    }
+
+    let s = "";
+    for (let i = 0; i < c; i++) {
+        s = alpha.charAt(number % 26) + s;
+        number = Math.floor(number / 26);
+    }
+
+    return s;
+}
+
+function __evaluate(expression, that) {
+    const object = Object.create(null);
+    for (const entry of that.__cells) {
+        const cell = JSON.parse(entry[0]);
+        object[`${cell[0]}${cell[1]}`] = entry[1][1];
+    }
+
+    const sheetObject = that;
+    let __value;
+
+    // Warning: Dragons and fire ahead.
+    with (that.__workbook) {
+        with (object) {
+            with (sheetObject) {
+                __value = eval(expression);
+            }
+        }
+    }
+    return __value;
+}
+
+class Sheet {
+    constructor(workbook) {
+        this.__cells = new Map();
+        this.__columns = new Set();
+        this.__workbook = workbook;
+        this.__currentCellPosition = undefined;
+    }
+
+    get_real_cell_contents(name) {
+        const cell = this.parse_cell_name(name);
+        if (cell === undefined) throw new TypeError("Invalid cell name");
+        return this.getCell(cell.column, cell.row)[0];
+    }
+
+    set_real_cell_contents(name, value) {
+        const cell = this.parse_cell_name(name);
+        if (cell === undefined) throw new TypeError("Invalid cell name");
+
+        this.setCell(cell.column, cell.row, value);
+    }
+
+    parse_cell_name(name) {
+        const match = /^([a-zA-Z]+)(\d+)$/.exec(name);
+        if (!Array.isArray(match)) return undefined;
+
+        return {
+            column: match[1],
+            row: +match[2],
+        };
+    }
+
+    current_cell_position() {
+        return this.__currentCellPosition;
+    }
+
+    column_index(name) {
+        let i = 0;
+        for (const column of this.__columns) {
+            if (column === name) return i;
+            ++i;
+        }
+    }
+
+    column_arithmetic(name, offset) {
+        if (offset < 0) {
+            const columns = this.getColumns();
+            let index = columns.indexOf(name);
+            if (index === -1) throw new TypeError(`${name} is not a valid column name`);
+
+            index += offset;
+            if (index < 0) return columns[0];
+            return columns[index];
+        }
+
+        let found = false;
+        for (const column of this.__columns) {
+            if (!found) found = column === name;
+            if (found) {
+                if (offset === 0) return column;
+                offset--;
+            }
+        }
+
+        if (!found) throw new TypeError(`${name} is not a valid column name`);
+
+        let newName;
+        for (let i = 0; i < offset; ++i) {
+            newName = toBijectiveBase(this.__columns.size);
+            this.addColumn(newName);
+        }
+        return newName;
+    }
+
+    get_column_bound(name) {
+        let bound = 0;
+        for (const entry of this.__cells) {
+            const [column, row] = JSON.parse(entry[0]);
+            if (column !== name) continue;
+            bound = Math.max(bound, row);
+        }
+        return row;
+    }
+
+    evaluate(currentColumn, currentRow, expression) {
+        const currentCellSave = this.__currentCellPosition;
+        this.__currentCellPosition = { column: currentColumn, row: currentRow };
+        try {
+            return __evaluate(expression, this);
+        } finally {
+            this.__currentCellPosition = currentCellSave;
+        }
+    }
+
+    addColumn(name) {
+        this.__columns.add(name);
+    }
+
+    getColumns() {
+        return Array.from(this.__columns);
+    }
+
+    setCell(column, row, source, value = undefined) {
+        this.addColumn(column);
+        source = `${source}`;
+        if (value === undefined) {
+            value = source;
+            if (value[0] === "=") value = this.evaluate(column, row, value.substr(1));
+        }
+
+        this.__cells.set(JSON.stringify([column, row]), [source, value]);
+        this[`${column}${row}`] = value;
+    }
+
+    getCell(column, row) {
+        const data = this.__cells.get(JSON.stringify([column, row]));
+        if (data === undefined) return undefined;
+        return data;
+    }
+
+    focusCell(column, row) {
+        this.__currentCellPosition = { column, row };
+    }
+
+    makeCurrent() {
+        thisSheet = this;
+        workbook = this.__workbook;
+    }
+}
+
+var createSheet = (workbook, name) => {
+    const sheet = new Sheet(workbook);
+    workbook.__sheets.set(name, sheet);
+    return sheet;
+};

+ 46 - 0
Userland/Applications/Spreadsheet/Tests/test-harness.js

@@ -0,0 +1,46 @@
+describe("Harness-defined functions", () => {
+    test("createWorkbook", () => {
+        expect(createWorkbook).toBeDefined();
+        const workbook = createWorkbook();
+        expect(workbook).toBeDefined();
+        expect(workbook.sheet).toBeDefined();
+    });
+    test("createSheet", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "foo");
+        expect(sheet).toBeDefined();
+        expect(sheet.get_real_cell_contents).toBeDefined();
+        expect(sheet.set_real_cell_contents).toBeDefined();
+        expect(sheet.parse_cell_name).toBeDefined();
+        expect(sheet.current_cell_position).toBeDefined();
+        expect(sheet.column_index).toBeDefined();
+        expect(sheet.column_arithmetic).toBeDefined();
+        expect(sheet.get_column_bound).toBeDefined();
+    });
+    test("Sheet mock behavior", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "foo");
+        sheet.setCell("A", 0, "10");
+        expect(sheet.getCell("A", 0)).toEqual(["10", "10"]);
+
+        sheet.setCell("A", 0, "=10");
+        expect(sheet.getCell("A", 0)).toEqual(["=10", 10]);
+
+        expect(sheet.getColumns()).toEqual(["A"]);
+    });
+    test("Workbook mock behavior", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "foo");
+        expect(workbook.sheet("foo")).toBe(sheet);
+        expect(workbook.sheet(0)).toBe(sheet);
+        expect(workbook.sheet(1)).toBeUndefined();
+        expect(workbook.sheet("bar")).toBeUndefined();
+    });
+    test("Referencing cells", () => {
+        const workbook = createWorkbook();
+        const sheet = createSheet(workbook, "foo");
+        sheet.setCell("A", 0, "42");
+        sheet.setCell("A", 1, "=A0");
+        expect(sheet.getCell("A", 1)).toEqual(["=A0", "42"]);
+    });
+});

+ 10 - 10
Userland/Libraries/LibTest/JavaScriptTestRunner.h

@@ -89,14 +89,14 @@
 #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 {};                                                          \
+#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&, JS::ExecutionContext&); \
+    } __testjs_common_run_file {};                                                                                 \
     ::Test::JS::IntermediateRunFileResult __TestJS_run_file::hook(__VA_ARGS__)
 
 #define TESTJS_CREATE_INTERPRETER_HOOK(...)               \
@@ -163,7 +163,7 @@ enum class RunFileHookResult {
 };
 
 using IntermediateRunFileResult = AK::Result<JSFileResult, RunFileHookResult>;
-extern IntermediateRunFileResult (*g_run_file)(const String&, JS::Interpreter&);
+extern IntermediateRunFileResult (*g_run_file)(const String&, JS::Interpreter&, JS::ExecutionContext&);
 
 class TestRunner : public ::Test::TestRunner {
 public:
@@ -300,7 +300,7 @@ 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);
+        auto result = g_run_file(test_path, *interpreter, global_execution_context);
         if (result.is_error() && result.error() == RunFileHookResult::SkipFile) {
             return {
                 test_path,

+ 1 - 1
Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp

@@ -25,7 +25,7 @@ HashMap<String, FunctionWithLength> s_exposed_global_functions;
 Function<void()> g_main_hook;
 Function<NonnullOwnPtr<JS::Interpreter>()> g_create_interpreter_hook;
 HashMap<bool*, Tuple<String, String, char>> g_extra_args;
-IntermediateRunFileResult (*g_run_file)(const String&, JS::Interpreter&) = nullptr;
+IntermediateRunFileResult (*g_run_file)(const String&, JS::Interpreter&, JS::ExecutionContext&) = nullptr;
 String g_test_root;
 int g_test_argc;
 char** g_test_argv;