Move equals check from node and token into test
diff --git a/lib/src/node.dart b/lib/src/node.dart
index 083f5c3..a0be614 100644
--- a/lib/src/node.dart
+++ b/lib/src/node.dart
@@ -33,18 +33,7 @@
     return t.length < 50 ? t : t.substring(0, 48) + '...';
   }
   
-  // Remove me.
-  // Only used for testing.
-  bool operator ==(o) => o is TextNode
-      && text == o.text
-      && start == o.start
-      && end == o.end;
-  
-  // TODO hashcode. import quiver.
-  
-  
-  void accept(Visitor visitor) => visitor.visitText(this);
-  
+  void accept(Visitor visitor) => visitor.visitText(this);  
 }
 
 class VariableNode extends Node {
@@ -54,20 +43,10 @@
   
   final String name;
   final bool escape;
-  
-  String toString() => '(VariableNode "$name" escape: $escape $start $end)';
-  
-  // Only used for testing.
-  bool operator ==(o) => o is VariableNode
-      && name == o.name
-      && escape == o.escape
-      && start == o.start
-      && end == o.end;
-  
-  // TODO hashcode. import quiver.
 
   void accept(Visitor visitor) => visitor.visitVariable(this);
   
+  String toString() => '(VariableNode "$name" escape: $escape $start $end)';  
 }
 
 
@@ -85,28 +64,14 @@
   int contentEnd; // Set in parser when close tag is parsed.
   final List<Node> children = <Node>[];
 
-  toString() => '(SectionNode $name inverse: $inverse $start $end)';
-  
-  // TODO Only used for testing.
-  //FIXME use deepequals in test for comparing children.
-  //Perhaps shift all of this == code into test.
-  bool operator ==(o) => o is SectionNode
-      && name == o.name
-      && delimiters == o.delimiters
-      && inverse == o.inverse
-      && start == o.start
-      && end == o.end;
-  
-  // TODO hashcode. import quiver.
-
   void accept(Visitor visitor) => visitor.visitSection(this);
   
   void visitChildren(Visitor visitor) {
     children.forEach((node) => node.accept(visitor));
   }
   
- 
-  }
+  toString() => '(SectionNode $name inverse: $inverse $start $end)'; 
+}
 
 class PartialNode extends Node {
 
@@ -119,15 +84,7 @@
   // it's content can be correctly indented.
   final String indent;
 
-  toString() => '(PartialNode $name $start $end "$indent")';
-  
-  //TODO move to test.
-  bool operator ==(o) => o is PartialNode
-      && name == o.name
-      && indent == o.indent;
-  
-  // TODO hashcode. import quiver.
-
   void accept(Visitor visitor) => visitor.visitPartial(this);
   
+  toString() => '(PartialNode $name $start $end "$indent")';  
 }
diff --git a/lib/src/token.dart b/lib/src/token.dart
index 682bc89..afb42b8 100644
--- a/lib/src/token.dart
+++ b/lib/src/token.dart
@@ -37,13 +37,4 @@
   final int end;
   
   String toString() => "(Token ${type.name} \"$value\" $start $end)";
-  
-  // Only used for testing.
-  bool operator ==(o) => o is Token
-      && type == o.type
-      && value == o.value
-      && start == o.start
-      && end == o.end;
-  
-  // TODO hashcode. import quiver.
 }
