blob: 82a3ab84535a5ae8305d631a98a331f3d098f51b [file] [log] [blame]
// Specification files can be downloaded here https://github.com/mustache/spec
// Test implemented by Georgios Valotasios.
// See: https://github.com/valotas/mustache4dart
library mustache_specs;
import 'dart:io';
import 'dart:convert';
import 'package:unittest/unittest.dart';
import 'package:mustache/mustache.dart';
String render(source, values, {partial}) {
var resolver = null;
resolver = (name) {
var source = partial(name);
if (source == null) return null;
return new Template(source, partialResolver: resolver, lenient: true);
};
var t = new Template(source, partialResolver: resolver, lenient: true);
return t.renderString(values);
}
main() {
defineTests();
}
defineTests () {
var specs_dir = new Directory('spec/specs');
specs_dir
.listSync()
.forEach((File f) {
var filename = f.path;
if (shouldRun(filename)) {
var text = f.readAsStringSync(encoding: UTF8);
_defineGroupFromFile(filename, text);
}
});
}
_defineGroupFromFile(filename, text) {
var json = JSON.decode(text);
var tests = json['tests'];
filename = filename.substring(filename.lastIndexOf('/') + 1);
group("Specs of $filename", () {
//Make sure that we reset the state of the Interpolation - Multiple Calls test
//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'].reset());
tests.forEach( (t) {
var testDescription = new StringBuffer(t['name']);
testDescription.write(': ');
testDescription.write(t['desc']);
var template = t['template'];
var data = t['data'];
var templateOneline = template.replaceAll('\n', '\\n').replaceAll('\r', '\\r');
var reason = new StringBuffer("Could not render right '''$templateOneline'''");
var expected = t['expected'];
var partials = t['partials'];
var partial = (String name) {
if (partials == null) {
return null;
}
return partials[name];
};
//swap the data.lambda with a dart real function
if (data['lambda'] != null) {
data['lambda'] = lambdas[t['name']];
}
reason.write(" with '$data'");
if (partials != null) {
reason.write(" and partial: $partials");
}
test(testDescription.toString(), () => expect(render(template, data, partial: partial), expected, reason: reason.toString()));
});
});
}
bool shouldRun(String filename) {
// filter out only .json files
if (!filename.endsWith('.json')) {
return false;
}
return true;
}
//Until we'll find a way to load a piece of code dynamically,
//we provide the lambdas at the test here
class _DummyCallableWithState {
var _callCounter = 0;
call (arg) => "${++_callCounter}";
reset () => _callCounter = 0;
}
Function wrapLambda(Function f) => (LambdaContext ctx) => ctx.renderSource(f(ctx.source).toString());
var lambdas = {
'Interpolation' : wrapLambda((t) => 'world'),
'Interpolation - Expansion': wrapLambda((t) => '{{planet}}'),
'Interpolation - Alternate Delimiters': wrapLambda((t) => "|planet| => {{planet}}"),
'Interpolation - Multiple Calls': new _DummyCallableWithState(), //function() { return (g=(function(){return this})()).calls=(g.calls||0)+1 }
'Escaping': wrapLambda((t) => '>'),
'Section': wrapLambda((txt) => txt == "{{x}}" ? "yes" : "no"),
'Section - Expansion': wrapLambda((txt) => "$txt{{planet}}$txt"),
'Section - Alternate Delimiters': wrapLambda((txt) => "$txt{{planet}} => |planet|$txt"),
'Section - Multiple Calls': wrapLambda((t) => "__${t}__"),
'Inverted Section': wrapLambda((txt) => false)
};