mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:17:44 +00:00
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 :^)
This commit is contained in:
parent
0fe97cdfe4
commit
bed129a69f
13 changed files with 578 additions and 12 deletions
192
Userland/Applications/Spreadsheet/Tests/mock.test-common.js
Normal file
192
Userland/Applications/Spreadsheet/Tests/mock.test-common.js
Normal file
|
@ -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;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue