Files
cellar/test/dependency_test.dart
T

94 lines
3.0 KiB
Dart

import 'package:cellar/cellar.dart';
import 'package:test/test.dart';
double numberOf(CellValue value) => (value as NumberValue).value;
void main() {
group('dependency graph recalculation', () {
test('changing a precedent recomputes a dependent', () {
final sheet = Sheet();
sheet.setValue('A1', '5');
sheet.setValue('B1', '=A1+1');
expect(numberOf(sheet.valueOf('B1')), 6);
sheet.setValue('A1', '10');
expect(numberOf(sheet.valueOf('B1')), 11);
});
test('a chain propagates through several levels', () {
final sheet = Sheet();
sheet.setValue('A1', '2');
sheet.setValue('B1', '=A1*2');
sheet.setValue('C1', '=B1*2');
sheet.setValue('D1', '=C1+1');
expect(numberOf(sheet.valueOf('D1')), 9);
sheet.setValue('A1', '5');
expect(numberOf(sheet.valueOf('B1')), 10);
expect(numberOf(sheet.valueOf('C1')), 20);
expect(numberOf(sheet.valueOf('D1')), 21);
});
test('a single precedent feeds multiple dependents', () {
final sheet = Sheet();
sheet.setValue('A1', '3');
sheet.setValue('B1', '=A1+1');
sheet.setValue('B2', '=A1*10');
sheet.setValue('B3', '=A1-1');
sheet.setValue('A1', '7');
expect(numberOf(sheet.valueOf('B1')), 8);
expect(numberOf(sheet.valueOf('B2')), 70);
expect(numberOf(sheet.valueOf('B3')), 6);
});
test('range dependencies recompute when a member changes', () {
final sheet = Sheet();
sheet.setValue('A1', '1');
sheet.setValue('A2', '2');
sheet.setValue('A3', '3');
sheet.setValue('B1', '=SUM(A1:A3)');
expect(numberOf(sheet.valueOf('B1')), 6);
sheet.setValue('A2', '20');
expect(numberOf(sheet.valueOf('B1')), 24);
});
});
group('cycle detection', () {
test('two cells referencing each other become #CYCLE!', () {
final sheet = Sheet();
sheet.setValue('A1', '=B1');
sheet.setValue('B1', '=A1');
expect(sheet.valueOf('A1'), const ErrorValue(ErrorKind.cycle));
expect(sheet.valueOf('B1'), const ErrorValue(ErrorKind.cycle));
});
test('self reference is a cycle', () {
final sheet = Sheet();
sheet.setValue('A1', '=A1+1');
expect(sheet.valueOf('A1'), const ErrorValue(ErrorKind.cycle));
});
test('a three cell cycle is detected', () {
final sheet = Sheet();
sheet.setValue('A1', '=B1');
sheet.setValue('B1', '=C1');
sheet.setValue('C1', '=A1');
expect(sheet.valueOf('A1'), const ErrorValue(ErrorKind.cycle));
expect(sheet.valueOf('B1'), const ErrorValue(ErrorKind.cycle));
expect(sheet.valueOf('C1'), const ErrorValue(ErrorKind.cycle));
});
test('breaking a cycle restores computation', () {
final sheet = Sheet();
sheet.setValue('A1', '=B1');
sheet.setValue('B1', '=A1');
expect(sheet.valueOf('A1'), const ErrorValue(ErrorKind.cycle));
sheet.setValue('B1', '5');
expect(numberOf(sheet.valueOf('B1')), 5);
expect(numberOf(sheet.valueOf('A1')), 5);
});
});
}