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'
'',
);
});
});
});
}