erlydtl_functional_tests.erl 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. test_list() ->
  39. % order is important.
  40. ["autoescape", "comment", "extends", "filters", "for", "for_list",
  41. "for_tuple", "for_list_preset", "for_preset", "for_records",
  42. "for_records_preset", "include", "if", "if_preset", "ifequal",
  43. "ifequal_preset", "ifnotequal", "ifnotequal_preset", "now",
  44. "var", "var_preset", "var_error", "cycle", "custom_tag",
  45. "custom_tag_error", "custom_call"].
  46. setup_compile("for_list_preset") ->
  47. CompileVars = [{fruit_list, [["apple", "apples"], ["banana", "bananas"], ["coconut", "coconuts"]]}],
  48. {ok, CompileVars};
  49. setup_compile("for_preset") ->
  50. CompileVars = [{fruit_list, ["preset-apple", "preset-banana", "preset-coconut"]}],
  51. {ok, CompileVars};
  52. setup_compile("for_records_preset") ->
  53. Link1a = [{name, "Amazon (preset)"}, {url, "http://amazon.com"}],
  54. Link2a = [{name, "Google (preset)"}, {url, "http://google.com"}],
  55. Link3a = [{name, "Microsoft (preset)"}, {url, "http://microsoft.com"}],
  56. CompileVars = [{software_links, [Link1a, Link2a, Link3a]}],
  57. {ok, CompileVars};
  58. setup_compile("if_preset") ->
  59. CompileVars = [{var1, "something"}],
  60. {ok, CompileVars};
  61. setup_compile("ifequal_preset") ->
  62. CompileVars = [{var1, "foo"}, {var2, "foo"}],
  63. {ok, CompileVars};
  64. setup_compile("ifnotequal_preset") ->
  65. CompileVars = [{var1, "foo"}, {var2, "foo"}],
  66. {ok, CompileVars};
  67. setup_compile("var_preset") ->
  68. CompileVars = [{preset_var1, "preset-var1"}, {preset_var2, "preset-var2"}],
  69. {ok, CompileVars};
  70. setup_compile("custom_tag_error") ->
  71. CompileVars = [],
  72. {error, CompileVars};
  73. setup_compile(_) ->
  74. {ok, []}.
  75. %% @spec (Name::string()) -> {CompileStatus::atom(), PresetVars::list(),
  76. %% RenderStatus::atom(), RenderVars::list()} | skip
  77. %% @doc
  78. %% @end
  79. %%--------------------------------------------------------------------
  80. setup("autoescape") ->
  81. RenderVars = [{var1, "<b>bold</b>"}],
  82. {ok, RenderVars};
  83. setup("extends") ->
  84. RenderVars = [{base_var, "base-barstring"}, {test_var, "test-barstring"}],
  85. {ok, RenderVars};
  86. setup("filters") ->
  87. RenderVars = [
  88. {date_var1, {1975,7,24}},
  89. {datetime_var1, {{1975,7,24}, {7,13,1}}},
  90. {'list', ["eins", "zwei", "drei"]}
  91. ],
  92. {ok, RenderVars};
  93. setup("for") ->
  94. RenderVars = [{fruit_list, ["apple", "banana", "coconut"]}],
  95. {ok, RenderVars};
  96. setup("for_list") ->
  97. RenderVars = [{fruit_list, [["apple", "apples", "$1"], ["banana", "bananas", "$2"], ["coconut", "coconuts", "$500"]]}],
  98. {ok, RenderVars};
  99. setup("for_tuple") ->
  100. RenderVars = [{fruit_list, [{"apple", "apples"}, {"banana", "bananas"}, {"coconut", "coconuts"}]}],
  101. {ok, RenderVars};
  102. setup("for_records") ->
  103. Link1 = [{name, "Amazon"}, {url, "http://amazon.com"}],
  104. Link2 = [{name, "Google"}, {url, "http://google.com"}],
  105. Link3 = [{name, "Microsoft"}, {url, "http://microsoft.com"}],
  106. RenderVars = [{link_list, [Link1, Link2, Link3]}],
  107. {ok, RenderVars};
  108. setup("for_records_preset") ->
  109. Link1b = [{name, "Canon"}, {url, "http://canon.com"}],
  110. Link2b = [{name, "Leica"}, {url, "http://leica.com"}],
  111. Link3b = [{name, "Nikon"}, {url, "http://nikon.com"}],
  112. RenderVars = [{photo_links, [Link1b, Link2b, Link3b]}],
  113. {ok, RenderVars};
  114. setup("include") ->
  115. RenderVars = [{var1, "foostring1"}, {var2, "foostring2"}],
  116. {ok, RenderVars};
  117. setup("if") ->
  118. RenderVars = [{var1, "something"}],
  119. {ok, RenderVars};
  120. setup("ifequal") ->
  121. RenderVars = [{var1, "foo"}, {var2, "foo"}, {var3, "bar"}],
  122. {ok, RenderVars};
  123. setup("ifequal_preset") ->
  124. RenderVars = [{var3, "bar"}],
  125. {ok, RenderVars};
  126. setup("ifnotequal") ->
  127. RenderVars = [{var1, "foo"}, {var2, "foo"}, {var3, "bar"}],
  128. {ok, RenderVars};
  129. setup("var") ->
  130. RenderVars = [{var1, "foostring1"}, {var2, "foostring2"}, {var_not_used, "foostring3"}],
  131. {ok, RenderVars};
  132. setup("var_preset") ->
  133. RenderVars = [{var1, "foostring1"}, {var2, "foostring2"}],
  134. {ok, RenderVars};
  135. setup("var_error") ->
  136. RenderVars = [{var1, "foostring1"}],
  137. {error, RenderVars};
  138. setup("cycle") ->
  139. RenderVars = [{test, [integer_to_list(X) || X <- lists:seq(1, 20)]},
  140. {a, "Apple"}, {b, "Banana"}, {c, "Cherry"}],
  141. {ok, RenderVars};
  142. %%--------------------------------------------------------------------
  143. %% Custom tags
  144. %%--------------------------------------------------------------------
  145. setup("custom_tag_error") ->
  146. RenderVars = [],
  147. {skip, RenderVars};
  148. setup("custom_call") ->
  149. RenderVars = [{var1, "something"}],
  150. {ok, RenderVars};
  151. setup(_) ->
  152. {ok, []}.
  153. run_tests() ->
  154. io:format("Running functional tests...~n"),
  155. case fold_tests() of
  156. {N, []}->
  157. Msg = lists:concat(["All ", N, " functional tests passed~n~n"]),
  158. io:format(Msg),
  159. {ok, Msg};
  160. {_, Errs} ->
  161. io:format("Errors: ~p~n~n",[Errs]),
  162. failed
  163. end.
  164. run_test(Name) ->
  165. test_compile_render(filename:join([templates_docroot(), Name])).
  166. %%====================================================================
  167. %% Internal functions
  168. %%====================================================================
  169. fold_tests() ->
  170. lists:foldl(fun(Name, {AccCount, AccErrs}) ->
  171. case test_compile_render(Name) of
  172. ok ->
  173. {AccCount + 1, AccErrs};
  174. {error, Reason} ->
  175. {AccCount + 1, [{Name, Reason} | AccErrs]}
  176. end
  177. end, {0, []}, test_list()
  178. ).
  179. test_compile_render(Name) ->
  180. File = filename:join([templates_docroot(), Name]),
  181. Module = "example_" ++ Name,
  182. case setup_compile(Name) of
  183. {CompileStatus, CompileVars} ->
  184. Options = [
  185. {vars, CompileVars},
  186. {force_recompile, true}],
  187. io:format(" Template: ~p, ... compiling ... ", [Name]),
  188. case erlydtl:compile(File, Module, Options) of
  189. ok ->
  190. case CompileStatus of
  191. ok -> test_render(Name, list_to_atom(Module));
  192. _ -> {error, "compiling should have failed :" ++ File}
  193. end;
  194. {error, Err} ->
  195. case CompileStatus of
  196. error ->
  197. io:format("~n"),
  198. ok;
  199. _ ->
  200. io:format("~nCompile errror: ~p~n",[Err]),
  201. Err
  202. end
  203. end;
  204. skip ->
  205. ok;
  206. _ ->
  207. {error, "no 'setup' clause defined for this test"}
  208. end.
  209. test_render(Name, Module) ->
  210. File = filename:join([templates_docroot(), Name]),
  211. {RenderStatus, Vars} = setup(Name),
  212. case catch Module:render(Vars) of
  213. {ok, Data} ->
  214. io:format("rendering~n"),
  215. case RenderStatus of
  216. ok ->
  217. {File, _} = Module:source(),
  218. OutFile = filename:join([templates_outdir(), filename:basename(File)]),
  219. case file:open(OutFile, [write]) of
  220. {ok, IoDev} ->
  221. file:write(IoDev, Data),
  222. file:close(IoDev),
  223. ok;
  224. Err ->
  225. Err
  226. end;
  227. _ ->
  228. {error, "rendering should have failed :" ++ File}
  229. end;
  230. {'EXIT', _} ->
  231. io:format("~n"),
  232. {error, "failed invoking render method:" ++ Module};
  233. Err ->
  234. io:format("~n"),
  235. case RenderStatus of
  236. error -> ok;
  237. _ -> Err
  238. end
  239. end.
  240. templates_docroot() ->
  241. filename:join([erlydtl_deps:get_base_dir(), "examples", "docroot"]).
  242. templates_outdir() ->
  243. filename:join([erlydtl_deps:get_base_dir(), "examples", "rendered_output"]).