diff --git a/test/parser_test.dart b/test/parser_test.dart
index 8d4137e..be6fba7 100644
--- a/test/parser_test.dart
+++ b/test/parser_test.dart
@@ -7,36 +7,34 @@
 import 'package:mustache/src/token.dart';
 
 main() {
-  
+    
   group('Scanner', () {
 
     test('scan text', () {
       var source = 'abc';
       var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
       var tokens = scanner.scan();
-      expect(tokens, orderedEquals([
-        new Token(TokenType.text, 'abc', 0, 3),
-        ]));
+      expectTokens(tokens, [ new Token(TokenType.text, 'abc', 0, 3)]);
     });
     
     test('scan tag', () {
       var source = 'abc{{foo}}def';     
       var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
       var tokens = scanner.scan();
-      expect(tokens, orderedEquals([
+      expectTokens(tokens, [
         new Token(TokenType.text, 'abc', 0, 3),
         new Token(TokenType.openDelimiter, '{{', 3, 5),
         new Token(TokenType.identifier, 'foo', 5, 8),
         new Token(TokenType.closeDelimiter, '}}', 8, 10),
         new Token(TokenType.text, 'def', 10, 13)
-      ]));
+      ]);
     });
      
    test('scan tag whitespace', () {
      var source = 'abc{{ foo }}def';
      var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
      var tokens = scanner.scan();
-     expect(tokens, orderedEquals([
+     expectTokens(tokens, [
        new Token(TokenType.text, 'abc', 0, 3),
        new Token(TokenType.openDelimiter, '{{', 3, 5),
        new Token(TokenType.whitespace, ' ', 5, 6),
@@ -44,14 +42,14 @@
        new Token(TokenType.whitespace, ' ', 9, 10),
        new Token(TokenType.closeDelimiter, '}}', 10, 12),
        new Token(TokenType.text, 'def', 12, 15)
-     ]));
+     ]);
    });
    
    test('scan tag sigil', () {
      var source = 'abc{{ # foo }}def';
      var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
      var tokens = scanner.scan();
-     expect(tokens, orderedEquals([
+     expectTokens(tokens, [
        new Token(TokenType.text, 'abc', 0, 3),
        new Token(TokenType.openDelimiter, '{{', 3, 5),
        new Token(TokenType.whitespace, ' ', 5, 6),
@@ -61,14 +59,14 @@
        new Token(TokenType.whitespace, ' ', 11, 12),
        new Token(TokenType.closeDelimiter, '}}', 12, 14),
        new Token(TokenType.text, 'def', 14, 17)
-     ]));
+     ]);
    });
 
    test('scan tag dot', () {
      var source = 'abc{{ foo.bar }}def';
      var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
      var tokens = scanner.scan();
-     expect(tokens, orderedEquals([
+     expectTokens(tokens, [
        new Token(TokenType.text, 'abc', 0, 3),
        new Token(TokenType.openDelimiter, '{{', 3, 5),
        new Token(TokenType.whitespace, ' ', 5, 6),
@@ -78,20 +76,20 @@
        new Token(TokenType.whitespace, ' ', 13, 14),
        new Token(TokenType.closeDelimiter, '}}', 14, 16),
        new Token(TokenType.text, 'def', 16, 19)
-     ]));
+     ]);
    });
 
    test('scan triple mustache', () {
      var source = 'abc{{{foo}}}def';     
      var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
      var tokens = scanner.scan();
-     expect(tokens, orderedEquals([
+     expectTokens(tokens, [
        new Token(TokenType.text, 'abc', 0, 3),
        new Token(TokenType.openDelimiter, '{{{', 3, 6),
        new Token(TokenType.identifier, 'foo', 6, 9),
        new Token(TokenType.closeDelimiter, '}}}', 9, 12),
        new Token(TokenType.text, 'def', 12, 15)
-     ]));
+     ]);
    });
 
    
@@ -99,7 +97,7 @@
      var source = 'abc{{{ foo }}}def';
      var scanner = new Scanner(source, 'foo', '{{ }}', lenient: false);
      var tokens = scanner.scan();
-     expect(tokens, orderedEquals([
+     expectTokens(tokens, [
        new Token(TokenType.text, 'abc', 0, 3),
        new Token(TokenType.openDelimiter, '{{{', 3, 6),
        new Token(TokenType.whitespace, ' ', 6, 7),
@@ -107,7 +105,7 @@
        new Token(TokenType.whitespace, ' ', 10, 11),
        new Token(TokenType.closeDelimiter, '}}}', 11, 14),
        new Token(TokenType.text, 'def', 14, 17)
-     ]));
+     ]);
    });
   });
    
@@ -117,100 +115,100 @@
      var source = 'abc{{foo}}def';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc', 0, 3),
        new VariableNode('foo', 3, 10, escape: true),
        new TextNode('def', 10, 13)
