graphTemplateHandler lowers a {nodes,edges} payload to SVG: a deterministic
circular layout of labelled <circle> nodes with <line> edges, self-contained
(own light backdrop + content colors, like a d2 card) and painted by the
shared renderer. Display-only (D-78); decoupled from the interactive graph
pane (T-323) since a static card only needs a layout->SVG. Honest error on
a duplicate id or an edge to an unknown node.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
2.1 KiB
Dart
82 lines
2.1 KiB
Dart
import 'package:clide/src/draw/draw_dispatch.dart';
|
|
import 'package:clide/src/draw/draw_doc.dart';
|
|
import 'package:clide/src/draw/graph_template.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
void main() {
|
|
final handler = graphTemplateHandler();
|
|
DrawingCardDoc doc(Map<String, Object?> fields) => DrawingCardDoc(template: 'graph', fields: {'template': 'graph', ...fields});
|
|
|
|
test('lays out nodes as labelled circles and edges as lines', () async {
|
|
final r = await handler(
|
|
doc({
|
|
'nodes': [
|
|
{'id': 'a', 'label': 'Alpha'},
|
|
{'id': 'b', 'label': 'Beta'},
|
|
],
|
|
'edges': [
|
|
{'from': 'a', 'to': 'b'},
|
|
],
|
|
}),
|
|
);
|
|
final svg = (r as DrawOk).svg;
|
|
expect('<circle'.allMatches(svg).length, 2);
|
|
expect('<line'.allMatches(svg).length, 1);
|
|
expect(svg, contains('>Alpha<'));
|
|
expect(svg, contains('>Beta<'));
|
|
});
|
|
|
|
test('a node label defaults to its id', () async {
|
|
final r = await handler(
|
|
doc({
|
|
'nodes': [
|
|
{'id': 'solo'},
|
|
],
|
|
}),
|
|
);
|
|
expect((r as DrawOk).svg, contains('>solo<'));
|
|
});
|
|
|
|
test('empty or missing nodes is an honest error', () async {
|
|
expect(await handler(doc({'nodes': const []})), isA<DrawErr>());
|
|
expect(await handler(doc(const {})), isA<DrawErr>());
|
|
});
|
|
|
|
test('a duplicate node id is an error', () async {
|
|
final r = await handler(
|
|
doc({
|
|
'nodes': [
|
|
{'id': 'x'},
|
|
{'id': 'x'},
|
|
],
|
|
}),
|
|
);
|
|
expect((r as DrawErr).message, contains('duplicate'));
|
|
});
|
|
|
|
test('an edge to an unknown node is an error', () async {
|
|
final r = await handler(
|
|
doc({
|
|
'nodes': [
|
|
{'id': 'a'},
|
|
],
|
|
'edges': [
|
|
{'from': 'a', 'to': 'ghost'},
|
|
],
|
|
}),
|
|
);
|
|
expect((r as DrawErr).message, contains('ghost'));
|
|
});
|
|
|
|
test('escapes label text', () async {
|
|
final r = await handler(
|
|
doc({
|
|
'nodes': [
|
|
{'id': 'a', 'label': '<b>&'},
|
|
],
|
|
}),
|
|
);
|
|
expect((r as DrawOk).svg, contains('<b>&'));
|
|
});
|
|
}
|