import 'package:clide/src/svg/svg_xml.dart';
import 'package:test/test.dart';
void main() {
XmlElement parse(String s) {
final root = parseXml(s);
expect(root, isNotNull, reason: 'expected an element root for: $s');
return root!;
}
group('parseXml', () {
test('element with attributes', () {
final e = parse('');
expect(e.name, 'rect');
expect(e.attrs, {'x': '1', 'y': '2', 'width': '3', 'height': '4'});
expect(e.children, isEmpty);
});
test('single-quoted and unquoted attribute values', () {
final e = parse("");
expect(e.attrs['fill'], 'red');
expect(e.attrs['opacity'], '0.5');
});
test('nested children preserve order', () {
final e = parse('');
expect(e.name, 'g');
expect(e.children.whereType().map((c) => c.name), ['rect', 'circle']);
});
test('text content is captured', () {
final e = parse('hello');
final t = e.children.single as XmlText;
expect(t.text, 'hello');
});
test('comments are skipped', () {
final e = parse('');
expect(e.children.whereType().map((c) => c.name), ['rect']);
expect(e.children.whereType(), isEmpty);
});
test('xml prolog and doctype are skipped', () {
final e = parse('');
expect(e.name, 'svg');
expect(e.attrs['width'], '10');
});
test('CDATA content is captured verbatim', () {
final e = parse('');
expect((e.children.single as XmlText).text, contains('.a { fill: red }'));
});
test('entities are decoded in text and attributes', () {
final e = parse('<tag> A');
expect(e.attrs['title'], 'a & b');
expect((e.children.single as XmlText).text, ' A');
});
test('style body is read as raw text, not markup', () {
// CSS with > and { } must not be parsed as elements.
final e = parse('');
expect(e.name, 'style');
final css = (e.children.single as XmlText).text;
expect(css, contains('.edge > .head'));
expect(css, contains('stroke:none'));
});
test('namespaced attribute names are kept verbatim', () {
final e = parse('');
expect(e.attrs['xlink:href'], 'a.png');
expect(e.attrs['href'], 'b.png');
});
test('mismatched close tag is tolerated, no throw', () {
final e = parse('');
expect(e.name, 'g');
expect(e.children.whereType().single.name, 'rect');
});
test('descendants walks the whole subtree', () {
final e = parse('');
final names = e.descendants().whereType().map((c) => c.name).toList();
expect(names, ['g', 'rect', 'circle']);
});
test('non-element root returns null, never throws', () {
expect(parseXml(''), isNull);
expect(parseXml(' '), isNull);
expect(parseXml('just text'), isNull);
});
test('unterminated tag does not throw', () {
// Should not hang or throw; returns whatever was understood.
expect(() => parseXml('