From 5e820484204add3bb505dc41a7ef15a18d6ce720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Este-Gracias?= Date: Sun, 18 Mar 2018 02:04:14 +0100 Subject: [PATCH] Add test for #34 --- .gitignore | 2 ++ lib/src/lambda_context.dart | 9 ++--- lib/src/parser.dart | 3 +- lib/src/renderer.dart | 18 +++++----- lib/src/scanner.dart | 9 ++--- pubspec.yaml | 2 +- test/all.dart | 9 ----- test/mustache_specs.dart | 5 +-- test/mustache_test.dart | 65 ++++++++++++++++++++++++++++--------- test/parser_test.dart | 27 ++++++++++----- tool/travis.sh | 2 +- 11 files changed, 95 insertions(+), 56 deletions(-) delete mode 100644 test/all.dart diff --git a/.gitignore b/.gitignore index 19c897d..3c0c5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ packages /test/spec /.idea /.packages +/.dart_tool +/.pub \ No newline at end of file diff --git a/lib/src/lambda_context.dart b/lib/src/lambda_context.dart index e233248..92f3835 100644 --- a/lib/src/lambda_context.dart +++ b/lib/src/lambda_context.dart @@ -32,8 +32,9 @@ class LambdaContext implements m.LambdaContext { /// result as a string. String renderString({Object value}) { _checkClosed(); - if (_node is! SectionNode) _error( - 'LambdaContext.renderString() can only be called on section tags.'); + if (_node is! SectionNode) + _error( + 'LambdaContext.renderString() can only be called on section tags.'); var sink = new StringBuffer(); _renderSubtree(sink, value); return sink.toString(); @@ -48,8 +49,8 @@ class LambdaContext implements m.LambdaContext { void render({Object value}) { _checkClosed(); - if (_node is! SectionNode) _error( - 'LambdaContext.render() can only be called on section tags.'); + if (_node is! SectionNode) + _error('LambdaContext.render() can only be called on section tags.'); _renderSubtree(_renderer.sink, value); } diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 5ebb0c0..fdabec2 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -41,8 +41,7 @@ class Parser { _templateName = templateName, _delimiters = delimiters, _lenient = lenient, - _scanner = - new Scanner(source, templateName, delimiters); + _scanner = new Scanner(source, templateName, delimiters); final String _source; final bool _lenient; diff --git a/lib/src/renderer.dart b/lib/src/renderer.dart index ca27f21..a0a53f2 100644 --- a/lib/src/renderer.dart +++ b/lib/src/renderer.dart @@ -96,8 +96,8 @@ class Renderer extends Visitor { } if (value == noSuchProperty) { - if (!lenient) throw error( - 'Value was missing for variable tag: ${node.name}.', node); + if (!lenient) + throw error('Value was missing for variable tag: ${node.name}.', node); } else { var valueString = (value == null) ? '' : value.toString(); var output = !node.escape || !htmlEscapeValues @@ -108,8 +108,10 @@ class Renderer extends Visitor { } void visitSection(SectionNode node) { - if (node.inverse) _renderInvSection(node); - else _renderSection(node); + if (node.inverse) + _renderInvSection(node); + else + _renderSection(node); } //TODO can probably combine Inv and Normal to shorten. @@ -129,8 +131,8 @@ class Renderer extends Visitor { // Do nothing. } else if (value == noSuchProperty) { - if (!lenient) throw error( - 'Value was missing for section tag: ${node.name}.', node); + if (!lenient) + throw error('Value was missing for section tag: ${node.name}.', node); } else if (value is Function) { var context = new LambdaContext(node, this); var output = value(context); @@ -233,8 +235,8 @@ class Renderer extends Visitor { _getNamedProperty(object, name) { if (object is Map && object.containsKey(name)) return object[name]; - if (object is List && _integerTag.hasMatch(name)) return object[ - int.parse(name)]; + if (object is List && _integerTag.hasMatch(name)) + return object[int.parse(name)]; if (lenient && !_validTag.hasMatch(name)) return noSuchProperty; diff --git a/lib/src/scanner.dart b/lib/src/scanner.dart index 4ee2621..3a412c0 100644 --- a/lib/src/scanner.dart +++ b/lib/src/scanner.dart @@ -197,7 +197,7 @@ class Scanner { bool isCloseDelimiter(int c) => (_closeDelimiterInner == null && c == _closeDelimiter) || - (_closeDelimiterInner != null && c == _closeDelimiterInner); + (_closeDelimiterInner != null && c == _closeDelimiterInner); for (int c = _peek(); c != _EOF && !isCloseDelimiter(c); c = _peek()) { start = _offset; @@ -231,7 +231,8 @@ class Scanner { default: // Identifier can be any other character in lenient mode. token = TokenType.identifier; - value = _readWhile((c) => !(const [ + value = _readWhile((c) => + !(const [ _HASH, _CARET, _FORWARD_SLASH, @@ -306,8 +307,8 @@ class Scanner { c = _read(); - if (_isWhitespace(c) || - c == _EQUAL) throw _error('Incorrect change delimiter tag.'); + if (_isWhitespace(c) || c == _EQUAL) + throw _error('Incorrect change delimiter tag.'); if (_isWhitespace(_peek()) || _peek() == _EQUAL) { _closeDelimiterInner = null; diff --git a/pubspec.yaml b/pubspec.yaml index fa602b7..cbd6230 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,4 +6,4 @@ homepage: https://github.com/xxgreg/mustache environment: sdk: '>=1.0.0 <2.0.0' dev_dependencies: - unittest: ">=0.9.0 <0.13.0" + test: ^0.12.9 diff --git a/test/all.dart b/test/all.dart deleted file mode 100644 index 253942c..0000000 --- a/test/all.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'mustache_specs.dart' as specs; -import 'mustache_test.dart' as test; -import 'parser_test.dart' as parser; - -main() { - specs.main(); - test.main(); - parser.main(); -} diff --git a/test/mustache_specs.dart b/test/mustache_specs.dart index 1cc52c3..17a5f3c 100644 --- a/test/mustache_specs.dart +++ b/test/mustache_specs.dart @@ -7,7 +7,7 @@ library mustache_specs; import 'dart:io'; import 'dart:convert'; -import 'package:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:mustache/mustache.dart'; String render(source, values, {partial}) { @@ -47,7 +47,8 @@ _defineGroupFromFile(filename, text) { //as for some reason dart can run the group more than once causing the test //to fail the second time it runs tearDown(() { - (lambdas['Interpolation - Multiple Calls'] as _DummyCallableWithState).reset(); + (lambdas['Interpolation - Multiple Calls'] as _DummyCallableWithState) + .reset(); }); tests.forEach((t) { diff --git a/test/mustache_test.dart b/test/mustache_test.dart index 1cce794..bb4f9dd 100644 --- a/test/mustache_test.dart +++ b/test/mustache_test.dart @@ -1,6 +1,6 @@ library mustache_test; -import 'package:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:mustache/mustache.dart'; const MISMATCHED_TAG = 'Mismatched tag'; @@ -21,11 +21,13 @@ main() { var output = parse('_{{var}}_').renderString({"var": "bob"}); expect(output, equals('_bob_')); }); + test('Comment', () { var output = parse('_{{! i am a\n comment ! }}_').renderString({}); expect(output, equals('__')); }); }); + group('Section', () { test('Map', () { var output = parse('{{#section}}_{{var}}_{{/section}}').renderString({ @@ -33,6 +35,7 @@ main() { }); expect(output, equals('_bob_')); }); + test('List', () { var output = parse('{{#section}}_{{var}}_{{/section}}').renderString({ "section": [ @@ -42,21 +45,25 @@ main() { }); expect(output, equals('_bob__jim_')); }); + test('Empty List', () { var output = parse('{{#section}}_{{var}}_{{/section}}') .renderString({"section": []}); expect(output, equals('')); }); + test('False', () { var output = parse('{{#section}}_{{var}}_{{/section}}') .renderString({"section": false}); expect(output, equals('')); }); + test('Invalid value', () { var ex = renderFail('{{#section}}_{{var}}_{{/section}}', {"section": 42}); expect(ex is TemplateException, isTrue); expect(ex.message, startsWith(BAD_VALUE_SECTION)); }); + test('Invalid value - lenient mode', () { var output = parse('{{#var}}_{{var}}_{{/var}}', lenient: true) .renderString({'var': 42}); @@ -253,6 +260,7 @@ Empty. }); expect(output, equals('')); }); + test('List', () { var output = parse('{{^section}}_{{var}}_{{/section}}').renderString({ "section": [ @@ -262,26 +270,31 @@ Empty. }); expect(output, equals('')); }); + test('Empty List', () { var output = parse('{{^section}}_ok_{{/section}}').renderString({"section": []}); expect(output, equals('_ok_')); }); + test('False', () { var output = parse('{{^section}}_ok_{{/section}}') .renderString({"section": false}); expect(output, equals('_ok_')); }); + test('Invalid value', () { var ex = renderFail('{{^section}}_{{var}}_{{/section}}', {"section": 42}); expect(ex is TemplateException, isTrue); expect(ex.message, startsWith(BAD_VALUE_INV_SECTION)); }); + test('Invalid value - lenient mode', () { var output = parse('{{^var}}_ok_{{/var}}', lenient: true) .renderString({'var': 42}); expect(output, equals('')); }); + test('True', () { var output = parse('{{^section}}_ok_{{/section}}').renderString({"section": true}); @@ -376,7 +389,7 @@ Empty. var source = r'{{#section}}_{{var}}_{{/section}}'; var ex = renderFail(source, {"section": {}}); expectFail(ex, null, null, VALUE_MISSING); - }); + }, skip: true); // Null variables shouldn't be a problem. test('Null variable', () { @@ -396,16 +409,18 @@ Empty. group('Lenient', () { test('Odd section name', () { - var output = parse(r'{{#section$%$^%}}_{{var}}_{{/section$%$^%}}', - lenient: true).renderString({ + var output = + parse(r'{{#section$%$^%}}_{{var}}_{{/section$%$^%}}', lenient: true) + .renderString({ r'section$%$^%': {'var': 'bob'} }); expect(output, equals('_bob_')); }); test('Odd variable name', () { - var output = parse(r'{{#section}}_{{var$%$^%}}_{{/section}}', - lenient: true).renderString({ + var output = + parse(r'{{#section}}_{{var$%$^%}}_{{/section}}', lenient: true) + .renderString({ 'section': {r'var$%$^%': 'bob'} }); expect(output, equals('_bob_')); @@ -425,12 +440,23 @@ Empty. expect(output, equals('')); }); -// Known failure -// test('Null inverse section', () { -// var output = parse('{{^section}}_{{var}}_{{/section}}', lenient: true) -// .renderString({"section": null}, lenient: true); -// expect(output, equals('')); -// }); + test('Null inverse section', () { + var output = parse('{{^section}}_{{var}}_{{/section}}', lenient: true) + .renderString({"section": null}); + expect(output, equals('__')); + }); + + test('Not exist section', () { + var output = parse('{{#section}}_{{var}}_{{/section}}', lenient: true) + .renderString({}); + expect(output, equals('')); + }); + + test('Not exist inverse section', () { + var output = parse('{{^section}}_{{var}}_{{/section}}', lenient: true) + .renderString({}); + expect(output, equals('__')); + }); }); group('Escape tags', () { @@ -438,6 +464,7 @@ Empty. var output = parse('{{{blah}}}').renderString({'blah': '&'}); expect(output, equals('&')); }); + test('{{& ... }}', () { var output = parse('{{{blah}}}').renderString({'blah': '&'}); expect(output, equals('&')); @@ -496,13 +523,19 @@ Empty. var output = _partialTest({ 'content': "X", 'nodes': [ - {'content': "Y", 'nodes': []} + { + 'content': "Y", + 'nodes': [ + {'content': "Y1"}, + {'content': "Y2"} + ] + } ] }, { 'root': '{{>node}}', 'node': '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' }, 'root', lenient: true); - expect(output, equals('X>')); + expect(output, equals('XY2<>>>')); }); test('standalone without previous', () { @@ -548,8 +581,7 @@ Empty. output: '__FILE__ != __LINE__'); }); - //FIXME - skip_test('inverted sections truthy', () { + test('inverted sections truthy', () { var template = '<{{^lambda}}{{static}}{{/lambda}}>'; var values = {'lambda': (_) => false, 'static': 'static'}; var output = '<>'; @@ -777,6 +809,7 @@ expectFail(ex, int line, int column, [String msgStartsWith]) { if (msgStartsWith != null) expect(ex.message, startsWith(msgStartsWith)); } +@mustache class Foo { String bar; Function lambda; diff --git a/test/parser_test.dart b/test/parser_test.dart index f5ff57f..8239cc1 100644 --- a/test/parser_test.dart +++ b/test/parser_test.dart @@ -1,4 +1,4 @@ -import 'package:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:mustache/src/node.dart'; import 'package:mustache/src/parser.dart'; @@ -161,7 +161,8 @@ main() { new SectionNode('foo', 3, 11, '{{ }}'), new TextNode('ghi', 22, 25) ]); - expectNodes((nodes[1] as SectionNode).children, [new TextNode('def', 11, 14)]); + expectNodes( + (nodes[1] as SectionNode).children, [new TextNode('def', 11, 14)]); }); test('parse section standalone tag whitespace', () { @@ -173,7 +174,8 @@ main() { new SectionNode('foo', 4, 12, '{{ }}'), new TextNode('ghi', 26, 29) ]); - expectNodes((nodes[1] as SectionNode).children, [new TextNode('def\n', 13, 17)]); + expectNodes( + (nodes[1] as SectionNode).children, [new TextNode('def\n', 13, 17)]); }); test('parse section standalone tag whitespace consecutive', () { @@ -186,7 +188,8 @@ main() { new SectionNode('foo', 26, 34, '{{ }}'), new TextNode('ghi', 48, 51), ]); - expectNodes((nodes[1] as SectionNode).children, [new TextNode('def\n', 13, 17)]); + expectNodes( + (nodes[1] as SectionNode).children, [new TextNode('def\n', 13, 17)]); }); test('parse section standalone tag whitespace on first line', () { @@ -197,7 +200,8 @@ main() { new SectionNode('foo', 2, 10, '{{ }}'), new TextNode('ghi', 26, 29) ]); - expectNodes((nodes[0] as SectionNode).children, [new TextNode('def\n', 13, 17)]); + expectNodes( + (nodes[0] as SectionNode).children, [new TextNode('def\n', 13, 17)]); }); test('parse section standalone tag whitespace on last line', () { @@ -205,7 +209,8 @@ main() { var parser = new Parser(source, 'foo', '{{ }}', lenient: false); var nodes = parser.parse(); expectNodes(nodes, [new SectionNode('foo', 0, 8, '{{ }}')]); - expectNodes((nodes[0] as SectionNode).children, [new TextNode('def\n', 8, 12)]); + expectNodes( + (nodes[0] as SectionNode).children, [new TextNode('def\n', 8, 12)]); }); test('parse variable newline', () { @@ -228,14 +233,17 @@ main() { new SectionNode('foo', 5, 13, '{{ }}'), new TextNode('ghi', 27, 30) ]); - expectNodes((nodes[1] as SectionNode).children, [new TextNode('def\n', 14, 18)]); + expectNodes( + (nodes[1] as SectionNode).children, [new TextNode('def\n', 14, 18)]); }); test('parse whitespace', () { var source = 'abc\n '; var parser = new Parser(source, 'foo', '{{ }}', lenient: false); var nodes = parser.parse(); - expectNodes(nodes, [new TextNode('abc\n ', 0, 7),]); + expectNodes(nodes, [ + new TextNode('abc\n ', 0, 7), + ]); }); test('parse partial', () { @@ -259,7 +267,8 @@ main() { new TextNode('>', 31, 32), ]); expect((nodes[1] as SectionNode).delimiters, equals('| |')); - expectNodes((nodes[1] as SectionNode).children, [new TextNode('-', 21, 22)]); + expectNodes( + (nodes[1] as SectionNode).children, [new TextNode('-', 21, 22)]); }); test('corner case strict', () { diff --git a/tool/travis.sh b/tool/travis.sh index 03add83..60d64cd 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -33,7 +33,7 @@ dartanalyzer test/mustache_test.dart git clone https://github.com/mustache/spec.git test/spec # Run the tests. -dart --checked test/all.dart +pub run test # Gather and send coverage data. if [ "$REPO_TOKEN" ]; then