test(functions): add text, logical and lookup tests
This commit is contained in:
1 parent
c31cea00f7
commit
5ba21bc427
3 files changed
+244
No files matched your search
@@ -0,0 +1,79 @@
|
|||||||
|
import 'package:cellar/cellar.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
CellValue ev(String formula) {
|
||||||
|
final sheet = Sheet();
|
||||||
|
sheet.setValue('Z1', formula);
|
||||||
|
return sheet.valueOf('Z1');
|
||||||
|
}
|
||||||
|
|
||||||
|
double num(CellValue value) => (value as NumberValue).value;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('logical functions', () {
|
||||||
|
test('IF chooses a branch', () {
|
||||||
|
expect(ev('=IF(2>1, "yes", "no")'), const TextValue('yes'));
|
||||||
|
expect(ev('=IF(2<1, "yes", "no")'), const TextValue('no'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('IFS picks the first true condition', () {
|
||||||
|
expect(ev('=IFS(FALSE, 1, TRUE, 2, TRUE, 3)'), const NumberValue(2));
|
||||||
|
expect(ev('=IFS(FALSE, 1, FALSE, 2)'), const ErrorValue(ErrorKind.na));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('SWITCH matches a value with a default', () {
|
||||||
|
expect(ev('=SWITCH(2, 1, "a", 2, "b", "z")'), const TextValue('b'));
|
||||||
|
expect(ev('=SWITCH(9, 1, "a", 2, "b", "z")'), const TextValue('z'));
|
||||||
|
expect(ev('=SWITCH(9, 1, "a")'), const ErrorValue(ErrorKind.na));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('AND OR NOT XOR', () {
|
||||||
|
expect(ev('=AND(TRUE, 1=1, 2>1)'), const BooleanValue(true));
|
||||||
|
expect(ev('=OR(FALSE, 1=2, 3>1)'), const BooleanValue(true));
|
||||||
|
expect(ev('=NOT(1=1)'), const BooleanValue(false));
|
||||||
|
expect(ev('=XOR(TRUE, TRUE, TRUE)'), const BooleanValue(true));
|
||||||
|
expect(ev('=XOR(TRUE, TRUE)'), const BooleanValue(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('IFERROR and IFNA', () {
|
||||||
|
expect(num(ev('=IFERROR(1/0, 42)')), 42);
|
||||||
|
expect(num(ev('=IFERROR(5, 42)')), 5);
|
||||||
|
expect(num(ev('=IFNA(NA(), 7)')), 7);
|
||||||
|
expect(ev('=IFNA(1/0, 7)'), const ErrorValue(ErrorKind.divZero));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('info functions', () {
|
||||||
|
test('type predicates', () {
|
||||||
|
expect(ev('=ISNUMBER(5)'), const BooleanValue(true));
|
||||||
|
expect(ev('=ISTEXT("x")'), const BooleanValue(true));
|
||||||
|
expect(ev('=ISLOGICAL(TRUE)'), const BooleanValue(true));
|
||||||
|
expect(ev('=ISNUMBER("x")'), const BooleanValue(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('error predicates', () {
|
||||||
|
expect(ev('=ISERROR(1/0)'), const BooleanValue(true));
|
||||||
|
expect(ev('=ISERR(1/0)'), const BooleanValue(true));
|
||||||
|
expect(ev('=ISERR(NA())'), const BooleanValue(false));
|
||||||
|
expect(ev('=ISNA(NA())'), const BooleanValue(true));
|
||||||
|
expect(ev('=ISNA(1/0)'), const BooleanValue(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ISBLANK reflects an empty cell', () {
|
||||||
|
final sheet = Sheet();
|
||||||
|
sheet.setValue('B1', '=ISBLANK(A1)');
|
||||||
|
sheet.setValue('B2', '=ISBLANK(A2)');
|
||||||
|
sheet.setValue('A2', 'x');
|
||||||
|
expect(sheet.valueOf('B1'), const BooleanValue(true));
|
||||||
|
expect(sheet.valueOf('B2'), const BooleanValue(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('N and TYPE', () {
|
||||||
|
expect(num(ev('=N(TRUE)')), 1);
|
||||||
|
expect(num(ev('=N("text")')), 0);
|
||||||
|
expect(num(ev('=TYPE(5)')), 1);
|
||||||
|
expect(num(ev('=TYPE("x")')), 2);
|
||||||
|
expect(num(ev('=TYPE(1/0)')), 16);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import 'package:cellar/cellar.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
double num(CellValue value) => (value as NumberValue).value;
|
||||||
|
|
||||||
|
Sheet lookupSheet() {
|
||||||
|
final sheet = Sheet();
|
||||||
|
final rows = [
|
||||||
|
['apple', '1', 'red'],
|
||||||
|
['banana', '2', 'yellow'],
|
||||||
|
['cherry', '3', 'red'],
|
||||||
|
];
|
||||||
|
for (var r = 0; r < rows.length; r++) {
|
||||||
|
sheet.setValue('A${r + 1}', rows[r][0]);
|
||||||
|
sheet.setValue('B${r + 1}', rows[r][1]);
|
||||||
|
sheet.setValue('C${r + 1}', rows[r][2]);
|
||||||
|
}
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('lookup functions', () {
|
||||||
|
test('VLOOKUP exact match returns another column', () {
|
||||||
|
final sheet = lookupSheet();
|
||||||
|
sheet.setValue('E1', '=VLOOKUP("banana", A1:C3, 3, FALSE)');
|
||||||
|
expect(sheet.valueOf('E1'), const TextValue('yellow'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('VLOOKUP approximate on sorted numbers', () {
|
||||||
|
final sheet = Sheet();
|
||||||
|
sheet.setValue('A1', '0');
|
||||||
|
sheet.setValue('B1', 'low');
|
||||||
|
sheet.setValue('A2', '10');
|
||||||
|
sheet.setValue('B2', 'mid');
|
||||||
|
sheet.setValue('A3', '20');
|
||||||
|
sheet.setValue('B3', 'high');
|
||||||
|
sheet.setValue('D1', '=VLOOKUP(15, A1:B3, 2)');
|
||||||
|
expect(sheet.valueOf('D1'), const TextValue('mid'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('VLOOKUP missing exact key is #N/A', () {
|
||||||
|
final sheet = lookupSheet();
|
||||||
|
sheet.setValue('E1', '=VLOOKUP("mango", A1:C3, 2, FALSE)');
|
||||||
|
expect(sheet.valueOf('E1'), const ErrorValue(ErrorKind.na));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('HLOOKUP across a row', () {
|
||||||
|
final sheet = Sheet();
|
||||||
|
sheet.setValue('A1', 'Q1');
|
||||||
|
sheet.setValue('B1', 'Q2');
|
||||||
|
sheet.setValue('C1', 'Q3');
|
||||||
|
sheet.setValue('A2', '10');
|
||||||
|
sheet.setValue('B2', '20');
|
||||||
|
sheet.setValue('C2', '30');
|
||||||
|
sheet.setValue('E1', '=HLOOKUP("Q2", A1:C2, 2, FALSE)');
|
||||||
|
expect(num(sheet.valueOf('E1')), 20);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MATCH exact and approximate', () {
|
||||||
|
final sheet = lookupSheet();
|
||||||
|
sheet.setValue('E1', '=MATCH("cherry", A1:A3, 0)');
|
||||||
|
expect(num(sheet.valueOf('E1')), 3);
|
||||||
|
final numbers = Sheet();
|
||||||
|
numbers.setValue('A1', '10');
|
||||||
|
numbers.setValue('A2', '20');
|
||||||
|
numbers.setValue('A3', '30');
|
||||||
|
numbers.setValue('B1', '=MATCH(25, A1:A3, 1)');
|
||||||
|
expect(num(numbers.valueOf('B1')), 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('INDEX and INDEX/MATCH', () {
|
||||||
|
final sheet = lookupSheet();
|
||||||
|
sheet.setValue('E1', '=INDEX(A1:C3, 2, 3)');
|
||||||
|
sheet.setValue('E2', '=INDEX(B1:B3, MATCH("cherry", A1:A3, 0))');
|
||||||
|
expect(sheet.valueOf('E1'), const TextValue('yellow'));
|
||||||
|
expect(num(sheet.valueOf('E2')), 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('CHOOSE ROWS COLUMNS ROW COLUMN', () {
|
||||||
|
final sheet = lookupSheet();
|
||||||
|
sheet.setValue('E1', '=CHOOSE(2, "a", "b", "c")');
|
||||||
|
sheet.setValue('E2', '=ROWS(A1:C3)');
|
||||||
|
sheet.setValue('E3', '=COLUMNS(A1:C3)');
|
||||||
|
sheet.setValue('E4', '=ROW(B5)');
|
||||||
|
sheet.setValue('E5', '=COLUMN(D2)');
|
||||||
|
expect(sheet.valueOf('E1'), const TextValue('b'));
|
||||||
|
expect(num(sheet.valueOf('E2')), 3);
|
||||||
|
expect(num(sheet.valueOf('E3')), 3);
|
||||||
|
expect(num(sheet.valueOf('E4')), 5);
|
||||||
|
expect(num(sheet.valueOf('E5')), 4);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import 'package:cellar/cellar.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
CellValue ev(String formula) {
|
||||||
|
final sheet = Sheet();
|
||||||
|
sheet.setValue('Z1', formula);
|
||||||
|
return sheet.valueOf('Z1');
|
||||||
|
}
|
||||||
|
|
||||||
|
double num(CellValue value) => (value as NumberValue).value;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('text functions', () {
|
||||||
|
test('slicing', () {
|
||||||
|
expect(ev('=LEFT("spreadsheet", 6)'), const TextValue('spread'));
|
||||||
|
expect(ev('=RIGHT("spreadsheet", 5)'), const TextValue('sheet'));
|
||||||
|
expect(ev('=MID("spreadsheet", 7, 5)'), const TextValue('sheet'));
|
||||||
|
expect(num(ev('=LEN("hello")')), 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('case and proper', () {
|
||||||
|
expect(ev('=UPPER("cellar")'), const TextValue('CELLAR'));
|
||||||
|
expect(ev('=LOWER("CELLAR")'), const TextValue('cellar'));
|
||||||
|
expect(ev('=PROPER("john the FIRST")'), const TextValue('John The First'));
|
||||||
|
expect(ev('=TRIM(" a b ")'), const TextValue('a b'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('concat and textjoin', () {
|
||||||
|
expect(ev('=CONCAT("foo", "bar")'), const TextValue('foobar'));
|
||||||
|
expect(ev('=TEXTJOIN("-", TRUE, "a", "", "b")'), const TextValue('a-b'));
|
||||||
|
expect(ev('=TEXTJOIN("-", FALSE, "a", "", "b")'), const TextValue('a--b'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('substitute and replace', () {
|
||||||
|
expect(ev('=SUBSTITUTE("a-b-c", "-", "+")'), const TextValue('a+b+c'));
|
||||||
|
expect(ev('=SUBSTITUTE("a-b-c", "-", "+", 2)'), const TextValue('a-b+c'));
|
||||||
|
expect(ev('=REPLACE("abcdef", 2, 3, "XY")'), const TextValue('aXYef'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find and search', () {
|
||||||
|
expect(num(ev('=FIND("c", "abcabc")')), 3);
|
||||||
|
expect(num(ev('=SEARCH("C", "abcabc")')), 3);
|
||||||
|
expect(ev('=FIND("z", "abc")'), const ErrorValue(ErrorKind.value));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('char and code', () {
|
||||||
|
expect(ev('=CHAR(65)'), const TextValue('A'));
|
||||||
|
expect(num(ev('=CODE("A")')), 65);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('value and numbervalue', () {
|
||||||
|
expect(num(ev('=VALUE("42.5")')), 42.5);
|
||||||
|
expect(num(ev('=NUMBERVALUE("1.234,50", ",", ".")')), 1234.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('TEXT formats a number', () {
|
||||||
|
expect(ev('=TEXT(1234.5, "#,##0.00")'), const TextValue('1,234.50'));
|
||||||
|
expect(ev('=TEXT(0.25, "0.0%")'), const TextValue('25.0%'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('regex helpers', () {
|
||||||
|
expect(ev('=REGEXMATCH("abc123", "[0-9]+")'), const BooleanValue(true));
|
||||||
|
expect(ev('=REGEXEXTRACT("order 42 done", "([0-9]+)")'), const TextValue('42'));
|
||||||
|
expect(ev('=REGEXREPLACE("a1b2c3", "[0-9]", "#")'), const TextValue('a#b#c#'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('REPT and EXACT', () {
|
||||||
|
expect(ev('=REPT("ab", 3)'), const TextValue('ababab'));
|
||||||
|
expect(ev('=EXACT("Abc", "abc")'), const BooleanValue(false));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in new issue
Block a user