Ocideck/test/chart_test.dart
Brenno de Winter b270e71755
Some checks failed
CI / Format · Analyze · Test (push) Has been cancelled
CI / Format · Analyze · Test (pull_request) Has been cancelled
Apply repo formatter across the tree
Run `make format` so the whole repo is consistent under the project formatter.
Whitespace only; no logic changes. Touches a few widgets and tests that were
unformatted on main (dart-format version drift), so `make check` is fully green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 22:17:07 +02:00

179 lines
5.7 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:ocideck/models/chart.dart';
void main() {
test('chart palette starts with the EU flag colors', () {
expect(chartColorPalette.take(2), ['#003399', '#FFCC00']);
});
group('parseCsv', () {
test('reads header series names and labelled rows', () {
final (x, series) = parseCsv('\n, 2025, 2026\nQ1, 10, 12\nQ2, 14, 9\n');
expect(x, ['Q1', 'Q2']);
expect(series.map((s) => s.name), ['2025', '2026']);
expect(series[0].data, [10, 14]);
expect(series[1].data, [12, 9]);
});
test('non-numeric cells become 0', () {
final (x, series) = parseCsv(',A\nQ1,oops');
expect(x, ['Q1']);
expect(series.single.data, [0]);
});
});
group('ChartSpec', () {
test('round-trips inline data through the block JSON', () {
const spec = ChartSpec(
type: ChartType.line,
title: 'Omzet',
x: ['Q1', 'Q2'],
rowColors: ['#003399', '#FFCC00'],
series: [
ChartSeries(name: '2025', data: [10, 14], color: '#EF4444'),
],
);
final back = ChartSpec.parse(spec.toBlock());
expect(back.type, ChartType.line);
expect(back.title, 'Omzet');
expect(back.x, ['Q1', 'Q2']);
expect(back.rowColors, ['#003399', '#FFCC00']);
expect(back.series.single.name, '2025');
expect(back.series.single.data, [10, 14]);
expect(back.series.single.color, '#EF4444');
expect(back.hasInlineData, isTrue);
});
test('storage form drops inline data when a source is linked', () {
const spec = ChartSpec(
type: ChartType.bar,
title: 'Omzet',
source: 'data/omzet.csv',
x: ['Q1', 'Q2'],
rowColors: ['#003399', '#FFCC00'],
series: [
ChartSeries(name: '2025', data: [10, 14], color: '#10B981'),
],
);
final stored = ChartSpec.parse(spec.toBlock(forStorage: true));
expect(stored.source, 'data/omzet.csv');
expect(stored.hasInlineData, isFalse);
expect(stored.rowColors, ['#003399', '#FFCC00']);
expect(stored.series.single.color, '#10B981');
// The in-app/full form keeps the data.
final full = ChartSpec.parse(spec.toBlock());
expect(full.hasInlineData, isTrue);
});
test('withCsv fills x/series and keeps the source', () {
const spec = ChartSpec(
type: ChartType.bar,
source: 'data/o.csv',
rowColors: ['#003399', '#FFCC00'],
series: [ChartSeries(name: 'oud', data: [], color: '#10B981')],
);
final filled = spec.withCsv(',A,B\nJan,1,2\nFeb,3,4');
expect(filled.source, 'data/o.csv');
expect(filled.x, ['Jan', 'Feb']);
expect(filled.series.map((s) => s.name), ['A', 'B']);
expect(filled.series[1].data, [2, 4]);
expect(filled.series[0].color, '#10B981');
expect(filled.series[1].color, isNull);
expect(filled.rowColors, ['#003399', '#FFCC00']);
});
test('invalid colors are ignored while valid colors are normalized', () {
final valid = ChartSeries.fromJson({
'name': 'A',
'data': [1],
'color': 'ef4444',
});
final invalid = ChartSeries.fromJson({
'name': 'B',
'data': [2],
'color': 'red',
});
expect(valid.color, '#EF4444');
expect(invalid.color, isNull);
});
test('parse is tolerant of malformed JSON', () {
final spec = ChartSpec.parse('{ not json');
expect(spec.type, ChartType.bar);
expect(spec.hasInlineData, isFalse);
});
test('round-trips optional min/max bound lines for bar/line', () {
const spec = ChartSpec(
type: ChartType.line,
x: ['Q1'],
series: [
ChartSeries(name: 'A', data: [10]),
],
minBound: 5,
maxBound: 20,
);
final back = ChartSpec.parse(spec.toBlock());
expect(back.minBound, 5);
expect(back.maxBound, 20);
});
test('bounds are dropped from a pie chart', () {
const spec = ChartSpec(
type: ChartType.pie,
x: ['Q1'],
series: [
ChartSeries(name: 'A', data: [10]),
],
minBound: 5,
maxBound: 20,
);
expect(spec.supportsBounds, isFalse);
final back = ChartSpec.parse(spec.toBlock());
expect(back.minBound, isNull);
expect(back.maxBound, isNull);
});
test('round-trips a spider/radar chart type', () {
const spec = ChartSpec(
type: ChartType.radar,
x: ['Snelheid', 'Kracht', 'Uithouding'],
series: [
ChartSeries(name: 'A', data: [3, 4, 5]),
],
);
final back = ChartSpec.parse(spec.toBlock());
expect(back.type, ChartType.radar);
expect(back.x, ['Snelheid', 'Kracht', 'Uithouding']);
expect(back.series.single.data, [3, 4, 5]);
});
test('radar keeps bounds as a scale but never draws bound lines', () {
const spec = ChartSpec(
type: ChartType.radar,
x: ['A', 'B', 'C'],
series: [
ChartSeries(name: 'A', data: [1, 2, 3]),
],
minBound: 1,
maxBound: 5,
);
expect(spec.supportsBounds, isTrue);
expect(spec.supportsBoundLines, isFalse);
final back = ChartSpec.parse(spec.toBlock());
expect(back.minBound, 1);
expect(back.maxBound, 5);
});
test('bar/line draw bound lines but pie does not', () {
const bar = ChartSpec(type: ChartType.bar);
const line = ChartSpec(type: ChartType.line);
const pie = ChartSpec(type: ChartType.pie);
expect(bar.supportsBoundLines, isTrue);
expect(line.supportsBoundLines, isTrue);
expect(pie.supportsBoundLines, isFalse);
expect(pie.supportsBounds, isFalse);
});
});
}