<commit_before>module("basic context");

Handlebars.registerHelper('helperMissing', function(helper, context) {
  if(helper === "link_to") {
    return new Handlebars.SafeString("<a>" + context + "</a>");
  }
});

var shouldCompileTo = function(string, hashOrArray, expected, message) {
  shouldCompileToWithPartials(string, hashOrArray, false, expected, message);
};
var shouldCompileToWithPartials = function(string, hashOrArray, partials, expected, message) {
  var template = CompilerContext[partials ? 'compileWithPartial' : 'compile'](string), ary;
  if(Object.prototype.toString.call(hashOrArray) === "[object Array]") {
    helpers = hashOrArray[1];

    if(helpers) {
      for(var prop in Handlebars.helpers) {
        helpers[prop] = Handlebars.helpers[prop];
      }
    }

    ary = [];
    ary.push(hashOrArray[0]);
    ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] });
  } else {
    ary = [hashOrArray];
  }

  result = template.apply(this, ary);
  equal(result, expected, "'" + expected + "' should === '" + result + "': " + message);
};

var shouldThrow = function(fn, exception, message) {
  var caught = false;
  try {
    fn();
  }
  catch (e) {
    if (e instanceof exception) {
      caught = true;
    }
  }

  ok(caught, message || null);
}


test("compiling with a basic context", function() {
  shouldCompileTo("Goodbye\n{{cruel}}\n{{world}}!", {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
                  "It works if all the required keys are provided");
});

test("comments", function() {
  shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!",
    {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
    "comments are ignored");
});

test("boolean", function() {
  var string   = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!";
  shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
                  "booleans show the contents when true");

  shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
                  "booleans do not show the contents when false");
});

test("zeros", function() {
	shouldCompileTo("num1: {{num1}}, num2: {{num2}}", {num1: 42, num2: 0},
			"num1: 42, num2: 0");
	shouldCompileTo("num: {{.}}", 0, "num: 0");
	shouldCompileTo("num: {{num1/num2}}", {num1: {num2: 0}}, "num: 0");
});

test("newlines", function() {
    shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
    shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
});

test("escaping text", function() {
  shouldCompileTo("Awesome's", {}, "Awesome's", "text is escaped so that it doesn't get caught on single quotes");
  shouldCompileTo("Awesome\\", {}, "Awesome\\", "text is escaped so that the closing quote can't be ignored");
  shouldCompileTo("Awesome\\\\ foo", {}, "Awesome\\\\ foo", "text is escaped so that it doesn't mess up backslashes");
  shouldCompileTo("Awesome {{foo}}", {foo: '\\'}, "Awesome \\", "text is escaped so that it doesn't mess up backslashes");
  shouldCompileTo(' " " ', {}, ' " " ', "double quotes never produce invalid javascript");
});

test("escaping expressions", function() {
 shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
        "expressions with 3 handlebars aren't escaped");

 shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>',
        "expressions with {{& handlebars aren't escaped");

 shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&amp;&quot;&#x27;&#x60;\\&lt;&gt;',
        "by default expressions should be escaped");

});

test("functions returning safestrings shouldn't be escaped", function() {
  var hash = {awesome: function() { return new Handlebars.SafeString("&\"\\<>"); }};
  shouldCompileTo("{{awesome}}", hash, '&\"\\<>',
      "functions returning safestrings aren't escaped");
});

test("functions", function() {
  shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
                  "functions are called and render their output");
});

test("functions with context argument", function() {
  shouldCompileTo("{{awesome frank}}",
      {awesome: function(context) { return context; },
        frank: "Frank"},
      "Frank", "functions are called with context arguments");
});

test("paths with hyphens", function() {
  shouldCompileTo("{{foo-bar}}", {"foo-bar": "baz"}, "baz", "Paths can contain hyphens (-)");
});

test("nested paths", function() {
  shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: "beautiful"}},
                  "Goodbye beautiful world!", "Nested paths access nested objects");
});

test("nested paths with empty string value", function() {
  shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: ""}},
                  "Goodbye  world!", "Nested paths access nested objects with empty string");
});

test("literal paths", function() {
	shouldCompileTo("Goodbye {{[@alan]/expression}} world!", {"@alan": {expression: "beautiful"}},
			"Goodbye beautiful world!", "Literal paths can be used");
});

test("--- TODO --- bad idea nested paths", function() {
  return;
	var hash     = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
  shouldThrow(function() {
      CompilerContext.compile("{{#goodbyes}}{{../name/../name}}{{/goodbyes}}")(hash);
    }, Handlebars.Exception,
    "Cannot jump (..) into previous context after moving into a context.");

  var string = "{{#goodbyes}}{{.././world}} {{/goodbyes}}";
  shouldCompileTo(string, hash, "world world world ", "Same context (.) is ignored in paths");
});
<commit_msg>Got more complex literal expressions working.<commit_after>module("basic context");

Handlebars.registerHelper('helperMissing', function(helper, context) {
  if(helper === "link_to") {
    return new Handlebars.SafeString("<a>" + context + "</a>");
  }
});

