erlydtl_functional_tests.erl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. %%%-------------------------------------------------------------------
  2. %%% File: erlydtl_tests.erl
  3. %%% @author Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
  4. %%% @author Evan Miller <emmiller@gmail.com>
  5. %%% @copyright 2008 Roberto Saccon, Evan Miller
  6. %%% @doc ErlyDTL test suite
  7. %%% @end
  8. %%%
  9. %%% The MIT License
  10. %%%
  11. %%% Copyright (c) 2007 Roberto Saccon
  12. %%%
  13. %%% Permission is hereby granted, free of charge, to any person obtaining a copy
  14. %%% of this software and associated documentation files (the "Software"), to deal
  15. %%% in the Software without restriction, including without limitation the rights
  16. %%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. %%% copies of the Software, and to permit persons to whom the Software is
  18. %%% furnished to do so, subject to the following conditions:
  19. %%%
  20. %%% The above copyright notice and this permission notice shall be included in
  21. %%% all copies or substantial portions of the Software.
  22. %%%
  23. %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24. %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  26. %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  28. %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  29. %%% THE SOFTWARE.
  30. %%%
  31. %%% @since 2008-02-11 by Roberto Saccon
  32. %%%-------------------------------------------------------------------
  33. -module(erlydtl_functional_tests).
  34. -author('rsaccon@gmail.com').
  35. -author('emmiller@gmail.com').
  36. %% API
  37. -export([run_tests/0, run_test/1]).
  38. %% @spec (Name::string()) -> {CompileStatus::atom(), PresetVars::list(),
  39. %% RenderStatus::atom(), RenderVars::list()} | skip
  40. %% @doc
  41. %% @end
  42. %%--------------------------------------------------------------------
  43. setup("autoescape") ->
  44. CompileVars = [],
  45. RenderVars = [{var1, "<b>bold</b>"}],
  46. {ok, CompileVars, ok, RenderVars};
  47. setup("comment") ->
  48. CompileVars = [],
  49. RenderVars =[],
  50. {ok, CompileVars, ok, RenderVars};
  51. setup("extends") ->
  52. CompileVars = [],
  53. RenderVars = [{base_var, "base-barstring"}, {test_var, "test-barstring"}],
  54. {ok, CompileVars, ok, RenderVars};
  55. setup("filters") ->
  56. CompileVars = [],
  57. RenderVars = [
  58. {date_var1, {1975,7,24}},
  59. {datetime_var1, {{1975,7,24}, {7,13,1}}},
  60. {'list', ["eins", "zwei", "drei"]}
  61. ],
  62. {ok, CompileVars, ok, RenderVars};
  63. setup("for") ->
  64. CompileVars = [],
  65. RenderVars = [{fruit_list, ["apple", "banana", "coconut"]}],
  66. {ok, CompileVars, ok, RenderVars};
  67. setup("for_list") ->
  68. CompileVars = [],
  69. RenderVars = [{fruit_list, [["apple", "apples", "$1"], ["banana", "bananas", "$2"], ["coconut", "coconuts", "$500"]]}],
  70. {ok, CompileVars, ok, RenderVars};
  71. setup("for_tuple") ->
  72. CompileVars = [],
  73. RenderVars = [{fruit_list, [{"apple", "apples"}, {"banana", "bananas"}, {"coconut", "coconuts"}]}],
  74. {ok, CompileVars, ok, RenderVars};
  75. setup("for_list_preset") ->
  76. CompileVars = [{fruit_list, [["apple", "apples"], ["banana", "bananas"], ["coconut", "coconuts"]]}],
  77. RenderVars = [],
  78. {ok, CompileVars, ok, RenderVars};
  79. setup("for_preset") ->
  80. CompileVars = [{fruit_list, ["preset-apple", "preset-banana", "preset-coconut"]}],
  81. RenderVars = [],
  82. {ok, CompileVars, ok, RenderVars};
  83. setup("for_records") ->
  84. CompileVars = [],
  85. Link1 = [{name, "Amazon"}, {url, "http://amazon.com"}],
  86. Link2 = [{name, "Google"}, {url, "http://google.com"}],
  87. Link3 = [{name, "Microsoft"}, {url, "http://microsoft.com"}],
  88. RenderVars = [{link_list, [Link1, Link2, Link3]}],
  89. {ok, CompileVars, ok, RenderVars};
  90. setup("for_records_preset") ->
  91. Link1a = [{name, "Amazon (preset)"}, {url, "http://amazon.com"}],
  92. Link2a = [{name, "Google (preset)"}, {url, "http://google.com"}],
  93. Link3a = [{name, "Microsoft (preset)"}, {url, "http://microsoft.com"}],
  94. CompileVars = [{software_links, [Link1a, Link2a, Link3a]}],
  95. Link1b = [{name, "Canon"}, {url, "http://canon.com"}],
  96. Link2b = [{name, "Leica"}, {url, "http://leica.com"}],
  97. Link3b = [{name, "Nikon"}, {url, "http://nikon.com"}],
  98. RenderVars = [{photo_links, [Link1b, Link2b, Link3b]}],
  99. {ok, CompileVars, ok, RenderVars};
  100. setup("include") ->
  101. CompileVars = [],
  102. RenderVars = [{var1, "foostring1"}, {var2, "foostring2"}],
  103. {ok, CompileVars, ok, RenderVars};
  104. setup("if") ->
  105. CompileVars = [],
  106. RenderVars = [{var1, "something"}],
  107. {ok, CompileVars, ok, RenderVars};
  108. setup("if_preset") ->
  109. CompileVars = [{var1, "something"}],
  110. RenderVars = [],
  111. {ok, CompileVars, ok, RenderVars};
  112. setup("ifequal") ->
  113. CompileVars = [],
  114. RenderVars = [{var1, "foo"}, {var2, "foo"}, {var3, "bar"}],
  115. {ok, CompileVars, ok, RenderVars};
  116. setup("ifequal_preset") ->
  117. CompileVars = [{var1, "foo"}, {var2, "foo"}],
  118. RenderVars = [{var3, "bar"}],
  119. {ok, CompileVars, ok, RenderVars};
  120. setup("ifnotequal") ->
  121. CompileVars = [],
  122. RenderVars = [{var1, "foo"}, {var2, "foo"}, {var3, "bar"}],
  123. {ok, CompileVars, ok, RenderVars};
  124. setup("ifnotequal_preset") ->
  125. CompileVars = [{var1, "foo"}, {var2, "foo"}],
  126. RenderVars = [],
  127. {ok, CompileVars, ok, RenderVars};
  128. setup("now") ->
  129. CompileVars = [],
  130. RenderVars = [],
  131. {ok, CompileVars, ok, RenderVars};
  132. setup("var") ->
  133. CompileVars = [],
  134. RenderVars = [{var1, "foostring1"}, {var2, "foostring2"}, {var_not_used, "foostring3"}],
  135. {ok, CompileVars, ok, RenderVars};
  136. setup("var_preset") ->
  137. CompileVars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
  138. RenderVars = [{var1, "foostring1"}, {var2, "foostring2"}],
  139. {ok, CompileVars, ok, RenderVars};
  140. setup("var_error") ->
  141. CompileVars = [],
  142. RenderVars = [{var1, "foostring1"}],
  143. {ok, CompileVars, error, RenderVars};
  144. setup("cycle") ->
  145. CompileVars = [],
  146. RenderVars = [{test, [integer_to_list(X) || X <- lists:seq(1, 20)]},
  147. {a, "Apple"}, {b, "Banana"}, {c, "Cherry"}],
  148. {ok, CompileVars, ok, RenderVars};
  149. %%--------------------------------------------------------------------
  150. %% Custom tags
  151. %%--------------------------------------------------------------------
  152. setup("custom_tag") ->
  153. CompileVars = [],
  154. RenderVars = [],
  155. {ok, CompileVars, ok, RenderVars};
  156. setup("custom_tag_error") ->
  157. CompileVars = [],
  158. RenderVars = [],
  159. {error, CompileVars, skip, RenderVars};
  160. setup("custom_call") ->
  161. CompileVars = [],
  162. RenderVars = [{var1, "something"}],
  163. {ok, CompileVars, ok, RenderVars};
  164. %%--------------------------------------------------------------------
  165. %% Files to ignore:
  166. %%--------------------------------------------------------------------
  167. setup("base") ->
  168. %% example base template used in the extends tag
  169. skip;
  170. setup("include.html") ->
  171. %% example plain text file used in include tag
  172. skip;
  173. setup(_) ->
  174. undefined.
  175. run_tests() ->
  176. io:format("Running functional tests...~n"),
  177. case fold_tests() of
  178. {N, []}->
  179. Msg = lists:concat(["All ", N, " functional tests passed~n~n"]),
  180. io:format(Msg),
  181. {ok, Msg};
  182. {_, Errs} ->
  183. io:format("Errors: ~p~n~n",[Errs]),
  184. failed
  185. end.
  186. run_test(Name) ->
  187. test_compile_render(filename:join([templates_docroot(), Name])).
  188. %%====================================================================
  189. %% Internal functions
  190. %%====================================================================
  191. fold_tests() ->
  192. filelib:fold_files(templates_docroot(), "^[^\.].+", false,
  193. fun
  194. (File, {AccCount, AccErrs}) ->
  195. case test_compile_render(File) of
  196. ok ->
  197. {AccCount + 1, AccErrs};
  198. {error, Reason} ->
  199. {AccCount + 1, [{File, Reason} | AccErrs]}
  200. end
  201. end, {0, []}).
  202. test_compile_render(File) ->
  203. Name = filename:rootname(filename:basename(File)),
  204. Module = "example_" ++ Name,
  205. case setup(Name) of
  206. {CompileStatus, CompileVars, RenderStatus, RenderVars} ->
  207. Options = [
  208. {vars, CompileVars},
  209. {force_recompile, true}],
  210. io:format(" Template: ~p, ... compiling ... ", [Name]),
  211. case erlydtl:compile(File, Module, Options) of
  212. ok ->
  213. case CompileStatus of
  214. ok -> test_render(File, list_to_atom(Module), RenderStatus, RenderVars);
  215. _ -> {error, "compiling should have failed :" ++ File}
  216. end;
  217. {error, Err} ->
  218. case CompileStatus of
  219. error ->
  220. io:format("~n"),
  221. ok;
  222. _ ->
  223. io:format("~nCompile errror: ~p~n",[Err]),
  224. Err
  225. end
  226. end;
  227. skip ->
  228. ok;
  229. _ ->
  230. {error, "no 'setup' clause defined for this test"}
  231. end.
  232. test_render(File, Module, RenderStatus, Vars) ->
  233. case catch Module:render(Vars) of
  234. {ok, Data} ->
  235. io:format("rendering~n"),
  236. case RenderStatus of
  237. ok ->
  238. {File, _} = Module:source(),
  239. OutFile = filename:join([templates_outdir(), filename:basename(File)]),
  240. case file:open(OutFile, [write]) of
  241. {ok, IoDev} ->
  242. file:write(IoDev, Data),
  243. file:close(IoDev),
  244. ok;
  245. Err ->
  246. Err
  247. end;
  248. _ ->
  249. {error, "rendering should have failed :" ++ File}
  250. end;
  251. {'EXIT', _} ->
  252. io:format("~n"),
  253. {error, "failed invoking render method:" ++ Module};
  254. Err ->
  255. io:format("~n"),
  256. case RenderStatus of
  257. error -> ok;
  258. _ -> Err
  259. end
  260. end.
  261. templates_docroot() ->
  262. filename:join([erlydtl_deps:get_base_dir(), "examples", "docroot"]).
  263. templates_outdir() ->
  264. filename:join([erlydtl_deps:get_base_dir(), "examples", "rendered_output"]).