Increase test coverage a touch

This commit is contained in:
kpdecker
2014-08-14 12:25:35 -05:00
parent 9ab31e1fc6
commit cb22ee5681
15 changed files with 186 additions and 44 deletions
+2 -1
View File
@@ -67,7 +67,8 @@ function registerDefaultHelpers(instance) {
});
instance.registerHelper('blockHelperMissing', function(context, options) {
var inverse = options.inverse || function() {}, fn = options.fn;
var inverse = options.inverse,
fn = options.fn;
if (isFunction(context)) { context = context.call(this); }
@@ -99,6 +99,7 @@ JavaScriptCompiler.prototype = {
// Flush any trailing content that might be pending.
this.pushSource('');
/* istanbul ignore next */
if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
throw new Exception('Compile completed with content left on stack');
}
@@ -551,10 +552,6 @@ JavaScriptCompiler.prototype = {
var helper = this.setupHelper(paramSize, name);
var lookup = (isSimple ? helper.name + ' || ' : '') + nonHelper + ' || helperMissing';
if (helper.paramsInit) {
lookup += ',' + helper.paramsInit;
}
this.push('((' + lookup + ').call(' + helper.callParams + '))');
// Always flush subexpressions. This is both to prevent the compounding size issue that
@@ -849,6 +846,7 @@ JavaScriptCompiler.prototype = {
return item.value;
} else {
if (!inline) {
/* istanbul ignore next */
if (!this.stackSlot) {
throw new Exception('Invalid stack pop');
}
+1
View File
@@ -23,6 +23,7 @@ export function checkRevision(compilerInfo) {
// TODO: Remove this line and break up compilePartial
export function template(templateSpec, env) {
/* istanbul ignore next */
if (!env) {
throw new Exception("No environment passed to template");
}
+3 -1
View File
@@ -14,7 +14,7 @@ var badChars = /[&<>"'`]/g;
var possible = /[&<>"'`]/;
function escapeChar(chr) {
return escape[chr] || "&amp;";
return escape[chr];
}
export function extend(obj /* , ...source */) {
@@ -37,6 +37,7 @@ var isFunction = function(value) {
return typeof value === 'function';
};
// fallback for older versions of Chrome and Safari
/* istanbul ignore next */
if (isFunction(/x/)) {
isFunction = function(value) {
return typeof value === 'function' && toString.call(value) === '[object Function]';
@@ -44,6 +45,7 @@ if (isFunction(/x/)) {
}
export var isFunction;
/* istanbul ignore next */
export var isArray = Array.isArray || function(value) {
return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
};
+1
View File
@@ -14,6 +14,7 @@ handlebars.print = printer.print;
module.exports = handlebars;
// Publish a Node.js require() handler for .handlebars and .hbs files
/* istanbul ignore else */
if (typeof require !== 'undefined' && require.extensions) {
var extension = function(module, filename) {
var fs = require("fs");
+10 -3
View File
@@ -39,6 +39,13 @@ describe('blocks', function() {
"Templates can access variables in contexts up the stack with relative path syntax");
});
it('multiple blocks with complex lookup', function() {
var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
});
it("block with complex lookup using nested context", function() {
var string = "{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}";
@@ -48,10 +55,10 @@ describe('blocks', function() {
});
it("block with deep nested complex lookup", function() {
var string = "{{#outer}}Goodbye {{#inner}}cruel {{../../omg}}{{/inner}}{{/outer}}";
var hash = {omg: "OMG!", outer: [{ inner: [{ text: "goodbye" }] }] };
var string = "{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}";
var hash = {omg: "OMG!", outer: [{ sibling: 'sad', inner: [{ text: "goodbye" }] }] };
shouldCompileTo(string, hash, "Goodbye cruel OMG!");
shouldCompileTo(string, hash, "Goodbye cruel sad OMG!");
});
describe('inverted sections', function() {
+70
View File
@@ -0,0 +1,70 @@
/*global Handlebars, shouldThrow */
describe('compiler', function() {
if (!Handlebars.compile) {
return;
}
describe('#equals', function() {
function compile(string) {
var ast = Handlebars.parse(string);
return new Handlebars.Compiler().compile(ast, {});
}
it('should treat as equal', function() {
equal(compile('foo').equals(compile('foo')), true);
equal(compile('{{foo}}').equals(compile('{{foo}}')), true);
equal(compile('{{foo.bar}}').equals(compile('{{foo.bar}}')), true);
equal(compile('{{foo.bar baz "foo" true false bat=1}}').equals(compile('{{foo.bar baz "foo" true false bat=1}}')), true);
equal(compile('{{foo.bar (baz bat=1)}}').equals(compile('{{foo.bar (baz bat=1)}}')), true);
equal(compile('{{#foo}} {{/foo}}').equals(compile('{{#foo}} {{/foo}}')), true);
});
it('should treat as not equal', function() {
equal(compile('foo').equals(compile('bar')), false);
equal(compile('{{foo}}').equals(compile('{{bar}}')), false);
equal(compile('{{foo.bar}}').equals(compile('{{bar.bar}}')), false);
equal(compile('{{foo.bar baz bat=1}}').equals(compile('{{foo.bar bar bat=1}}')), false);
equal(compile('{{foo.bar (baz bat=1)}}').equals(compile('{{foo.bar (bar bat=1)}}')), false);
equal(compile('{{#foo}} {{/foo}}').equals(compile('{{#bar}} {{/bar}}')), false);
equal(compile('{{#foo}} {{/foo}}').equals(compile('{{#foo}} {{foo}}{{/foo}}')), false);
});
});
describe('#compile', function() {
it('should fail with invalid input', function() {
shouldThrow(function() {
Handlebars.compile(null);
}, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null');
shouldThrow(function() {
Handlebars.compile({});
}, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed [object Object]');
});
it('can utilize AST instance', function() {
equal(Handlebars.compile(new Handlebars.AST.ProgramNode(true, [ new Handlebars.AST.ContentNode("Hello")]))(), 'Hello');
});
it("can pass through an empty string", function() {
equal(Handlebars.compile('')(), '');
});
});
describe('#precompile', function() {
it('should fail with invalid input', function() {
shouldThrow(function() {
Handlebars.precompile(null);
}, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed null');
shouldThrow(function() {
Handlebars.precompile({});
}, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed [object Object]');
});
it('can utilize AST instance', function() {
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.ProgramNode(true, [ new Handlebars.AST.ContentNode("Hello")]))), true);
});
it("can pass through an empty string", function() {
equal(/return ""/.test(Handlebars.precompile('')), true);
});
});
});
+1 -1
View File
@@ -44,7 +44,7 @@ global.shouldThrow = function(callback, type, msg) {
throw new Error('Type failure');
}
if (msg && !(msg.test ? msg.test(err.message) : msg === err.message)) {
throw new Error('Message failure');
equal(msg, err.message);
}
}
if (failed) {
+32 -11
View File
@@ -208,20 +208,41 @@ describe('helpers', function() {
});
});
it("Multiple global helper registration", function() {
var helpers = handlebarsEnv.helpers;
handlebarsEnv.helpers = {};
describe('registration', function() {
it('unregisters', function() {
var helpers = handlebarsEnv.helpers;
handlebarsEnv.helpers = {};
handlebarsEnv.registerHelper({
'if': helpers['if'],
world: function() { return "world!"; },
test_helper: function() { return 'found it!'; }
handlebarsEnv.registerHelper('foo', function() {
return 'fail';
});
handlebarsEnv.unregisterHelper('foo');
equals(handlebarsEnv.helpers.foo, undefined);
});
shouldCompileTo(
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}",
[{cruel: "cruel"}],
"found it! Goodbye cruel world!!");
it('allows multiple globals', function() {
var helpers = handlebarsEnv.helpers;
handlebarsEnv.helpers = {};
handlebarsEnv.registerHelper({
'if': helpers['if'],
world: function() { return "world!"; },
test_helper: function() { return 'found it!'; }
});
shouldCompileTo(
"{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}",
[{cruel: "cruel"}],
"found it! Goodbye cruel world!!");
});
it('fails with multiple and args', function() {
shouldThrow(function() {
handlebarsEnv.registerHelper({
world: function() { return "world!"; },
test_helper: function() { return 'found it!'; }
}, {});
}, Error, 'Arg not supported with multiple helpers');
});
});
it("decimal number literals work", function() {
+1 -1
View File
@@ -1,4 +1,4 @@
/*global Handlebars */
/*global Handlebars, shouldThrow */
describe('parser', function() {
if (!Handlebars.print) {
return;
+3
View File
@@ -91,6 +91,9 @@ describe('partials', function() {
var dude = "{{name}}";
var hash = {name:"Jeepers", another_dude:"Creepers"};
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed");
handlebarsEnv.unregisterPartial('global_test');
equals(handlebarsEnv.partials.global_test, undefined);
});
it("Multiple partial registration", function() {
+44 -1
View File
@@ -10,9 +10,12 @@ describe('precompiler', function() {
Precompiler = require('../lib/precompiler');
var log,
logFunction;
logFunction,
precompile;
beforeEach(function() {
precompile = Handlebars.precompile;
logFunction = console.log;
log = '';
console.log = function() {
@@ -20,6 +23,7 @@ describe('precompiler', function() {
};
});
afterEach(function() {
Handlebars.precompile = precompile;
console.log = logFunction;
});
@@ -37,4 +41,43 @@ describe('precompiler', function() {
Precompiler.cli({templates: ['foo']});
}, Handlebars.Exception, 'Unable to open template file "foo"');
});
it('should throw when combining simple and minimized', function() {
shouldThrow(function() {
Precompiler.cli({templates: [__dirname], simple: true, min: true});
}, Handlebars.Exception, 'Unable to minimze simple output');
});
it('should throw when combining simple and multiple templates', function() {
shouldThrow(function() {
Precompiler.cli({templates: [__dirname + '/artifacts/empty.handlebars', __dirname + '/artifacts/empty.handlebars'], simple: true});
}, Handlebars.Exception, 'Unable to output multiple templates in simple mode');
});
it('should throw when combining simple and directories', function() {
shouldThrow(function() {
Precompiler.cli({templates: [__dirname], simple: true});
}, Handlebars.Exception, 'Unable to output multiple templates in simple mode');
});
it('should enumerate directories by extension', function() {
Precompiler.cli({templates: [__dirname + '/artifacts'], extension: 'hbs'});
equal(/'example_2'/.test(log), true);
log = '';
Precompiler.cli({templates: [__dirname + '/artifacts'], extension: 'handlebars'});
equal(/'empty'/.test(log), true);
equal(/'example_1'/.test(log), true);
});
it('should output simple templates', function() {
Handlebars.precompile = function() { return 'simple'; };
Precompiler.cli({templates: [__dirname + '/artifacts/empty.handlebars'], simple: true, extension: 'handlebars'});
equal(log, 'simple\n');
});
it('should output amd templates', function() {
Handlebars.precompile = function() { return 'amd'; };
Precompiler.cli({templates: [__dirname + '/artifacts/empty.handlebars'], amd: true, extension: 'handlebars'});
equal(/template\(amd\)/.test(log), true);
});
it('should output commonjs templates', function() {
Handlebars.precompile = function() { return 'commonjs'; };
Precompiler.cli({templates: [__dirname + '/artifacts/empty.handlebars'], commonjs: true, extension: 'handlebars'});
equal(/template\(commonjs\)/.test(log), true);
});
});
-16
View File
@@ -130,12 +130,6 @@ describe('Regressions', function() {
shouldCompileTo(string, data, "Hello Chris. You have just won $10000! Well, $6000, after taxes.", "the hello world mustache example works");
});
it("Passing falsy values to Handlebars.compile throws an error", function() {
shouldThrow(function() {
CompilerContext.compile(null);
}, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed null');
});
it('GH-731: zero context rendering', function() {
shouldCompileTo('{{#foo}} This is {{bar}} ~ {{/foo}}', {foo: 0, bar: 'OK'}, ' This is ~ ');
});
@@ -143,14 +137,4 @@ describe('Regressions', function() {
it('GH-820: zero pathed rendering', function() {
shouldCompileTo('{{foo.bar}}', {foo: 0}, '');
});
if (Handlebars.AST) {
it("can pass through an already-compiled AST via compile/precompile", function() {
equal(Handlebars.compile(new Handlebars.AST.ProgramNode(true, [ new Handlebars.AST.ContentNode("Hello")]))(), 'Hello');
});
it("can pass through an empty string", function() {
equal(Handlebars.compile('')(), '');
});
}
});
+16
View File
@@ -56,4 +56,20 @@ describe('utils', function() {
equals(Handlebars.Utils.isEmpty({bar: 1}), false);
});
});
describe('#extend', function() {
it('should ignore prototype values', function() {
function A() {
this.a = 1;
}
A.prototype.b = 4;
var b = {b: 2};
Handlebars.Utils.extend(b, new A());
equals(b.a, 1);
equals(b.b, 2);
});
});
});
-5
View File
@@ -67,11 +67,6 @@ ID [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
this.begin('raw');
return 'CLOSE_RAW_BLOCK';
}
<mu>"{{{{"[^\x00]*"}}}}" {
yytext = yytext.substr(4, yyleng-8);
this.popState();
return 'RAW_BLOCK';
}
<mu>"{{"{LEFT_STRIP}?">" return 'OPEN_PARTIAL';
<mu>"{{"{LEFT_STRIP}?"#" return 'OPEN_BLOCK';
<mu>"{{"{LEFT_STRIP}?"/" return 'OPEN_ENDBLOCK';