| library mustache_test; |
| |
| import 'package:mustache/mustache.dart'; |
| import 'package:test/test.dart'; |
| |
| const MISMATCHED_TAG = 'Mismatched tag'; |
| const UNEXPECTED_EOF = 'Unexpected end of input'; |
| const BAD_VALUE_SECTION = 'Invalid value type for section'; |
| const BAD_VALUE_INV_SECTION = 'Invalid value type for inverse section'; |
| const BAD_TAG_NAME = 'Unless in lenient mode, tags may only contain'; |
| const VALUE_NULL = 'Value was null or missing'; |
| const VALUE_MISSING = 'Value was missing'; |
| const UNCLOSED_TAG = 'Unclosed tag'; |
| |
| Template parse(String source, {bool lenient: false}) => |
| new Template(source, lenient: lenient); |
| |
| main() { |
| group('Basic', () { |
| test('Variable', () { |
| 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({ |
| "section": {"var": "bob"} |
| }); |
| expect(output, equals('_bob_')); |
| }); |
| test('List', () { |
| var output = parse('{{#section}}_{{var}}_{{/section}}').renderString({ |
| "section": [ |
| {"var": "bob"}, |
| {"var": "jim"} |
| ] |
| }); |
| 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}); |
| expect(output, equals('_42_')); |
| }); |
| |
| test('True', () { |
| var output = |
| parse('{{#section}}_ok_{{/section}}').renderString({"section": true}); |
| expect(output, equals('_ok_')); |
| }); |
| |
| test('Nested', () { |
| var output = parse( |
| '{{#section}}.{{var}}.{{#nested}}_{{nestedvar}}_{{/nested}}.{{/section}}') |
| .renderString({ |
| "section": { |
| "var": "bob", |
| "nested": [ |
| {"nestedvar": "jim"}, |
| {"nestedvar": "sally"} |
| ] |
| } |
| }); |
| expect(output, equals('.bob._jim__sally_.')); |
| }); |
| |
| test('isNotEmpty', () { |
| var t = new Template('''{{^ section }} |
| Empty. |
| {{/ section }} |
| {{# section.isNotEmpty }} |
| <ul> |
| {{# section }} |
| <li>{{ . }}</li> |
| {{/ section }} |
| </ul> |
| {{/ section.isNotEmpty }} |
| '''); |
| expect( |
| t.renderString({ |
| "section": [1, 2, 3] |
| }), |
| equals(''' <ul> |
| <li>1</li> |
| <li>2</li> |
| <li>3</li> |
| </ul> |
| ''')); |
| expect(t.renderString({"section": []}), equals('Empty.\n')); |
| }); |
| |
| test('Whitespace in section tags', () { |
| expect( |
| parse('{{#foo.bar}}oi{{/foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{# foo.bar}}oi{{/foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{#foo.bar }}oi{{/foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{# foo.bar }}oi{{/foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{#foo.bar}}oi{{/ foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{#foo.bar}}oi{{/foo.bar }}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{#foo.bar}}oi{{/ foo.bar }}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| expect( |
| parse('{{# foo.bar }}oi{{/ foo.bar }}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('oi')); |
| }); |
| |
| test('Whitespace in variable tags', () { |
| expect( |
| parse('{{foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('true')); |
| expect( |
| parse('{{ foo.bar}}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('true')); |
| expect( |
| parse('{{foo.bar }}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('true')); |
| expect( |
| parse('{{ foo.bar }}').renderString({ |
| 'foo': {'bar': true} |
| }), |
| equals('true')); |
| }); |
| |
| test('Odd whitespace in tags', () { |
| render(source, values, output) => expect( |
| parse(source, lenient: true).renderString(values), equals(output)); |
| |
| render("{{\t# foo}}oi{{\n/foo}}", {'foo': true}, 'oi'); |
| |
| render( |
| "{{ # # foo }} {{ oi }} {{ / # foo }}", |
| { |
| '# foo': [ |
| {'oi': 'OI!'} |
| ] |
| }, |
| ' OI! '); |
| |
| render( |
| "{{ #foo }} {{ oi }} {{ /foo }}", |
| { |
| 'foo': [ |
| {'oi': 'OI!'} |
| ] |
| }, |
| ' OI! '); |
| |
| render( |
| "{{\t#foo }} {{ oi }} {{ /foo }}", |
| { |
| 'foo': [ |
| {'oi': 'OI!'} |
| ] |
| }, |
| ' OI! '); |
| |
| render("{{{ #foo }}} {{{ /foo }}}", {'#foo': 1, '/foo': 2}, '1 2'); |
| |
| // Invalid - I'm ok with that for now. |
| // render( |
| // "{{{ { }}}", |
| // {'{': 1}, |
| // '1'); |
| |
| render("{{\nfoo}}", {'foo': 'bar'}, 'bar'); |
| |
| render("{{\tfoo}}", {'foo': 'bar'}, 'bar'); |
| |
| render("{{\t# foo}}oi{{\n/foo}}", {'foo': true}, 'oi'); |
| |
| render("{{{\tfoo\t}}}", {'foo': true}, 'true'); |
| |
| //FIXME empty, or error in strict mode. |
| // render( |
| // "{{ > }}", |
| // {'>': 'oi'}, |
| // ''); |
| }); |
| |
| test('Empty source', () { |
| var t = new Template(''); |
| expect(t.renderString({}), equals('')); |
| }); |
| |
| test('Template name', () { |
| var t = new Template('', name: 'foo'); |
| expect(t.name, equals('foo')); |
| }); |
| |
| test('Bad tag', () { |
| expect(() => new Template('{{{ foo }|'), throwsException); |
| }); |
| }); |
| |
| group('Inverse Section', () { |
| test('Map', () { |
| var output = parse('{{^section}}_{{var}}_{{/section}}').renderString({ |
| "section": {"var": "bob"} |
| }); |
| expect(output, equals('')); |
| }); |
| test('List', () { |
| var output = parse('{{^section}}_{{var}}_{{/section}}').renderString({ |
| "section": [ |
| {"var": "bob"}, |
| {"var": "jim"} |
| ] |
| }); |
| 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}); |
| expect(output, equals('')); |
| }); |
| }); |
| |
| group('Html escape', () { |
| test('Escape at start', () { |
| var output = parse('_{{var}}_').renderString({"var": "&."}); |
| expect(output, equals('_&._')); |
| }); |
| |
| test('Escape at end', () { |
| var output = parse('_{{var}}_').renderString({"var": ".&"}); |
| expect(output, equals('_.&_')); |
| }); |
| |
| test('&', () { |
| var output = parse('_{{var}}_').renderString({"var": "&"}); |
| expect(output, equals('_&_')); |
| }); |
| |
| test('<', () { |
| var output = parse('_{{var}}_').renderString({"var": "<"}); |
| expect(output, equals('_<_')); |
| }); |
| |
| test('>', () { |
| var output = parse('_{{var}}_').renderString({"var": ">"}); |
| expect(output, equals('_>_')); |
| }); |
| |
| test('"', () { |
| var output = parse('_{{var}}_').renderString({"var": '"'}); |
| expect(output, equals('_"_')); |
| }); |
| |
| test("'", () { |
| var output = parse('_{{var}}_').renderString({"var": "'"}); |
| expect(output, equals('_'_')); |
| }); |
| |
| test("/", () { |
| var output = parse('_{{var}}_').renderString({"var": "/"}); |
| expect(output, equals('_/_')); |
| }); |
| }); |
| |
| group('Invalid format', () { |
| test('Mismatched tag', () { |
| var source = '{{#section}}_{{var}}_{{/notsection}}'; |
| var ex = renderFail(source, { |
| "section": {"var": "bob"} |
| }); |
| expectFail(ex, 1, 22, 'Mismatched tag'); |
| }); |
| |
| test('Unexpected EOF', () { |
| var source = '{{#section}}_{{var}}_{{/section'; |
| var ex = renderFail(source, { |
| "section": {"var": "bob"} |
| }); |
| expectFail(ex, 1, 31, UNEXPECTED_EOF); |
| }); |
| |
| test('Bad tag name, open section', () { |
| var source = r'{{#section$%$^%}}_{{var}}_{{/section}}'; |
| var ex = renderFail(source, { |
| "section": {"var": "bob"} |
| }); |
| expectFail(ex, null, null, BAD_TAG_NAME); |
| }); |
| |
| test('Bad tag name, close section', () { |
| var source = r'{{#section}}_{{var}}_{{/section$%$^%}}'; |
| var ex = renderFail(source, { |
| "section": {"var": "bob"} |
| }); |
| expectFail(ex, null, null, BAD_TAG_NAME); |
| }); |
| |
| test('Bad tag name, variable', () { |
| var source = r'{{#section}}_{{var$%$^%}}_{{/section}}'; |
| var ex = renderFail(source, { |
| "section": {"var": "bob"} |
| }); |
| expectFail(ex, null, null, BAD_TAG_NAME); |
| }); |
| |
| test('Missing variable', () { |
| var source = r'{{#section}}_{{var}}_{{/section}}'; |
| var ex = renderFail(source, {"section": {}}); |
| expectFail(ex, null, null, VALUE_MISSING); |
| }); |
| |
| // Null variables shouldn't be a problem. |
| test('Null variable', () { |
| var t = new Template('{{#section}}_{{var}}_{{/section}}'); |
| var output = t.renderString({ |
| "section": {'var': null} |
| }); |
| expect(output, equals('__')); |
| }); |
| |
| test('Unclosed section', () { |
| var source = r'{{#section}}foo'; |
| var ex = renderFail(source, {"section": {}}); |
| expectFail(ex, null, null, UNCLOSED_TAG); |
| }); |
| }); |
| |
| group('Lenient', () { |
| test('Odd section name', () { |
| 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({ |
| 'section': {r'var$%$^%': 'bob'} |
| }); |
| expect(output, equals('_bob_')); |
| }); |
| |
| test('Null variable', () { |
| var output = parse(r'{{#section}}_{{var}}_{{/section}}', lenient: true) |
| .renderString({ |
| 'section': {'var': null} |
| }); |
| expect(output, equals('__')); |
| }); |
| |
| test('Null section', () { |
| var output = parse('{{#section}}_{{var}}_{{/section}}', lenient: true) |
| .renderString({"section": null}); |
| 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('')); |
| // }); |
| }); |
| |
| group('Escape tags', () { |
| test('{{{ ... }}}', () { |
| var output = parse('{{{blah}}}').renderString({'blah': '&'}); |
| expect(output, equals('&')); |
| }); |
| test('{{& ... }}', () { |
| var output = parse('{{{blah}}}').renderString({'blah': '&'}); |
| expect(output, equals('&')); |
| }); |
| }); |
| |
| group('Partial tag', () { |
| String _partialTest(Map values, Map sources, String renderTemplate, |
| {bool lenient: false}) { |
| var templates = new Map<String, Template>(); |
| var resolver = (String name) => templates[name]; |
| for (var k in sources.keys) { |
| templates[k] = new Template(sources[k], |
| name: k, lenient: lenient, partialResolver: resolver); |
| } |
| var t = resolver(renderTemplate); |
| return t.renderString(values); |
| } |
| |
| test('basic', () { |
| var output = _partialTest({'foo': 'bar'}, |
| {'root': '{{>partial}}', 'partial': '{{foo}}'}, 'root'); |
| expect(output, 'bar'); |
| }); |
| |
| test('missing partial strict', () { |
| var threw = false; |
| try { |
| _partialTest({'foo': 'bar'}, {'root': '{{>partial}}'}, 'root', |
| lenient: false); |
| } catch (e) { |
| expect(e is TemplateException, isTrue); |
| threw = true; |
| } |
| expect(threw, isTrue); |
| }); |
| |
| test('missing partial lenient', () { |
| var output = _partialTest( |
| {'foo': 'bar'}, {'root': '{{>partial}}'}, 'root', |
| lenient: true); |
| expect(output, equals('')); |
| }); |
| |
| test('context', () { |
| var output = _partialTest({ |
| 'text': 'content' |
| }, { |
| 'root': '"{{>partial}}"', |
| 'partial': '*{{text}}*' |
| }, 'root', lenient: true); |
| expect(output, equals('"*content*"')); |
| }); |
| |
| test('recursion', () { |
| var output = _partialTest({ |
| 'content': "X", |
| 'nodes': [ |
| {'content': "Y", 'nodes': []} |
| ] |
| }, { |
| 'root': '{{>node}}', |
| 'node': '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' |
| }, 'root', lenient: true); |
| expect(output, equals('X<Y<>>')); |
| }); |
| |
| test('standalone without previous', () { |
| var output = _partialTest( |
| {}, {'root': ' {{>partial}}\n>', 'partial': '>\n>'}, 'root', |
| lenient: true); |
| expect(output, equals(' >\n >>')); |
| }); |
| |
| test('standalone indentation', () { |
| var output = _partialTest({ |
| 'content': "<\n->" |
| }, { |
| 'root': "\\\n {{>partial}}\n\/\n", |
| 'partial': "|\n{{{content}}}\n|\n" |
| }, 'root', lenient: true); |
| expect(output, equals("\\\n |\n <\n->\n |\n\/\n")); |
| }); |
| }); |
| |
| group('Lambdas', () { |
| _lambdaTest({template, lambda, output}) => expect( |
| parse(template).renderString({'lambda': lambda}), equals(output)); |
| |
| test('basic', () { |
| _lambdaTest( |
| template: 'Hello, {{lambda}}!', |
| lambda: (_) => 'world', |
| output: 'Hello, world!'); |
| }); |
| |
| test('escaping', () { |
| _lambdaTest( |
| template: '<{{lambda}}{{{lambda}}}', |
| lambda: (_) => '>', |
| output: '<>>'); |
| }); |
| |
| test('sections', () { |
| _lambdaTest( |
| template: '{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}', |
| lambda: (LambdaContext ctx) => '__${ctx.renderString()}__', |
| output: '__FILE__ != __LINE__'); |
| }); |
| |
| //FIXME |
| test('inverted sections truthy', () { |
| var template = '<{{^lambda}}{{static}}{{/lambda}}>'; |
| var values = {'lambda': (_) => false, 'static': 'static'}; |
| var output = '<>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }, skip: "skip test"); |
| |
| test("seth's use case", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'markdown': (ctx) => ctx.renderString().toLowerCase(), |
| 'content': 'OI YOU!' |
| }; |
| var output = '<oi you!>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("Lambda v2", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = {'markdown': (ctx) => ctx.source, 'content': 'OI YOU!'}; |
| var output = '<{{content}}>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("Lambda v2...", () { |
| var template = '<{{#markdown}}dsfsf dsfsdf dfsdfsd{{/markdown}}>'; |
| var values = {'markdown': (ctx) => ctx.source}; |
| var output = '<dsfsf dsfsdf dfsdfsd>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test('Alternate Delimiters', () { |
| // A lambda's return value should parse with the default delimiters. |
| |
| var template = '{{= | | =}}\nHello, (|&lambda|)!'; |
| |
| //function() { return "|planet| => {{planet}}" } |
| var values = { |
| 'planet': 'world', |
| 'lambda': (LambdaContext ctx) => |
| ctx.renderSource('|planet| => {{planet}}') |
| }; |
| |
| var output = 'Hello, (|planet| => world)!'; |
| |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test('Alternate Delimiters 2', () { |
| // Lambdas used for sections should parse with the current delimiters. |
| |
| var template = '{{= | | =}}<|#lambda|-|/lambda|>'; |
| |
| //function() { return "|planet| => {{planet}}" } |
| var values = { |
| 'planet': 'Earth', |
| 'lambda': (LambdaContext ctx) { |
| var txt = ctx.source; |
| return ctx.renderSource('$txt{{planet}} => |planet|$txt'); |
| } |
| }; |
| |
| var output = '<-{{planet}} => Earth->'; |
| |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test('LambdaContext.lookup', () { |
| var t = new Template('{{ foo }}'); |
| var s = t.renderString({'foo': (lc) => lc.lookup('bar'), 'bar': 'jim'}); |
| expect(s, equals('jim')); |
| }); |
| |
| test('LambdaContext.lookup closed', () { |
| var t = new Template('{{ foo }}'); |
| var lc2; |
| t.renderString({'foo': (lc) => lc2 = lc, 'bar': 'jim'}); |
| expect(() => lc2.lookup('foo'), throwsException); |
| }); |
| }); |
| |
| group('Other', () { |
| test('Standalone line', () { |
| var val = parse('|\n{{#bob}}\n{{/bob}}\n|').renderString({'bob': []}); |
| expect(val, equals('|\n|')); |
| }); |
| }); |
| |
| group('Array indexing', () { |
| test('Basic', () { |
| var val = parse('{{array.1}}').renderString({ |
| 'array': [1, 2, 3] |
| }); |
| expect(val, equals('2')); |
| }); |
| test('RangeError', () { |
| var error = renderFail('{{array.5}}', { |
| 'array': [1, 2, 3] |
| }); |
| expect(error, isRangeError); |
| }); |
| }); |
| |
| group('Mirrors', () { |
| test('Simple field', () { |
| var output = parse('_{{bar}}_').renderString(new Foo()..bar = 'bob'); |
| expect(output, equals('_bob_')); |
| }); |
| |
| test('Simple field', () { |
| var output = parse('_{{jim}}_').renderString(new Foo()); |
| expect(output, equals('_bob_')); |
| }); |
| |
| test('Lambda', () { |
| var output = |
| parse('_{{lambda}}_').renderString(new Foo()..lambda = (_) => 'yo'); |
| expect(output, equals('_yo_')); |
| }); |
| }); |
| |
| group('Delimiters', () { |
| test('Basic', () { |
| var val = parse('{{=<% %>=}}(<%text%>)').renderString({'text': 'Hey!'}); |
| expect(val, equals('(Hey!)')); |
| }); |
| |
| test('Single delimiters', () { |
| var val = parse('({{=[ ]=}}[text])').renderString({'text': 'It worked!'}); |
| expect(val, equals('(It worked!)')); |
| }); |
| }); |
| |
| group('Template with custom delimiters', () { |
| test('Basic', () { |
| var t = new Template('(<%text%>)', delimiters: '<% %>'); |
| var val = t.renderString({'text': 'Hey!'}); |
| expect(val, equals('(Hey!)')); |
| }); |
| }); |
| |
| group('Lambda context', () { |
| test("LambdaContext write", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'markdown': (ctx) { |
| ctx.write('foo'); |
| } |
| }; |
| var output = '<foo>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("LambdaContext render", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'content': 'bar', |
| 'markdown': (ctx) { |
| ctx.render(); |
| } |
| }; |
| var output = '<bar>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("LambdaContext render with value", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'markdown': (LambdaContext ctx) { |
| ctx.render(value: {'content': 'oi!'}); |
| } |
| }; |
| var output = '<oi!>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("LambdaContext renderString with value", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'markdown': (LambdaContext ctx) { |
| return ctx.renderString(value: {'content': 'oi!'}); |
| } |
| }; |
| var output = '<oi!>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("LambdaContext write and return", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'markdown': (LambdaContext ctx) { |
| ctx.write('foo'); |
| return 'bar'; |
| } |
| }; |
| var output = '<foobar>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| |
| test("LambdaContext renderSource with value", () { |
| var template = '<{{#markdown}}{{content}}{{/markdown}}>'; |
| var values = { |
| 'markdown': (LambdaContext ctx) { |
| return ctx.renderSource(ctx.source, value: {'content': 'oi!'}); |
| } |
| }; |
| var output = '<oi!>'; |
| expect(parse(template).renderString(values), equals(output)); |
| }); |
| }); |
| } |
| |
| renderFail(source, values) { |
| try { |
| parse(source).renderString(values); |
| return null; |
| } catch (e) { |
| return e; |
| } |
| } |
| |
| expectFail(ex, int line, int column, [String msgStartsWith]) { |
| expect(ex is TemplateException, isTrue); |
| if (line != null) expect(ex.line, equals(line)); |
| if (column != null) expect(ex.column, equals(column)); |
| if (msgStartsWith != null) expect(ex.message, startsWith(msgStartsWith)); |
| } |
| |
| class Foo { |
| String bar; |
| Function lambda; |
| jim() => 'bob'; |
| } |