var shouldCompileTo = function(string, hashOrArray, expected, message) {
  shouldCompileToWithPartials(string, hashOrArray, false, expected, message);
};
var shouldCompileToWithPartials = function(string, hashOrArray, partials, expected, message) {
  var template = CompilerContext[partials ? 'compileWithPartial' : 'compile'](string), ary;
  if(Object.prototype.toString.call(hashOrArray) === "[object Array]") {
    helpers = hashOrArray[1];

    if(helpers) {
      for(var prop in Handlebars.helpers) {
        helpers[prop] = Handlebars.helpers[prop];
      }
    }

    ary = [];
    ary.push(hashOrArray[0]);
    ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] });
  } else {
    ary = [hashOrArray];
  }

  result = template.apply(this, ary);
  equal(result, expected, "'" + expected + "' should === '" + result + "': " + message);
};

var shouldThrow = function(fn, exception, message) {
  var caught = false;
  try {
    fn();
  }
  catch (e) {
    if (e instanceof exception) {
      caught = true;
    }
  }

  ok(caught, message || null);
}


test("compiling with a basic context", function() {
  shouldCompileTo("Goodbye\n{{cruel}}\n{{world}}!", {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
                  "It works if all the required keys are provided");
});

test("comments", function() {
  shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!",
    {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
    "comments are ignored");
});

test("boolean", function() {
  var string   = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!";
  shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
                  "booleans show the contents when true");

  shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
                  "booleans do not show the contents when false");
});

test("zeros", function() {
	shouldCompileTo("num1: {{num1}}, num2: {{num2}}", {num1: 42, num2: 0},
			"num1: 42, num2: 0");
	shouldCompileTo("num: {{.}}", 0, "num: 0");
	shouldCompileTo("num: {{num1/num2}}", {num1: {num2: 0}}, "num: 0");
});

test("newlines", function() {
    shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
    shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
});

test("escaping text", function() {
  shouldCompileTo("Awesome's", {}, "Awesome's", "text is escaped so that it doesn't get caught on single quotes");
  shouldCompileTo("Awesome\\", {}, "Awesome\\", "text is escaped so that the closing quote can't be ignored");
  shouldCompileTo("Awesome\\\\ foo", {}, "Awesome\\\\ foo", "text is escaped so that it doesn't mess up backslashes");
  shouldCompileTo("Awesome {{foo}}", {foo: '\\'}, "Awesome \\", "text is escaped so that it doesn't mess up backslashes");
  shouldCompileTo(' " " ', {}, ' " " ', "double quotes never produce invalid javascript");
});

test("escaping expressions", function() {
 shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
        "expressions with 3 handlebars aren't escaped");

 shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>',
        "expressions with {{& handlebars aren't escaped");

 shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&amp;&quot;&#x27;&#x60;\\&lt;&gt;',
        "by default expressions should be escaped");

});

test("functions returning safestrings shouldn't be escaped", function() {
  var hash = {awesome: function() { return new Handlebars.SafeString("&\"\\<>"); }};
  shouldCompileTo("{{awesome}}", hash, '&\"\\<>',
      "functions returning safestrings aren't escaped");
});

test("functions", function() {
  shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
                  "functions are called and render their output");
});

test("functions with context argument", function() {
  shouldCompileTo("{{awesome frank}}",
      {awesome: function(context) { return context; },
        frank: "Frank"},
      "Frank", "functions are called with context arguments");
});

test("paths with hyphens", function() {
  shouldCompileTo("{{foo-bar}}", {"foo-bar": "baz"}, "baz", "Paths can contain hyphens (-)");
});

test("nested paths", function() {
  shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: "beautiful"}},
                  "Goodbye beautiful world!", "Nested paths access nested objects");
});

test("nested paths with empty string value", function() {
  shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: ""}},
                  "Goodbye  world!", "Nested paths access nested objects with empty string");
});

test("literal paths", function() {
	shouldCompileTo("Goodbye {{[@alan]/expression}} world!", {"@alan": {expression: "beautiful"}},
			"Goodbye beautiful world!", "Literal paths can be used");
});

test("literal paths with square brackets in them", function() {
	shouldCompileTo("Goodbye {{[@alan]]/expression}} world!", {"@alan]": {expression: "beautiful"}},
			"Goodbye beautiful world!", "Literal paths with square brackets in them can be used");
});

test("--- TODO --- bad idea nested paths", function() {
  return;
	var hash     = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
  shouldThrow(function() {
      CompilerContext.compile("{{#goodbyes}}{{../name/../name}}{{/goodbyes}}")(hash);
    }, Handlebars.Exception,
    "Cannot jump (..) into previous context after moving into a context.");

  var string = "{{#goodbyes}}{{.././world}} {{/goodbyes}}";
  shouldCompileTo(string, hash, "world world world ", "Same context (.) is ignored in paths");
});

{'fraction_non_alphanumeric': 0.20346961903931654, 'fraction_numerical': 0.0054049341818498825, 'mean_word_length': 4.335813953488372, 'pattern_counts': {'":': 5, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7086147', 'n_tokens_mistral': 3782, 'n_tokens_neox': 3536, 'n_words': 936}