import 'package:test/test.dart'; import 'package:xml/xml.dart'; void main() { group('normalizer', () { test('remove empty text', () { final element = XmlElement.tag( 'element', children: [ XmlText(''), XmlElement(XmlName('element1')), XmlText(''), XmlElement(XmlName('element2')), XmlText(''), ], ); element.normalize(); expect(element.children.length, 2); expect( element.toXmlString(), '', ); }); test('join adjacent text', () { final element = XmlElement.tag( 'element', children: [XmlText('aaa'), XmlText('bbb'), XmlText('ccc')], ); element.normalize(); expect(element.children.length, 1); expect(element.toXmlString(), 'aaabbbccc'); }); test('trim whitespace', () { final element = XmlElement.tag( 'element', children: [XmlText(' a '), XmlText(' b ')], ); element.normalize(trimAllWhitespace: true); expect(element.children.length, 1); expect(element.toXmlString(), 'a b'); }); test('selectively trim whitespace', () { final element = XmlElement.tag( 'element', children: [ XmlElement.tag('a', children: [XmlText(' 1 ')]), XmlElement.tag('b', children: [XmlText(' 2 ')]), ], ); element.normalize(trimWhitespace: (node) => node.value == ' 2 '); expect(element.toXmlString(), ' 1 2'); }); test('collapse whitespace', () { final element = XmlElement.tag( 'element', children: [XmlText(' a '), XmlText(' b ')], ); element.normalize(collapseAllWhitespace: true); expect(element.children.length, 1); expect(element.toXmlString(), ' a b '); }); test('selectively collapse whitespace', () { final element = XmlElement.tag( 'element', children: [ XmlElement.tag('a', children: [XmlText('1 1')]), XmlElement.tag('b', children: [XmlText('2 2')]), ], ); element.normalize(collapseWhitespace: (node) => node.value == '2 2'); expect(element.toXmlString(), '1 12 2'); }); test('normalize newlines', () { final element = XmlElement.tag( 'element', children: [ XmlElement.tag('xD', children: [XmlText('\r')]), XmlElement.tag('xD-xA', children: [XmlText('\r\n')]), XmlElement.tag('xD-x85', children: [XmlText('\r\u0085')]), XmlElement.tag('x85', children: [XmlText('\u0085')]), XmlElement.tag('x2028', children: [XmlText('\u2028')]), ], ); element.normalize(normalizeAllNewline: true); expect( element.children.map((child) => child.innerText), everyElement('\n'), ); }); test('selectively normalize newlines', () { final element = XmlElement.tag( 'element', children: [ XmlElement.tag('xD', children: [XmlText('\r')]), XmlElement.tag('xD-xA', children: [XmlText('\r\n')]), XmlElement.tag('xD-x85', children: [XmlText('\r\u0085')]), XmlElement.tag('x85', children: [XmlText('\u0085')]), XmlElement.tag('x2028', children: [XmlText('\u2028')]), ], ); element.normalize(normalizeNewline: (node) => node.value.length > 1); expect(element.children.map((child) => child.innerText), [ '\r', '\n', '\n', '\u0085', '\u2028', ]); }); test('document fragment', () { final fragment = XmlDocumentFragment([ XmlText(''), XmlText('aaa'), XmlText(''), XmlElement(XmlName('element1')), XmlText(''), XmlText('bbb'), XmlText(''), XmlText('ccc'), XmlText(''), XmlElement(XmlName('element2')), XmlText(''), XmlText('ddd'), XmlText(''), ]); fragment.normalize(); final element = XmlElement(XmlName('element')); element.children.add(fragment); expect(element.children.length, 5); expect( element.toXmlString(), 'aaabbbcccddd', ); }); }); group('writer', () { final document = XmlDocument.parse( '\n' ' \tWhat\r the heck?\n\n' ' \tWhat\r the heck?\n\n' '', ); test('default', () { final output = document.toXmlString(); expect( output, '\n' ' \tWhat\r the heck?\n\n' ' \tWhat\r the heck?\n\n' '', ); }); test('pretty', () { final output = document.toXmlString(pretty: true); expect( output, '\n' ' What the heck?\n' ' What the heck?\n' '', ); }); test('indent', () { final output = document.toXmlString(pretty: true, indent: '\t'); expect( output, '\n' '\tWhat the heck?\n' '\tWhat the heck?\n' '', ); }); test('newline', () { final output = document.toXmlString(pretty: true, newLine: '\r\n'); expect( output, '\r\n' ' What the heck?\r\n' ' What the heck?\r\n' '', ); }); group('whitespace', () { test('preserve all', () { final output = document.toXmlString( pretty: true, preserveWhitespace: (node) => true, ); expect( output, '\n' ' \tWhat\r the heck?\n\n' ' \tWhat\r the heck?\n\n' '', ); }); test('preserve some', () { final output = document.toXmlString( pretty: true, preserveWhitespace: (node) => node is XmlElement && node.localName == 'b', ); expect( output, '\n' ' What the heck?\n' ' \tWhat\r the heck?\n\n' '', ); }); test('preserve nested', () { final input = XmlDocument.parse( '' '

bold, italic and both.

' '', ); final output = input.toXmlString( pretty: true, preserveWhitespace: (node) => node is XmlElement && node.localName == 'p', ); expect( output, '\n' ' \n' '

bold, italic and both.

\n' ' \n' '', ); }); test('normalize text', () { final input = XmlDocument([ XmlElement.tag( 'contents', children: [ XmlText(' Hello '), XmlText(' '), XmlText(' World '), XmlText(' '), ], ), ]); final output = input.toXmlString(pretty: true); expect(output, 'Hello World'); }); }); group('attributes', () { const input = '' 'AAA' 'BBB' 'CCC' ''; final document = XmlDocument.parse(input); tearDown( () => expect( document.toXmlString(), input, reason: 'Modified the original DOM.', ), ); test('indent none', () { final output = document.toXmlString( pretty: true, indentAttribute: (node) => false, ); expect( output, '\n' ' AAA\n' ' BBB\n' ' CCC\n' '', ); }); test('indent all', () { final output = document.toXmlString( pretty: true, indentAttribute: (node) => true, ); expect( output, '\n' ' AAA\n' ' BBB\n' ' CCC\n' '', ); }); test('intend after first', () { final output = document.toXmlString( pretty: true, indentAttribute: (node) => node.parent!.attributes.first != node, ); expect( output, '\n' ' AAA\n' ' BBB\n' ' CCC\n' '', ); }); test('indent when multiple', () { final output = document.toXmlString( pretty: true, indentAttribute: (node) => node.parent!.attributes.length > 1, ); expect( output, '\n' ' AAA\n' ' BBB\n' ' CCC\n' '', ); }); test('indent every second', () { final output = document.toXmlString( pretty: true, indentAttribute: (node) { final index = node.parent!.attributes.indexOf(node); return index > 0 && index.isEven; }, ); expect( output, '\n' ' AAA\n' ' BBB\n' ' CCC\n' '', ); }); test('no indent in preserve mode', () { final output = document.toXmlString( pretty: true, preserveWhitespace: (node) => true, indentAttribute: (node) => true, ); expect( output, '' 'AAA' 'BBB' 'CCC' '', ); }); test('sort reverse', () { final output = document.toXmlString( pretty: true, sortAttributes: (a, b) => b.name.qualified.compareTo(a.name.qualified), ); expect( output, '\n' ' AAA\n' ' BBB\n' ' CCC\n' '', ); }); test('sort reverse in preserve mode', () { final output = document.toXmlString( pretty: true, preserveWhitespace: (n) => true, sortAttributes: (a, b) => b.name.qualified.compareTo(a.name.qualified), ); expect( output, '' 'AAA' 'BBB' 'CCC' '', ); }); test('insert space before self-closing', () { final element = XmlElement.tag( 'base', children: [ XmlElement(XmlName('simple')), XmlElement.tag( 'with-attributes', attributes: [XmlAttribute(XmlName('attr'), 'val')], ), XmlElement(XmlName('do-not-add')), ], ); final output = element.toXmlString( pretty: true, spaceBeforeSelfClose: (node) => node is XmlElement && node.localName != 'do-not-add', ); expect( output, '\n' ' \n' ' \n' ' \n' '', ); }); }); }); }