import 'package:test/test.dart';
import 'package:xml/xml.dart';
import 'utils/assertions.dart';
import 'utils/matchers.dart';
const nameStartChars = {
'A',
'Z',
'_',
'a',
'z',
'\u{c0}',
'\u{d6}',
'\u{d8}',
'\u{f6}',
'\u{f8}',
'\u{2ff}',
'\u{370}',
'\u{37d}',
'\u{37f}',
'\u{1fff}',
'\u{200c}',
'\u{200d}',
'\u{2070}',
'\u{218f}',
'\u{2c00}',
'\u{2fef}',
'\u{3001}',
'\u{d7ff}',
'\u{f900}',
'\u{fdcf}',
'\u{fdf0}',
'\u{fffd}',
'\u{10000}',
'\u{effff}',
};
const nameChars = {
...nameStartChars,
'-',
'.',
'0',
'9',
'\u{B7}',
'\u{300}',
'\u{36F}',
'\u{203F}',
'\u{2040}',
};
void main() {
group('document', () {
test('cdata', () {
assertDocumentParseInvariants('');
});
test('cdata with xml', () {
assertDocumentParseInvariants(']]>');
});
test('comment', () {
assertDocumentParseInvariants(
''
'',
);
});
test('comment with xml', () {
assertDocumentParseInvariants(
''
'',
);
});
test('declaration', () {
assertDocumentParseInvariants('');
});
test('declaration with attribute', () {
assertDocumentParseInvariants('');
});
test('doctype (system)', () {
assertDocumentParseInvariants(
''
'',
);
});
test('doctype (public)', () {
assertDocumentParseInvariants(
''
'',
);
});
test('doctype (empty)', () {
assertDocumentParseInvariants(
'\n'
'',
);
});
test('doctype (comment)', () {
assertDocumentParseInvariants(
'\n'
']>\n'
'',
);
});
test('doctype (processing)', () {
assertDocumentParseInvariants(
'\n'
']>\n'
'',
);
});
test('doctype (element type declarations)', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (element content models)', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (element mixed content)', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (attribute-list)', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (internal entity)', () {
assertDocumentParseInvariants(
'\n'
']>\n'
'',
);
});
test('doctype (internal entity, included)', () {
assertDocumentParseInvariants(
'\n'
' \n'
']>\n'
'',
);
});
test('doctype (internal entity, replacement text)', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (entity reference)', () {
assertDocumentParseInvariants(
'\n'
']>\n'
'',
);
});
test('doctype (external entities )', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (notation)', () {
assertDocumentParseInvariants(
'\n'
' \n'
' \n'
']>\n'
'',
);
});
test('doctype (ambiguous)', () {
assertDocumentParseInvariants(
'] -->\n'
' ]" ?>\n'
' ]" \'[]\'>\n'
' ]">\n'
' ]\'>\n'
' ]">\n'
' ]\'>\n'
' \n'
' \n'
' \n'
' \n'
' ]" #REQUIRED>\n'
' ]\' #IMPLIED>\n'
']>\n'
'',
);
});
test('element', () {
assertDocumentParseInvariants('');
assertDocumentParseInvariants('');
assertDocumentParseInvariants('');
assertDocumentParseInvariants('');
});
test('element with namespace', () {
assertDocumentParseInvariants('');
});
test('element with closing', () {
assertDocumentParseInvariants('');
});
test('element with double quote attribute', () {
assertDocumentParseInvariants('');
assertDocumentParseInvariants('');
});
test('element with single quote attribute', () {
assertDocumentParseInvariants("");
assertDocumentParseInvariants("");
});
test('element with attribute without quotes', () {
assertDocumentParseInvariants('');
assertDocumentParseInvariants('');
});
test('element with attribute without value', () {
assertDocumentParseInvariants('');
assertDocumentParseInvariants('');
});
test('element with special initial char', () {
for (final char in nameStartChars) {
final qualified = char;
final closed = XmlDocument.parse('<$qualified />');
expect(closed.rootElement.name.qualified, qualified);
final openClosed = XmlDocument.parse('<$qualified>$qualified>');
expect(openClosed.rootElement.name.qualified, qualified);
}
});
test('element with special continuation char', () {
for (final char in nameChars) {
final qualified = 'x$char';
final closed = XmlDocument.parse('<$qualified />');
expect(closed.rootElement.name.qualified, qualified);
final openClosed = XmlDocument.parse('<$qualified>$qualified>');
expect(openClosed.rootElement.name.qualified, qualified);
}
});
test('element with attribute with special initial char', () {
for (final char in nameStartChars) {
final qualified = char;
final root = XmlDocument.parse('');
expect(root.rootElement.attributes.first.name.qualified, qualified);
expect(root.rootElement.getAttribute(qualified), 'ok');
}
});
test('element with attribute with with special continuation char', () {
for (final char in nameChars) {
final qualified = 'x$char';
final root = XmlDocument.parse('');
expect(root.rootElement.attributes.first.name.qualified, qualified);
expect(root.rootElement.getAttribute(qualified), 'ok');
}
});
test('processing instruction', () {
assertDocumentParseInvariants('');
});
test('processing instruction with attribute', () {
assertDocumentParseInvariants('');
});
test('document with comments', () {
assertDocumentParseInvariants(
''
''
''
'',
);
assertDocumentParseInvariants(
''
''
''
'',
);
assertDocumentParseInvariants(
''
''
''
'',
);
});
group('validation errors', () {
test('empty', () {
expect(
() => XmlDocument.parse(''),
throwsA(
isXmlParserException(
message: 'Expected a single root element',
position: 0,
),
),
);
});
test('whitespace', () {
expect(
() => XmlDocument.parse(' '),
throwsA(
isXmlParserException(
message: 'Expected a single root element',
position: 2,
),
),
);
});
test('repeated declaration', () {
expect(
() => XmlDocument.parse(
''
''
'',
),
throwsA(
isXmlParserException(
message: 'Expected at most one XML declaration',
position: 21,
),
),
);
});
test('repeated doctype', () {
expect(
() => XmlDocument.parse(
''
''
'',
),
throwsA(
isXmlParserException(
message: 'Expected at most one doctype declaration',
position: 37,
),
),
);
});
test('unexpected declaration', () {
expect(
() => XmlDocument.parse(
''
'',
),
throwsA(
isXmlParserException(
message: 'Unexpected XML declaration',
position: 37,
),
),
);
expect(
() => XmlDocument.parse(
''
'',
),
throwsA(
isXmlParserException(
message: 'Unexpected XML declaration',
position: 8,
),
),
);
});
test('unexpected doctype', () {
expect(
() => XmlDocument.parse(
''
'',
),
throwsA(
isXmlParserException(
message: 'Unexpected doctype declaration',
position: 8,
),
),
);
});
test('unexpected root element', () {
expect(
() => XmlDocument.parse(''),
throwsA(
isXmlParserException(
message: 'Unexpected root element',
position: 9,
),
),
);
});
});
group('parse errors', () {
test('nesting', () {
expect(
() => XmlDocument.parse(''),
throwsA(
isXmlTagException(
message: 'Expected , but found ',
position: 5,
),
),
);
expect(
() => XmlDocument.parse(''),
throwsA(isXmlTagException(message: 'Missing ', position: 5)),
);
expect(
() => XmlDocument.parse(''),
throwsA(isXmlTagException(message: 'Unexpected ', position: 0)),
);
});
test('element', () {
expect(
() => XmlDocument.parse('<'),
throwsA(isXmlParserException(message: 'name expected', position: 1)),
);
expect(
() => XmlDocument.parse('" expected', position: 5)),
);
expect(
() => XmlDocument.parse('" expected', position: 9)),
);
expect(
() => XmlDocument.parse('" expected', position: 9)),
);
});
test('comment', () {
expect(
() => XmlDocument.parse('" expected', position: 4)),
);
expect(
() => XmlDocument.parse('" expected', position: 4)),
);
});
test('cdata', () {
expect(
() => XmlDocument.parse('" expected', position: 9)),
);
expect(
() => XmlDocument.parse('" expected', position: 9)),
);
});
test('doctype', () {
expect(
() => XmlDocument.parse(' XmlDocument.parse('" expected', position: 14)),
);
expect(
() => XmlDocument.parse('" expected', position: 15)),
);
});
test('declaration', () {
expect(
() => XmlDocument.parse(''),
throwsA(isXmlParserException(message: 'name expected', position: 2)),
);
expect(
() => XmlDocument.parse('" expected', position: 5)),
);
expect(
() => XmlDocument.parse('" expected', position: 13)),
);
expect(
() => XmlDocument.parse('" expected', position: 13)),
);
expect(
() => XmlDocument.parse('" expected', position: 13)),
);
});
test('processing', () {
expect(
() => XmlDocument.parse(''),
throwsA(isXmlParserException(message: 'name expected', position: 2)),
);
expect(
() => XmlDocument.parse('" expected', position: 12)),
);
expect(
() => XmlDocument.parse('" expected', position: 12)),
);
});
});
});
group('fragment', () {
test('cdata', () {
assertFragmentParseInvariants('');
});
test('cdata with xml', () {
assertFragmentParseInvariants(']]>');
});
test('comment', () {
assertFragmentParseInvariants('');
});
test('comment with xml', () {
assertFragmentParseInvariants('');
});
test('declaration', () {
assertFragmentParseInvariants('');
});
test('declaration with attribute', () {
assertFragmentParseInvariants('');
});
test('doctype (system)', () {
assertFragmentParseInvariants(
'',
);
});
test('doctype (public)', () {
assertFragmentParseInvariants(
'',
);
});
test('doctype (subset)', () {
assertFragmentParseInvariants(
''
' '
' '
']>',
);
});
test('doctype (combined)', () {
assertFragmentParseInvariants(
''
' '
' '
']>',
);
});
test('element', () {
assertFragmentParseInvariants('');
assertFragmentParseInvariants('');
assertFragmentParseInvariants('');
assertFragmentParseInvariants('');
});
test('element with namespace', () {
assertFragmentParseInvariants('');
});
test('element with closing', () {
assertFragmentParseInvariants('');
});
test('element double quote attribute', () {
assertFragmentParseInvariants('');
});
test('element single quote attribute', () {
assertFragmentParseInvariants('');
});
test('processing instruction', () {
assertFragmentParseInvariants('');
});
test('processing instruction with attribute', () {
assertFragmentParseInvariants('');
});
test('text', () {
assertFragmentParseInvariants(
'I have a heart I swear I do, '
'Just not baby when it comes to you.',
);
});
test('empty', () {
assertFragmentParseInvariants('');
assertFragmentParseInvariants(' ');
assertFragmentParseInvariants('\t');
assertFragmentParseInvariants('\n');
assertFragmentParseInvariants(' ');
});
group('parse errors', () {
test('nesting', () {
expect(
() => XmlDocumentFragment.parse(''),
throwsA(
isXmlTagException(
message: 'Expected , but found ',
position: 5,
),
),
);
expect(
() => XmlDocumentFragment.parse(''),
throwsA(isXmlTagException(message: 'Missing ', position: 5)),
);
expect(
() => XmlDocumentFragment.parse(''),
throwsA(isXmlTagException(message: 'Unexpected ', position: 0)),
);
});
test('element', () {
expect(
() => XmlDocumentFragment.parse('<'),
throwsA(isXmlParserException(message: 'name expected', position: 1)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 5)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 9)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 9)),
);
});
test('comment', () {
expect(
() => XmlDocumentFragment.parse('" expected', position: 4)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 4)),
);
});
test('cdata', () {
expect(
() => XmlDocumentFragment.parse('" expected', position: 9)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 9)),
);
});
test('doctype', () {
expect(
() => XmlDocumentFragment.parse(' XmlDocumentFragment.parse('" expected', position: 14)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 15)),
);
});
test('declaration', () {
expect(
() => XmlDocumentFragment.parse(''),
throwsA(isXmlParserException(message: 'name expected', position: 2)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 5)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 13)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 13)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 13)),
);
});
test('processing', () {
expect(
() => XmlDocumentFragment.parse(''),
throwsA(isXmlParserException(message: 'name expected', position: 2)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 12)),
);
expect(
() => XmlDocumentFragment.parse('" expected', position: 12)),
);
});
});
});
}