moving most test cases into unit files

moving reusable test code into util library
diff --git a/pkgs/markdown/lib/src/html_renderer.dart b/pkgs/markdown/lib/src/html_renderer.dart
index edb09a0..87fb05c 100644
--- a/pkgs/markdown/lib/src/html_renderer.dart
+++ b/pkgs/markdown/lib/src/html_renderer.dart
@@ -25,7 +25,7 @@
   var lines = markdown.replaceAll('\r\n', '\n').split('\n');
   document.parseRefLinks(lines);
 
-  return renderToHtml(document.parseLines(lines));
+  return renderToHtml(document.parseLines(lines)) + '\n';
 }
 
 String renderToHtml(List<Node> nodes) => new HtmlRenderer().render(nodes);
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml
index 5861600..0c2eedf 100644
--- a/pkgs/markdown/pubspec.yaml
+++ b/pkgs/markdown/pubspec.yaml
@@ -6,4 +6,5 @@
 environment:
   sdk: '>=1.8.0 <2.0.0'
 dev_dependencies:
+  path: '^1.3.1'
   test: '^0.12.4+1'
diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart
index b747289..736488b 100644
--- a/pkgs/markdown/test/markdown_test.dart
+++ b/pkgs/markdown/test/markdown_test.dart
@@ -14,1337 +14,37 @@
 /// Most of these tests are based on observing how showdown behaves:
 /// http://softwaremaniacs.org/playground/showdown-highlight/
 void main() {
-  group('Paragraphs', () {
-    validate(
-        'consecutive lines form a single paragraph',
-        '''
-        This is the first line.
-        This is the second line.
-        ''',
-        '''
-        <p>This is the first line.
-        This is the second line.</p>
-        ''');
-
-    // TODO(rnystrom): The rules here for what happens to lines following a
-    // paragraph appear to be completely arbitrary in markdown. If it makes the
-    // code significantly cleaner, we should consider ourselves free to change
-    // these tests.
-
-    validate(
-        'are terminated by a header',
-        '''
-        para
-        # header
-        ''',
-        '''
-        <p>para</p>
-        <h1>header</h1>
-        ''');
-
-    validate(
-        'are terminated by a setext header',
-        '''
-        para
-        header
-        ==
-        ''',
-        '''
-        <p>para</p>
-        <h1>header</h1>
-        ''');
-
-    validate(
-        'are terminated by a hr',
-        '''
-        para
-        ___
-        ''',
-        '''
-        <p>para</p>
-        <hr />
-        ''');
-
-    validate(
-        'consume an unordered list',
-        '''
-        para
-        * list
-        ''',
-        '''
-        <p>para
-        * list</p>
-        ''');
-
-    validate(
-        'consume an ordered list',
-        '''
-        para
-        1. list
-        ''',
-        '''
-        <p>para
-        1. list</p>
-        ''');
-
-    // Windows line endings have a \r\n format
-    // instead of the unix \n format.
-    validate(
-        'take account of windows line endings',
-        '''
-        line1\r\n\r\n        line2\r\n
-        ''',
-        '''
-        <p>line1</p>
-        <p>line2</p>
-        ''');
-  });
-
-  group('Setext headers', () {
-    validate(
-        'h1',
-        '''
-        text
-        ===
-        ''',
-        '''
-        <h1>text</h1>
-        ''');
-
-    validate(
-        'h2',
-        '''
-        text
-        ---
-        ''',
-        '''
-        <h2>text</h2>
-        ''');
-
-    validate(
-        'h1 on first line becomes text',
-        '''
-        ===
-        ''',
-        '''
-        <p>===</p>
-        ''');
-
-    validate(
-        'h2 on first line becomes text',
-        '''
-        -
-        ''',
-        '''
-        <p>-</p>
-        ''');
-
-    validate(
-        'h1 turns preceding list into text',
-        '''
-        - list
-        ===
-        ''',
-        '''
-        <h1>- list</h1>
-        ''');
-
-    validate(
-        'h2 turns preceding list into text',
-        '''
-        - list
-        ===
-        ''',
-        '''
-        <h1>- list</h1>
-        ''');
-
-    validate(
-        'h1 turns preceding blockquote into text',
-        '''
-        > quote
-        ===
-        ''',
-        '''
-        <h1>> quote</h1>
-        ''');
-
-    validate(
-        'h2 turns preceding blockquote into text',
-        '''
-        > quote
-        ===
-        ''',
-        '''
-        <h1>> quote</h1>
-        ''');
-  });
-
-  group('Headers', () {
-    validate(
-        'h1',
-        '''
-        # header
-        ''',
-        '''
-        <h1>header</h1>
-        ''');
-
-    validate(
-        'h2',
-        '''
-        ## header
-        ''',
-        '''
-        <h2>header</h2>
-        ''');
-
-    validate(
-        'h3',
-        '''
-        ### header
-        ''',
-        '''
-        <h3>header</h3>
-        ''');
-
-    validate(
-        'h4',
-        '''
-        #### header
-        ''',
-        '''
-        <h4>header</h4>
-        ''');
-
-    validate(
-        'h5',
-        '''
-        ##### header
-        ''',
-        '''
-        <h5>header</h5>
-        ''');
-
-    validate(
-        'h6',
-        '''
-        ###### header
-        ''',
-        '''
-        <h6>header</h6>
-        ''');
-
-    validate(
-        'h7 is not a header',
-        '''
-        ####### header
-        ''',
-        '''
-        <p>####### header</p>
-        ''');
-
-    validate(
-        'h6 must not be followed by non-space ',
-        '''
-        ######A header
-        ''',
-        '''
-        <p>######A header</p>
-        ''');
-
-    validate(
-        'trailing "#" are removed',
-        '''
-        # header ######
-        ''',
-        '''
-        <h1>header</h1>
-        ''');
-  });
-
-  group('Unordered lists', () {
-    validate(
-        'asterisk, plus and hyphen',
-        '''
-        * star
-        - dash
-        + plus
-        ''',
-        '''
-        <ul>
-          <li>star</li>
-          <li>dash</li>
-          <li>plus</li>
-        </ul>
-        ''');
-
-    validate(
-        'allow numbered lines after first',
-        '''
-        * a
-        1. b
-        ''',
-        '''
-        <ul>
-          <li>a</li>
-          <li>b</li>
-        </ul>
-        ''');
-
-    validate(
-        'allow a tab after the marker',
-        '''
-        *\ta
-        +\tb
-        -\tc
-        1.\td
-        ''',
-        '''
-        <ul>
-          <li>a</li>
-          <li>b</li>
-          <li>c</li>
-          <li>d</li>
-        </ul>
-        ''');
-
-    validate(
-        'wrap items in paragraphs if blank lines separate',
-        '''
-        * one
-
-        * two
-        ''',
-        '''
-        <ul>
-          <li><p>one</p></li>
-          <li><p>two</p></li>
-        </ul>
-        ''');
-
-    validate(
-        'force paragraph on item before and after blank lines',
-        '''
-        *   one
-        *   two
-
-        *   three
-        ''',
-        '''
-        <ul>
-          <li>one</li>
-          <li>
-            <p>two</p>
-          </li>
-          <li>
-            <p>three</p>
-          </li>
-        </ul>
-        ''');
-
-    validate(
-        'do not force paragraph if item is already block',
-        '''
-        * > quote
-
-        * # header
-        ''',
-        '''
-        <ul>
-          <li><blockquote><p>quote</p></blockquote></li>
-          <li><h1>header</h1></li>
-        </ul>
-        ''');
-
-    validate(
-        'can contain multiple paragraphs',
-        '''
-        *   one
-
-            two
-
-        *   three
-        ''',
-        '''
-        <ul>
-          <li>
-            <p>one</p>
-            <p>two</p>
-          </li>
-          <li>
-            <p>three</p>
-          </li>
-        </ul>
-        ''');
-
-    validate(
-        'can span newlines',
-        '''
-        *   one
-            two
-        *   three
-        ''',
-        '''
-        <ul>
-          <li>
-            <p>one
-            two</p>
-          </li>
-          <li>
-            three
-          </li>
-        </ul>
-        ''');
-
-    // TODO(rnystrom): This is how most other markdown parsers handle
-    // this but that seems like a nasty special case. For now, let's not
-    // worry about it.
-    /*
-    validate('can nest using indentation', '''
-        *   parent
-            *   child
-        ''', '''
-        <ul>
-        <li>parent
-        <ul><li>child</li></ul></li>
-        </ul>
-        ''');
-    */
-  });
-
-  group('Ordered lists', () {
-    validate(
-        'start with numbers',
-        '''
-        1. one
-        45.  two
-           12345. three
-        ''',
-        '''
-        <ol>
-          <li>one</li>
-          <li>two</li>
-          <li>three</li>
-        </ol>
-        ''');
-
-    validate(
-        'allow unordered lines after first',
-        '''
-        1. a
-        * b
-        ''',
-        '''
-        <ol>
-          <li>a</li>
-          <li>b</li>
-        </ol>
-        ''');
-  });
-
-  group('Blockquotes', () {
-    validate(
-        'single line',
-        '''
-        > blah
-        ''',
-        '''
-        <blockquote>
-          <p>blah</p>
-        </blockquote>
-        ''');
-
-    validate(
-        'with two paragraphs',
-        '''
-        > first
-        >
-        > second
-        ''',
-        '''
-        <blockquote>
-          <p>first</p>
-          <p>second</p>
-        </blockquote>
-        ''');
-
-    validate(
-        'nested',
-        '''
-        > one
-        >> two
-        > > > three
-        ''',
-        '''
-        <blockquote>
-          <p>one</p>
-          <blockquote>
-            <p>two</p>
-            <blockquote>
-              <p>three</p>
-            </blockquote>
-          </blockquote>
-        </blockquote>
-        ''');
-  });
-
-  group('Code blocks', () {
-    validate(
-        'single line',
-        '''
-            code
-        ''',
-        '''
-        <pre><code>code</code></pre>
-        ''');
-
-    validate(
-        'include leading whitespace after indentation',
-        '''
-            zero
-             one
-              two
-               three
-        ''',
-        '''
-        <pre><code>zero
-         one
-          two
-           three</code></pre>
-        ''');
-
-    validate(
-        'code blocks separated by newlines form one block',
-        '''
-            zero
-            one
-
-            two
-
-            three
-        ''',
-        '''
-        <pre><code>zero
-         one
-
-         two
-
-         three</code></pre>
-        ''');
-
-    validate(
-        'code blocks separated by two newlines form multiple blocks',
-        '''
-            zero
-            one
-
-
-            two
-
-
-            three
-        ''',
-        '''
-        <pre><code>zero
-         one</code></pre>
-        <pre><code>two</code></pre>
-        <pre><code>three</code></pre>
-        ''');
-
-    validate(
-        'escape HTML characters',
-        '''
-            <&>
-        ''',
-        '''
-        <pre><code>&lt;&amp;&gt;</code></pre>
-        ''');
-  });
-
-  group('Fenced code blocks', () {
-    validate(
-        'without an optional language identifier',
-        '''
-        ```
-        code
-        ```
-        ''',
-        '''
-        <pre><code>code
-        </code></pre>
-        ''');
-
-    validate(
-        'with an optional language identifier',
-        '''
-        ```dart
-        code
-        ```
-        ''',
-        '''
-        <pre class="dart"><code>code
-        </code></pre>
-        ''');
-
-    validate(
-        'escape HTML characters',
-        '''
-        ```
-        <&>
-        ```
-        ''',
-        '''
-        <pre><code>&lt;&amp;&gt;
-        </code></pre>
-        ''');
-
-    validate(
-        'Pandoc style without language identifier',
-        '''
-        ~~~~~
-        code
-        ~~~~~
-        ''',
-        '''
-        <pre><code>code
-        </code></pre>
-        ''');
-
-    validate(
-        'Pandoc style with language identifier',
-        '''
-        ~~~~~dart
-        code
-        ~~~~~
-        ''',
-        '''
-        <pre class="dart"><code>code
-        </code></pre>
-        ''');
-
-    validate(
-        'Pandoc style with inner tildes row',
-        '''
-        ~~~~~
-        ~~~
-        code
-        ~~~
-        ~~~~~
-        ''',
-        '''
-        <pre><code>~~~
-        code
-        ~~~
-        </code></pre>
-        ''');
-  });
-
-  group('Horizontal rules', () {
-    validate(
-        'from dashes',
-        '''
-        ---
-        ''',
-        '''
-        <hr />
-        ''');
-
-    validate(
-        'from asterisks',
-        '''
-        ***
-        ''',
-        '''
-        <hr />
-        ''');
-
-    validate(
-        'from underscores',
-        '''
-        ___
-        ''',
-        '''
-        <hr />
-        ''');
-
-    validate(
-        'can include up to two spaces',
-        '''
-        _ _  _
-        ''',
-        '''
-        <hr />
-        ''');
-  });
-
-  group('Block-level HTML', () {
-    validate(
-        'single line',
-        '''
-        <table></table>
-        ''',
-        '''
-        <table></table>
-        ''');
-
-    validate(
-        'multi-line',
-        '''
-        <table>
-            blah
-        </table>
-        ''',
-        '''
-        <table>
-            blah
-        </table>
-        ''');
-
-    validate(
-        'blank line ends block',
-        '''
-        <table>
-            blah
-        </table>
-
-        para
-        ''',
-        '''
-        <table>
-            blah
-        </table>
-        <p>para</p>
-        ''');
-
-    validate(
-        'HTML can be bogus',
-        '''
-        <bogus>
-        blah
-        </weird>
-
-        para
-        ''',
-        '''
-        <bogus>
-        blah
-        </weird>
-        <p>para</p>
-        ''');
-  });
-
-  group('Strong', () {
-    validate(
-        'using asterisks',
-        '''
-        before **strong** after
-        ''',
-        '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate(
-        'using underscores',
-        '''
-        before __strong__ after
-        ''',
-        '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate(
-        'unmatched asterisks',
-        '''
-        before ** after
-        ''',
-        '''
-        <p>before ** after</p>
-        ''');
-
-    validate(
-        'unmatched underscores',
-        '''
-        before __ after
-        ''',
-        '''
-        <p>before __ after</p>
-        ''');
-
-    validate(
-        'multiple spans in one text',
-        '''
-        a **one** b __two__ c
-        ''',
-        '''
-        <p>a <strong>one</strong> b <strong>two</strong> c</p>
-        ''');
-
-    validate(
-        'multi-line',
-        '''
-        before **first
-        second** after
-        ''',
-        '''
-        <p>before <strong>first
-        second</strong> after</p>
-        ''');
-  });
-
-  group('Emphasis and strong', () {
-    validate(
-        'single asterisks',
-        '''
-        before *em* after
-        ''',
-        '''
-        <p>before <em>em</em> after</p>
-        ''');
-
-    validate(
-        'single underscores',
-        '''
-        before _em_ after
-        ''',
-        '''
-        <p>before <em>em</em> after</p>
-        ''');
-
-    validate(
-        'double asterisks',
-        '''
-        before **strong** after
-        ''',
-        '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate(
-        'double underscores',
-        '''
-        before __strong__ after
-        ''',
-        '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate(
-        'unmatched asterisk',
-        '''
-        before *after
-        ''',
-        '''
-        <p>before *after</p>
-        ''');
-
-    validate(
-        'unmatched underscore',
-        '''
-        before _after
-        ''',
-        '''
-        <p>before _after</p>
-        ''');
-
-    validate(
-        'multiple spans in one text',
-        '''
-        a *one* b _two_ c
-        ''',
-        '''
-        <p>a <em>one</em> b <em>two</em> c</p>
-        ''');
-
-    validate(
-        'multi-line',
-        '''
-        before *first
-        second* after
-        ''',
-        '''
-        <p>before <em>first
-        second</em> after</p>
-        ''');
-
-    validate(
-        'not processed when surrounded by spaces',
-        '''
-        a * b * c _ d _ e
-        ''',
-        '''
-        <p>a * b * c _ d _ e</p>
-        ''');
-
-    validate(
-        'strong then emphasis',
-        '''
-        **strong***em*
-        ''',
-        '''
-        <p><strong>strong</strong><em>em</em></p>
-        ''');
-
-    validate(
-        'emphasis then strong',
-        '''
-        *em***strong**
-        ''',
-        '''
-        <p><em>em</em><strong>strong</strong></p>
-        ''');
-
-    validate(
-        'emphasis inside strong',
-        '''
-        **strong *em***
-        ''',
-        '''
-        <p><strong>strong <em>em</em></strong></p>
-        ''');
-
-    validate(
-        'mismatched in nested',
-        '''
-        *a _b* c_
-        ''',
-        '''
-        <p><em>a _b</em> c_</p>
-        ''');
-
-    validate(
-        'cannot nest tags of same type',
-        '''
-        *a _b *c* d_ e*
-        ''',
-        '''
-        <p><em>a _b </em>c<em> d_ e</em></p>
-        ''');
-  });
-
-  group('Inline code', () {
-    validate(
-        'simple case',
-        '''
-        before `source` after
-        ''',
-        '''
-        <p>before <code>source</code> after</p>
-        ''');
-
-    validate(
-        'unmatched backtick',
-        '''
-        before ` after
-        ''',
-        '''
-        <p>before ` after</p>
-        ''');
-    validate(
-        'multiple spans in one text',
-        '''
-        a `one` b `two` c
-        ''',
-        '''
-        <p>a <code>one</code> b <code>two</code> c</p>
-        ''');
-
-    validate(
-        'multi-line',
-        '''
-        before `first
-        second` after
-        ''',
-        '''
-        <p>before <code>first
-        second</code> after</p>
-        ''');
-
-    validate(
-        'simple double backticks',
-        '''
-        before ``source`` after
-        ''',
-        '''
-        <p>before <code>source</code> after</p>
-        ''');
-
-    validate(
-        'double backticks',
-        '''
-        before ``can `contain` backticks`` after
-        ''',
-        '''
-        <p>before <code>can `contain` backticks</code> after</p>
-        ''');
-
-    validate(
-        'double backticks with spaces',
-        '''
-        before `` `tick` `` after
-        ''',
-        '''
-        <p>before <code>`tick`</code> after</p>
-        ''');
-
-    validate(
-        'multiline double backticks with spaces',
-        '''
-        before ``in `tick`
-        another`` after
-        ''',
-        '''
-        <p>before <code>in `tick`
-        another</code> after</p>
-        ''');
-
-    validate(
-        'ignore markup inside code',
-        '''
-        before `*b* _c_` after
-        ''',
-        '''
-        <p>before <code>*b* _c_</code> after</p>
-        ''');
-
-    validate(
-        'escape HTML characters',
-        '''
-        `<&>`
-        ''',
-        '''
-        <p><code>&lt;&amp;&gt;</code></p>
-        ''');
-
-    validate(
-        'escape HTML tags',
-        '''
-        '*' `<em>`
-        ''',
-        '''
-        <p>'*' <code>&lt;em&gt;</code></p>
-        ''');
-  });
-
-  group('HTML encoding', () {
-    validate(
-        'less than and ampersand are escaped',
-        '''
-        < &
-        ''',
-        '''
-        <p>&lt; &amp;</p>
-        ''');
-    validate(
-        'greater than is not escaped',
-        '''
-        not you >
-        ''',
-        '''
-        <p>not you ></p>
-        ''');
-    validate(
-        'existing entities are untouched',
-        '''
-        &amp;
-        ''',
-        '''
-        <p>&amp;</p>
-        ''');
-  });
-
-  group('Autolinks', () {
-    validate(
-        'basic link',
-        '''
-        before <http://foo.com/> after
-        ''',
-        '''
-        <p>before <a href="http://foo.com/">http://foo.com/</a> after</p>
-        ''');
-    validate(
-        'handles ampersand in url',
-        '''
-        <http://foo.com/?a=1&b=2>
-        ''',
-        '''
-        <p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&amp;b=2</a></p>
-        ''');
-  });
-
-  group('Reference links', () {
-    validate(
-        'double quotes for title',
-        '''
-        links [are] [a] awesome
-
-        [a]: http://foo.com "woo"
-        ''',
-        '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate(
-        'single quoted title',
-        """
-        links [are] [a] awesome
-
-        [a]: http://foo.com 'woo'
-        """,
-        '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate(
-        'parentheses for title',
-        '''
-        links [are] [a] awesome
-
-        [a]: http://foo.com (woo)
-        ''',
-        '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate(
-        'no title',
-        '''
-        links [are] [a] awesome
-
-        [a]: http://foo.com
-        ''',
-        '''
-        <p>links <a href="http://foo.com">are</a> awesome</p>
-        ''');
-    validate(
-        'unknown link becomes plaintext',
-        '''
-        [not] [known]
-        ''',
-        '''
-        <p>[not] [known]</p>
-        ''');
-    validate(
-        'can style link contents',
-        '''
-        links [*are*] [a] awesome
-
-        [a]: http://foo.com
-        ''',
-        '''
-        <p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
-        ''');
-    validate(
-        'inline styles after a bad link are processed',
-        '''
-        [bad] `code`
-        ''',
-        '''
-        <p>[bad] <code>code</code></p>
-        ''');
-    validate(
-        'empty reference uses text from link',
-        '''
-        links [are][] awesome
-
-        [are]: http://foo.com
-        ''',
-        '''
-        <p>links <a href="http://foo.com">are</a> awesome</p>
-        ''');
-    validate(
-        'references are case-insensitive',
-        '''
-        links [ARE][] awesome
-
-        [are]: http://foo.com
-        ''',
-        '''
-        <p>links <a href="http://foo.com">ARE</a> awesome</p>
-        ''');
-  });
-
-  group('Inline links', () {
-    validate(
-        'double quotes for title',
-        '''
-        links [are](http://foo.com "woo") awesome
-        ''',
-        '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate(
-        'no title',
-        '''
-        links [are] (http://foo.com) awesome
-        ''',
-        '''
-        <p>links <a href="http://foo.com">are</a> awesome</p>
-        ''');
-    validate(
-        'can style link contents',
-        '''
-        links [*are*](http://foo.com) awesome
-        ''',
-        '''
-        <p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
-        ''');
-  });
-
-  group('Inline Images', () {
-    validate(
-        'image',
-        '''
-        ![](http://foo.com/foo.png)
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png">
-            <img src="http://foo.com/foo.png"></img>
-          </a>
-        </p>
-        ''');
-
-    validate(
-        'alternate text',
-        '''
-        ![alternate text](http://foo.com/foo.png)
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png">
-            <img alt="alternate text" src="http://foo.com/foo.png"></img>
-          </a>
-        </p>
-        ''');
-
-    validate(
-        'title',
-        '''
-        ![](http://foo.com/foo.png "optional title")
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png" title="optional title">
-            <img src="http://foo.com/foo.png" title="optional title"></img>
-          </a>
-        </p>
-        ''');
-    validate(
-        'invalid alt text',
-        '''
-        ![`alt`](http://foo.com/foo.png)
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png">
-            <img src="http://foo.com/foo.png"></img>
-          </a>
-        </p>
-        ''');
-  });
-
-  group('Reference Images', () {
-    validate(
-        'image',
-        '''
-        ![][foo]
-        [foo]: http://foo.com/foo.png
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png">
-            <img src="http://foo.com/foo.png"></img>
-          </a>
-        </p>
-        ''');
-
-    validate(
-        'alternate text',
-        '''
-        ![alternate text][foo]
-        [foo]: http://foo.com/foo.png
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png">
-            <img alt="alternate text" src="http://foo.com/foo.png"></img>
-          </a>
-        </p>
-        ''');
-
-    validate(
-        'title',
-        '''
-        ![][foo]
-        [foo]: http://foo.com/foo.png "optional title"
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png" title="optional title">
-            <img src="http://foo.com/foo.png" title="optional title"></img>
-          </a>
-        </p>
-        ''');
-
-    validate(
-        'invalid alt text',
-        '''
-        ![`alt`][foo]
-        [foo]: http://foo.com/foo.png "optional title"
-        ''',
-        '''
-        <p>
-          <a href="http://foo.com/foo.png" title="optional title">
-            <img src="http://foo.com/foo.png" title="optional title"></img>
-          </a>
-        </p>
-        ''');
-  });
+  testDirectory('original');
 
   group('Resolver', () {
     Node nyanResolver(String text) => new Text('~=[,,_${text}_,,]:3');
+    validateCore('simple link resolver', '''
+resolve [this] thing
+''', '''
+<p>resolve ~=[,,_this_,,]:3 thing</p>
+''', linkResolver: nyanResolver);
 
-    validate(
-        'simple link resolver',
-        '''
-        resolve [this] thing
-        ''',
-        '''
-        <p>resolve ~=[,,_this_,,]:3 thing</p>
-        ''',
-        linkResolver: nyanResolver);
-    validate(
-        'simple image resolver',
-        '''
-        resolve ![this] thing
-        ''',
-        '''
-        <p>resolve ~=[,,_this_,,]:3 thing</p>
-        ''',
-        imageLinkResolver: nyanResolver);
+    validateCore('simple image resolver', '''
+resolve ![this] thing
+''', '''
+<p>resolve ~=[,,_this_,,]:3 thing</p>
+''', imageLinkResolver: nyanResolver);
 
-    validate(
-        'can resolve link containing inline tags',
-        '''
-        resolve [*star* _underline_] thing
-        ''',
-        '''
-        <p>resolve ~=[,,_*star* _underline__,,]:3 thing</p>
-        ''',
-        linkResolver: nyanResolver);
+    validateCore('can resolve link containing inline tags', '''
+resolve [*star* _underline_] thing
+''', '''
+<p>resolve ~=[,,_*star* _underline__,,]:3 thing</p>\n
+''', linkResolver: nyanResolver);
   });
 
   group('Custom inline syntax', () {
-    validate(
-        'simple inline syntax',
-        '''
-        nyan
-        ''',
-        '''
-        <p>~=[,,_,,]:3</p>
-        ''',
-        inlineSyntaxes: [new TextSyntax('nyan', sub: '~=[,,_,,]:3')]);
+    var nyanSyntax = <InlineSyntax>[new TextSyntax('nyan', sub: '~=[,,_,,]:3')];
+    validateCore('simple inline syntax', '''
+nyan''', '''<p>~=[,,_,,]:3</p>
+''', inlineSyntaxes: nyanSyntax);
 
-    validate('dart custom links', 'links [are<foo>] awesome',
-        '<p>links <a>are&lt;foo></a> awesome</p>',
+    validateCore('dart custom links', 'links [are<foo>] awesome',
+        '<p>links <a>are&lt;foo></a> awesome</p>\n',
         linkResolver: (text) =>
             new Element.text('a', text.replaceAll('<', '&lt;')));
 
@@ -1354,70 +54,49 @@
   });
 
   group('Inline only', () {
-    validate(
-        'simple line',
-        '''
+    validateCore('simple line', '''
         This would normally create a paragraph.
         ''',
         '''
         This would normally create a paragraph.
-        ''',
-        inlineOnly: true);
-    validate(
-        'strong and em',
-        '''
+        ''', inlineOnly: true);
+    validateCore('strong and em', '''
         This would _normally_ create a **paragraph**.
         ''',
         '''
         This would <em>normally</em> create a <strong>paragraph</strong>.
-        ''',
-        inlineOnly: true);
-    validate(
-        'link',
-        '''
+        ''', inlineOnly: true);
+    validateCore('link', '''
         This [link](http://www.example.com/) will work normally.
         ''',
         '''
         This <a href="http://www.example.com/">link</a> will work normally.
-        ''',
-        inlineOnly: true);
-    validate(
-        'references do not work',
-        '''
+        ''', inlineOnly: true);
+    validateCore('references do not work', '''
         [This][] shouldn't work, though.
         ''',
         '''
         [This][] shouldn't work, though.
-        ''',
-        inlineOnly: true);
-    validate(
-        'less than and ampersand are escaped',
-        '''
+        ''', inlineOnly: true);
+    validateCore('less than and ampersand are escaped', '''
         < &
         ''',
         '''
         &lt; &amp;
-        ''',
-        inlineOnly: true);
-    validate(
-        'keeps newlines',
-        '''
+        ''', inlineOnly: true);
+    validateCore('keeps newlines', '''
         This paragraph
         continues after a newline.
         ''',
         '''
         This paragraph
         continues after a newline.
-        ''',
-        inlineOnly: true);
-    validate(
-        'ignores block-level markdown syntax',
-        '''
+        ''', inlineOnly: true);
+    validateCore('ignores block-level markdown syntax', '''
         1. This will not be an <ol>.
         ''',
         '''
         1. This will not be an &lt;ol>.
-        ''',
-        inlineOnly: true);
+        ''', inlineOnly: true);
   });
 }
diff --git a/pkgs/markdown/test/original/autolinks.unit b/pkgs/markdown/test/original/autolinks.unit
new file mode 100644
index 0000000..804b65c
--- /dev/null
+++ b/pkgs/markdown/test/original/autolinks.unit
@@ -0,0 +1,10 @@
+>>> basic link
+before <http://foo.com/> after
+
+<<<
+<p>before <a href="http://foo.com/">http://foo.com/</a> after</p>
+>>> handles ampersand in url
+<http://foo.com/?a=1&b=2>
+
+<<<
+<p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&amp;b=2</a></p>
diff --git a/pkgs/markdown/test/original/block_level_html.unit b/pkgs/markdown/test/original/block_level_html.unit
new file mode 100644
index 0000000..ce40760
--- /dev/null
+++ b/pkgs/markdown/test/original/block_level_html.unit
@@ -0,0 +1,38 @@
+>>> single line
+<table></table>
+
+<<<
+<table></table>
+>>> multi-line
+<table>
+    blah
+</table>
+
+<<<
+<table>
+    blah
+</table>
+>>> blank line ends block
+<table>
+    blah
+</table>
+
+para
+
+<<<
+<table>
+    blah
+</table>
+<p>para</p>
+>>> HTML can be bogus
+<bogus>
+blah
+</weird>
+
+para
+
+<<<
+<bogus>
+blah
+</weird>
+<p>para</p>
diff --git a/pkgs/markdown/test/original/block_quotes.unit b/pkgs/markdown/test/original/block_quotes.unit
new file mode 100644
index 0000000..26d8ed7
--- /dev/null
+++ b/pkgs/markdown/test/original/block_quotes.unit
@@ -0,0 +1,27 @@
+>>> single line
+> blah
+
+<<<
+<blockquote>
+<p>blah</p></blockquote>
+>>> with two paragraphs
+> first
+>
+> second
+
+<<<
+<blockquote>
+<p>first</p>
+<p>second</p></blockquote>
+>>> nested
+> one
+>> two
+> > > three
+
+<<<
+<blockquote>
+<p>one</p>
+<blockquote>
+<p>two</p>
+<blockquote>
+<p>three</p></blockquote></blockquote></blockquote>
diff --git a/pkgs/markdown/test/original/code_blocks.unit b/pkgs/markdown/test/original/code_blocks.unit
new file mode 100644
index 0000000..b219fe7
--- /dev/null
+++ b/pkgs/markdown/test/original/code_blocks.unit
@@ -0,0 +1,58 @@
+>>> single line
+    code
+
+<<<
+<pre><code>code
+</code></pre>
+>>> include leading whitespace after indentation
+    zero
+     one
+      two
+       three
+
+<<<
+<pre><code>zero
+ one
+  two
+   three
+</code></pre>
+>>> code blocks separated by newlines form one block
+    zero
+    one
+
+    two
+
+    three
+
+<<<
+<pre><code>zero
+one
+
+two
+
+three
+</code></pre>
+>>> code blocks separated by two newlines form multiple blocks
+    zero
+    one
+
+
+    two
+
+
+    three
+
+<<<
+<pre><code>zero
+one
+</code></pre>
+<pre><code>two
+</code></pre>
+<pre><code>three
+</code></pre>
+>>> escape HTML characters
+    <&>
+
+<<<
+<pre><code>&lt;&amp;&gt;
+</code></pre>
diff --git a/pkgs/markdown/test/original/emphasis_and_strong.unit b/pkgs/markdown/test/original/emphasis_and_strong.unit
new file mode 100644
index 0000000..5e67fc0
--- /dev/null
+++ b/pkgs/markdown/test/original/emphasis_and_strong.unit
@@ -0,0 +1,72 @@
+>>> single asterisks
+before *em* after
+
+<<<
+<p>before <em>em</em> after</p>
+>>> single underscores
+before _em_ after
+
+<<<
+<p>before <em>em</em> after</p>
+>>> double asterisks
+before **strong** after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> double underscores
+before __strong__ after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> unmatched asterisk
+before *after
+
+<<<
+<p>before *after</p>
+>>> unmatched underscore
+before _after
+
+<<<
+<p>before _after</p>
+>>> multiple spans in one text
+a *one* b _two_ c
+
+<<<
+<p>a <em>one</em> b <em>two</em> c</p>
+>>> multi-line
+before *first
+second* after
+
+<<<
+<p>before <em>first
+second</em> after</p>
+>>> not processed when surrounded by spaces
+a * b * c _ d _ e
+
+<<<
+<p>a * b * c _ d _ e</p>
+>>> strong then emphasis
+**strong***em*
+
+<<<
+<p><strong>strong</strong><em>em</em></p>
+>>> emphasis then strong
+*em***strong**
+
+<<<
+<p><em>em</em><strong>strong</strong></p>
+>>> emphasis inside strong
+**strong *em***
+
+<<<
+<p><strong>strong <em>em</em></strong></p>
+>>> mismatched in nested
+*a _b* c_
+
+<<<
+<p><em>a _b</em> c_</p>
+>>> cannot nest tags of same type
+*a _b *c* d_ e*
+
+<<<
+<p><em>a _b </em>c<em> d_ e</em></p>
diff --git a/pkgs/markdown/test/original/fenced_code_blocks.unit b/pkgs/markdown/test/original/fenced_code_blocks.unit
new file mode 100644
index 0000000..ceb1f16
--- /dev/null
+++ b/pkgs/markdown/test/original/fenced_code_blocks.unit
@@ -0,0 +1,52 @@
+>>> without an optional language identifier
+```
+code
+```
+
+<<<
+<pre><code>code
+</code></pre>
+>>> with an optional language identifier
+```dart
+code
+```
+
+<<<
+<pre class="dart"><code>code
+</code></pre>
+>>> escape HTML characters
+```
+<&>
+```
+
+<<<
+<pre><code>&lt;&amp;&gt;
+</code></pre>
+>>> Pandoc style without language identifier
+~~~~~
+code
+~~~~~
+
+<<<
+<pre><code>code
+</code></pre>
+>>> Pandoc style with language identifier
+~~~~~dart
+code
+~~~~~
+
+<<<
+<pre class="dart"><code>code
+</code></pre>
+>>> Pandoc style with inner tildes row
+~~~~~
+~~~
+code
+~~~
+~~~~~
+
+<<<
+<pre><code>~~~
+code
+~~~
+</code></pre>
diff --git a/pkgs/markdown/test/original/headers.unit b/pkgs/markdown/test/original/headers.unit
new file mode 100644
index 0000000..928da8b
--- /dev/null
+++ b/pkgs/markdown/test/original/headers.unit
@@ -0,0 +1,35 @@
+>>> h1
+# header
+
+<<<
+<h1>header</h1>
+>>> h2
+## header
+
+<<<
+<h2>header</h2>
+>>> h3
+### header
+
+<<<
+<h3>header</h3>
+>>> h4
+#### header
+
+<<<
+<h4>header</h4>
+>>> h5
+##### header
+
+<<<
+<h5>header</h5>
+>>> h6
+###### header
+
+<<<
+<h6>header</h6>
+>>> trailing "#" are removed
+# header ######
+
+<<<
+<h1>header</h1>
diff --git a/pkgs/markdown/test/original/horizontal_rules.unit b/pkgs/markdown/test/original/horizontal_rules.unit
new file mode 100644
index 0000000..36642e9
--- /dev/null
+++ b/pkgs/markdown/test/original/horizontal_rules.unit
@@ -0,0 +1,20 @@
+>>> from dashes
+---
+
+<<<
+<hr />
+>>> from asterisks
+***
+
+<<<
+<hr />
+>>> from underscores
+___
+
+<<<
+<hr />
+>>> can include up to two spaces
+_ _  _
+
+<<<
+<hr />
diff --git a/pkgs/markdown/test/original/html_encoding.unit b/pkgs/markdown/test/original/html_encoding.unit
new file mode 100644
index 0000000..9333783
--- /dev/null
+++ b/pkgs/markdown/test/original/html_encoding.unit
@@ -0,0 +1,15 @@
+>>> less than and ampersand are escaped
+< &
+
+<<<
+<p>&lt; &amp;</p>
+>>> greater than is not escaped
+not you >
+
+<<<
+<p>not you ></p>
+>>> existing entities are untouched
+&amp;
+
+<<<
+<p>&amp;</p>
diff --git a/pkgs/markdown/test/original/inline_code.unit b/pkgs/markdown/test/original/inline_code.unit
new file mode 100644
index 0000000..30fd05c
--- /dev/null
+++ b/pkgs/markdown/test/original/inline_code.unit
@@ -0,0 +1,59 @@
+>>> simple case
+before `source` after
+
+<<<
+<p>before <code>source</code> after</p>
+>>> unmatched backtick
+before ` after
+
+<<<
+<p>before ` after</p>
+>>> multiple spans in one text
+a `one` b `two` c
+
+<<<
+<p>a <code>one</code> b <code>two</code> c</p>
+>>> multi-line
+before `first
+second` after
+
+<<<
+<p>before <code>first
+second</code> after</p>
+>>> simple double backticks
+before ``source`` after
+
+<<<
+<p>before <code>source</code> after</p>
+>>> double backticks
+before ``can `contain` backticks`` after
+
+<<<
+<p>before <code>can `contain` backticks</code> after</p>
+>>> double backticks with spaces
+before `` `tick` `` after
+
+<<<
+<p>before <code>`tick`</code> after</p>
+>>> multiline double backticks with spaces
+before ``in `tick`
+another`` after
+
+<<<
+<p>before <code>in `tick`
+another</code> after</p>
+>>> ignore markup inside code
+before `*b* _c_` after
+
+<<<
+<p>before <code>*b* _c_</code> after</p>
+>>> escape HTML characters
+`<&>`
+
+<<<
+<p><code>&lt;&amp;&gt;</code></p>
+>>> escape HTML tags
+'*' `<em>`
+
+<<<
+<p>'*' <code>&lt;em&gt;</code></p>
diff --git a/pkgs/markdown/test/original/inline_images.unit b/pkgs/markdown/test/original/inline_images.unit
new file mode 100644
index 0000000..a17a8e2
--- /dev/null
+++ b/pkgs/markdown/test/original/inline_images.unit
@@ -0,0 +1,20 @@
+>>> image
+![](http://foo.com/foo.png)
+
+<<<
+<p><a href="http://foo.com/foo.png"><img src="http://foo.com/foo.png"></img></a></p>
+>>> alternate text
+![alternate text](http://foo.com/foo.png)
+
+<<<
+<p><a href="http://foo.com/foo.png"><img alt="alternate text" src="http://foo.com/foo.png"></img></a></p>
+>>> title
+![](http://foo.com/foo.png "optional title")
+
+<<<
+<p><a href="http://foo.com/foo.png" title="optional title"><img src="http://foo.com/foo.png" title="optional title"></img></a></p>
+>>> invalid alt text
+![`alt`](http://foo.com/foo.png)
+
+<<<
+<p><a href="http://foo.com/foo.png"><img src="http://foo.com/foo.png"></img></a></p>
diff --git a/pkgs/markdown/test/original/inline_links.unit b/pkgs/markdown/test/original/inline_links.unit
new file mode 100644
index 0000000..f42b6c6
--- /dev/null
+++ b/pkgs/markdown/test/original/inline_links.unit
@@ -0,0 +1,15 @@
+>>> double quotes for title
+links [are](http://foo.com "woo") awesome
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> no title
+links [are] (http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> can style link contents
+links [*are*](http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
diff --git a/pkgs/markdown/test/original/ordered_lists.unit b/pkgs/markdown/test/original/ordered_lists.unit
new file mode 100644
index 0000000..277dba9
--- /dev/null
+++ b/pkgs/markdown/test/original/ordered_lists.unit
@@ -0,0 +1,13 @@
+>>> start with numbers
+1. one
+45.  two
+   12345. three
+
+<<<
+<ol><li>one</li><li>two</li><li>three</li></ol>
+>>> allow unordered lines after first
+1. a
+* b
+
+<<<
+<ol><li>a</li><li>b</li></ol>
diff --git a/pkgs/markdown/test/original/paragraphs.unit b/pkgs/markdown/test/original/paragraphs.unit
new file mode 100644
index 0000000..52d923f
--- /dev/null
+++ b/pkgs/markdown/test/original/paragraphs.unit
@@ -0,0 +1,52 @@
+>>> consecutive lines form a single paragraph
+This is the first line.
+This is the second line.
+
+<<<
+<p>This is the first line.
+This is the second line.</p>
+>>> are terminated by a header
+para
+# header
+
+<<<
+<p>para</p>
+<h1>header</h1>
+>>> are terminated by a setext header
+para
+header
+==
+
+<<<
+<p>para</p>
+<h1>header</h1>
+>>> are terminated by a hr
+para
+___
+
+<<<
+<p>para</p>
+<hr />
+>>> consume an unordered list
+para
+* list
+
+<<<
+<p>para
+* list</p>
+>>> consume an ordered list
+para
+1. list
+
+<<<
+<p>para
+1. list</p>
+>>> take account of windows line endings
+line1
+
+line2
+
+
+<<<
+<p>line1</p>
+<p>line2</p>
diff --git a/pkgs/markdown/test/original/reference_images.unit b/pkgs/markdown/test/original/reference_images.unit
new file mode 100644
index 0000000..84d1820
--- /dev/null
+++ b/pkgs/markdown/test/original/reference_images.unit
@@ -0,0 +1,24 @@
+>>> image
+![][foo]
+[foo]: http://foo.com/foo.png
+
+<<<
+<p><a href="http://foo.com/foo.png"><img src="http://foo.com/foo.png"></img></a></p>
+>>> alternate text
+![alternate text][foo]
+[foo]: http://foo.com/foo.png
+
+<<<
+<p><a href="http://foo.com/foo.png"><img alt="alternate text" src="http://foo.com/foo.png"></img></a></p>
+>>> title
+![][foo]
+[foo]: http://foo.com/foo.png "optional title"
+
+<<<
+<p><a href="http://foo.com/foo.png" title="optional title"><img src="http://foo.com/foo.png" title="optional title"></img></a></p>
+>>> invalid alt text
+![`alt`][foo]
+[foo]: http://foo.com/foo.png "optional title"
+
+<<<
+<p><a href="http://foo.com/foo.png" title="optional title"><img src="http://foo.com/foo.png" title="optional title"></img></a></p>
diff --git a/pkgs/markdown/test/original/reference_links.unit b/pkgs/markdown/test/original/reference_links.unit
new file mode 100644
index 0000000..e70475f
--- /dev/null
+++ b/pkgs/markdown/test/original/reference_links.unit
@@ -0,0 +1,59 @@
+>>> double quotes for title
+links [are] [a] awesome
+
+[a]: http://foo.com "woo"
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> single quoted title
+links [are] [a] awesome
+
+[a]: http://foo.com 'woo'
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> parentheses for title
+links [are] [a] awesome
+
+[a]: http://foo.com (woo)
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> no title
+links [are] [a] awesome
+
+[a]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> unknown link becomes plaintext
+[not] [known]
+
+<<<
+<p>[not] [known]</p>
+>>> can style link contents
+links [*are*] [a] awesome
+
+[a]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
+>>> inline styles after a bad link are processed
+[bad] `code`
+
+<<<
+<p>[bad] <code>code</code></p>
+>>> empty reference uses text from link
+links [are][] awesome
+
+[are]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> references are case-insensitive
+links [ARE][] awesome
+
+[are]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com">ARE</a> awesome</p>
diff --git a/pkgs/markdown/test/original/setext_headers.unit b/pkgs/markdown/test/original/setext_headers.unit
new file mode 100644
index 0000000..6e610cf
--- /dev/null
+++ b/pkgs/markdown/test/original/setext_headers.unit
@@ -0,0 +1,46 @@
+>>> h1
+text
+===
+
+<<<
+<h1>text</h1>
+>>> h2
+text
+---
+
+<<<
+<h2>text</h2>
+>>> h1 on first line becomes text
+===
+
+<<<
+<p>===</p>
+>>> h2 on first line becomes text
+-
+
+<<<
+<p>-</p>
+>>> h1 turns preceding list into text
+- list
+===
+
+<<<
+<h1>- list</h1>
+>>> h2 turns preceding list into text
+- list
+===
+
+<<<
+<h1>- list</h1>
+>>> h1 turns preceding blockquote into text
+> quote
+===
+
+<<<
+<h1>> quote</h1>
+>>> h2 turns preceding blockquote into text
+> quote
+===
+
+<<<
+<h1>> quote</h1>
diff --git a/pkgs/markdown/test/original/strong.unit b/pkgs/markdown/test/original/strong.unit
new file mode 100644
index 0000000..e558424
--- /dev/null
+++ b/pkgs/markdown/test/original/strong.unit
@@ -0,0 +1,32 @@
+>>> using asterisks
+before **strong** after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> using underscores
+before __strong__ after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> unmatched asterisks
+before ** after
+
+<<<
+<p>before ** after</p>
+>>> unmatched underscores
+before __ after
+
+<<<
+<p>before __ after</p>
+>>> multiple spans in one text
+a **one** b __two__ c
+
+<<<
+<p>a <strong>one</strong> b <strong>two</strong> c</p>
+>>> multi-line
+before **first
+second** after
+
+<<<
+<p>before <strong>first
+second</strong> after</p>
diff --git a/pkgs/markdown/test/original/unordered_lists.unit b/pkgs/markdown/test/original/unordered_lists.unit
new file mode 100644
index 0000000..7bca8e5
--- /dev/null
+++ b/pkgs/markdown/test/original/unordered_lists.unit
@@ -0,0 +1,71 @@
+>>> asterisk, plus and hyphen
+* star
+- dash
++ plus
+
+<<<
+<ul><li>star</li><li>dash</li><li>plus</li></ul>
+>>> allow numbered lines after first
+* a
+1. b
+
+<<<
+<ul><li>a</li><li>b</li></ul>
+>>> allow a tab after the marker
+* a
++ b
+- c
+1.  d
+
+<<<
+<ul><li>a</li><li>b</li><li>c</li><li>d</li></ul>
+>>> wrap items in paragraphs if blank lines separate
+* one
+
+* two
+
+<<<
+<ul><li>
+<p>one</p></li><li>
+<p>two</p></li></ul>
+>>> force paragraph on item before and after blank lines
+*   one
+*   two
+
+*   three
+
+<<<
+<ul><li>one</li><li>
+<p>two</p></li><li>
+<p>three</p></li></ul>
+>>> do not force paragraph if item is already block
+* > quote
+
+* # header
+
+<<<
+<ul><li>
+<blockquote>
+<p>quote</p></blockquote></li><li>
+<h1>header</h1></li></ul>
+>>> can contain multiple paragraphs
+*   one
+
+    two
+
+*   three
+
+<<<
+<ul><li>
+<p>one</p>
+<p>two</p></li><li>
+<p>three</p></li></ul>
+>>> can span newlines
+*   one
+    two
+*   three
+
+<<<
+<ul><li>
+<p>one
+two</p></li><li>three</li></ul>
diff --git a/pkgs/markdown/test/util.dart b/pkgs/markdown/test/util.dart
index d9a6e38..309bfaf 100644
--- a/pkgs/markdown/test/util.dart
+++ b/pkgs/markdown/test/util.dart
@@ -1,95 +1,71 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library markdown.test.utils;
+library markdown.test.util;
 
-import 'package:test/test.dart';
+import 'dart:io';
 
 import 'package:markdown/markdown.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
 
-/// Removes eight spaces of leading indentation from a multiline string.
-///
-/// Note that this is very sensitive to how the literals are styled. They should
-/// be:
-///     '''
-///     Text starts on own line. Lines up with subsequent lines.
-///     Lines are indented exactly 8 characters from the left margin.'''
-///
-/// This does nothing if text is only a single line.
-// TODO(nweiz): Make this auto-detect the indentation level from the first
-// non-whitespace line.
-String cleanUpLiteral(String text) {
-  var lines = text.split('\n');
-  if (lines.length <= 1) return text;
+final _indentPattern = new RegExp(r"^\(indent (\d+)\)\s*");
 
-  for (var j = 0; j < lines.length; j++) {
-    if (lines[j].length > 8) {
-      lines[j] = lines[j].substring(8, lines[j].length);
-    } else {
-      lines[j] = '';
-    }
+/// Run tests defined in "*.unit" files inside directory [name].
+void testDirectory(String name) {
+  var dir = p.join(p.dirname(p.fromUri(Platform.script)), name);
+  var entries =
+      new Directory(dir).listSync().where((e) => e.path.endsWith('.unit'));
+
+  for (var entry in entries) {
+    group("$name ${p.basename(entry.path)}", () {
+      var lines = (entry as File).readAsLinesSync();
+
+      var i = 0;
+      while (i < lines.length) {
+        var description = lines[i++].replaceAll(">>>", "").trim();
+
+        // Let the test specify a leading indentation. This is handy for
+        // regression tests which often come from a chunk of nested code.
+        var indentMatch = _indentPattern.firstMatch(description);
+        if (indentMatch != null) {
+          // The test specifies it in spaces, but the formatter expects levels.
+          description = description.substring(indentMatch.end);
+        }
+
+        if (description == "") {
+          description = "line ${i + 1}";
+        } else {
+          description = "line ${i + 1}: $description";
+        }
+
+        var input = "";
+        while (!lines[i].startsWith("<<<")) {
+          input += lines[i++] + "\n";
+        }
+
+        var expectedOutput = "";
+        while (++i < lines.length && !lines[i].startsWith(">>>")) {
+          expectedOutput += lines[i] + "\n";
+        }
+
+        validateCore(description, input, expectedOutput);
+      }
+    });
   }
-
-  return lines.join('\n');
 }
 
-void validate(String description, String markdown, String html,
-    {List<InlineSyntax> inlineSyntaxes,
-    Resolver linkResolver,
-    Resolver imageLinkResolver,
-    bool inlineOnly: false}) {
+void validateCore(String description, String markdown, String html,
+    {List<InlineSyntax> inlineSyntaxes, Resolver linkResolver,
+    Resolver imageLinkResolver, bool inlineOnly: false}) {
   test(description, () {
-    markdown = cleanUpLiteral(markdown);
-    html = cleanUpLiteral(html);
-
     var result = markdownToHtml(markdown,
         inlineSyntaxes: inlineSyntaxes,
         linkResolver: linkResolver,
         imageLinkResolver: imageLinkResolver,
         inlineOnly: inlineOnly);
-    var passed = compareOutput(html, result);
 
-    if (!passed) {
-      // Remove trailing newline.
-      html = html.substring(0, html.length - 1);
-
-      var sb = new StringBuffer();
-      sb.writeln('Expected: ${html.replaceAll("\n", "\n          ")}');
-      sb.writeln('  Actual: ${result.replaceAll("\n", "\n          ")}');
-
-      fail(sb.toString());
-    }
+    expect(result, html);
   });
 }
-
-/// Does a loose comparison of the two strings of HTML. Ignores differences in
-/// newlines and indentation.
-bool compareOutput(String a, String b) {
-  int i = 0;
-  int j = 0;
-
-  skipIgnored(String s, int i) {
-    // Ignore newlines.
-    while ((i < s.length) && (s[i] == '\n')) {
-      i++;
-      // Ignore indentation.
-      while ((i < s.length) && (s[i] == ' ')) i++;
-    }
-
-    return i;
-  }
-
-  while (true) {
-    i = skipIgnored(a, i);
-    j = skipIgnored(b, j);
-
-    // If one string runs out of non-ignored strings, the other must too.
-    if (i == a.length) return j == b.length;
-    if (j == b.length) return i == a.length;
-
-    if (a[i] != b[j]) return false;
-    i++;
-    j++;
-  }
-}