-html_to_json = (html) ->
- return JSON.stringify parse_html html
-test_equals "empty", html_to_json, "", '[]'
-test_equals "just text", html_to_json, "abc", '[[1,"abc"]]'
-test_equals "named entity", html_to_json, "a&1234", '[[1,"a&1234"]]'
-test_equals "broken named character references", html_to_json, "1&2&&3&aabbcc;", '[[1,"1&2&&3&aabbcc;"]]'
-test_equals "numbered entity overrides", html_to_json, "1€€ ƒ", '[[1,"1€€ ƒ"]]'
-test_equals "open tag", html_to_json, "foo<span>bar", '[[1,"foo"],[0,"span",{},[[1,"bar"]]]]'
-test_equals "open tag with attributes", html_to_json, "foo<span style=\"foo: bar\" title=\"hi\">bar", '[[1,"foo"],[0,"span",{"style":"foo: bar","title":"hi"},[[1,"bar"]]]]'
-test_equals "open tag with attributes of various quotings", html_to_json, "foo<span abc=\"def\" g=hij klm='nopqrstuv\"' autofocus>bar", '[[1,"foo"],[0,"span",{"abc":"def","g":"hij","klm":"nopqrstuv\\\"","autofocus":""},[[1,"bar"]]]]'
-test_equals "attribute entity exceptions dq", html_to_json, "foo<a href=\"foo?t=1&=2&o=3&lt=foo\">bar", '[[1,"foo"],[0,"a",{"href":"foo?t=1&=2&o=3<=foo"},[[1,"bar"]]]]'
-test_equals "attribute entity exceptions sq", html_to_json, "foo<a href='foo?t=1&=2&o=3&lt=foo'>bar", '[[1,"foo"],[0,"a",{"href":"foo?t=1&=2&o=3<=foo"},[[1,"bar"]]]]'
-test_equals "attribute entity exceptions uq", html_to_json, "foo<a href=foo?t=1&=2&o=3&lt=foo>bar", '[[1,"foo"],[0,"a",{"href":"foo?t=1&=2&o=3<=foo"},[[1,"bar"]]]]'
-test_equals "matching closing tags", html_to_json, "foo<a href=\"hi\">hi</a><div>1<div>foo</div>2</div>bar", '[[1,"foo"],[0,"a",{"href":"hi"},[[1,"hi"]]],[0,"div",{},[[1,"1"],[0,"div",{},[[1,"foo"]]],[1,"2"]]],[1,"bar"]]'
-test_equals "mis-matched closing tags", html_to_json, "foo<div>bar<span>baz</div>qux", '[[1,"foo"],[0,"div",{},[[1,"bar"],[0,"span",{},[[1,"baz"]]]]],[1,"qux"]]'
+serialize_els = (els, shallow, show_ids) ->
+ serialized = ''
+ sep = ''
+ for t in els
+ serialized += sep
+ sep = ','
+ serialized += t.serialize shallow, show_ids
+ return serialized
+test_parser = (args) ->
+ debug_log_reset()
+ parse_errors = []
+ errors_cb = (i) ->
+ parse_errors.push i
+ prev_node_id = 0 # reset counter
+ parsed = parse_html args.html, errors_cb
+ serialized = serialize_els parsed, false, false
+ if serialized isnt args.expected
+ debug_log_each (str) ->
+ console.log str
+ console.log "FAILED: \"#{args.name}\""
+ console.log " Input: #{args.html}"
+ console.log " Correct: #{args.expected}"
+ console.log " Output: #{serialized}"
+ if parse_errors.length > 0
+ console.log " parse errs: #{JSON.stringify parse_errors}"
+ else
+ console.log " No parse errors"
+ else
+ console.log "passed \"#{args.name}\""
+
+test_parser name: "empty", \
+ html: "",
+ expected: ''
+test_parser name: "just text", \
+ html: "abc",
+ expected: 'text:"abc"'
+test_parser name: "named entity", \
+ html: "a&1234",
+ expected: 'text:"a&1234"'
+test_parser name: "broken named character references", \
+ html: "1&2&&3&aabbcc;",
+ expected: 'text:"1&2&&3&aabbcc;"'
+test_parser name: "numbered entity overrides", \
+ html: "1€€ ƒ",
+ expected: 'text:"1€€ ƒ"'
+test_parser name: "open tag", \
+ html: "foo<span>bar",
+ expected: 'text:"foo",tag:"span",{},[text:"bar"]'
+test_parser name: "open tag with attributes", \
+ html: "foo<span style=\"foo: bar\" title=\"hi\">bar",
+ expected: 'text:"foo",tag:"span",{"style":"foo: bar","title":"hi"},[text:"bar"]'
+test_parser name: "open tag with attributes of various quotings", \
+ html: "foo<span abc=\"def\" g=hij klm='nopqrstuv\"' autofocus>bar",
+ expected: 'text:"foo",tag:"span",{"abc":"def","g":"hij","klm":"nopqrstuv\\"","autofocus":""},[text:"bar"]'
+test_parser name: "attribute entity exceptions dq", \
+ html: "foo<a href=\"foo?t=1&=2&o=3&lt=foo\">bar",
+ expected: 'text:"foo",tag:"a",{"href":"foo?t=1&=2&o=3<=foo"},[text:"bar"]'
+test_parser name: "attribute entity exceptions sq", \
+ html: "foo<a href='foo?t=1&=2&o=3&lt=foo'>bar",
+ expected: 'text:"foo",tag:"a",{"href":"foo?t=1&=2&o=3<=foo"},[text:"bar"]'
+test_parser name: "attribute entity exceptions uq", \
+ html: "foo<a href=foo?t=1&=2&o=3&lt=foo>bar",
+ expected: 'text:"foo",tag:"a",{"href":"foo?t=1&=2&o=3<=foo"},[text:"bar"]'
+test_parser name: "matching closing tags", \
+ html: "foo<a href=\"hi\">hi</a><div>1<div>foo</div>2</div>bar",
+ expected: 'text:"foo",tag:"a",{"href":"hi"},[text:"hi"],tag:"div",{},[text:"1",tag:"div",{},[text:"foo"],text:"2"],text:"bar"'
+test_parser name: "missing closing tag inside", \
+ html: "foo<div>bar<span>baz</div>qux",
+ expected: 'text:"foo",tag:"div",{},[text:"bar",tag:"span",{},[text:"baz"]],text:"qux"'
+test_parser name: "mis-matched closing tags", \
+ html: "<span>12<div>34</span>56</div>78",
+ expected: 'tag:"span",{},[text:"12",tag:"div",{},[text:"3456"],text:"78"]'
+test_parser name: "mis-matched formatting elements", \
+ html: "12<b>34<i>56</b>78</i>90",
+ expected: 'text:"12",tag:"b",{},[text:"34",tag:"i",{},[text:"56"]],tag:"i",{},[text:"78"],text:"90"'
+test_parser name: "8.2.8.1 Misnested tags: <b><i></b></i>", \
+ html: '<p>1<b>2<i>3</b>4</i>5</p>',
+ expected: 'tag:"p",{},[text:"1",tag:"b",{},[text:"2",tag:"i",{},[text:"3"]],tag:"i",{},[text:"4"],text:"5"]'
+test_parser name: "8.2.8.2 Misnested tags: <b><p></b></p>", \
+ html: '<b>1<p>2</b>3</p>',
+ expected: 'tag:"b",{},[text:"1"],tag:"p",{},[tag:"b",{},[text:"2"],text:"3"]'
+test_parser name: "crazy formatting elements test", \
+ html: "<b><i><a><s><tt><div></b>first</b></div></tt></s></a>second</i>",
+ # chrome does this: expected: 'tag:"b",{},[tag:"i",{},[tag:"a",{},[tag:"s",{},[tag:"tt",{},[]]],text:"second"]],tag:"a",{},[tag:"s",{},[tag:"tt",{},[tag:"div",{},[tag:"b",{},[],text:"first"]]]]'
+ # firefox does this:
+ expected: 'tag:"b",{},[tag:"i",{},[tag:"a",{},[tag:"s",{},[tag:"tt",{},[]]]]],tag:"a",{},[tag:"s",{},[tag:"tt",{},[tag:"div",{},[tag:"b",{},[],text:"first"]]]],text:"second"'
+# tests from https://github.com/html5lib/html5lib-tests/blob/master/tree-construction/adoption01.dat
+test_parser name: "html5lib aaa 1", \
+ html: '<a><p></a></p>',
+ expected: 'tag:"a",{},[],tag:"p",{},[tag:"a",{},[]]'
+test_parser name: "html5lib aaa 2", \
+ html: '<a>1<p>2</a>3</p>',
+ expected: 'tag:"a",{},[text:"1"],tag:"p",{},[tag:"a",{},[text:"2"],text:"3"]'
+test_parser name: "html5lib aaa 3", \
+ html: '<a>1<button>2</a>3</button>',
+ expected: 'tag:"a",{},[text:"1"],tag:"button",{},[tag:"a",{},[text:"2"],text:"3"]'
+test_parser name: "html5lib aaa 4", \
+ html: '<a>1<b>2</a>3</b>',
+ expected: 'tag:"a",{},[text:"1",tag:"b",{},[text:"2"]],tag:"b",{},[text:"3"]'
+test_parser name: "html5lib aaa 5 (two divs deep)", \
+ html: '<a>1<div>2<div>3</a>4</div>5</div>',
+ expected: 'tag:"a",{},[text:"1"],tag:"div",{},[tag:"a",{},[text:"2"],tag:"div",{},[tag:"a",{},[text:"3"],text:"4"],text:"5"]'
+test_parser name: "html5lib aaa 6 (foster parenting)", \
+ html: '<table><a>1<p>2</a>3</p>',
+ expected: 'tag:"a",{},[text:"1"],tag:"p",{},[tag:"a",{},[text:"2"],text:"3"],tag:"table",{},[]'
+test_parser name: "html5lib aaa 7 (aaa, eof) 1", \
+ html: '<b><b><a><p></a>',
+ expected: 'tag:"b",{},[tag:"b",{},[tag:"a",{},[],tag:"p",{},[tag:"a",{},[]]]]'
+test_parser name: "html5lib aaa 8 (aaa, eof) 2", \
+ html: '<b><a><b><p></a>',
+ expected: 'tag:"b",{},[tag:"a",{},[tag:"b",{},[]],tag:"b",{},[tag:"p",{},[tag:"a",{},[]]]]'
+test_parser name: "html5lib aaa 9 (aaa, eof) 3", \
+ html: '<a><b><b><p></a>',
+ expected: 'tag:"a",{},[tag:"b",{},[tag:"b",{},[]]],tag:"b",{},[tag:"b",{},[tag:"p",{},[tag:"a",{},[]]]]'
+test_parser name: "html5lib aaa 10 (formatting, nesting, attrs, aaa)", \
+ html: '<p>1<s id="A">2<b id="B">3</p>4</s>5</b>',
+ expected: 'tag:"p",{},[text:"1",tag:"s",{"id":"A"},[text:"2",tag:"b",{"id":"B"},[text:"3"]]],tag:"s",{"id":"A"},[tag:"b",{"id":"B"},[text:"4"]],tag:"b",{"id":"B"},[text:"5"]'
+test_parser name: "html5lib aaa 11 (table with foster parenting, formatting el and td)", \
+ html: '<table><a>1<td>2</td>3</table>',
+ expected: 'tag:"a",{},[text:"1"],tag:"a",{},[text:"3"],tag:"table",{},[tag:"tbody",{},[tag:"tr",{},[tag:"td",{},[text:"2"]]]]'
+test_parser name: "html5lib aaa 12 (table with foster parenting, split text)", \
+ html: '<table>A<td>B</td>C</table>',
+ expected: 'text:"AC",tag:"table",{},[tag:"tbody",{},[tag:"tr",{},[tag:"td",{},[text:"B"]]]]'
+# TODO implement svg and namespacing
+#test_parser name: "html5lib aaa 13 (svg tr input)", \
+# html: '<a><svg><tr><input></a>',
+# expected: 'tag:"a",{},[svg:"svg",{},[svg:"tr",{},[svg:"input"]]]'
+test_parser name: "html5lib aaa 14 (deep ?outer aaa)", \
+ html: '<div><a><b><div><div><div><div><div><div><div><div><div><div></a>',
+ expected: 'tag:"div",{},[tag:"a",{},[tag:"b",{},[]],tag:"b",{},[tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[],tag:"div",{},[tag:"a",{},[tag:"div",{},[tag:"div",{},[]]]]]]]]]]]]]'
+test_parser name: "html5lib aaa 15 (deep ?inner aaa)", \
+ html: '<div><a><b><u><i><code><div></a>',
+ expected: 'tag:"div",{},[tag:"a",{},[tag:"b",{},[tag:"u",{},[tag:"i",{},[tag:"code",{},[]]]]],tag:"u",{},[tag:"i",{},[tag:"code",{},[tag:"div",{},[tag:"a",{},[]]]]]]'