EngineTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. /*
  3. * This file is part of Mustache.php.
  4. *
  5. * (c) 2012 Justin Hileman
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. /**
  11. * @group unit
  12. */
  13. class Mustache_Test_EngineTest extends PHPUnit_Framework_TestCase
  14. {
  15. private static $tempDir;
  16. public static function setUpBeforeClass()
  17. {
  18. self::$tempDir = sys_get_temp_dir() . '/mustache_test';
  19. if (file_exists(self::$tempDir)) {
  20. self::rmdir(self::$tempDir);
  21. }
  22. }
  23. public function testConstructor()
  24. {
  25. $logger = new Mustache_Logger_StreamLogger(tmpfile());
  26. $loader = new Mustache_Loader_StringLoader;
  27. $partialsLoader = new Mustache_Loader_ArrayLoader;
  28. $mustache = new Mustache_Engine(array(
  29. 'template_class_prefix' => '__whot__',
  30. 'cache' => self::$tempDir,
  31. 'cache_file_mode' => 777,
  32. 'logger' => $logger,
  33. 'loader' => $loader,
  34. 'partials_loader' => $partialsLoader,
  35. 'partials' => array(
  36. 'foo' => '{{ foo }}',
  37. ),
  38. 'helpers' => array(
  39. 'foo' => array($this, 'getFoo'),
  40. 'bar' => 'BAR',
  41. ),
  42. 'escape' => 'strtoupper',
  43. 'charset' => 'ISO-8859-1',
  44. ));
  45. $this->assertSame($logger, $mustache->getLogger());
  46. $this->assertSame($loader, $mustache->getLoader());
  47. $this->assertSame($partialsLoader, $mustache->getPartialsLoader());
  48. $this->assertEquals('{{ foo }}', $partialsLoader->load('foo'));
  49. $this->assertContains('__whot__', $mustache->getTemplateClassName('{{ foo }}'));
  50. $this->assertEquals('strtoupper', $mustache->getEscape());
  51. $this->assertEquals('ISO-8859-1', $mustache->getCharset());
  52. $this->assertTrue($mustache->hasHelper('foo'));
  53. $this->assertTrue($mustache->hasHelper('bar'));
  54. $this->assertFalse($mustache->hasHelper('baz'));
  55. $this->assertInstanceOf('Mustache_Cache_FilesystemCache', $mustache->getCache());
  56. }
  57. public static function getFoo()
  58. {
  59. return 'foo';
  60. }
  61. public function testRender()
  62. {
  63. $source = '{{ foo }}';
  64. $data = array('bar' => 'baz');
  65. $output = 'TEH OUTPUT';
  66. $template = $this->getMockBuilder('Mustache_Template')
  67. ->disableOriginalConstructor()
  68. ->getMock();
  69. $mustache = new MustacheStub;
  70. $mustache->template = $template;
  71. $template->expects($this->once())
  72. ->method('render')
  73. ->with($data)
  74. ->will($this->returnValue($output));
  75. $this->assertEquals($output, $mustache->render($source, $data));
  76. $this->assertEquals($source, $mustache->source);
  77. }
  78. public function testSettingServices()
  79. {
  80. $logger = new Mustache_Logger_StreamLogger(tmpfile());
  81. $loader = new Mustache_Loader_StringLoader;
  82. $tokenizer = new Mustache_Tokenizer;
  83. $parser = new Mustache_Parser;
  84. $compiler = new Mustache_Compiler;
  85. $mustache = new Mustache_Engine;
  86. $cache = new Mustache_Cache_FilesystemCache(self::$tempDir);
  87. $this->assertNotSame($logger, $mustache->getLogger());
  88. $mustache->setLogger($logger);
  89. $this->assertSame($logger, $mustache->getLogger());
  90. $this->assertNotSame($loader, $mustache->getLoader());
  91. $mustache->setLoader($loader);
  92. $this->assertSame($loader, $mustache->getLoader());
  93. $this->assertNotSame($loader, $mustache->getPartialsLoader());
  94. $mustache->setPartialsLoader($loader);
  95. $this->assertSame($loader, $mustache->getPartialsLoader());
  96. $this->assertNotSame($tokenizer, $mustache->getTokenizer());
  97. $mustache->setTokenizer($tokenizer);
  98. $this->assertSame($tokenizer, $mustache->getTokenizer());
  99. $this->assertNotSame($parser, $mustache->getParser());
  100. $mustache->setParser($parser);
  101. $this->assertSame($parser, $mustache->getParser());
  102. $this->assertNotSame($compiler, $mustache->getCompiler());
  103. $mustache->setCompiler($compiler);
  104. $this->assertSame($compiler, $mustache->getCompiler());
  105. $this->assertNotSame($cache, $mustache->getCache());
  106. $mustache->setCache($cache);
  107. $this->assertSame($cache, $mustache->getCache());
  108. }
  109. /**
  110. * @group functional
  111. */
  112. public function testCache()
  113. {
  114. $mustache = new Mustache_Engine(array(
  115. 'template_class_prefix' => '__whot__',
  116. 'cache' => self::$tempDir,
  117. ));
  118. $source = '{{ foo }}';
  119. $template = $mustache->loadTemplate($source);
  120. $className = $mustache->getTemplateClassName($source);
  121. $this->assertInstanceOf($className, $template);
  122. }
  123. /**
  124. * @expectedException Mustache_Exception_InvalidArgumentException
  125. * @dataProvider getBadEscapers
  126. */
  127. public function testNonCallableEscapeThrowsException($escape)
  128. {
  129. new Mustache_Engine(array('escape' => $escape));
  130. }
  131. public function getBadEscapers()
  132. {
  133. return array(
  134. array('nothing'),
  135. array('foo', 'bar'),
  136. );
  137. }
  138. /**
  139. * @expectedException Mustache_Exception_RuntimeException
  140. */
  141. public function testImmutablePartialsLoadersThrowException()
  142. {
  143. $mustache = new Mustache_Engine(array(
  144. 'partials_loader' => new Mustache_Loader_StringLoader,
  145. ));
  146. $mustache->setPartials(array('foo' => '{{ foo }}'));
  147. }
  148. public function testMissingPartialsTreatedAsEmptyString()
  149. {
  150. $mustache = new Mustache_Engine(array(
  151. 'partials_loader' => new Mustache_Loader_ArrayLoader(array(
  152. 'foo' => 'FOO',
  153. 'baz' => 'BAZ',
  154. ))
  155. ));
  156. $this->assertEquals('FOOBAZ', $mustache->render('{{>foo}}{{>bar}}{{>baz}}', array()));
  157. }
  158. public function testHelpers()
  159. {
  160. $foo = array($this, 'getFoo');
  161. $bar = 'BAR';
  162. $mustache = new Mustache_Engine(array('helpers' => array(
  163. 'foo' => $foo,
  164. 'bar' => $bar,
  165. )));
  166. $helpers = $mustache->getHelpers();
  167. $this->assertTrue($mustache->hasHelper('foo'));
  168. $this->assertTrue($mustache->hasHelper('bar'));
  169. $this->assertTrue($helpers->has('foo'));
  170. $this->assertTrue($helpers->has('bar'));
  171. $this->assertSame($foo, $mustache->getHelper('foo'));
  172. $this->assertSame($bar, $mustache->getHelper('bar'));
  173. $mustache->removeHelper('bar');
  174. $this->assertFalse($mustache->hasHelper('bar'));
  175. $mustache->addHelper('bar', $bar);
  176. $this->assertSame($bar, $mustache->getHelper('bar'));
  177. $baz = array($this, 'wrapWithUnderscores');
  178. $this->assertFalse($mustache->hasHelper('baz'));
  179. $this->assertFalse($helpers->has('baz'));
  180. $mustache->addHelper('baz', $baz);
  181. $this->assertTrue($mustache->hasHelper('baz'));
  182. $this->assertTrue($helpers->has('baz'));
  183. // ... and a functional test
  184. $tpl = $mustache->loadTemplate('{{foo}} - {{bar}} - {{#baz}}qux{{/baz}}');
  185. $this->assertEquals('foo - BAR - __qux__', $tpl->render());
  186. $this->assertEquals('foo - BAR - __qux__', $tpl->render(array('qux' => "won't mess things up")));
  187. }
  188. public static function wrapWithUnderscores($text)
  189. {
  190. return '__'.$text.'__';
  191. }
  192. /**
  193. * @expectedException Mustache_Exception_InvalidArgumentException
  194. */
  195. public function testSetHelpersThrowsExceptions()
  196. {
  197. $mustache = new Mustache_Engine;
  198. $mustache->setHelpers('monkeymonkeymonkey');
  199. }
  200. /**
  201. * @expectedException Mustache_Exception_InvalidArgumentException
  202. */
  203. public function testSetLoggerThrowsExceptions()
  204. {
  205. $mustache = new Mustache_Engine;
  206. $mustache->setLogger(new StdClass);
  207. }
  208. public function testLoadPartialCascading()
  209. {
  210. $loader = new Mustache_Loader_ArrayLoader(array(
  211. 'foo' => 'FOO',
  212. ));
  213. $mustache = new Mustache_Engine(array('loader' => $loader));
  214. $tpl = $mustache->loadTemplate('foo');
  215. $this->assertSame($tpl, $mustache->loadPartial('foo'));
  216. $mustache->setPartials(array(
  217. 'foo' => 'f00',
  218. ));
  219. // setting partials overrides the default template loading fallback.
  220. $this->assertNotSame($tpl, $mustache->loadPartial('foo'));
  221. // but it didn't overwrite the original template loader templates.
  222. $this->assertSame($tpl, $mustache->loadTemplate('foo'));
  223. }
  224. public function testPartialLoadFailLogging()
  225. {
  226. $name = tempnam(sys_get_temp_dir(), 'mustache-test');
  227. $mustache = new Mustache_Engine(array(
  228. 'logger' => new Mustache_Logger_StreamLogger($name, Mustache_Logger::WARNING),
  229. 'partials' => array(
  230. 'foo' => 'FOO',
  231. 'bar' => 'BAR',
  232. ),
  233. ));
  234. $result = $mustache->render('{{> foo }}{{> bar }}{{> baz }}', array());
  235. $this->assertEquals('FOOBAR', $result);
  236. $this->assertContains('WARNING: Partial not found: "baz"', file_get_contents($name));
  237. }
  238. public function testCacheWarningLogging()
  239. {
  240. $name = tempnam(sys_get_temp_dir(), 'mustache-test');
  241. $mustache = new Mustache_Engine(array(
  242. 'logger' => new Mustache_Logger_StreamLogger($name, Mustache_Logger::WARNING)
  243. ));
  244. $result = $mustache->render('{{ foo }}', array('foo' => 'FOO'));
  245. $this->assertEquals('FOO', $result);
  246. $this->assertContains('WARNING: Template cache disabled, evaluating', file_get_contents($name));
  247. }
  248. public function testLoggingIsNotTooAnnoying()
  249. {
  250. $name = tempnam(sys_get_temp_dir(), 'mustache-test');
  251. $mustache = new Mustache_Engine(array(
  252. 'logger' => new Mustache_Logger_StreamLogger($name)
  253. ));
  254. $result = $mustache->render('{{ foo }}{{> bar }}', array('foo' => 'FOO'));
  255. $this->assertEquals('FOO', $result);
  256. $this->assertEmpty(file_get_contents($name));
  257. }
  258. public function testVerboseLoggingIsVerbose()
  259. {
  260. $name = tempnam(sys_get_temp_dir(), 'mustache-test');
  261. $mustache = new Mustache_Engine(array(
  262. 'logger' => new Mustache_Logger_StreamLogger($name, Mustache_Logger::DEBUG)
  263. ));
  264. $result = $mustache->render('{{ foo }}{{> bar }}', array('foo' => 'FOO'));
  265. $this->assertEquals('FOO', $result);
  266. $log = file_get_contents($name);
  267. $this->assertContains("DEBUG: Instantiating template: ", $log);
  268. $this->assertContains("WARNING: Partial not found: \"bar\"", $log);
  269. }
  270. private static function rmdir($path)
  271. {
  272. $path = rtrim($path, '/').'/';
  273. $handle = opendir($path);
  274. while (($file = readdir($handle)) !== false) {
  275. if ($file == '.' || $file == '..') {
  276. continue;
  277. }
  278. $fullpath = $path.$file;
  279. if (is_dir($fullpath)) {
  280. self::rmdir($fullpath);
  281. } else {
  282. unlink($fullpath);
  283. }
  284. }
  285. closedir($handle);
  286. rmdir($path);
  287. }
  288. }
  289. class MustacheStub extends Mustache_Engine
  290. {
  291. public $source;
  292. public $template;
  293. public function loadTemplate($source)
  294. {
  295. $this->source = $source;
  296. return $this->template;
  297. }
  298. }