OLD | NEW |
| (Empty) |
1 // Copyright 2014 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Flags: --harmony-templates --harmony-unicode | |
6 | |
7 var num = 5; | |
8 var str = "str"; | |
9 function fn() { return "result"; } | |
10 var obj = { | |
11 num: num, | |
12 str: str, | |
13 fn: function() { return "result"; } | |
14 }; | |
15 | |
16 (function testBasicExpressions() { | |
17 assertEquals("foo 5 bar", `foo ${num} bar`); | |
18 assertEquals("foo str bar", `foo ${str} bar`); | |
19 assertEquals("foo [object Object] bar", `foo ${obj} bar`); | |
20 assertEquals("foo result bar", `foo ${fn()} bar`); | |
21 assertEquals("foo 5 bar", `foo ${obj.num} bar`); | |
22 assertEquals("foo str bar", `foo ${obj.str} bar`); | |
23 assertEquals("foo result bar", `foo ${obj.fn()} bar`); | |
24 })(); | |
25 | |
26 (function testExpressionsContainingTemplates() { | |
27 assertEquals("foo bar 5", `foo ${`bar ${num}`}`); | |
28 })(); | |
29 | |
30 (function testMultilineTemplates() { | |
31 assertEquals("foo\n bar\n baz", `foo | |
32 bar | |
33 baz`); | |
34 | |
35 assertEquals("foo\n bar\n baz", eval("`foo\r\n bar\r baz`")); | |
36 })(); | |
37 | |
38 (function testLineContinuation() { | |
39 assertEquals("\n", `\ | |
40 | |
41 `); | |
42 })(); | |
43 | |
44 (function testTaggedTemplates() { | |
45 var calls = 0; | |
46 (function(s) { | |
47 calls++; | |
48 })`test`; | |
49 assertEquals(1, calls); | |
50 | |
51 calls = 0; | |
52 // assert tag is invoked in right context | |
53 obj = { | |
54 fn: function() { | |
55 calls++; | |
56 assertEquals(obj, this); | |
57 } | |
58 }; | |
59 | |
60 obj.fn`test`; | |
61 assertEquals(1, calls); | |
62 | |
63 calls = 0; | |
64 // Simple templates only have a callSiteObj | |
65 (function(s) { | |
66 calls++; | |
67 assertEquals(1, arguments.length); | |
68 })`test`; | |
69 assertEquals(1, calls); | |
70 | |
71 // Templates containing expressions have the values of evaluated expressions | |
72 calls = 0; | |
73 (function(site, n, s, o, f, r) { | |
74 calls++; | |
75 assertEquals(6, arguments.length); | |
76 assertEquals("number", typeof n); | |
77 assertEquals("string", typeof s); | |
78 assertEquals("object", typeof o); | |
79 assertEquals("function", typeof f); | |
80 assertEquals("result", r); | |
81 })`${num}${str}${obj}${fn}${fn()}`; | |
82 assertEquals(1, calls); | |
83 | |
84 // The TV and TRV of NoSubstitutionTemplate :: `` is the empty code unit | |
85 // sequence. | |
86 calls = 0; | |
87 (function(s) { | |
88 calls++; | |
89 assertEquals(1, s.length); | |
90 assertEquals(1, s.raw.length); | |
91 assertEquals("", s[0]); | |
92 | |
93 // Failure: expected <""> found <"foo barfoo barfoo foo foo foo testtest"> | |
94 assertEquals("", s.raw[0]); | |
95 })``; | |
96 assertEquals(1, calls); | |
97 | |
98 // The TV and TRV of TemplateHead :: `${ is the empty code unit sequence. | |
99 calls = 0; | |
100 (function(s) { | |
101 calls++; | |
102 assertEquals(2, s.length); | |
103 assertEquals(2, s.raw.length); | |
104 assertEquals("", s[0]); | |
105 assertEquals("", s.raw[0]); | |
106 })`${1}`; | |
107 assertEquals(1, calls); | |
108 | |
109 // The TV and TRV of TemplateMiddle :: }${ is the empty code unit sequence. | |
110 calls = 0; | |
111 (function(s) { | |
112 calls++; | |
113 assertEquals(3, s.length); | |
114 assertEquals(3, s.raw.length); | |
115 assertEquals("", s[1]); | |
116 assertEquals("", s.raw[1]); | |
117 })`${1}${2}`; | |
118 assertEquals(1, calls); | |
119 | |
120 // The TV and TRV of TemplateTail :: }` is the empty code unit sequence. | |
121 calls = 0; | |
122 (function(s) { | |
123 calls++; | |
124 assertEquals(2, s.length); | |
125 assertEquals(2, s.raw.length); | |
126 assertEquals("", s[1]); | |
127 assertEquals("", s.raw[1]); | |
128 })`${1}`; | |
129 assertEquals(1, calls); | |
130 | |
131 // The TV of NoSubstitutionTemplate :: ` TemplateCharacters ` is the TV of | |
132 // TemplateCharacters. | |
133 calls = 0; | |
134 (function(s) { calls++; assertEquals("foo", s[0]); })`foo`; | |
135 assertEquals(1, calls); | |
136 | |
137 // The TV of TemplateHead :: ` TemplateCharacters ${ is the TV of | |
138 // TemplateCharacters. | |
139 calls = 0; | |
140 (function(s) { calls++; assertEquals("foo", s[0]); })`foo${1}`; | |
141 assertEquals(1, calls); | |
142 | |
143 // The TV of TemplateMiddle :: } TemplateCharacters ${ is the TV of | |
144 // TemplateCharacters. | |
145 calls = 0; | |
146 (function(s) { calls++; assertEquals("foo", s[1]); })`${1}foo${2}`; | |
147 assertEquals(1, calls); | |
148 | |
149 // The TV of TemplateTail :: } TemplateCharacters ` is the TV of | |
150 // TemplateCharacters. | |
151 calls = 0; | |
152 (function(s) { calls++; assertEquals("foo", s[1]); })`${1}foo`; | |
153 assertEquals(1, calls); | |
154 | |
155 // The TV of TemplateCharacters :: TemplateCharacter is the TV of | |
156 // TemplateCharacter. | |
157 calls = 0; | |
158 (function(s) { calls++; assertEquals("f", s[0]); })`f`; | |
159 assertEquals(1, calls); | |
160 | |
161 // The TV of TemplateCharacter :: $ is the code unit value 0x0024. | |
162 calls = 0; | |
163 (function(s) { calls++; assertEquals("$", s[0]); })`$`; | |
164 assertEquals(1, calls); | |
165 | |
166 // The TV of TemplateCharacter :: \ EscapeSequence is the CV of | |
167 // EscapeSequence. | |
168 calls = 0; | |
169 (function(s) { calls++; assertEquals("안녕", s[0]); })`\uc548\uB155`; | |
170 (function(s) { calls++; assertEquals("\xff", s[0]); })`\xff`; | |
171 (function(s) { calls++; assertEquals("\n", s[0]); })`\n`; | |
172 assertEquals(3, calls); | |
173 | |
174 // The TV of TemplateCharacter :: LineContinuation is the TV of | |
175 // LineContinuation. The TV of LineContinuation :: \ LineTerminatorSequence is | |
176 // the empty code unit sequence. | |
177 calls = 0; | |
178 (function(s) { calls++; assertEquals("", s[0]); })`\ | |
179 `; | |
180 assertEquals(1, calls); | |
181 | |
182 // The TRV of NoSubstitutionTemplate :: ` TemplateCharacters ` is the TRV of | |
183 // TemplateCharacters. | |
184 calls = 0; | |
185 (function(s) { calls++; assertEquals("test", s.raw[0]); })`test`; | |
186 assertEquals(1, calls); | |
187 | |
188 // The TRV of TemplateHead :: ` TemplateCharacters ${ is the TRV of | |
189 // TemplateCharacters. | |
190 calls = 0; | |
191 (function(s) { calls++; assertEquals("test", s.raw[0]); })`test${1}`; | |
192 assertEquals(1, calls); | |
193 | |
194 // The TRV of TemplateMiddle :: } TemplateCharacters ${ is the TRV of | |
195 // TemplateCharacters. | |
196 calls = 0; | |
197 (function(s) { calls++; assertEquals("test", s.raw[1]); })`${1}test${2}`; | |
198 assertEquals(1, calls); | |
199 | |
200 // The TRV of TemplateTail :: } TemplateCharacters ` is the TRV of | |
201 // TemplateCharacters. | |
202 calls = 0; | |
203 (function(s) { calls++; assertEquals("test", s.raw[1]); })`${1}test`; | |
204 assertEquals(1, calls); | |
205 | |
206 // The TRV of TemplateCharacters :: TemplateCharacter is the TRV of | |
207 // TemplateCharacter. | |
208 calls = 0; | |
209 (function(s) { calls++; assertEquals("f", s.raw[0]); })`f`; | |
210 assertEquals(1, calls); | |
211 | |
212 // The TRV of TemplateCharacter :: $ is the code unit value 0x0024. | |
213 calls = 0; | |
214 (function(s) { calls++; assertEquals("\u0024", s.raw[0]); })`$`; | |
215 assertEquals(1, calls); | |
216 | |
217 // The TRV of EscapeSequence :: 0 is the code unit value 0x0030. | |
218 calls = 0; | |
219 (function(s) { calls++; assertEquals("\u005C\u0030", s.raw[0]); })`\0`; | |
220 assertEquals(1, calls); | |
221 | |
222 // The TRV of TemplateCharacter :: \ EscapeSequence is the sequence consisting | |
223 // of the code unit value 0x005C followed by the code units of TRV of | |
224 // EscapeSequence. | |
225 | |
226 // The TRV of EscapeSequence :: HexEscapeSequence is the TRV of the | |
227 // HexEscapeSequence. | |
228 calls = 0; | |
229 (function(s) { calls++; assertEquals("\u005Cxff", s.raw[0]); })`\xff`; | |
230 assertEquals(1, calls); | |
231 | |
232 // The TRV of EscapeSequence :: UnicodeEscapeSequence is the TRV of the | |
233 // UnicodeEscapeSequence. | |
234 calls = 0; | |
235 (function(s) { calls++; assertEquals("\u005Cuc548", s.raw[0]); })`\uc548`; | |
236 assertEquals(1, calls); | |
237 | |
238 // The TRV of CharacterEscapeSequence :: SingleEscapeCharacter is the TRV of | |
239 // the SingleEscapeCharacter. | |
240 calls = 0; | |
241 (function(s) { calls++; assertEquals("\u005C\u0027", s.raw[0]); })`\'`; | |
242 (function(s) { calls++; assertEquals("\u005C\u0022", s.raw[0]); })`\"`; | |
243 (function(s) { calls++; assertEquals("\u005C\u005C", s.raw[0]); })`\\`; | |
244 (function(s) { calls++; assertEquals("\u005Cb", s.raw[0]); })`\b`; | |
245 (function(s) { calls++; assertEquals("\u005Cf", s.raw[0]); })`\f`; | |
246 (function(s) { calls++; assertEquals("\u005Cn", s.raw[0]); })`\n`; | |
247 (function(s) { calls++; assertEquals("\u005Cr", s.raw[0]); })`\r`; | |
248 (function(s) { calls++; assertEquals("\u005Ct", s.raw[0]); })`\t`; | |
249 (function(s) { calls++; assertEquals("\u005Cv", s.raw[0]); })`\v`; | |
250 (function(s) { calls++; assertEquals("\u005C`", s.raw[0]); })`\``; | |
251 assertEquals(10, calls); | |
252 | |
253 // The TRV of CharacterEscapeSequence :: NonEscapeCharacter is the CV of the | |
254 // NonEscapeCharacter. | |
255 calls = 0; | |
256 (function(s) { calls++; assertEquals("\u005Cz", s.raw[0]); })`\z`; | |
257 assertEquals(1, calls); | |
258 | |
259 // The TRV of LineTerminatorSequence :: <LF> is the code unit value 0x000A. | |
260 // The TRV of LineTerminatorSequence :: <CR> is the code unit value 0x000A. | |
261 // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence consisting of | |
262 // the code unit value 0x000A. | |
263 calls = 0; | |
264 function testRawLineNormalization(cs) { | |
265 calls++; | |
266 assertEquals(cs.raw[0], "\n\n\n"); | |
267 assertEquals(cs.raw[1], "\n\n\n"); | |
268 } | |
269 eval("testRawLineNormalization`\r\n\n\r${1}\r\n\n\r`"); | |
270 assertEquals(1, calls); | |
271 | |
272 // The TRV of LineContinuation :: \ LineTerminatorSequence is the sequence | |
273 // consisting of the code unit value 0x005C followed by the code units of TRV | |
274 // of LineTerminatorSequence. | |
275 calls = 0; | |
276 function testRawLineContinuation(cs) { | |
277 calls++; | |
278 assertEquals(cs.raw[0], "\u005C\n\u005C\n\u005C\n"); | |
279 assertEquals(cs.raw[1], "\u005C\n\u005C\n\u005C\n"); | |
280 } | |
281 eval("testRawLineContinuation`\\\r\n\\\n\\\r${1}\\\r\n\\\n\\\r`"); | |
282 assertEquals(1, calls); | |
283 })(); | |
284 | |
285 | |
286 (function testCallSiteObj() { | |
287 var calls = 0; | |
288 function tag(cs) { | |
289 calls++; | |
290 assertTrue(cs.hasOwnProperty("raw")); | |
291 assertTrue(Object.isFrozen(cs)); | |
292 assertTrue(Object.isFrozen(cs.raw)); | |
293 var raw = Object.getOwnPropertyDescriptor(cs, "raw"); | |
294 assertFalse(raw.writable); | |
295 assertFalse(raw.configurable); | |
296 assertFalse(raw.enumerable); | |
297 assertEquals(Array.prototype, Object.getPrototypeOf(cs.raw)); | |
298 assertTrue(Array.isArray(cs.raw)); | |
299 assertEquals(Array.prototype, Object.getPrototypeOf(cs)); | |
300 assertTrue(Array.isArray(cs)); | |
301 | |
302 var cooked0 = Object.getOwnPropertyDescriptor(cs, "0"); | |
303 assertFalse(cooked0.writable); | |
304 assertFalse(cooked0.configurable); | |
305 assertTrue(cooked0.enumerable); | |
306 | |
307 var raw0 = Object.getOwnPropertyDescriptor(cs.raw, "0"); | |
308 assertFalse(cooked0.writable); | |
309 assertFalse(cooked0.configurable); | |
310 assertTrue(cooked0.enumerable); | |
311 | |
312 var length = Object.getOwnPropertyDescriptor(cs, "length"); | |
313 assertFalse(length.writable); | |
314 assertFalse(length.configurable); | |
315 assertFalse(length.enumerable); | |
316 | |
317 length = Object.getOwnPropertyDescriptor(cs.raw, "length"); | |
318 assertFalse(length.writable); | |
319 assertFalse(length.configurable); | |
320 assertFalse(length.enumerable); | |
321 } | |
322 tag`${1}`; | |
323 assertEquals(1, calls); | |
324 })(); | |
325 | |
326 | |
327 (function testUTF16ByteOrderMark() { | |
328 assertEquals("\uFEFFtest", `\uFEFFtest`); | |
329 assertEquals("\uFEFFtest", eval("`\uFEFFtest`")); | |
330 })(); | |
331 | |
332 | |
333 (function testStringRawAsTagFn() { | |
334 assertEquals("\\u0065\\`\\r\\r\\n\\ntestcheck", | |
335 String.raw`\u0065\`\r\r\n\n${"test"}check`); | |
336 assertEquals("\\\n\\\n\\\n", eval("String.raw`\\\r\\\r\n\\\n`")); | |
337 assertEquals("", String.raw``); | |
338 })(); | |
339 | |
340 | |
341 (function testCallSiteCaching() { | |
342 var callSites = []; | |
343 function tag(cs) { callSites.push(cs); } | |
344 var a = 1; | |
345 var b = 2; | |
346 | |
347 tag`head${a}tail`; | |
348 tag`head${b}tail`; | |
349 | |
350 assertEquals(2, callSites.length); | |
351 assertSame(callSites[0], callSites[1]); | |
352 | |
353 eval("tag`head${a}tail`"); | |
354 assertEquals(3, callSites.length); | |
355 assertSame(callSites[1], callSites[2]); | |
356 | |
357 eval("tag`head${b}tail`"); | |
358 assertEquals(4, callSites.length); | |
359 assertSame(callSites[2], callSites[3]); | |
360 | |
361 (new Function("tag", "a", "b", "return tag`head${a}tail`;"))(tag, 1, 2); | |
362 assertEquals(5, callSites.length); | |
363 assertSame(callSites[3], callSites[4]); | |
364 | |
365 (new Function("tag", "a", "b", "return tag`head${b}tail`;"))(tag, 1, 2); | |
366 assertEquals(6, callSites.length); | |
367 assertSame(callSites[4], callSites[5]); | |
368 | |
369 callSites = []; | |
370 | |
371 tag`foo${a}bar`; | |
372 tag`foo\${.}bar`; | |
373 assertEquals(2, callSites.length); | |
374 assertEquals(2, callSites[0].length); | |
375 assertEquals(1, callSites[1].length); | |
376 | |
377 callSites = []; | |
378 | |
379 eval("tag`\\\r\n\\\n\\\r`"); | |
380 eval("tag`\\\r\n\\\n\\\r`"); | |
381 assertEquals(2, callSites.length); | |
382 assertSame(callSites[0], callSites[1]); | |
383 assertEquals("", callSites[0][0]); | |
384 assertEquals("\\\n\\\n\\\n", callSites[0].raw[0]); | |
385 | |
386 callSites = []; | |
387 | |
388 tag`\uc548\ub155`; | |
389 tag`\uc548\ub155`; | |
390 assertEquals(2, callSites.length); | |
391 assertSame(callSites[0], callSites[1]); | |
392 assertEquals("안녕", callSites[0][0]); | |
393 assertEquals("\\uc548\\ub155", callSites[0].raw[0]); | |
394 | |
395 callSites = []; | |
396 | |
397 tag`\uc548\ub155`; | |
398 tag`안녕`; | |
399 assertEquals(2, callSites.length); | |
400 assertTrue(callSites[0] !== callSites[1]); | |
401 assertEquals("안녕", callSites[0][0]); | |
402 assertEquals("\\uc548\\ub155", callSites[0].raw[0]); | |
403 assertEquals("안녕", callSites[1][0]); | |
404 assertEquals("안녕", callSites[1].raw[0]); | |
405 | |
406 // Extra-thorough UTF8 decoding test. | |
407 callSites = []; | |
408 | |
409 tag`Iñtërnâtiônàlizætiøn\u2603\uD83D\uDCA9`; | |
410 tag`Iñtërnâtiônàlizætiøn☃💩`; | |
411 | |
412 assertEquals(2, callSites.length); | |
413 assertTrue(callSites[0] !== callSites[1]); | |
414 assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[0][0]); | |
415 assertEquals( | |
416 "Iñtërnâtiônàlizætiøn\\u2603\\uD83D\\uDCA9", callSites[0].raw[0]); | |
417 assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[1][0]); | |
418 assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[1].raw[0]); | |
419 })(); | |
420 | |
421 | |
422 (function testExtendedArrayPrototype() { | |
423 Object.defineProperty(Array.prototype, 0, { | |
424 set: function() { | |
425 assertUnreachable(); | |
426 }, | |
427 configurable: true | |
428 }); | |
429 function tag(){} | |
430 tag`a${1}b`; | |
431 delete Array.prototype[0]; | |
432 })(); | |
433 | |
434 | |
435 (function testRawLineNormalization() { | |
436 function raw0(callSiteObj) { | |
437 return callSiteObj.raw[0]; | |
438 } | |
439 assertEquals(eval("raw0`\r`"), "\n"); | |
440 assertEquals(eval("raw0`\r\n`"), "\n"); | |
441 assertEquals(eval("raw0`\r\r\n`"), "\n\n"); | |
442 assertEquals(eval("raw0`\r\n\r\n`"), "\n\n"); | |
443 assertEquals(eval("raw0`\r\r\r\n`"), "\n\n\n"); | |
444 })(); | |
445 | |
446 | |
447 (function testHarmonyUnicode() { | |
448 function raw0(callSiteObj) { | |
449 return callSiteObj.raw[0]; | |
450 } | |
451 assertEquals(raw0`a\u{62}c`, "a\\u{62}c"); | |
452 assertEquals(raw0`a\u{000062}c`, "a\\u{000062}c"); | |
453 assertEquals(raw0`a\u{0}c`, "a\\u{0}c"); | |
454 | |
455 assertEquals(`a\u{62}c`, "abc"); | |
456 assertEquals(`a\u{000062}c`, "abc"); | |
457 })(); | |
458 | |
459 | |
460 (function testLiteralAfterRightBrace() { | |
461 // Regression test for https://code.google.com/p/v8/issues/detail?id=3734 | |
462 function f() {} | |
463 `abc`; | |
464 | |
465 function g() {}`def`; | |
466 | |
467 { | |
468 // block | |
469 } | |
470 `ghi`; | |
471 | |
472 { | |
473 // block | |
474 }`jkl`; | |
475 })(); | |
476 | |
477 | |
478 (function testLegacyOctal() { | |
479 assertEquals('\u0000', `\0`); | |
480 assertEquals('\u0000a', `\0a`); | |
481 for (var i = 0; i < 8; i++) { | |
482 var code = "`\\0" + i + "`"; | |
483 assertThrows(code, SyntaxError); | |
484 code = "(function(){})" + code; | |
485 assertThrows(code, SyntaxError); | |
486 } | |
487 | |
488 assertEquals('\\0', String.raw`\0`); | |
489 })(); | |
490 | |
491 | |
492 (function testSyntaxErrorsNonEscapeCharacter() { | |
493 assertThrows("`\\x`", SyntaxError); | |
494 assertThrows("`\\u`", SyntaxError); | |
495 for (var i = 1; i < 8; i++) { | |
496 var code = "`\\" + i + "`"; | |
497 assertThrows(code, SyntaxError); | |
498 code = "(function(){})" + code; | |
499 assertThrows(code, SyntaxError); | |
500 } | |
501 })(); | |
502 | |
503 | |
504 (function testValidNumericEscapes() { | |
505 assertEquals("8", `\8`); | |
506 assertEquals("9", `\9`); | |
507 assertEquals("\u00008", `\08`); | |
508 assertEquals("\u00009", `\09`); | |
509 })(); | |
510 | |
511 | |
512 (function testLegacyOctalEscapesInExpressions() { | |
513 // Allowed in sloppy expression | |
514 assertEquals("\x07", `${"\07"}`); | |
515 | |
516 // Disallowed in template tail | |
517 assertThrows("`${\"\\07\"}\\07`", SyntaxError); | |
518 | |
519 // Disallowed in strict expression | |
520 assertThrows("`${(function() { \"use strict\"; return \"\\07\"; })()}`", | |
521 SyntaxError); | |
522 })(); | |
523 | |
524 | |
525 var global = this; | |
526 (function testCallNew() { | |
527 "use strict"; | |
528 var called = false; | |
529 var calledWith; | |
530 global.log = function(x) { called = true; calledWith = x; } | |
531 | |
532 assertInstanceof(new Function`log("test")`, Object); | |
533 assertTrue(called); | |
534 assertSame("test", calledWith); | |
535 delete global.log; | |
536 })(); | |
537 | |
538 | |
539 (function testCallNew2() { | |
540 "use strict"; | |
541 var log = []; | |
542 function tag(x) { | |
543 log.push(x); | |
544 if (!(this instanceof tag)) { | |
545 return tag; | |
546 } | |
547 this.x = x === void 0 ? null : x; | |
548 return this; | |
549 } | |
550 // No arguments passed to constructor | |
551 var instance = new tag`x``y``z`; | |
552 assertInstanceof(instance, tag); | |
553 assertSame(tag.prototype, Object.getPrototypeOf(instance)); | |
554 assertEquals({ x: null }, instance); | |
555 assertEquals([["x"], ["y"], ["z"], undefined], log); | |
556 | |
557 // Arguments passed to constructor | |
558 log.length = 0; | |
559 instance = new tag`x2` `y2` `z2` (`test`); | |
560 assertInstanceof(instance, tag); | |
561 assertSame(tag.prototype, Object.getPrototypeOf(instance)); | |
562 assertEquals({ x: "test" }, instance); | |
563 assertEquals([["x2"], ["y2"], ["z2"], "test"], log); | |
564 })(); | |
565 | |
566 | |
567 (function testCallResultOfTagFn() { | |
568 "use strict"; | |
569 var i = 0; | |
570 var raw = []; | |
571 function tag(cs) { | |
572 var args = Array.prototype.slice.call(arguments); | |
573 var text = String.raw.apply(null, args); | |
574 if (i++ < 2) { | |
575 raw.push("tag;" + text); | |
576 return tag; | |
577 } | |
578 | |
579 raw.push("raw;" + text); | |
580 return text; | |
581 } | |
582 assertEquals("test3", tag`test1``test2``test3`); | |
583 assertEquals([ | |
584 "tag;test1", | |
585 "tag;test2", | |
586 "raw;test3" | |
587 ], raw); | |
588 })(); | |
OLD | NEW |