OLD | NEW |
(Empty) | |
| 1 /** Additional feature tests that aren't based on test data. */ |
| 2 library parser_feature_test; |
| 3 |
| 4 import 'package:unittest/unittest.dart'; |
| 5 import 'package:html5lib/dom.dart'; |
| 6 import 'package:html5lib/dom_parsing.dart'; |
| 7 import 'package:html5lib/parser.dart'; |
| 8 import 'package:html5lib/src/constants.dart'; |
| 9 import 'package:html5lib/src/tokenizer.dart'; |
| 10 import 'package:html5lib/src/treebuilder.dart'; |
| 11 |
| 12 main() { |
| 13 test('doctype is cloneable', () { |
| 14 var doc = parse('<!DOCTYPE HTML>'); |
| 15 DocumentType doctype = doc.nodes[0]; |
| 16 expect(doctype.clone().outerHtml, '<!DOCTYPE html>'); |
| 17 }); |
| 18 |
| 19 test('line counter', () { |
| 20 // http://groups.google.com/group/html5lib-discuss/browse_frm/thread/f4f00e4
a2f26d5c0 |
| 21 var doc = parse("<pre>\nx\n>\n</pre>"); |
| 22 expect(doc.body.innerHtml, "<pre>x\n>\n</pre>"); |
| 23 }); |
| 24 |
| 25 test('namespace html elements on', () { |
| 26 var doc = new HtmlParser('', tree: new TreeBuilder(true)).parse(); |
| 27 expect(doc.nodes[0].namespace, Namespaces.html); |
| 28 }); |
| 29 |
| 30 test('namespace html elements off', () { |
| 31 var doc = new HtmlParser('', tree: new TreeBuilder(false)).parse(); |
| 32 expect(doc.nodes[0].namespace, null); |
| 33 }); |
| 34 |
| 35 test('parse error spans - full', () { |
| 36 var parser = new HtmlParser(''' |
| 37 <!DOCTYPE html> |
| 38 <html> |
| 39 <body> |
| 40 <!DOCTYPE html> |
| 41 </body> |
| 42 </html> |
| 43 ''', generateSpans: true, sourceUrl: 'ParseError'); |
| 44 var doc = parser.parse(); |
| 45 expect(doc.body.outerHtml, '<body>\n \n \n\n</body>'); |
| 46 expect(parser.errors.length, 1); |
| 47 ParseError error = parser.errors[0]; |
| 48 expect(error.errorCode, 'unexpected-doctype'); |
| 49 |
| 50 // Note: these values are 0-based, but the printed format is 1-based. |
| 51 expect(error.span.start.line, 3); |
| 52 expect(error.span.end.line, 3); |
| 53 expect(error.span.start.column, 2); |
| 54 expect(error.span.end.column, 17); |
| 55 expect(error.span.text, '<!DOCTYPE html>'); |
| 56 |
| 57 expect(error.toString(), ''' |
| 58 ParseError:4:3: Unexpected DOCTYPE. Ignored. |
| 59 <!DOCTYPE html> |
| 60 ^^^^^^^^^^^^^^^'''); |
| 61 }); |
| 62 |
| 63 test('parse error spans - minimal', () { |
| 64 var parser = new HtmlParser(''' |
| 65 <!DOCTYPE html> |
| 66 <html> |
| 67 <body> |
| 68 <!DOCTYPE html> |
| 69 </body> |
| 70 </html> |
| 71 '''); |
| 72 var doc = parser.parse(); |
| 73 expect(doc.body.outerHtml, '<body>\n \n \n\n</body>'); |
| 74 expect(parser.errors.length, 1); |
| 75 ParseError error = parser.errors[0]; |
| 76 expect(error.errorCode, 'unexpected-doctype'); |
| 77 expect(error.span.start.line, 3); |
| 78 // Note: error position is at the end, not the beginning |
| 79 expect(error.span.start.column, 17); |
| 80 }); |
| 81 |
| 82 test('text spans should have the correct length', () { |
| 83 var textContent = '\n hello {{name}}'; |
| 84 var html = '<body><div>$textContent</div>'; |
| 85 var doc = parse(html, generateSpans: true); |
| 86 var text = doc.body.nodes[0].nodes[0]; |
| 87 expect(text, new isInstanceOf<Text>()); |
| 88 expect(text.value, textContent); |
| 89 expect(text.sourceSpan.start.offset, html.indexOf(textContent)); |
| 90 expect(text.sourceSpan.length, textContent.length); |
| 91 }); |
| 92 |
| 93 test('attribute spans', () { |
| 94 var text = '<element name="x-foo" extends="x-bar" constructor="Foo">'; |
| 95 var doc = parse(text, generateSpans: true); |
| 96 var elem = doc.query('element'); |
| 97 expect(elem.sourceSpan.start.offset, 0); |
| 98 expect(elem.sourceSpan.end.offset, text.length); |
| 99 expect(elem.sourceSpan.text, text); |
| 100 |
| 101 expect(elem.attributeSpans['quux'], null); |
| 102 |
| 103 var span = elem.attributeSpans['extends']; |
| 104 expect(span.start.offset, text.indexOf('extends')); |
| 105 expect(span.text, 'extends="x-bar"'); |
| 106 }); |
| 107 |
| 108 test('attribute value spans', () { |
| 109 var text = '<element name="x-foo" extends="x-bar" constructor="Foo">'; |
| 110 var doc = parse(text, generateSpans: true); |
| 111 var elem = doc.query('element'); |
| 112 |
| 113 expect(elem.attributeValueSpans['quux'], null); |
| 114 |
| 115 var span = elem.attributeValueSpans['extends']; |
| 116 expect(span.start.offset, text.indexOf('x-bar')); |
| 117 expect(span.text, 'x-bar'); |
| 118 }); |
| 119 |
| 120 test('attribute spans if no attributes', () { |
| 121 var text = '<element>'; |
| 122 var doc = parse(text, generateSpans: true); |
| 123 var elem = doc.query('element'); |
| 124 |
| 125 expect(elem.attributeSpans['quux'], null); |
| 126 expect(elem.attributeValueSpans['quux'], null); |
| 127 }); |
| 128 |
| 129 test('attribute spans if no attribute value', () { |
| 130 var text = '<foo template>'; |
| 131 var doc = parse(text, generateSpans: true); |
| 132 var elem = doc.query('foo'); |
| 133 |
| 134 expect(elem.attributeSpans['template'].start.offset, |
| 135 text.indexOf('template')); |
| 136 expect(elem.attributeValueSpans.containsKey('template'), false); |
| 137 }); |
| 138 |
| 139 test('attribute spans null if code parsed without spans', () { |
| 140 var text = '<element name="x-foo" extends="x-bar" constructor="Foo">'; |
| 141 var doc = parse(text); |
| 142 var elem = doc.query('element'); |
| 143 expect(elem.sourceSpan, null); |
| 144 expect(elem.attributeSpans['quux'], null); |
| 145 expect(elem.attributeSpans['extends'], null); |
| 146 }); |
| 147 |
| 148 test('void element innerHTML', () { |
| 149 var doc = parse('<div></div>'); |
| 150 expect(doc.body.innerHtml, '<div></div>'); |
| 151 doc = parse('<body><script></script></body>'); |
| 152 expect(doc.body.innerHtml, '<script></script>'); |
| 153 doc = parse('<br>'); |
| 154 expect(doc.body.innerHtml, '<br>'); |
| 155 doc = parse('<br><foo><bar>'); |
| 156 expect(doc.body.innerHtml, '<br><foo><bar></bar></foo>'); |
| 157 }); |
| 158 |
| 159 test('empty document has html, body, and head', () { |
| 160 var doc = parse(''); |
| 161 expect(doc.outerHtml, '<html><head></head><body></body></html>'); |
| 162 expect(doc.head.outerHtml, '<head></head>'); |
| 163 expect(doc.body.outerHtml, '<body></body>'); |
| 164 }); |
| 165 |
| 166 test('strange table case', () { |
| 167 var doc = parseFragment('<table><tbody><foo>'); |
| 168 expect(doc.outerHtml, '<foo></foo><table><tbody></tbody></table>'); |
| 169 }); |
| 170 |
| 171 group('html serialization', () { |
| 172 test('attribute order', () { |
| 173 // Note: the spec only requires a stable order. |
| 174 // However, we preserve the input order via LinkedHashMap |
| 175 var doc = parseFragment('<foo d=1 a=2 c=3 b=4>'); |
| 176 expect(doc.outerHtml, '<foo d="1" a="2" c="3" b="4"></foo>'); |
| 177 expect(doc.query('foo').attributes.remove('a'), '2'); |
| 178 expect(doc.outerHtml, '<foo d="1" c="3" b="4"></foo>'); |
| 179 doc.query('foo').attributes['a'] = '0'; |
| 180 expect(doc.outerHtml, '<foo d="1" c="3" b="4" a="0"></foo>'); |
| 181 }); |
| 182 |
| 183 test('escaping Text node in <script>', () { |
| 184 var doc = parseFragment('<script>a && b</script>'); |
| 185 expect(doc.outerHtml, '<script>a && b</script>'); |
| 186 }); |
| 187 |
| 188 test('escaping Text node in <span>', () { |
| 189 var doc = parseFragment('<span>a && b</span>'); |
| 190 expect(doc.outerHtml, '<span>a && b</span>'); |
| 191 }); |
| 192 |
| 193 test('Escaping attributes', () { |
| 194 var doc = parseFragment('<div class="a<b>">'); |
| 195 expect(doc.outerHtml, '<div class="a<b>"></div>'); |
| 196 doc = parseFragment('<div class=\'a"b\'>'); |
| 197 expect(doc.outerHtml, '<div class="a"b"></div>'); |
| 198 }); |
| 199 |
| 200 test('Escaping non-breaking space', () { |
| 201 var text = '<span>foO\u00A0bar</span>'; |
| 202 expect(text.codeUnitAt(text.indexOf('O') + 1), 0xA0); |
| 203 var doc = parseFragment(text); |
| 204 expect(doc.outerHtml, '<span>foO bar</span>'); |
| 205 }); |
| 206 |
| 207 test('Newline after <pre>', () { |
| 208 var doc = parseFragment('<pre>\n\nsome text</span>'); |
| 209 expect(doc.query('pre').nodes[0].value, '\nsome text'); |
| 210 expect(doc.outerHtml, '<pre>\n\nsome text</pre>'); |
| 211 |
| 212 doc = parseFragment('<pre>\nsome text</span>'); |
| 213 expect(doc.query('pre').nodes[0].value, 'some text'); |
| 214 expect(doc.outerHtml, '<pre>some text</pre>'); |
| 215 }); |
| 216 |
| 217 test('xml namespaces', () { |
| 218 // Note: this is a nonsensical example, but it triggers the behavior |
| 219 // we're looking for with attribute names in foreign content. |
| 220 var doc = parse(''' |
| 221 <body> |
| 222 <svg> |
| 223 <desc xlink:type="simple" |
| 224 xlink:href="http://example.com/logo.png" |
| 225 xlink:show="new"></desc> |
| 226 '''); |
| 227 var n = doc.query('desc'); |
| 228 var keys = n.attributes.keys.toList(); |
| 229 expect(keys[0], new isInstanceOf<AttributeName>()); |
| 230 expect(keys[0].prefix, 'xlink'); |
| 231 expect(keys[0].namespace, 'http://www.w3.org/1999/xlink'); |
| 232 expect(keys[0].name, 'type'); |
| 233 |
| 234 expect(n.outerHtml, '<desc xlink:type="simple" ' |
| 235 'xlink:href="http://example.com/logo.png" xlink:show="new"></desc>'); |
| 236 }); |
| 237 }); |
| 238 |
| 239 test('error printing without spans', () { |
| 240 var parser = new HtmlParser('foo'); |
| 241 var doc = parser.parse(); |
| 242 expect(doc.body.innerHtml, 'foo'); |
| 243 expect(parser.errors.length, 1); |
| 244 expect(parser.errors[0].errorCode, 'expected-doctype-but-got-chars'); |
| 245 expect(parser.errors[0].message, |
| 246 'Unexpected non-space characters. Expected DOCTYPE.'); |
| 247 expect(parser.errors[0].toString(), |
| 248 'ParserError:1:4: Unexpected non-space characters. ' |
| 249 'Expected DOCTYPE.'); |
| 250 }); |
| 251 } |
OLD | NEW |