Merge remote-tracking branch 'dartlang/master' into commonmark
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml index 7740d41..dc8a73d 100644 --- a/pkgs/markdown/pubspec.yaml +++ b/pkgs/markdown/pubspec.yaml
@@ -8,6 +8,7 @@ dev_dependencies: args: '^0.13.3+1' collection: ^1.2.0 + html: '^0.12.2' path: '^1.3.1' test: '^0.12.4+1' yaml: '^2.1.8'
diff --git a/pkgs/markdown/tool/common_mark_stats.dart b/pkgs/markdown/tool/common_mark_stats.dart index f34ca05..87c8039 100644 --- a/pkgs/markdown/tool/common_mark_stats.dart +++ b/pkgs/markdown/tool/common_mark_stats.dart
@@ -6,6 +6,7 @@ import 'dart:mirrors'; import 'package:collection/collection.dart'; +import 'package:html/parser.dart' show parseFragment; import 'package:markdown/markdown.dart'; import 'package:path/path.dart' as p; @@ -28,12 +29,20 @@ sections.forEach((section, examples) { for (var e in examples) { - var output = markdownToHtml(e.markdown); - + var output; var nestedMap = scores.putIfAbsent(section, () => new SplayTreeMap<int, bool>()); - nestedMap[e.example] = (output == e.html); + try { + output = markdownToHtml(e.markdown); + } catch (exc) { + nestedMap[e.example] = false; + continue; + } + + var expected = parseFragment(e.html); + var actual = parseFragment(output); + nestedMap[e.example] = compareHtml(expected.children, actual.children); } }); @@ -91,6 +100,60 @@ '– ${pct}% TOTAL'); } +/// Compare two DOM trees for equality. +bool compareHtml(List<Element> expectedElements, List<Element> actualElements) { + if (expectedElements.length != actualElements.length) { + return false; + } + + for (var childNum = 0; childNum < expectedElements.length; childNum++) { + var expected = expectedElements[childNum]; + var actual = actualElements[childNum]; + + if (expected.runtimeType != actual.runtimeType) { + return false; + } + + if (expected is Element) { + if (expected.localName != actual.localName) { + return false; + } + + if (expected.attributes.length != actual.attributes.length) { + return false; + } + + var expectedAttrKeys = expected.attributes.keys.toList(); + expectedAttrKeys.sort(); + + var actualAttrKeys = actual.attributes.keys.toList(); + actualAttrKeys.sort(); + + for (var attrNum = 0; attrNum < actualAttrKeys.length; attrNum++) { + var expectedAttrKey = expectedAttrKeys[attrNum]; + var actualAttrKey = actualAttrKeys[attrNum]; + + if (expectedAttrKey != actualAttrKey) { + return false; + } + + if (expected.attributes[expectedAttrKey] != + actual.attributes.keys[actualAttrKey]) { + return false; + } + } + } + + var childrenEqual = compareHtml(expected.children, actual.children); + + if (!childrenEqual) { + return false; + } + } + + return true; +} + Map<String, List<CommonMarkTestCase>> loadCommonMarkSections() { var testFile = new File(p.join(_currentDir, _commonMarkTests)); var testsJson = testFile.readAsStringSync();