Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: packages/html/test/parser_feature_test.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « packages/html/test/dom_test.dart ('k') | packages/html/test/parser_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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:html/dom.dart';
6 import 'package:html/parser.dart';
7 import 'package:html/src/constants.dart';
8 import 'package:html/src/encoding_parser.dart';
9 import 'package:html/src/treebuilder.dart';
10 import 'package:source_span/source_span.dart';
11
12 main() {
13 _testElementSpans();
14 test('doctype is cloneable', () {
15 var doc = parse('<!doctype HTML>');
16 DocumentType doctype = doc.nodes[0];
17 expect(doctype.clone(false).toString(), '<!DOCTYPE html>');
18 });
19
20 test('line counter', () {
21 // http://groups.google.com/group/html5lib-discuss/browse_frm/thread/f4f00e4 a2f26d5c0
22 var doc = parse("<pre>\nx\n&gt;\n</pre>");
23 expect(doc.body.innerHtml, "<pre>x\n&gt;\n</pre>");
24 });
25
26 test('namespace html elements on', () {
27 var doc = new HtmlParser('', tree: new TreeBuilder(true)).parse();
28 expect(doc.nodes[0].namespaceUri, Namespaces.html);
29 });
30
31 test('namespace html elements off', () {
32 var doc = new HtmlParser('', tree: new TreeBuilder(false)).parse();
33 expect(doc.nodes[0].namespaceUri, null);
34 });
35
36 test('parse error spans - full', () {
37 var parser = new HtmlParser('''
38 <!DOCTYPE html>
39 <html>
40 <body>
41 <!DOCTYPE html>
42 </body>
43 </html>
44 ''', generateSpans: true, sourceUrl: 'ParseError');
45 var doc = parser.parse();
46 expect(doc.body.outerHtml, '<body>\n \n \n\n</body>');
47 expect(parser.errors.length, 1);
48 ParseError error = parser.errors[0];
49 expect(error.errorCode, 'unexpected-doctype');
50
51 // Note: these values are 0-based, but the printed format is 1-based.
52 expect(error.span.start.line, 3);
53 expect(error.span.end.line, 3);
54 expect(error.span.start.column, 2);
55 expect(error.span.end.column, 17);
56 expect(error.span.text, '<!DOCTYPE html>');
57
58 expect(error.toString(), '''
59 On line 4, column 3 of ParseError: Unexpected DOCTYPE. Ignored.
60 <!DOCTYPE html>
61 ^^^^^^^^^^^^^^^''');
62 });
63
64 test('parse error spans - minimal', () {
65 var parser = new HtmlParser('''
66 <!DOCTYPE html>
67 <html>
68 <body>
69 <!DOCTYPE html>
70 </body>
71 </html>
72 ''');
73 var doc = parser.parse();
74 expect(doc.body.outerHtml, '<body>\n \n \n\n</body>');
75 expect(parser.errors.length, 1);
76 ParseError error = parser.errors[0];
77 expect(error.errorCode, 'unexpected-doctype');
78 expect(error.span.start.line, 3);
79 // Note: error position is at the end, not the beginning
80 expect(error.span.start.column, 17);
81 });
82
83 test('text spans should have the correct length', () {
84 var textContent = '\n hello {{name}}';
85 var html = '<body><div>$textContent</div>';
86 var doc = parse(html, generateSpans: true);
87 Text text = doc.body.nodes[0].nodes[0];
88 expect(text, new isInstanceOf<Text>());
89 expect(text.data, textContent);
90 expect(text.sourceSpan.start.offset, html.indexOf(textContent));
91 expect(text.sourceSpan.length, textContent.length);
92 });
93
94 test('attribute spans', () {
95 var text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
96 var doc = parse(text, generateSpans: true);
97 var elem = doc.querySelector('element');
98 expect(elem.sourceSpan.start.offset, 0);
99 expect(elem.sourceSpan.end.offset, text.length);
100 expect(elem.sourceSpan.text, text);
101
102 expect(elem.attributeSpans['quux'], null);
103
104 var span = elem.attributeSpans['extends'];
105 expect(span.start.offset, text.indexOf('extends'));
106 expect(span.text, 'extends="x-bar"');
107 });
108
109 test('attribute value spans', () {
110 var text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
111 var doc = parse(text, generateSpans: true);
112 var elem = doc.querySelector('element');
113
114 expect(elem.attributeValueSpans['quux'], null);
115
116 var span = elem.attributeValueSpans['extends'];
117 expect(span.start.offset, text.indexOf('x-bar'));
118 expect(span.text, 'x-bar');
119 });
120
121 test('attribute spans if no attributes', () {
122 var text = '<element>';
123 var doc = parse(text, generateSpans: true);
124 var elem = doc.querySelector('element');
125
126 expect(elem.attributeSpans['quux'], null);
127 expect(elem.attributeValueSpans['quux'], null);
128 });
129
130 test('attribute spans if no attribute value', () {
131 var text = '<foo template>';
132 var doc = parse(text, generateSpans: true);
133 var elem = doc.querySelector('foo');
134
135 expect(
136 elem.attributeSpans['template'].start.offset, text.indexOf('template'));
137 expect(elem.attributeValueSpans.containsKey('template'), false);
138 });
139
140 test('attribute spans null if code parsed without spans', () {
141 var text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
142 var doc = parse(text);
143 var elem = doc.querySelector('element');
144 expect(elem.sourceSpan, null);
145 expect(elem.attributeSpans['quux'], null);
146 expect(elem.attributeSpans['extends'], null);
147 });
148
149 test('void element innerHTML', () {
150 var doc = parse('<div></div>');
151 expect(doc.body.innerHtml, '<div></div>');
152 doc = parse('<body><script></script></body>');
153 expect(doc.body.innerHtml, '<script></script>');
154 doc = parse('<br>');
155 expect(doc.body.innerHtml, '<br>');
156 doc = parse('<br><foo><bar>');
157 expect(doc.body.innerHtml, '<br><foo><bar></bar></foo>');
158 });
159
160 test('empty document has html, body, and head', () {
161 var doc = parse('');
162 var html = '<html><head></head><body></body></html>';
163 expect(doc.outerHtml, html);
164 expect(doc.documentElement.outerHtml, html);
165 expect(doc.head.outerHtml, '<head></head>');
166 expect(doc.body.outerHtml, '<body></body>');
167 });
168
169 test('strange table case', () {
170 var doc = parse('<table><tbody><foo>').body;
171 expect(doc.innerHtml, '<foo></foo><table><tbody></tbody></table>');
172 });
173
174 group('html serialization', () {
175 test('attribute order', () {
176 // Note: the spec only requires a stable order.
177 // However, we preserve the input order via LinkedHashMap
178 var body = parse('<foo d=1 a=2 c=3 b=4>').body;
179 expect(body.innerHtml, '<foo d="1" a="2" c="3" b="4"></foo>');
180 expect(body.querySelector('foo').attributes.remove('a'), '2');
181 expect(body.innerHtml, '<foo d="1" c="3" b="4"></foo>');
182 body.querySelector('foo').attributes['a'] = '0';
183 expect(body.innerHtml, '<foo d="1" c="3" b="4" a="0"></foo>');
184 });
185
186 test('escaping Text node in <script>', () {
187 Element e = parseFragment('<script>a && b</script>').firstChild;
188 expect(e.outerHtml, '<script>a && b</script>');
189 });
190
191 test('escaping Text node in <span>', () {
192 Element e = parseFragment('<span>a && b</span>').firstChild;
193 expect(e.outerHtml, '<span>a &amp;&amp; b</span>');
194 });
195
196 test('Escaping attributes', () {
197 Element e = parseFragment('<div class="a<b>">').firstChild;
198 expect(e.outerHtml, '<div class="a<b>"></div>');
199 e = parseFragment('<div class=\'a"b\'>').firstChild;
200 expect(e.outerHtml, '<div class="a&quot;b"></div>');
201 });
202
203 test('Escaping non-breaking space', () {
204 var text = '<span>foO\u00A0bar</span>';
205 expect(text.codeUnitAt(text.indexOf('O') + 1), 0xA0);
206 Element e = parseFragment(text).firstChild;
207 expect(e.outerHtml, '<span>foO&nbsp;bar</span>');
208 });
209
210 test('Newline after <pre>', () {
211 Element e = parseFragment('<pre>\n\nsome text</span>').firstChild;
212 expect((e.firstChild as Text).data, '\nsome text');
213 expect(e.outerHtml, '<pre>\n\nsome text</pre>');
214
215 e = parseFragment('<pre>\nsome text</span>').firstChild;
216 expect((e.firstChild as Text).data, 'some text');
217 expect(e.outerHtml, '<pre>some text</pre>');
218 });
219
220 test('xml namespaces', () {
221 // Note: this is a nonsensical example, but it triggers the behavior
222 // we're looking for with attribute names in foreign content.
223 var doc = parse('''
224 <body>
225 <svg>
226 <desc xlink:type="simple"
227 xlink:href="http://example.com/logo.png"
228 xlink:show="new"></desc>
229 ''');
230 var n = doc.querySelector('desc');
231 var keys = n.attributes.keys.toList();
232 expect(keys[0], new isInstanceOf<AttributeName>());
233 expect(keys[0].prefix, 'xlink');
234 expect(keys[0].namespace, 'http://www.w3.org/1999/xlink');
235 expect(keys[0].name, 'type');
236
237 expect(n.outerHtml, '<desc xlink:type="simple" '
238 'xlink:href="http://example.com/logo.png" xlink:show="new"></desc>');
239 });
240 });
241
242 test('error printing without spans', () {
243 var parser = new HtmlParser('foo');
244 var doc = parser.parse();
245 expect(doc.body.innerHtml, 'foo');
246 expect(parser.errors.length, 1);
247 expect(parser.errors[0].errorCode, 'expected-doctype-but-got-chars');
248 expect(parser.errors[0].message,
249 'Unexpected non-space characters. Expected DOCTYPE.');
250 expect(parser.errors[0].toString(),
251 'ParserError on line 1, column 4: Unexpected non-space characters. '
252 'Expected DOCTYPE.\n'
253 'foo\n'
254 ' ^');
255 });
256
257 test('Element.text', () {
258 var doc = parseFragment('<div>foo<div>bar</div>baz</div>');
259 var e = doc.firstChild;
260 var text = e.firstChild;
261 expect((text as Text).data, 'foo');
262 expect(e.text, 'foobarbaz');
263
264 e.text = 'FOO';
265 expect(e.nodes.length, 1);
266 expect(e.firstChild, isNot(text), reason: 'should create a new tree');
267 expect((e.firstChild as Text).data, 'FOO');
268 expect(e.text, 'FOO');
269 });
270
271 test('Text.text', () {
272 var doc = parseFragment('<div>foo<div>bar</div>baz</div>');
273 var e = doc.firstChild;
274 Text text = e.firstChild;
275 expect(text.data, 'foo');
276 expect(text.text, 'foo');
277
278 text.text = 'FOO';
279 expect(text.data, 'FOO');
280 expect(e.text, 'FOObarbaz');
281 expect(text.text, 'FOO');
282 });
283
284 test('Comment.text', () {
285 var doc = parseFragment('<div><!--foo-->bar</div>');
286 var e = doc.firstChild;
287 var c = e.firstChild;
288 expect((c as Comment).data, 'foo');
289 expect(c.text, 'foo');
290 expect(e.text, 'bar');
291
292 c.text = 'qux';
293 expect(c.data, 'qux');
294 expect(c.text, 'qux');
295 expect(e.text, 'bar');
296 });
297
298 test('foreignObject end tag', () {
299 var p = new HtmlParser('''
300 <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"
301 version="1.1">
302 <foreignObject width="320px" height="200px">
303 <x-flow></x-flow>
304 </foreignObject>
305 </svg>''');
306 var doc = p.parseFragment();
307 expect(p.errors, isEmpty);
308 var svg = doc.querySelector('svg');
309 expect(svg.children[0].children[0].localName, 'x-flow');
310 });
311
312 group('Encoding pre-parser', () {
313 getEncoding(s) => new EncodingParser(s.codeUnits).getEncoding();
314
315 test('gets encoding from meta charset', () {
316 expect(getEncoding('<meta charset="utf-16">'), 'utf-16');
317 });
318
319 test('gets encoding from meta in head', () {
320 expect(getEncoding('<head><meta charset="utf-16">'), 'utf-16');
321 });
322
323 test('skips comments', () {
324 expect(getEncoding('<!--comment--><meta charset="utf-16">'), 'utf-16');
325 });
326
327 test('stops if no match', () {
328 // missing closing tag
329 expect(getEncoding('<meta charset="utf-16"'), null);
330 });
331
332 test('ignores whitespace', () {
333 expect(getEncoding(' <meta charset="utf-16">'), 'utf-16');
334 });
335 });
336 }
337
338 _testElementSpans() {
339 assertSpan(SourceSpan span, int offset, int end, String text) {
340 expect(span, isNotNull);
341 expect(span.start.offset, offset);
342 expect(span.end.offset, end);
343 expect(span.text, text);
344 }
345
346 group('element spans', () {
347 test('html and body', () {
348 var text = '<html><body>123</body></html>';
349 var doc = parse(text, generateSpans: true);
350 {
351 var elem = doc.querySelector('html');
352 assertSpan(elem.sourceSpan, 0, 6, '<html>');
353 assertSpan(elem.endSourceSpan, 22, 29, '</html>');
354 }
355 {
356 var elem = doc.querySelector('body');
357 assertSpan(elem.sourceSpan, 6, 12, '<body>');
358 assertSpan(elem.endSourceSpan, 15, 22, '</body>');
359 }
360 });
361
362 test('normal', () {
363 var text = '<div><element><span></span></element></div>';
364 var doc = parse(text, generateSpans: true);
365 var elem = doc.querySelector('element');
366 assertSpan(elem.sourceSpan, 5, 14, '<element>');
367 assertSpan(elem.endSourceSpan, 27, 37, '</element>');
368 });
369
370 test('block', () {
371 var text = '<div>123</div>';
372 var doc = parse(text, generateSpans: true);
373 var elem = doc.querySelector('div');
374 assertSpan(elem.sourceSpan, 0, 5, '<div>');
375 assertSpan(elem.endSourceSpan, 8, 14, '</div>');
376 });
377
378 test('form', () {
379 var text = '<form>123</form>';
380 var doc = parse(text, generateSpans: true);
381 var elem = doc.querySelector('form');
382 assertSpan(elem.sourceSpan, 0, 6, '<form>');
383 assertSpan(elem.endSourceSpan, 9, 16, '</form>');
384 });
385
386 test('p explicit end', () {
387 var text = '<p>123</p>';
388 var doc = parse(text, generateSpans: true);
389 var elem = doc.querySelector('p');
390 assertSpan(elem.sourceSpan, 0, 3, '<p>');
391 assertSpan(elem.endSourceSpan, 6, 10, '</p>');
392 });
393
394 test('p implicit end', () {
395 var text = '<div><p>123<p>456</div>';
396 var doc = parse(text, generateSpans: true);
397 var elem = doc.querySelector('p');
398 assertSpan(elem.sourceSpan, 5, 8, '<p>');
399 expect(elem.endSourceSpan, isNull);
400 });
401
402 test('li', () {
403 var text = '<li>123</li>';
404 var doc = parse(text, generateSpans: true);
405 var elem = doc.querySelector('li');
406 assertSpan(elem.sourceSpan, 0, 4, '<li>');
407 assertSpan(elem.endSourceSpan, 7, 12, '</li>');
408 });
409
410 test('heading', () {
411 var text = '<h1>123</h1>';
412 var doc = parse(text, generateSpans: true);
413 var elem = doc.querySelector('h1');
414 assertSpan(elem.sourceSpan, 0, 4, '<h1>');
415 assertSpan(elem.endSourceSpan, 7, 12, '</h1>');
416 });
417
418 test('formatting', () {
419 var text = '<b>123</b>';
420 var doc = parse(text, generateSpans: true);
421 var elem = doc.querySelector('b');
422 assertSpan(elem.sourceSpan, 0, 3, '<b>');
423 assertSpan(elem.endSourceSpan, 6, 10, '</b>');
424 });
425
426 test('table tbody', () {
427 var text = '<table><tbody> </tbody></table>';
428 var doc = parse(text, generateSpans: true);
429 {
430 var elem = doc.querySelector('tbody');
431 assertSpan(elem.sourceSpan, 7, 14, '<tbody>');
432 assertSpan(elem.endSourceSpan, 16, 24, '</tbody>');
433 }
434 });
435
436 test('table tr td', () {
437 var text = '<table><tr><td>123</td></tr></table>';
438 var doc = parse(text, generateSpans: true);
439 {
440 var elem = doc.querySelector('table');
441 assertSpan(elem.sourceSpan, 0, 7, '<table>');
442 assertSpan(elem.endSourceSpan, 28, 36, '</table>');
443 }
444 {
445 var elem = doc.querySelector('tr');
446 assertSpan(elem.sourceSpan, 7, 11, '<tr>');
447 assertSpan(elem.endSourceSpan, 23, 28, '</tr>');
448 }
449 {
450 var elem = doc.querySelector('td');
451 assertSpan(elem.sourceSpan, 11, 15, '<td>');
452 assertSpan(elem.endSourceSpan, 18, 23, '</td>');
453 }
454 });
455
456 test('select optgroup option', () {
457 var text = '<select><optgroup><option>123</option></optgroup></select>';
458 var doc = parse(text, generateSpans: true);
459 {
460 var elem = doc.querySelector('select');
461 assertSpan(elem.sourceSpan, 0, 8, '<select>');
462 assertSpan(elem.endSourceSpan, 49, 58, '</select>');
463 }
464 {
465 var elem = doc.querySelector('optgroup');
466 assertSpan(elem.sourceSpan, 8, 18, '<optgroup>');
467 assertSpan(elem.endSourceSpan, 38, 49, '</optgroup>');
468 }
469 {
470 var elem = doc.querySelector('option');
471 assertSpan(elem.sourceSpan, 18, 26, '<option>');
472 assertSpan(elem.endSourceSpan, 29, 38, '</option>');
473 }
474 });
475 });
476 }
OLDNEW
« no previous file with comments | « packages/html/test/dom_test.dart ('k') | packages/html/test/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698