summaryrefslogtreecommitdiff
path: root/t/04-template-handling.t
blob: a75bc26e47efc952c43e19bee20c5a0997e1f243 (plain)
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. # Absolute directory name required to not trip up Template::Latex
  5. $ENV{TMPDIR} = "$ENV{PWD}/t/var";
  6. use Test::More 'no_plan';
  7. use Test::Trap qw(trap $trap);
  8. use Test::Exception;
  9. use Error qw(:try :warndie);
  10. use LedgerSMB::AM;
  11. use LedgerSMB::Form;
  12. use LedgerSMB::Sysconfig;
  13. use LedgerSMB::Locale;
  14. use LedgerSMB::Template;
  15. use LedgerSMB::Template::HTML;
  16. use LedgerSMB::Template::PDF;
  17. use LedgerSMB::Template::PS;
  18. use LedgerSMB::Template::TXT;
  19. $LedgerSMB::Sysconfig::tempdir = 't/var';
  20. my @r;
  21. my $temp;
  22. my $form;
  23. my $myconfig;
  24. my $template;
  25. my $FH;
  26. my $locale;
  27. $locale = LedgerSMB::Locale->get_handle('fr');
  28. ##############
  29. ## AM tests ##
  30. ##############
  31. # AM->check_template_name checks
  32. # check_template operates by calling $form->error if the checks fail
  33. $form = new Form;
  34. $myconfig = {'templates' => 'test'};
  35. for my $ext ('css', 'tex', 'txt', 'html', 'xml') {
  36. $form->{file} = "test/apples.${ext}";
  37. @r = trap{AM->check_template_name($myconfig, $form)};
  38. ok(!defined $trap->die,
  39. "AM, check_template_name: Template directory, ${ext}");
  40. }
  41. $form->{file} = 'css/apples.txt';
  42. @r = trap{AM->check_template_name($myconfig, $form)};
  43. ok(!defined $trap->die,
  44. 'AM, check_template_name: CSS directory, txt');
  45. $form->{file} = 'test2/apples.txt';
  46. @r = trap{AM->check_template_name($myconfig, $form)};
  47. is($trap->die, "Error: Not in a whitelisted directory: test2/apples.txt\n",
  48. 'AM, check_template_name: Invalid directory, non-css denial');
  49. $form->{file} = 'test/apples.exe';
  50. @r = trap{AM->check_template_name($myconfig, $form)};
  51. is($trap->die, "Error: Error: File is of type that is not allowed.\n",
  52. 'AM, check_template_name: Disallowed type denial');
  53. # adjusting backuppath to avoid triggering directory traversal detection
  54. $temp = ${LedgerSMB::Sysconfig::backuppath};
  55. ${LedgerSMB::Sysconfig::backuppath} = "foo";
  56. $form->{file} = "${LedgerSMB::Sysconfig::backuppath}/apples.txt";
  57. @r = trap{AM->check_template_name($myconfig, $form)};
  58. is($trap->die, "Error: Not allowed to access foo/ with this method\n",
  59. 'AM, check_template_name: Backup path denial');
  60. ${LedgerSMB::Sysconfig::backuppath} = $temp;
  61. $form->{file} = "css/../apples.txt";
  62. @r = trap{AM->check_template_name($myconfig, $form)};
  63. is($trap->die, "Error: Directory transversal not allowed.\n",
  64. 'AM, check_template_name: Directory transversal denial 1');
  65. $form->{file} = "/tmp/apples.txt";
  66. @r = trap{AM->check_template_name($myconfig, $form)};
  67. is($trap->die, "Error: Directory transversal not allowed.\n",
  68. 'AM, check_template_name: Directory transversal denial 2');
  69. $form->{file} = "test/apples.txt:evil";
  70. @r = trap{AM->check_template_name($myconfig, $form)};
  71. is($trap->die, "Error: Directory transversal not allowed.\n",
  72. 'AM, check_template_name: Directory transversal denial 3');
  73. $form->{file} = "c:\\evil.txt";
  74. @r = trap{AM->check_template_name($myconfig, $form)};
  75. is($trap->die, "Error: Directory transversal not allowed.\n",
  76. 'AM, check_template_name: Directory transversal denial 4');
  77. # AM->load_template checks
  78. # load_template takes its file name from form
  79. $form = new Form;
  80. $myconfig = {'templates' => 't/data'};
  81. $form->{file} = 't/data/04-not-there.txt';
  82. @r = trap{AM->load_template($myconfig, $form)};
  83. is($trap->die, "Error: t/data/04-not-there.txt : No such file or directory\n",
  84. 'AM, load_template: Die on non-existent file');
  85. $form->{file} = 't/data/04-template.html';
  86. AM->load_template($myconfig, $form);
  87. is($form->{body}, "I am a template.\nLook at me <?lsmb login ?>.\n",
  88. 'AM, load_template: Read existing file');
  89. # AM->save_template checks
  90. $form = new Form;
  91. $myconfig = {'templates' => 't/var/not here'};
  92. $form->{body} = "I am a template.\nLook at me.\n";
  93. $form->{file} = "$myconfig->{templates}/test.txt";
  94. @r = trap{AM->save_template($myconfig, $form)};
  95. is($trap->die,
  96. "Error: t/var/not here/test.txt : No such file or directory\n",
  97. 'AM, save_template: Die on unwritable file');
  98. $myconfig = {'templates' => 't/var'};
  99. $form->{body} = "I am a template.\nLook at me.";
  100. $form->{file} = "$myconfig->{templates}/04-template-save-test-$$.txt";
  101. ok(!-e $form->{file}, 'AM, save_template: Environment clean');
  102. AM->save_template($myconfig, $form);
  103. ok(-e $form->{file}, 'AM, save_template: File created');
  104. open($FH, '<', $form->{file});
  105. @r = <$FH>;
  106. close($FH);
  107. chomp(@r);
  108. is(join("\n", @r), $form->{body}, 'AM, save_template: Good save');
  109. is(unlink($form->{file}), 1, 'AM, save_template: removing testfile');
  110. ok(!-e $form->{file}, 'AM, save_template: testfile removed');
  111. ######################################
  112. ## LedgerSMB::Template::HTML checks ##
  113. ######################################
  114. is(LedgerSMB::Template::HTML::get_template('04-template'), '04-template.html',
  115. 'HTML, get_template: Returned correct template file name');
  116. is(LedgerSMB::Template::HTML::preprocess('04-template'), '04-template',
  117. 'HTML, preprocess: Returned simple string unchanged');
  118. is(LedgerSMB::Template::HTML::preprocess('14 > 12'), '14 &gt; 12',
  119. 'HTML, preprocess: Returned properly escaped string');
  120. is_deeply(LedgerSMB::Template::HTML::preprocess([0, 'apple', 'mango&durian']),
  121. [0, 'apple', 'mango&amp;durian'],
  122. 'HTML, preprocess: Returned properly escaped array ref contents');
  123. is_deeply(LedgerSMB::Template::HTML::preprocess({'fruit' => '&veggies',
  124. 'test' => 1}),
  125. {'fruit' => '&amp;veggies', 'test' => 1},
  126. 'HTML, preprocess: Returned properly escaped hash ref contents');
  127. is_deeply(LedgerSMB::Template::HTML::preprocess({'fruit' => '&veggies',
  128. 'test' => ['nest', 'bird', '0 < 15', 1]}),
  129. {'fruit' => '&amp;veggies', 'test' => ['nest', 'bird', '0 &lt; 15', 1]},
  130. 'HTML, preprocess: Returned properly escaped nested contents');
  131. is(LedgerSMB::Template::HTML::postprocess({outputfile => '04-template'}),
  132. '04-template.html', 'HTML, postprocess: Return output filename');
  133. ####################
  134. ## Template tests ##
  135. ####################
  136. # Template->new
  137. $myconfig = {'templates' => 't/data'};
  138. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => 'x/0')}
  139. qr/Invalid language/, 'Template, new: Invalid language caught 1';
  140. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '1\\2')}
  141. qr/Invalid language/, 'Template, new: Invalid language caught 2';
  142. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '1:2')}
  143. qr/Invalid language/, 'Template, new: Invalid language caught 3';
  144. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '..')}
  145. qr/Invalid language/, 'Template, new: Invalid language caught 4';
  146. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '.svn')}
  147. qr/Invalid language/,
  148. 'Template, new: Invalid language caught 5';
  149. $template = undef;
  150. $template = new LedgerSMB::Template('user' => $myconfig, 'language' => 'de');
  151. ok(defined $template, 'Template, new: Object creation with valid language');
  152. isa_ok($template, 'LedgerSMB::Template',
  153. 'Template, new: Object creation with valid language');
  154. is($template->{include_path}, 't/data/de;t/data',
  155. 'Template, new: Object creation with valid language has good include_path');
  156. $template = undef;
  157. $template = new LedgerSMB::Template('user' => $myconfig, 'language' => 'de',
  158. 'path' => 't/data', 'outputfile' => 'test');
  159. ok(defined $template,
  160. 'Template, new: Object creation with valid language and path');
  161. isa_ok($template, 'LedgerSMB::Template',
  162. 'Template, new: Object creation with valid language and path');
  163. is($template->{include_path}, 't/data',
  164. 'Template, new: Object creation with valid path overrides language');
  165. is($template->{outputfile}, 't/var/test',
  166. 'Template, new: Object creation with filename is correct');
  167. $template = undef;
  168. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  169. 'template' => '04-template', 'locale' => $locale);
  170. ok(defined $template,
  171. 'Template, new: Object creation with locale');
  172. isa_ok($template, 'LedgerSMB::Template',
  173. 'Template, new: Object creation with locale');
  174. $template = undef;
  175. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  176. 'template' => '04-template-2', 'no_auto_output' => 1);
  177. ok(defined $template,
  178. 'Template, new: Object creation with non-existent template');
  179. throws_ok{$template->render({'login' => 'foo'})} qr/not found/,
  180. 'Template, render: File not found caught';
  181. $template = undef;
  182. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'TODO',
  183. 'template' => '04-template', 'no_auto_output' => 1);
  184. ok(defined $template,
  185. 'Template, new: Object creation with non-existent format');
  186. throws_ok{$template->render({'login' => 'foo'})} qr/Can't locate/,
  187. 'Template, render: Invalid format caught';
  188. #####################
  189. ## Rendering tests ##
  190. #####################
  191. $template = undef;
  192. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'PDF',
  193. 'template' => '04-template', 'no_auto_output' => 1);
  194. ok(defined $template,
  195. 'Template, new (PDF): Object creation with format and template');
  196. isa_ok($template, 'LedgerSMB::Template',
  197. 'Template, new (PDF): Object creation with format and template');
  198. is($template->{include_path}, 't/data',
  199. 'Template, new (PDF): Object creation with format and template');
  200. is($template->render({'login' => 'foo&bar'}), "t/var/04-template-output-$$.pdf",
  201. 'Template, render (PDF): Simple PDF template, default filename');
  202. ok(-e "t/var/04-template-output-$$.pdf",
  203. 'Template, render (PDF): File created');
  204. is(unlink("t/var/04-template-output-$$.pdf"), 1,
  205. 'Template, render (PDF): removing testfile');
  206. ok(!-e "t/var/04-template-output-$$.pdf",
  207. 'Template, render (PDF): testfile removed');
  208. $template = undef;
  209. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'PS',
  210. 'template' => '04-template', 'no_auto_output' => 1);
  211. ok(defined $template,
  212. 'Template, new (PS): Object creation with format and template');
  213. isa_ok($template, 'LedgerSMB::Template',
  214. 'Template, new (PS): Object creation with format and template');
  215. is($template->{include_path}, 't/data',
  216. 'Template, new (PS): Object creation with format and template');
  217. is($template->render({'login' => 'foo\&bar'}),
  218. "t/var/04-template-output-$$.ps",
  219. 'Template, render (PS): Simple Postscript template, default filename');
  220. ok(-e "t/var/04-template-output-$$.ps", 'Template, render (PS): File created');
  221. is(unlink("t/var/04-template-output-$$.ps"), 1,
  222. 'Template, render (PS): removing testfile');
  223. ok(!-e "t/var/04-template-output-$$.ps",
  224. 'Template, render (PS): testfile removed');
  225. $template = undef;
  226. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'TXT',
  227. 'template' => '04-template', 'no_auto_output' => 1);
  228. ok(defined $template,
  229. 'Template, new (TXT): Object creation with format and template');
  230. isa_ok($template, 'LedgerSMB::Template',
  231. 'Template, new (TXT): Object creation with format and template');
  232. is($template->{include_path}, 't/data',
  233. 'Template, new (TXT): Object creation with format and template');
  234. is($template->render({'login' => 'foo&bar'}),
  235. "t/var/04-template-output-$$.txt",
  236. 'Template, render: Simple text template, default filename');
  237. ok(-e "t/var/04-template-output-$$.txt",
  238. 'Template, render (TXT): File created');
  239. open($FH, '<', "t/var/04-template-output-$$.txt");
  240. @r = <$FH>;
  241. close($FH);
  242. chomp(@r);
  243. is(join("\n", @r), "I am a template.\nLook at me foo&bar.",
  244. 'Template, render (TXT): Simple TXT template, correct output');
  245. is(unlink("t/var/04-template-output-$$.txt"), 1,
  246. 'Template, render (TXT): removing testfile');
  247. ok(!-e "t/var/04-template-output-$$.txt",
  248. 'Template, render (TXT): testfile removed');
  249. $template = undef;
  250. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  251. 'template' => '04-template', 'no_auto_output' => 1);
  252. ok(defined $template,
  253. 'Template, new (HTML): Object creation with format and template');
  254. isa_ok($template, 'LedgerSMB::Template',
  255. 'Template, new (HTML): Object creation with format and template');
  256. is($template->{include_path}, 't/data',
  257. 'Template, new (HTML): Object creation with format and template');
  258. is($template->render({'login' => 'foo&bar'}),
  259. "t/var/04-template-output-$$.html",
  260. 'Template, render (HTML): Simple HTML template, default filename');
  261. ok(-e "t/var/04-template-output-$$.html",
  262. 'Template, render (HTML): File created');
  263. open($FH, '<', "t/var/04-template-output-$$.html");
  264. @r = <$FH>;
  265. close($FH);
  266. chomp(@r);
  267. is(join("\n", @r), "I am a template.\nLook at me foo&amp;bar.",
  268. 'Template, render (HTML): Simple HTML template, correct output');
  269. is(unlink("t/var/04-template-output-$$.html"), 1,
  270. 'Template, render (HTML): removing testfile');
  271. ok(!-e "t/var/04-template-output-$$.html",
  272. 'Template, render (HTML): testfile removed');
  273. $template = undef;
  274. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  275. 'template' => '04-gettext', 'outputfile' => '04-gettext',
  276. 'no_auto_output' => 1);
  277. ok(defined $template,
  278. 'Template, new (HTML): Object creation with outputfile');
  279. isa_ok($template, 'LedgerSMB::Template',
  280. 'Template, new (HTML): Object creation with outputfile');
  281. is($template->{include_path}, 't/data',
  282. 'Template, new (HTML): Object creation with outputfile');
  283. is($template->render({'month' => 'June', 'login' => 'foo&bar',
  284. 'fr' => $locale}), 't/var/04-gettext.html',
  285. 'Template, render (HTML): Gettext HTML template');
  286. ok(-e 't/var/04-gettext.html', 'Template, render (HTML): File created');
  287. open($FH, '<', 't/var/04-gettext.html');
  288. @r = <$FH>;
  289. close($FH);
  290. chomp(@r);
  291. is(join("\n", @r),
  292. "I am a foo&amp;bar.\nLook at me Juin.\njuni\nAan foo&amp;bar",
  293. 'Template, render (HTML): Gettext HTML template, correct output');
  294. is(unlink('t/var/04-gettext.html'), 1,
  295. 'Template, render (HTML): removing testfile');
  296. ok(!-e 't/var/04-gettext.html',
  297. 'Template, render (HTML): testfile removed');
  298. ## XeTeX test, requires PDFLATEX to be xelatex and modified Template::Latex
  299. SKIP: {
  300. skip 'XeTeX and modified Template::Latex requiring PDF tests';
  301. $template = undef;
  302. $template = new LedgerSMB::Template('user' => $myconfig,
  303. 'format' => 'PDF', 'template' => '04-gettext',
  304. 'no_auto_output' => 1);
  305. ok(defined $template,
  306. 'Template, new (PDF): XeTeX template creation');
  307. isa_ok($template, 'LedgerSMB::Template',
  308. 'Template, new (PDF): XeTeX template creation');
  309. is($template->{include_path}, 't/data',
  310. 'Template, new (PDF): XeTeX template creation');
  311. is($template->render({'login' => 'foo&bar'}),
  312. "t/var/04-gettext-output-$$.pdf",
  313. 'Template, render (PDF): XeTeX PDF template, default filename');
  314. ok(-e "t/var/04-gettext-output-$$.pdf",
  315. 'Template, render (PDF): File created');
  316. is(unlink("t/var/04-gettext-output-$$.pdf"), 1,
  317. 'Template, render (PDF): removing testfile');
  318. ok(!-e "t/var/04-gettext-output-$$.pdf",
  319. 'Template, render (PDF): testfile removed');
  320. }