-     ]));
+     ]);
    });
 
    test('parse variable whitespace', () {
      var source = 'abc{{ foo }}def';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc', 0, 3),
        new VariableNode('foo', 3, 12, escape: true),
        new TextNode('def', 12, 15)
-     ]));
+     ]);
    });
    
    test('parse section', () {
      var source = 'abc{{#foo}}def{{/foo}}ghi';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc', 0, 3),
        new SectionNode('foo', 3, 11, '{{ }}'),
        new TextNode('ghi', 22, 25)
-     ]));
-     expect(nodes[1].children, orderedEquals([new TextNode('def', 11, 14)]));
+     ]);
+     expectNodes(nodes[1].children, [new TextNode('def', 11, 14)]);
    });
 
    test('parse section standalone tag whitespace', () {
      var source = 'abc\n{{#foo}}\ndef\n{{/foo}}\nghi';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc\n', 0, 4),
        new SectionNode('foo', 4, 12, '{{ }}'),
        new TextNode('ghi', 26, 29)
-     ]));
-     expect(nodes[1].children, orderedEquals([new TextNode('def\n', 13, 17)]));
+     ]);
+     expectNodes(nodes[1].children, [new TextNode('def\n', 13, 17)]);
    });
 
    test('parse section standalone tag whitespace consecutive', () {
      var source = 'abc\n{{#foo}}\ndef\n{{/foo}}\n{{#foo}}\ndef\n{{/foo}}\nghi';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc\n', 0, 4),
        new SectionNode('foo', 4, 12, '{{ }}'),
        new SectionNode('foo', 26, 34, '{{ }}'),
        new TextNode('ghi', 48, 51),
-     ]));
-     expect(nodes[1].children, orderedEquals([new TextNode('def\n', 13, 17)]));
+     ]);
+     expectNodes(nodes[1].children, [new TextNode('def\n', 13, 17)]);
    });
    
    test('parse section standalone tag whitespace on first line', () {
      var source = '  {{#foo}}  \ndef\n{{/foo}}\nghi';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new SectionNode('foo', 2, 10, '{{ }}'),
        new TextNode('ghi', 26, 29)
-     ]));
-     expect(nodes[0].children, orderedEquals([new TextNode('def\n', 13, 17)]));
+     ]);
+     expectNodes(nodes[0].children, [new TextNode('def\n', 13, 17)]);
    });
 
    test('parse section standalone tag whitespace on last line', () {
      var source = '{{#foo}}def\n  {{/foo}}  ';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new SectionNode('foo', 0, 8, '{{ }}')
-     ]));
-     expect(nodes[0].children, orderedEquals([new TextNode('def\n', 8, 12)]));
+     ]);
+     expectNodes(nodes[0].children, [new TextNode('def\n', 8, 12)]);
    });
    
    test('parse whitespace', () {
      var source = 'abc\n   ';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc\n   ', 0, 7),
-     ]));
+     ]);
    });
    
    test('parse partial', () {
      var source = 'abc\n   {{>foo}}def';
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('abc\n   ', 0, 7),
        new PartialNode('foo', 7, 15, '   '),
        new TextNode('def', 15, 18)
-     ]));
+     ]);
    });
 
    test('parse change delimiters', () {
@@ -218,12 +216,12 @@
      var parser = new Parser(source, 'foo', '{{ }}', lenient: false);
      var nodes = parser.parse();
      expect(nodes[1].delimiters, equals('| |'));
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new TextNode('<', 11, 12),
        new SectionNode('lambda', 12, 21, '| |'),
        new TextNode('>', 31, 32),
-     ]));     
-     expect(nodes[1].children.first, new TextNode('-', 21, 22));
+     ]);
+     expectNodes(nodes[1].children, [new TextNode('-', 21, 22)]);
    });   
    
    test('corner case strict', () {
@@ -241,11 +239,11 @@
      var source = "{{{ #foo }}} {{{ /foo }}}";
      var parser = new Parser(source, 'foo', '{{ }}', lenient: true);
      var nodes = parser.parse();
-     expect(nodes, orderedEquals([
+     expectNodes(nodes, [
        new VariableNode('#foo', 0, 12, escape: false),
        new TextNode(' ', 12, 13),
        new VariableNode('/foo', 13, 25, escape: false)
-     ]));     
+     ]);     
    });
    
   parseFail(source) {
@@ -318,4 +316,58 @@
    
   });
   
-}
\ No newline at end of file
+}
+
+nodeEqual(a, b) {
+  if (a is TextNode) {
+    return b is TextNode
+        && a.text == b.text
+        && a.start == b.start
+        && a.end == b.end;
+  
+  } else if (a is VariableNode) {
+    return a is VariableNode
+        && a.name == b.name
+        && a.escape == b.escape
+        && a.start == b.start
+        && a.end == b.end;
+
+  } else if (a is SectionNode) {
+    return a is SectionNode
+        && a.name == b.name
+        && a.delimiters == b.delimiters
+        && a.inverse == b.inverse
+        && a.start == b.start
+        && a.end == b.end;
+    
+  } else if (a is PartialNode) {
+    return a is PartialNode
+        && a.name == b.name
+        && a.indent == b.indent;
+    
+  } else {
+    return false;
+  }
+}
+
+tokenEqual(Token a, Token b) {    
+  return a is Token
+      && a.type == b.type
+      && a.value == b.value
+      && a.start == b.start
+      && a.end == b.end;
+}
+
+expectTokens(List<Token> a, List<Token> b) {
+  expect(a.length, equals(b.length), reason: "$a != $b");
+  for (var i = 0; i < a.length; i++) {
+    expect(tokenEqual(a[i], b[i]), isTrue, reason: "$a != $b");
+  }
+}
+
+expectNodes(List<Node> a, List<Node> b) {
+  expect(a.length, equals(b.length), reason: "$a != $b");
+  for (var i = 0; i < a.length; i++) {
+    expect(nodeEqual(a[i], b[i]), isTrue, reason: "$a != $b");
+  }
+}