Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

661 Zeilen
14KB

  1. // the compiler tests are the exact same as the interpreter tests
  2. // so instead of writing all the tests twice, override the to_html
  3. // method
  4. module('Compiler', {
  5. setup: function() {
  6. this._oldToHtml = Mustache.to_html;
  7. Mustache.to_html = function(template, view, partials) {
  8. var compiler = Mustache.compile(template, partials);
  9. return compiler(view);
  10. }
  11. },
  12. teardown: function() {
  13. Mustache.to_html = this._oldToHtml;
  14. }
  15. });
  16. test("Argument validation", function() {
  17. expect(4);
  18. equals(Mustache.to_html(undefined), '', 'No parameters');
  19. equals(Mustache.to_html('{{hi}}'), '', ' No View or Partials');
  20. equals(Mustache.to_html('{{hi}}', {hi:'Hi.'}), 'Hi.', 'No Partials');
  21. equals(Mustache.to_html('{{>hi}}', undefined, {hi:'{{p}}'}), '', 'Partial but no view');
  22. });
  23. test("Parser", function() {
  24. expect(4);
  25. // matches whitespace_partial.html
  26. equals(
  27. Mustache.to_html(
  28. '<h1>{{ greeting }}</h1>\n{{> partial }}\n<h3>{{ farewell }}</h3>',
  29. {
  30. greeting: function() {
  31. return "Welcome";
  32. },
  33. farewell: function() {
  34. return "Fair enough, right?";
  35. },
  36. partial: {
  37. name: "Chris",
  38. value: 10000,
  39. taxed_value: function() {
  40. return this.value - (this.value * 0.4);
  41. },
  42. in_ca: true
  43. }
  44. },
  45. {partial:'Hello {{ name}}\nYou have just won ${{value }}!\n{{# in_ca }}\nWell, ${{ taxed_value }}, after taxes.\n{{/ in_ca }}\n'}
  46. ),
  47. '<h1>Welcome</h1>\nHello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n\n\n<h3>Fair enough, right?</h3>',
  48. 'Whitespace in Tag names'
  49. );
  50. equals(
  51. Mustache.to_html(
  52. '{{tag1}}\n\n\n{{tag2}}\n',
  53. { tag1: 'Hello', tag2: 'World' },
  54. {}
  55. ),
  56. 'Hello\n\n\nWorld\n',
  57. 'Preservation of white space'
  58. );
  59. try {
  60. Mustache.to_html(
  61. '{{=tag1}}',
  62. { tag1: 'Hello' },
  63. {}
  64. );
  65. ok(false);
  66. } catch (e) {
  67. equals(e.message, 'Unexpected end of document.');
  68. }
  69. var partials = { 'partial' : '{{key}}' };
  70. Mustache.compile('{{>partial}}', partials );
  71. equals(partials['partial'], '{{key}}', 'Partials compiler must be non-destructive');
  72. });
  73. test("Basic Variables", function() {
  74. expect(3);
  75. // matches escaped.html
  76. equals(
  77. Mustache.to_html(
  78. '<h1>{{title}}</h1>\nBut not {{entities}}.\n',
  79. {
  80. title: function() {
  81. return "Bear > Shark";
  82. },
  83. entities: "&quot;"
  84. },
  85. {}
  86. ),
  87. '<h1>Bear &gt; Shark</h1>\nBut not &amp;quot;.\n',
  88. 'HTML Escaping'
  89. );
  90. // matches null_string.html
  91. equals(
  92. Mustache.to_html(
  93. 'Hello {{name}}\nglytch {{glytch}}\nbinary {{binary}}\nvalue {{value}}\nnumeric {{numeric}}',
  94. {
  95. name: "Elise",
  96. glytch: true,
  97. binary: false,
  98. value: null,
  99. numeric: function() {
  100. return NaN;
  101. }
  102. },
  103. {}
  104. ),
  105. 'Hello Elise\nglytch true\nbinary false\nvalue \nnumeric NaN',
  106. 'Different variable types'
  107. );
  108. // matches two_in_a_row.html
  109. equals(
  110. Mustache.to_html(
  111. '{{greeting}}, {{name}}!',
  112. {
  113. name: "Joe",
  114. greeting: "Welcome"
  115. },
  116. {}
  117. ),
  118. 'Welcome, Joe!'
  119. );
  120. });
  121. test("'{' or '&' (Unescaped Variable)", function() {
  122. expect(2);
  123. // matches unescaped.html
  124. equals(
  125. Mustache.to_html(
  126. '<h1>{{{title}}}</h1>',
  127. {
  128. title: function() {
  129. return "Bear > Shark";
  130. }
  131. },
  132. {}
  133. ),
  134. '<h1>Bear > Shark</h1>',
  135. '{ character'
  136. );
  137. equals(
  138. Mustache.to_html(
  139. '<h1>{{&title}}</h1>',
  140. {
  141. title: function() {
  142. return "Bear > Shark";
  143. }
  144. },
  145. {}
  146. ),
  147. '<h1>Bear > Shark</h1>',
  148. '& character'
  149. );
  150. });
  151. test("'#' (Sections)", function() {
  152. expect(7);
  153. // matches array_of_partials_implicit_partial.html
  154. equals(
  155. Mustache.to_html(
  156. 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}',
  157. { numbers: ['1', '2', '3', '4'] },
  158. { partial: '{{.}}' }
  159. ),
  160. 'Here is some stuff!\n\n1\n\n2\n\n3\n\n4\n',
  161. 'Array of Partials (Implicit)'
  162. );
  163. // matches array_of_partials_partial.html
  164. equals(
  165. Mustache.to_html(
  166. 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}',
  167. { numbers: [{i: '1'}, {i: '2'}, {i: '3'}, {i: '4'}] },
  168. { partial: '{{i}}' }
  169. ),
  170. 'Here is some stuff!\n\n1\n\n2\n\n3\n\n4\n',
  171. 'Array of Partials (Explicit)'
  172. );
  173. // matches array_of_strings.html
  174. equals(
  175. Mustache.to_html(
  176. '{{#array_of_strings}}{{.}} {{/array_of_strings}}',
  177. {array_of_strings: ['hello', 'world']},
  178. {}
  179. ),
  180. 'hello world ',
  181. 'Array of Strings'
  182. );
  183. // mathces higher_order_sections.html
  184. equals(
  185. Mustache.to_html(
  186. '{{#bolder}}Hi {{name}}.{{/bolder}}\n',
  187. {
  188. "name": "Tater",
  189. "helper": "To tinker?",
  190. "bolder": function() {
  191. return function(text, render) {
  192. return "<b>" + render(text) + '</b> ' + this.helper;
  193. }
  194. }
  195. },
  196. {}
  197. ),
  198. '<b>Hi Tater.</b> To tinker?\n'
  199. );
  200. // matches recursion_with_same_names.html
  201. equals(
  202. Mustache.to_html(
  203. '{{ name }}\n{{ description }}\n\n{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n',
  204. {
  205. name: 'name',
  206. description: 'desc',
  207. terms: [
  208. {name: 't1', index: 0},
  209. {name: 't2', index: 1}
  210. ]
  211. },
  212. {}
  213. ),
  214. 'name\ndesc\n\n\n t1\n 0\n\n t2\n 1\n\n'
  215. );
  216. // matches reuse_of_enumerables.html
  217. equals(
  218. Mustache.to_html(
  219. '{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n',
  220. {
  221. terms: [
  222. {name: 't1', index: 0},
  223. {name: 't2', index: 1}
  224. ]
  225. },
  226. {}
  227. ),
  228. '\n t1\n 0\n\n t2\n 1\n\n\n t1\n 0\n\n t2\n 1\n\n',
  229. 'Lazy match of Section and Inverted Section'
  230. );
  231. // matches section_as_context.html
  232. equals(
  233. Mustache.to_html(
  234. '{{#a_object}}\n <h1>{{title}}</h1>\n <p>{{description}}</p>\n <ul>\n {{#a_list}}\n <li>{{label}}</li>\n {{/a_list}}\n </ul>\n{{/a_object}}\n',
  235. {
  236. a_object: {
  237. title: 'this is an object',
  238. description: 'one of its attributes is a list',
  239. a_list: [{label: 'listitem1'}, {label: 'listitem2'}]
  240. }
  241. },
  242. {}
  243. ),
  244. '\n <h1>this is an object</h1>\n <p>one of its attributes is a list</p>\n <ul>\n \n <li>listitem1</li>\n \n <li>listitem2</li>\n \n </ul>\n\n',
  245. 'Lazy match of Section and Inverted Section'
  246. );
  247. });
  248. test("'^' (Inverted Section)", function() {
  249. expect(1);
  250. // matches inverted_section.html
  251. equals(
  252. Mustache.to_html(
  253. '{{#repo}}<b>{{name}}</b>{{/repo}}\n{{^repo}}No repos :({{/repo}}\n',
  254. {
  255. "repo": []
  256. },
  257. {}
  258. ),
  259. '\nNo repos :(\n'
  260. );
  261. });
  262. test("'>' (Partials)", function() {
  263. expect(5);
  264. // matches view_partial.html
  265. equals(
  266. Mustache.to_html(
  267. '<h1>{{greeting}}</h1>\n{{>partial}}\n<h3>{{farewell}}</h3>',
  268. {
  269. greeting: function() {
  270. return "Welcome";
  271. },
  272. farewell: function() {
  273. return "Fair enough, right?";
  274. },
  275. partial: {
  276. name: "Chris",
  277. value: 10000,
  278. taxed_value: function() {
  279. return this.value - (this.value * 0.4);
  280. },
  281. in_ca: true
  282. }
  283. },
  284. {partial: 'Hello {{name}}\nYou have just won ${{value}}!\n{{#in_ca}}\nWell, ${{ taxed_value }}, after taxes.\n{{/in_ca}}\n'}
  285. ),
  286. '<h1>Welcome</h1>\nHello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n\n\n<h3>Fair enough, right?</h3>'
  287. );
  288. // matches array_partial.html
  289. equals(
  290. Mustache.to_html(
  291. '{{>partial}}',
  292. {
  293. partial: {
  294. array: ['1', '2', '3', '4']
  295. }
  296. },
  297. { partial: 'Here\'s a non-sense array of values\n{{#array}}\n {{.}}\n{{/array}}' }
  298. ),
  299. 'Here\'s a non-sense array of values\n\n 1\n\n 2\n\n 3\n\n 4\n'
  300. );
  301. // matches template_partial.html
  302. equals(
  303. Mustache.to_html(
  304. '<h1>{{title}}</h1>\n{{>partial}}',
  305. {
  306. title: function() {
  307. return "Welcome";
  308. },
  309. partial: {
  310. again: "Goodbye"
  311. }
  312. },
  313. {partial:'Again, {{again}}!'}
  314. ),
  315. '<h1>Welcome</h1>\nAgain, Goodbye!'
  316. );
  317. // matches partial_recursion.html
  318. equals(
  319. Mustache.to_html(
  320. '{{name}}\n{{#kids}}\n{{>partial}}\n{{/kids}}',
  321. {
  322. name: '1',
  323. kids: [
  324. {
  325. name: '1.1',
  326. children: [
  327. {name: '1.1.1'}
  328. ]
  329. }
  330. ]
  331. },
  332. {partial:'{{name}}\n{{#children}}\n{{>partial}}\n{{/children}}'}
  333. ),
  334. '1\n\n1.1\n\n1.1.1\n\n\n'
  335. );
  336. try {
  337. Mustache.to_html(
  338. '{{>partial}}',
  339. {},
  340. {partal: ''}
  341. );
  342. ok(false);
  343. } catch(e) {
  344. equals(e.message, "Unknown partial 'partial'");
  345. }
  346. });
  347. test("'=' (Set Delimiter)", function() {
  348. expect(1);
  349. // matches delimiter.html
  350. equals(
  351. Mustache.to_html(
  352. '{{=<% %>=}}*\n<% first %>\n* <% second %>\n<%=| |=%>\n* | third |\n|={{ }}=|\n* {{ fourth }}',
  353. {
  354. first: "It worked the first time.",
  355. second: "And it worked the second time.",
  356. third: "Then, surprisingly, it worked the third time.",
  357. fourth: "Fourth time also fine!."
  358. },
  359. {}
  360. ),
  361. '*\nIt worked the first time.\n* And it worked the second time.\n\n* Then, surprisingly, it worked the third time.\n\n* Fourth time also fine!.',
  362. 'Simple Set Delimiter'
  363. );
  364. });
  365. test("'!' (Comments)", function() {
  366. expect(4);
  367. equals(
  368. Mustache.to_html('{{! this is a single line comment !}}'),
  369. '',
  370. 'Single Line Comments');
  371. equals(
  372. Mustache.to_html('{{!this is a multiline comment\ni said this is a multiline comment!}}'),
  373. '',
  374. 'Multiline Comments');
  375. equals(
  376. Mustache.to_html('{{!this {{is}} {{#a}} {{/multiline}} comment\ni {{^said}} ! hello !! bye!}}'),
  377. '',
  378. 'Correct tokenization');
  379. // matches comments.html
  380. equals(
  381. Mustache.to_html(
  382. '<h1>{{title}}{{! just something interesting... or not... !}}</h1>\n',
  383. {
  384. title: function() {
  385. return "A Comedy of Errors";
  386. }
  387. },
  388. {}
  389. ),
  390. '<h1>A Comedy of Errors</h1>\n'
  391. );
  392. });
  393. test("'%' (Pragmas)", function() {
  394. expect(3);
  395. // matches array_of_strings_options.html
  396. equals(
  397. Mustache.to_html(
  398. '{{%IMPLICIT-ITERATOR iterator=rob}}\n{{#array_of_strings_options}}{{rob}} {{/array_of_strings_options}}',
  399. {array_of_strings_options: ['hello', 'world']},
  400. {}
  401. ),
  402. '\nhello world ',
  403. 'IMPLICIT-ITERATOR pragma'
  404. );
  405. // matches unknown_pragma.txt
  406. try {
  407. equals(
  408. Mustache.to_html(
  409. '{{%I-HAVE-THE-GREATEST-MUSTACHE}}\n',
  410. {},
  411. {}
  412. ),
  413. 'hello world ',
  414. 'IMPLICIT-ITERATOR pragma'
  415. );
  416. ok(false);
  417. } catch (e) {
  418. equals(e.message, 'This implementation of mustache doesn\'t understand the \'I-HAVE-THE-GREATEST-MUSTACHE\' pragma');
  419. }
  420. equals(
  421. Mustache.to_html(
  422. '{{%IMPLICIT-ITERATOR}}{{#dataSet}}{{.}}:{{/dataSet}}',
  423. { dataSet: [ 'Object 1', 'Object 2', 'Object 3' ] },
  424. {}
  425. ),
  426. "Object 1:Object 2:Object 3:"
  427. );
  428. });
  429. test("Empty", function() {
  430. expect(2);
  431. // matches empty_template.html
  432. equals(
  433. Mustache.to_html(
  434. '<html><head></head><body><h1>Test</h1></body></html>',
  435. {},
  436. {}
  437. ),
  438. '<html><head></head><body><h1>Test</h1></body></html>',
  439. 'Empty Template'
  440. );
  441. // matches empty_partial.html
  442. equals(
  443. Mustache.to_html(
  444. 'hey {{foo}}\n{{>partial}}\n',
  445. {
  446. foo: 1
  447. },
  448. {partial: 'yo'}
  449. ),
  450. 'hey 1\nyo\n',
  451. 'Empty Partial'
  452. );
  453. });
  454. test("Demo", function() {
  455. expect(2);
  456. // matches simple.html
  457. equals(
  458. Mustache.to_html(
  459. 'Hello {{name}}\nYou have just won ${{value}}!\n{{#in_ca}}\nWell, ${{ taxed_value }}, after taxes.\n{{/in_ca}}',
  460. {
  461. name: "Chris",
  462. value: 10000,
  463. taxed_value: function() {
  464. return this.value - (this.value * 0.4);
  465. },
  466. in_ca: true
  467. },
  468. {}
  469. ),
  470. 'Hello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n',
  471. 'A simple template'
  472. );
  473. // matches complex.html
  474. var template = [
  475. '<h1>{{header}}</h1>',
  476. '{{#list}}',
  477. ' <ul>',
  478. ' {{#item}}',
  479. ' {{#current}}',
  480. ' <li><strong>{{name}}</strong></li>',
  481. ' {{/current}}',
  482. ' {{#link}}',
  483. ' <li><a href="{{url}}">{{name}}</a></li>',
  484. ' {{/link}}',
  485. ' {{/item}}',
  486. ' </ul>',
  487. '{{/list}}',
  488. '{{#empty}}',
  489. ' <p>The list is empty.</p>',
  490. '{{/empty}}'
  491. ].join('\n');
  492. var view = {
  493. header: function() {
  494. return "Colors";
  495. },
  496. item: [
  497. {name: "red", current: true, url: "#Red"},
  498. {name: "green", current: false, url: "#Green"},
  499. {name: "blue", current: false, url: "#Blue"}
  500. ],
  501. link: function() {
  502. return this["current"] !== true;
  503. },
  504. list: function() {
  505. return this.item.length !== 0;
  506. },
  507. empty: function() {
  508. return this.item.length === 0;
  509. }
  510. };
  511. var expected_result = '<h1>Colors</h1>\n\n <ul>\n \n \n <li><strong>red</strong></li>\n \n \n <li><a href=\"#Red\">red</a></li>\n \n \n \n \n <li><a href=\"#Green\">green</a></li>\n \n \n \n \n <li><a href=\"#Blue\">blue</a></li>\n \n \n </ul>\n\n';
  512. equals(
  513. Mustache.to_html(
  514. template,
  515. view,
  516. {}
  517. ),
  518. expected_result,
  519. 'A complex template'
  520. );
  521. });
  522. test("Performance", function() {
  523. expect(1);
  524. var start, end;
  525. // This performance test is copied form skymustache
  526. // (https://github.com/schuyler1d/handlebars.js/blob/sky_test/test/perf.js)
  527. // set up the templates
  528. var template = "This is the story of guys who work on a project\n" +
  529. "called {{project}}. Their names were {{#people}}{{firstName}} and {{/people}}\n" +
  530. "they both enjoyed working on {{project}}.\n\n" +
  531. "{{#people}}\n" +
  532. "{{>personPet}}\n" +
  533. "{{/people}}";
  534. var partials = {
  535. personPet: "{{firstName}} {{lastName}} {{#pet}} owned a {{species}}. Its name was {{name}}.{{/pet}}{{^pet}}didn't own a pet.{{/pet}}"
  536. };
  537. var view = {
  538. project: "Handlebars",
  539. people: [
  540. { firstName: "Yehuda", lastName: "Katz" },
  541. { firstName: "Alan", lastName: "Johnson", pet: { species: "cat", name: "Luke" } }
  542. ]
  543. }
  544. start = new Date();
  545. for (var j=0;j<1000;++j) {
  546. this._oldToHtml(template, view, partials);
  547. }
  548. end = new Date();
  549. var interpreter_time = end.getTime() - start.getTime();
  550. start = new Date();
  551. var compiler = Mustache.compile(template, partials);
  552. for (var k=0;k<1000;++k) {
  553. compiler(view);
  554. }
  555. end = new Date();
  556. var compiler_time = end.getTime() - start.getTime();
  557. ok(compiler_time<interpreter_time, 'Compiler is faster (' + compiler_time + ' vs ' + interpreter_time + ').');
  558. });
  559. test("Regression Suite", function() {
  560. expect(3);
  561. // matches bug_11_eating_whitespace.html
  562. equals(
  563. Mustache.to_html(
  564. '{{tag}} foo',
  565. { tag: "yo" },
  566. {}
  567. ),
  568. 'yo foo',
  569. 'Issue 11'
  570. );
  571. // matches delimiters_partial.html
  572. equals(
  573. Mustache.to_html(
  574. '{{#enumerate}}\n{{>partial}}\n{{/enumerate}}',
  575. { enumerate: [ { text: 'A' }, { text: 'B' } ] },
  576. { partial: '{{=[[ ]]=}}\n{{text}}\n[[={{ }}=]]' }
  577. ),
  578. '\n\n{{text}}\n\n\n\n{{text}}\n\n',
  579. 'Issue 44'
  580. );
  581. // matches bug_46_set_delimiter.html
  582. equals(
  583. Mustache.to_html(
  584. '{{=[[ ]]=}}[[#IsMustacheAwesome]]mustache is awesome![[/IsMustacheAwesome]]',
  585. {IsMustacheAwesome: true},
  586. {}
  587. ),
  588. 'mustache is awesome!',
  589. 'Issue 46'
  590. );
  591. });