summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/home/anon/.config/Tests.ini3
-rw-r--r--Meta/Lagom/CMakeLists.txt13
-rwxr-xr-xMeta/build-root-filesystem.sh1
-rw-r--r--Tests/CMakeLists.txt1
-rw-r--r--Tests/LibJS/test-js.cpp2
-rw-r--r--Tests/Spreadsheet/CMakeLists.txt3
-rw-r--r--Tests/Spreadsheet/test-spreadsheet.cpp44
-rw-r--r--Userland/Applications/Spreadsheet/Tests/basic.js97
-rw-r--r--Userland/Applications/Spreadsheet/Tests/free-functions.js166
-rw-r--r--Userland/Applications/Spreadsheet/Tests/mock.test-common.js192
-rw-r--r--Userland/Applications/Spreadsheet/Tests/test-harness.js46
-rw-r--r--Userland/Libraries/LibTest/JavaScriptTestRunner.h20
-rw-r--r--Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp2
13 files changed, 578 insertions, 12 deletions
diff --git a/Base/home/anon/.config/Tests.ini b/Base/home/anon/.config/Tests.ini
index 1298391211..c60374fb72 100644
--- a/Base/home/anon/.config/Tests.ini
+++ b/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
diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt
index b2c4b10c94..2058f84ace 100644
--- a/Meta/Lagom/CMakeLists.txt
+++ b/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")
diff --git a/Meta/build-root-filesystem.sh b/Meta/build-root-filesystem.sh
index fe26f63944..c8fe60db3b 100755
--- a/Meta/build-root-filesystem.sh
+++ b/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... "
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 17e076de14..4af1b491da 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -27,3 +27,4 @@ if (${SERENITY_ARCH} STREQUAL "i686")
endif()
add_subdirectory(LibCrypto)
add_subdirectory(LibTLS)
+add_subdirectory(Spreadsheet)
diff --git a/Tests/LibJS/test-js.cpp b/Tests/LibJS/test-js.cpp
index 54e98eef0e..c9936dd910 100644
--- a/Tests/LibJS/test-js.cpp
+++ b/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;
diff --git a/Tests/Spreadsheet/CMakeLists.txt b/Tests/Spreadsheet/CMakeLists.txt
new file mode 100644
index 0000000000..1a710f372a
--- /dev/null
+++ b/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)
diff --git a/Tests/Spreadsheet/test-spreadsheet.cpp b/Tests/Spreadsheet/test-spreadsheet.cpp
new file mode 100644
index 0000000000..e3d27895ea
--- /dev/null
+++ b/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;
+}
diff --git a/Userland/Applications/Spreadsheet/Tests/basic.js b/Userland/Applications/Spreadsheet/Tests/basic.js
new file mode 100644
index 0000000000..2f30be3bd5
--- /dev/null
+++ b/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);
+ });
+});
diff --git a/Userland/Applications/Spreadsheet/Tests/free-functions.js b/Userland/Applications/Spreadsheet/Tests/free-functions.js
new file mode 100644
index 0000000000..80cc1b59f7
--- /dev/null
+++ b/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");
+ });
+});
diff --git a/Userland/Applications/Spreadsheet/Tests/mock.test-common.js b/Userland/Applications/Spreadsheet/Tests/mock.test-common.js
new file mode 100644
index 0000000000..4aa7dcaab5
--- /dev/null
+++ b/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;
+};
diff --git a/Userland/Applications/Spreadsheet/Tests/test-harness.js b/Userland/Applications/Spreadsheet/Tests/test-harness.js
new file mode 100644
index 0000000000..283d76a000
--- /dev/null
+++ b/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"]);
+ });
+});
diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunner.h b/Userland/Libraries/LibTest/JavaScriptTestRunner.h
index 69a1556be5..5b25df2c2b 100644
--- a/Userland/Libraries/LibTest/JavaScriptTestRunner.h
+++ b/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,
diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp b/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp
index 108a8ba21e..ebff8e9e5a 100644
--- a/Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp
+++ b/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;