diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /js/src/tests/non262/template-strings | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/non262/template-strings')
-rw-r--r-- | js/src/tests/non262/template-strings/browser.js | 2 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/bug1559123.js | 15 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/debugLineNumber.js | 50 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/lineNumber.js | 72 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/noSubst.js | 148 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/shell.js | 0 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/tagTempl.js | 464 | ||||
-rw-r--r-- | js/src/tests/non262/template-strings/templLit.js | 118 |
8 files changed, 869 insertions, 0 deletions
diff --git a/js/src/tests/non262/template-strings/browser.js b/js/src/tests/non262/template-strings/browser.js new file mode 100644 index 0000000000..139597f9cb --- /dev/null +++ b/js/src/tests/non262/template-strings/browser.js @@ -0,0 +1,2 @@ + + diff --git a/js/src/tests/non262/template-strings/bug1559123.js b/js/src/tests/non262/template-strings/bug1559123.js new file mode 100644 index 0000000000..a739dd7dee --- /dev/null +++ b/js/src/tests/non262/template-strings/bug1559123.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!xulRuntime.shell) + +const getStrings = (strings, ...values) => strings; +const getRef = () => getStrings`test`; +let c = getRef(); +relazifyFunctions(getRef); +assertEq(getRef(), c); +// Note the failure case here looks like this: +// Assertion failed: got ["test"], expected ["test"] +// If you're reading this test and going "wtf", it's because this is testing +// reference identity of the array object - they're actually different arrays, +// but have the same contents. + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/non262/template-strings/debugLineNumber.js b/js/src/tests/non262/template-strings/debugLineNumber.js new file mode 100644 index 0000000000..aba1656866 --- /dev/null +++ b/js/src/tests/non262/template-strings/debugLineNumber.js @@ -0,0 +1,50 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// TEST BEGIN + +// verify debugger line numbers are accurate +try { + ` + a + b + c + `; + throw Error("error"); +} catch (e) { + assertEq(e.lineNumber, 14); +} + +try { + function tagThatThrows(...args) { throw new Error(); } + + tagThatThrows` + multi-line + template + string`; +} catch (e) { + var stackLines = e.stack.split('\n'); + var firstLine = stackLines[0].split(':'); + var secondLine = stackLines[1].split(':'); + var firstLineSize = firstLine.length; + var secondLineSize = secondLine.length; + assertEq(firstLine[firstLineSize - 2], "20"); + assertEq(firstLine[firstLineSize - 1], "45"); + assertEq(secondLine[secondLineSize - 2], "22"); + assertEq(secondLine[secondLineSize - 1], "18"); +} + +try { + ` multi-line + template + with + ${substitutionThatThrows()}` + +} catch (e) { + assertEq(e.lineNumber, 42); +} + + + +reportCompare(0, 0, "ok"); diff --git a/js/src/tests/non262/template-strings/lineNumber.js b/js/src/tests/non262/template-strings/lineNumber.js new file mode 100644 index 0000000000..6163d5421d --- /dev/null +++ b/js/src/tests/non262/template-strings/lineNumber.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +var BUGNUMBER = 1253847; +var summary = 'Line numbers should be updated correctly when a template literal contains CRLF sequences.'; + +print(BUGNUMBER + ": " + summary); + +// lineNumber after template literal. +var base, x, lineno; +eval([ + "base = new Error().lineNumber;", + "x = `", + "`;", + "lineno = new Error().lineNumber;", +].join("\r\n")); +assertEq(lineno, base + 3); + +eval([ + "base = new Error().lineNumber;", + "x = `", + "", + "`;", + "lineno = new Error().lineNumber;", +].join("\r\n")); +assertEq(lineno, base + 4); + +eval([ + "base = new Error().lineNumber;", + "x = `a", + "b`;", + "lineno = new Error().lineNumber;", +].join("\r\n")); +assertEq(lineno, base + 3); + +// lineNumber inside template literal +eval([ + "base = new Error().lineNumber;", + "x = `${new Error().lineNumber}", + "${new Error().lineNumber}", + "${new Error().lineNumber}`;", + "lineno = new Error().lineNumber;", +].join("\r\n")); +assertEq(lineno, base + 4); +assertEq(x, (base + 1) + '\n' + (base + 2) + '\n' + (base + 3)); + +eval([ + "var base = new Error().lineNumber;", + "var x = `", + "${new Error().lineNumber}", + "${new Error().lineNumber}", + "${new Error().lineNumber}", + "`;", + "var lineno = new Error().lineNumber;", +].join("\r\n")); +assertEq(lineno, base + 6); +assertEq(x, '\n' + (base + 2) + '\n' + (base + 3) + '\n' + (base + 4) + '\n'); + +// When CR, LF, and CRLF are mixed. +eval([ + "var base = new Error().lineNumber;", "\n", + "var x = `${new Error().lineNumber}", "\n", + "${new Error().lineNumber}", "\r\n", + "${new Error().lineNumber}", "\r", + "${new Error().lineNumber}`;", "\n", + "var lineno = new Error().lineNumber;", +].join("")); +assertEq(lineno, base + 5); +assertEq(x, (base + 1) + '\n' + (base + 2) + '\n' + (base + 3) + '\n' + (base + 4)); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/non262/template-strings/noSubst.js b/js/src/tests/non262/template-strings/noSubst.js new file mode 100644 index 0000000000..730275fd99 --- /dev/null +++ b/js/src/tests/non262/template-strings/noSubst.js @@ -0,0 +1,148 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// This test case is weird in the sense the actual work happens at the eval +// at the end. If template strings are not enabled, the test cases would throw +// a syntax error and we'd have failure reported. To avoid that, the entire +// test case is commented out and is part of a function. We use toString to +// get the string version, obtain the actual lines to run, and then use eval to +// do the actual evaluation. + +function syntaxError (script) { + try { + Function(script); + } catch (e) { + if (e.name === "SyntaxError") { + return; + } + } + throw "Expected syntax error: " + script; +} + +// TEST BEGIN + +// unterminated quasi literal +syntaxError("`"); +syntaxError("`$"); +syntaxError("`${"); +syntaxError("`${}"); +syntaxError("`${1}"); +syntaxError("`${1 + 2}"); + +// almost template substitutions +assertEq("$", `$`); +assertEq("$}", `$}`); +assertEq("}", `}`); +assertEq("{", `{`); + + +// character escape sequence (single escape character) +assertEq("\'", `\'`); +assertEq("\"", `\"`); +assertEq("\\", `\\`); +assertEq("\b", `\b`); +assertEq("\f", `\f`); +assertEq("\n", `\n`); +assertEq("\r", `\r`); +assertEq("\t", `\t`); +assertEq("\v", `\v`); +assertEq("\r\n", `\r\n`); + + +assertEq("\0", eval("`\\" + String.fromCharCode(0) + "`")); +assertEq("$", `\$`); +assertEq(".", `\.`); +assertEq("A", `\A`); +assertEq("a", `\a`); + + +// digit escape sequence +assertEq("\0", `\0`); +syntaxError("`\\1`"); +syntaxError("`\\2`"); +syntaxError("`\\3`"); +syntaxError("`\\4`"); +syntaxError("`\\5`"); +syntaxError("`\\6`"); +syntaxError("`\\7`"); +syntaxError("`\\01`"); +syntaxError("`\\001`"); +syntaxError("`\\00`"); + +// hex escape sequence +syntaxError("`\\x`"); +syntaxError("`\\x0`"); +syntaxError("`\\x0Z`"); +syntaxError("`\\xZ`"); + +assertEq("\0", `\x00`); +assertEq("$", `\x24`); +assertEq(".", `\x2E`); +assertEq("A", `\x41`); +assertEq("a", `\x61`); +assertEq("AB", `\x41B`); +assertEq(String.fromCharCode(0xFF), `\xFF`); + + +// unicode escape sequence + +assertEq("\0", `\u0000`); +assertEq("$", `\u0024`); +assertEq(".", `\u002E`); +assertEq("A", `\u0041`); +assertEq("a", `\u0061`); +assertEq("AB", `\u0041B`); +assertEq(String.fromCharCode(0xFFFF), `\uFFFF`); + + +// line continuation +assertEq("", eval("`\\\n`")); +assertEq("", eval("`\\\r`")); +assertEq("", eval("`\\\u2028`")); +assertEq("", eval("`\\\u2029`")); +assertEq("\u2028", eval("`\u2028`")); +assertEq("\u2029", eval("`\u2029`")); + +assertEq("a\nb", eval("`a\rb`")) +assertEq("a\nb", eval("`a\r\nb`")) +assertEq("a\n\nb", eval("`a\r\rb`")) + + +// source character +for (var i = 0; i < 0xFF; ++i) { + var c = String.fromCharCode(i); + if (c == "`" || c == "\\" || c == "\r") continue; + assertEq(c, eval("`" + c + "`")); +} + +assertEq("", ``); +assertEq("`", `\``); +assertEq("$", `$`); +assertEq("$$", `$$`); +assertEq("$$}", `$$}`); + +// multi-line +assertEq(`hey +there`, "hey\nthere"); + +// differences between strings and template strings +syntaxError("var obj = { `illegal`: 1}"); + +// test for JSON.parse +assertThrowsInstanceOf(() => JSON.parse('[1, `false`]'), SyntaxError); + +syntaxError('({get `name`() { return 10; }});'); + +// test for "use strict" directive +assertEq(5, Function("`use strict`; return 05;")()); +var func = function f() { + `ignored string`; + "use strict"; + return 06; +} +assertEq(6, func()); +syntaxError("\"use strict\"; return 06;"); + + +reportCompare(0, 0, "ok"); diff --git a/js/src/tests/non262/template-strings/shell.js b/js/src/tests/non262/template-strings/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/template-strings/shell.js diff --git a/js/src/tests/non262/template-strings/tagTempl.js b/js/src/tests/non262/template-strings/tagTempl.js new file mode 100644 index 0000000000..6078f4ad9e --- /dev/null +++ b/js/src/tests/non262/template-strings/tagTempl.js @@ -0,0 +1,464 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// This test case is weird in the sense the actual work happens at the eval +// at the end. If template strings are not enabled, the test cases would throw +// a syntax error and we'd have failure reported. To avoid that, the entire +// test case is commented out and is part of a function. We use toString to +// get the string version, obtain the actual lines to run, and then use eval to +// do the actual evaluation. + +function syntaxError (script) { + try { + Function(script); + } catch (e) { + if (e.name === "SyntaxError") { + return; + } + } + throw new Error('Expected syntax error: ' + script); +} + +// function definitions +function check(actual, expected) { + assertEq(actual.length, expected.length); + for (var i = 0; i < expected.length; i++) + assertEq(actual[i], expected[i]); +} + +function cooked(cs) { return cs; } +function raw(cs) { return cs.raw; } +function args(cs, ...rest) { return rest; } + + +// TEST BEGIN + +// Literals +check(raw``, [""]); +check(raw`${4}a`, ["","a"]); +check(raw`${4}`, ["",""]); +check(raw`a${4}`, ["a",""]); +check(raw`a${4}b`, ["a","b"]); +check(raw`a${4}b${3}`, ["a","b",""]); +check(raw`a${4}b${3}c`, ["a","b","c"]); +check(raw`a${4}${3}c`, ["a","","c"]); +check(raw`${4}${3}`, ["","",""]); +check(raw`${4}\r\r${3}`, ["","\\r\\r",""]); +check(raw`${4}${3}c`, ["","","c"]); +check(raw`zyx${4}wvut${3}c`, ["zyx","wvut","c"]); +check(raw`zyx${4}wvut${3}\r\n`, ["zyx","wvut","\\r\\n"]); + +check(raw`hey`, ["hey"]); +check(raw`he\r\ny`, ["he\\r\\ny"]); +check(raw`he\ry`, ["he\\ry"]); +check(raw`he\r\ry`, ["he\\r\\ry"]); +check(raw`he\ny`, ["he\\ny"]); +check(raw`he\n\ny`, ["he\\n\\ny"]); + +check(cooked`hey`, ["hey"]); +check(cooked`he\r\ny`, ["he\r\ny"]); +check(cooked`he\ry`, ["he\ry"]); +check(cooked`he\r\ry`, ["he\r\ry"]); +check(cooked`he\ny`, ["he\ny"]); +check(cooked`he\n\ny`, ["he\n\ny"]); + +check(eval("raw`\r`"), ["\n"]); +check(eval("raw`\r\n`"), ["\n"]); +check(eval("raw`\r\r\n`"), ["\n\n"]); +check(eval("raw`he\r\ny`"), ["he\ny"]); +check(eval("raw`he\ry`"), ["he\ny"]); +check(eval("raw`he\r\ry`"), ["he\n\ny"]); +check(eval("raw`he\r\r\ny`"), ["he\n\ny"]); + + +check(eval("cooked`\r`"), ["\n"]); +check(eval("cooked`\r\n`"), ["\n"]); +check(eval("cooked`\r\r\n`"), ["\n\n"]); +check(eval("cooked`he\r\ny`"), ["he\ny"]); +check(eval("cooked`he\ry`"), ["he\ny"]); +check(eval("cooked`he\r\ry`"), ["he\n\ny"]); +check(eval("cooked`he\r\r\ny`"), ["he\n\ny"]); + +// Expressions +check(args`hey${"there"}now`, ["there"]); +check(args`hey${4}now`, [4]); +check(args`hey${4}`, [4]); +check(args`${4}`, [4]); +check(args`${4}${5}`, [4,5]); +check(args`a${4}${5}`, [4,5]); +check(args`a${4}b${5}`, [4,5]); +check(args`a${4}b${5}c`, [4,5]); +check(args`${4}b${5}c`, [4,5]); +check(args`${4}${5}c`, [4,5]); + +var a = 10; +var b = 15; +check(args`${4 + a}${5 + b}c`, [14,20]); +check(args`${4 + a}${a + b}c`, [14,25]); +check(args`${b + a}${5 + b}c`, [25,20]); +check(args`${4 + a}${a + b}c${"a"}`, [14,25,"a"]); +check(args`a${"b"}${"c"}${"d"}`, ["b","c","d"]); +check(args`a${"b"}${"c"}${a + b}`, ["b","c",25]); +check(args`a${"b"}`, ["b"]); + +// Expressions - complex substitutions +check(args`${`hey ${b + a} there`}${5 + b}c`, ["hey 25 there",20]); +check(args`${`hey ${`my ${b + a} good`} there`}${5 + b}c`, ["hey my 25 good there",20]); + +syntaxError("args`${}`"); +syntaxError("args`${`"); +syntaxError("args`${\\n}`"); +syntaxError("args`${yield 0}`"); +syntaxError("args`"); +syntaxError("args`$"); +syntaxError("args`${"); +syntaxError("args.``"); + +// Template substitution tests in the context of tagged templates +// Extra whitespace inside a template substitution is ignored. +check(args`a${ +0 +}`, [0]); + +// Extra whitespace between tag and template is ignored +check(args +`a +${ +0 +}`, [0]); + + +check(args`${5}${ // Comments work in template substitutions. +// Even comments that look like code: +// 0}`, "FAIL"); /* NOTE: This whole line is a comment. +0}`, [5,0]); + +check(args // Comments work in template substitutions. +// Even comments that look like code: +// 0}`, "FAIL"); /* NOTE: This whole line is a comment. +`${5}${0}`, [5,0]); + + +// Template substitutions are expressions, not statements. +syntaxError("args`${0;}`"); +check(args`${ + function f() { + return "ok"; + }() +}`, ["ok"]); + +// Template substitutions can have side effects. +var x = 0; +check(args`${x += 1}`, [1]); +assertEq(x, 1); + +// The production for a template substitution is Expression, not +// AssignmentExpression. +x = 0; +check(args`${++x, "o"}k`, ["o"]); +assertEq(x, 1); + + +// --> is not a comment inside a template. +check(cooked` +--> this is text +`, ["\n--> this is text\n"]); + +// reentrancy +function f(n) { + if (n === 0) + return ""; + var res = args`${n}${f(n - 1)}`; + return res[0] + res[1] + ""; +} +assertEq(f(9), "987654321"); + +// Template string substitutions in generator functions can yield. +function* g() { + var res = args`${yield 1} ${yield 2}`; + return res[0] + res[1] + ""; +} + +var it = g(); +var next = it.next(); +assertEq(next.done, false); +assertEq(next.value, 1); +next = it.next("hello"); +assertEq(next.done, false); +assertEq(next.value, 2); +next = it.next("world"); +assertEq(next.done, true); +assertEq(next.value, "helloworld"); + +// undefined +assertEq(args`${void 0}`[0] + "", "undefined"); +assertEq(args`${Object.doesNotHaveThisProperty}`[0] + "", "undefined"); + +var callSiteObj = []; +callSiteObj[0] = cooked`aa${4}bb`; +for (var i = 1; i < 3; i++) + callSiteObj[i] = cooked`aa${4}bb`; + +// Same call site object behavior +assertEq(callSiteObj[1], callSiteObj[2]); +// Template objects are canonicalized +assertEq(callSiteObj[0] !== callSiteObj[1], true); +assertEq("raw" in callSiteObj[0], true); + +// Array length +assertEq(callSiteObj[0].raw.length, 2); +assertEq(callSiteObj[0].length, 2); + +// Frozen objects +assertEq(Object.isFrozen(callSiteObj[0]), true); +assertEq(Object.isFrozen(callSiteObj[0].raw), true); + +// Raw not enumerable +assertEq(callSiteObj[0].propertyIsEnumerable(callSiteObj[0].raw), false); + +// Allow call syntax +check(new ((cs, sub) => function(){ return sub }) `${[1, 2, 3]}`, [1,2,3]); + +var a = []; +function test() { + var x = callSite => callSite; + for (var i = 0; i < 2; i++) + a[i] = eval("x``"); +} +test(); +assertEq(a[0] !== a[1], true); + +// Test that |obj.method`template`| works +var newObj = { + methodRetThis : function () { + return this; + }, + methodRetCooked : function (a) { + return a; + }, + methodRetRaw : function (a) { + return a.raw; + }, + methodRetArgs : function (a, ...args) { + return args; + } +} + +assertEq(newObj.methodRetThis`abc${4}`, newObj); +check(newObj.methodRetCooked`abc${4}\r`, ["abc","\r"]); +check(eval("newObj.methodRetCooked`abc${4}\r`"), ["abc","\n"]); +check(newObj.methodRetRaw`abc${4}\r`, ["abc","\\r"]); +check(eval("newObj.methodRetRaw`abc${4}\r`"), ["abc","\n"]); +check(eval("newObj.methodRetArgs`abc${4}${5}\r${6}`"), [4,5,6]); + +// Chained calls +function func(a) { + if (a[0] === "hey") { + return function(a) { + if (a[0] === "there") { + return function(a) { + if (a[0] === "mine") + return "was mine"; + else + return "was not mine"; + } + } else { + return function(a) { + return "was not there"; + } + } + } + } else { + return function(a) { + return function(a) { + return "was not hey"; + } + } + } +} + +assertEq(func`hey``there``mine`, "was mine"); +assertEq(func`hey``there``amine`, "was not mine"); +assertEq(func`hey``tshere``amine`, "was not there"); +assertEq(func`heys``there``mine`, "was not hey"); + +// String.raw +assertEq(String.raw`h\r\ney${4}there\n`, "h\\r\\ney4there\\n"); +assertEq(String.raw`hey`, "hey"); +assertEq(String.raw``, ""); + +// Invalid escape sequences +check(raw`\01`, ["\\01"]); +check(raw`\01${0}right`, ["\\01","right"]); +check(raw`left${0}\01`, ["left","\\01"]); +check(raw`left${0}\01${1}right`, ["left","\\01","right"]); +check(raw`\1`, ["\\1"]); +check(raw`\1${0}right`, ["\\1","right"]); +check(raw`left${0}\1`, ["left","\\1"]); +check(raw`left${0}\1${1}right`, ["left","\\1","right"]); +check(raw`\xg`, ["\\xg"]); +check(raw`\xg${0}right`, ["\\xg","right"]); +check(raw`left${0}\xg`, ["left","\\xg"]); +check(raw`left${0}\xg${1}right`, ["left","\\xg","right"]); +check(raw`\xAg`, ["\\xAg"]); +check(raw`\xAg${0}right`, ["\\xAg","right"]); +check(raw`left${0}\xAg`, ["left","\\xAg"]); +check(raw`left${0}\xAg${1}right`, ["left","\\xAg","right"]); +check(raw`\u0`, ["\\u0"]); +check(raw`\u0${0}right`, ["\\u0","right"]); +check(raw`left${0}\u0`, ["left","\\u0"]); +check(raw`left${0}\u0${1}right`, ["left","\\u0","right"]); +check(raw`\u0g`, ["\\u0g"]); +check(raw`\u0g${0}right`, ["\\u0g","right"]); +check(raw`left${0}\u0g`, ["left","\\u0g"]); +check(raw`left${0}\u0g${1}right`, ["left","\\u0g","right"]); +check(raw`\u00g`, ["\\u00g"]); +check(raw`\u00g${0}right`, ["\\u00g","right"]); +check(raw`left${0}\u00g`, ["left","\\u00g"]); +check(raw`left${0}\u00g${1}right`, ["left","\\u00g","right"]); +check(raw`\u000g`, ["\\u000g"]); +check(raw`\u000g${0}right`, ["\\u000g","right"]); +check(raw`left${0}\u000g`, ["left","\\u000g"]); +check(raw`left${0}\u000g${1}right`, ["left","\\u000g","right"]); +check(raw`\u{}`, ["\\u{}"]); +check(raw`\u{}${0}right`, ["\\u{}","right"]); +check(raw`left${0}\u{}`, ["left","\\u{}"]); +check(raw`left${0}\u{}${1}right`, ["left","\\u{}","right"]); +check(raw`\u{-0}`, ["\\u{-0}"]); +check(raw`\u{-0}${0}right`, ["\\u{-0}","right"]); +check(raw`left${0}\u{-0}`, ["left","\\u{-0}"]); +check(raw`left${0}\u{-0}${1}right`, ["left","\\u{-0}","right"]); +check(raw`\u{g}`, ["\\u{g}"]); +check(raw`\u{g}${0}right`, ["\\u{g}","right"]); +check(raw`left${0}\u{g}`, ["left","\\u{g}"]); +check(raw`left${0}\u{g}${1}right`, ["left","\\u{g}","right"]); +check(raw`\u{0`, ["\\u{0"]); +check(raw`\u{0${0}right`, ["\\u{0","right"]); +check(raw`left${0}\u{0`, ["left","\\u{0"]); +check(raw`left${0}\u{0${1}right`, ["left","\\u{0","right"]); +check(raw`\u{\u{0}`, ["\\u{\\u{0}"]); +check(raw`\u{\u{0}${0}right`, ["\\u{\\u{0}","right"]); +check(raw`left${0}\u{\u{0}`, ["left","\\u{\\u{0}"]); +check(raw`left${0}\u{\u{0}${1}right`, ["left","\\u{\\u{0}","right"]); +check(raw`\u{110000}`, ["\\u{110000}"]); +check(raw`\u{110000}${0}right`, ["\\u{110000}","right"]); +check(raw`left${0}\u{110000}`, ["left","\\u{110000}"]); +check(raw`left${0}\u{110000}${1}right`, ["left","\\u{110000}","right"]); + +check(cooked`\01`, [void 0]); +check(cooked`\01${0}right`, [void 0,"right"]); +check(cooked`left${0}\01`, ["left",void 0]); +check(cooked`left${0}\01${1}right`, ["left",void 0,"right"]); +check(cooked`\1`, [void 0]); +check(cooked`\1${0}right`, [void 0,"right"]); +check(cooked`left${0}\1`, ["left",void 0]); +check(cooked`left${0}\1${1}right`, ["left",void 0,"right"]); +check(cooked`\xg`, [void 0]); +check(cooked`\xg${0}right`, [void 0,"right"]); +check(cooked`left${0}\xg`, ["left",void 0]); +check(cooked`left${0}\xg${1}right`, ["left",void 0,"right"]); +check(cooked`\xAg`, [void 0]); +check(cooked`\xAg${0}right`, [void 0,"right"]); +check(cooked`left${0}\xAg`, ["left",void 0]); +check(cooked`left${0}\xAg${1}right`, ["left",void 0,"right"]); +check(cooked`\u0`, [void 0]); +check(cooked`\u0${0}right`, [void 0,"right"]); +check(cooked`left${0}\u0`, ["left",void 0]); +check(cooked`left${0}\u0${1}right`, ["left",void 0,"right"]); +check(cooked`\u0g`, [void 0]); +check(cooked`\u0g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u0g`, ["left",void 0]); +check(cooked`left${0}\u0g${1}right`, ["left",void 0,"right"]); +check(cooked`\u00g`, [void 0]); +check(cooked`\u00g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u00g`, ["left",void 0]); +check(cooked`left${0}\u00g${1}right`, ["left",void 0,"right"]); +check(cooked`\u000g`, [void 0]); +check(cooked`\u000g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u000g`, ["left",void 0]); +check(cooked`left${0}\u000g${1}right`, ["left",void 0,"right"]); +check(cooked`\u{}`, [void 0]); +check(cooked`\u{}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{}`, ["left",void 0]); +check(cooked`left${0}\u{}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{-0}`, [void 0]); +check(cooked`\u{-0}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{-0}`, ["left",void 0]); +check(cooked`left${0}\u{-0}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{g}`, [void 0]); +check(cooked`\u{g}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{g}`, ["left",void 0]); +check(cooked`left${0}\u{g}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{0`, [void 0]); +check(cooked`\u{0${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{0`, ["left",void 0]); +check(cooked`left${0}\u{0${1}right`, ["left",void 0,"right"]); +check(cooked`\u{\u{0}`, [void 0]); +check(cooked`\u{\u{0}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{\u{0}`, ["left",void 0]); +check(cooked`left${0}\u{\u{0}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{110000}`, [void 0]); +check(cooked`\u{110000}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{110000}`, ["left",void 0]); +check(cooked`left${0}\u{110000}${1}right`, ["left",void 0,"right"]); + +syntaxError("`\\01`"); +syntaxError("`\\01${0}right`"); +syntaxError("`left${0}\\01`"); +syntaxError("`left${0}\\01${1}right`"); +syntaxError("`\\1`"); +syntaxError("`\\1${0}right`"); +syntaxError("`left${0}\\1`"); +syntaxError("`left${0}\\1${1}right`"); +syntaxError("`\\xg`"); +syntaxError("`\\xg${0}right`"); +syntaxError("`left${0}\\xg`"); +syntaxError("`left${0}\\xg${1}right`"); +syntaxError("`\\xAg`"); +syntaxError("`\\xAg${0}right`"); +syntaxError("`left${0}\\xAg`"); +syntaxError("`left${0}\\xAg${1}right`"); +syntaxError("`\\u0`"); +syntaxError("`\\u0${0}right`"); +syntaxError("`left${0}\\u0`"); +syntaxError("`left${0}\\u0${1}right`"); +syntaxError("`\\u0g`"); +syntaxError("`\\u0g${0}right`"); +syntaxError("`left${0}\\u0g`"); +syntaxError("`left${0}\\u0g${1}right`"); +syntaxError("`\\u00g`"); +syntaxError("`\\u00g${0}right`"); +syntaxError("`left${0}\\u00g`"); +syntaxError("`left${0}\\u00g${1}right`"); +syntaxError("`\\u000g`"); +syntaxError("`\\u000g${0}right`"); +syntaxError("`left${0}\\u000g`"); +syntaxError("`left${0}\\u000g${1}right`"); +syntaxError("`\\u{}`"); +syntaxError("`\\u{}${0}right`"); +syntaxError("`left${0}\\u{}`"); +syntaxError("`left${0}\\u{}${1}right`"); +syntaxError("`\\u{-0}`"); +syntaxError("`\\u{-0}${0}right`"); +syntaxError("`left${0}\\u{-0}`"); +syntaxError("`left${0}\\u{-0}${1}right`"); +syntaxError("`\\u{g}`"); +syntaxError("`\\u{g}${0}right`"); +syntaxError("`left${0}\\u{g}`"); +syntaxError("`left${0}\\u{g}${1}right`"); +syntaxError("`\\u{0`"); +syntaxError("`\\u{0${0}right`"); +syntaxError("`left${0}\\u{0`"); +syntaxError("`left${0}\\u{0${1}right`"); +syntaxError("`\\u{\\u{0}`"); +syntaxError("`\\u{\\u{0}${0}right`"); +syntaxError("`left${0}\\u{\\u{0}`"); +syntaxError("`left${0}\\u{\\u{0}${1}right`"); +syntaxError("`\\u{110000}`"); +syntaxError("`\\u{110000}${0}right`"); +syntaxError("`left${0}\\u{110000}`"); +syntaxError("`left${0}\\u{110000}${1}right`"); + + +reportCompare(0, 0, "ok"); diff --git a/js/src/tests/non262/template-strings/templLit.js b/js/src/tests/non262/template-strings/templLit.js new file mode 100644 index 0000000000..0b85ad7d1f --- /dev/null +++ b/js/src/tests/non262/template-strings/templLit.js @@ -0,0 +1,118 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// This test case is weird in the sense the actual work happens at the eval +// at the end. If template strings are not enabled, the test cases would throw +// a syntax error and we'd have failure reported. To avoid that, the entire +// test case is commented out and is part of a function. We use toString to +// get the string version, obtain the actual lines to run, and then use eval to +// do the actual evaluation. + +function syntaxError (script) { + try { + Function(script); + } catch (e) { + if (e.name === "SyntaxError") { + return; + } + } + throw new Error('Expected syntax error: ' + script); +} + +// TEST BEGIN + + + +// combinations of substitutions +assertEq("abcdef", `ab${"cd"}ef`); +assertEq("ab9ef", `ab${4+5}ef`); +assertEq("cdef", `${"cd"}ef`); +assertEq("abcd", `ab${"cd"}`); +assertEq("cd", `${"cd"}`); +assertEq("", `${""}`); +assertEq("4", `${4}`); + +// multiple substitutions +assertEq("abcdef", `ab${"cd"}e${"f"}`); +assertEq("abcdef", `ab${"cd"}${"e"}f`); +assertEq("abcdef", `a${"b"}${"cd"}e${"f"}`); +assertEq("abcdef", `${"ab"}${"cd"}${"ef"}`); + +// inception +assertEq("abcdef", `a${`b${"cd"}e${"f"}`}`); + +syntaxError("`${}`"); +syntaxError("`${`"); +syntaxError("`${\\n}`"); +syntaxError("`${yield 0}`"); + +// Extra whitespace inside a template substitution is ignored. +assertEq(`${ +0 +}`, "0"); + +assertEq(`${ // Comments work in template substitutions. +// Even comments that look like code: +// 0}`, "FAIL"); /* NOTE: This whole line is a comment. +0}`, "0"); + +// Template substitutions are expressions, not statements. +syntaxError("`${0;}`"); +assertEq(`${{}}`, "[object Object]"); +assertEq(`${ + function f() { + return "ok"; + }() +}`, "ok"); + +// Template substitutions can have side effects. +var x = 0; +assertEq(`= ${x += 1}`, "= 1"); +assertEq(x, 1); + +// The production for a template substitution is Expression, not +// AssignmentExpression. +x = 0; +assertEq(`${++x, "o"}k`, "ok"); +assertEq(x, 1); + +// --> is not a comment inside a template. +assertEq(` +--> this is text +`, "\n--> this is text\n"); + +// reentrancy +function f(n) { + if (n === 0) + return ""; + return `${n}${f(n - 1)}`; +} +assertEq(f(9), "987654321"); + +// Template string substitutions in generator functions can yield. +function* g() { + return `${yield 1} ${yield 2}`; +} + +var it = g(); +var next = it.next(); +assertEq(next.done, false); +assertEq(next.value, 1); +next = it.next("hello"); +assertEq(next.done, false); +assertEq(next.value, 2); +next = it.next("world"); +assertEq(next.done, true); +assertEq(next.value, "hello world"); + +// undefined +assertEq(`${void 0}`, "undefined"); +assertEq(`${Object.doesNotHaveThisProperty}`, "undefined"); + +// toString behavior +assertEq("<toString>", `${{valueOf: () => "<valueOf>", toString: () => "<toString>"}}`); +assertEq("Hi 42", Function("try {`${{toString: () => { throw 42;}}}`} catch(e) {return \"Hi \" + e;}")()); + + +reportCompare(0, 0, "ok"); |