You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
9.1 KiB

  1. %% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. %% @author Chris Bernard <cebernard@gmail.com>
  28. %% @doc This tests functionality provided by the rebar command 'eunit'.
  29. %% @copyright 2009, 2010 Dave Smith
  30. %% -------------------------------------------------------------------
  31. -module(rebar_eunit_tests).
  32. -compile(export_all).
  33. -include_lib("eunit/include/eunit.hrl").
  34. %% Assuming this test is run inside the rebar 'eunit'
  35. %% command, the current working directory will be '.eunit'
  36. -define(REBAR_SCRIPT, "../rebar").
  37. -define(TMP_DIR, "tmp_eunit/").
  38. %% ====================================================================
  39. %% Rebar EUnit and Cover Tests
  40. %% ====================================================================
  41. eunit_test_() ->
  42. {"Ensure EUnit runs with tests in a 'test' dir and no defined suite",
  43. setup, fun() -> setup_basic_project(), rebar("-v eunit") end,
  44. fun teardown/1,
  45. fun(RebarOut) ->
  46. [{"Tests in 'test' directory are found and run",
  47. ?_assert(string:str(RebarOut, "myapp_mymod_tests:") =/= 0)},
  48. {"Tests in 'src' directory are found and run",
  49. ?_assert(string:str(RebarOut, "myapp_mymod:") =/= 0)},
  50. {"Tests are only run once",
  51. ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}]
  52. end}.
  53. cover_test_() ->
  54. {"Ensure Cover runs with tests in a test dir and no defined suite",
  55. setup, fun() -> setup_cover_project(), rebar("-v eunit") end,
  56. fun teardown/1,
  57. [{"All cover reports are generated",
  58. assert_files_in("the temporary eunit directory",
  59. expected_cover_generated_files())},
  60. {"Only production modules get coverage reports",
  61. assert_files_not_in("the temporary eunit directory",
  62. [".eunit/myapp_mymod_tests.COVER.html"])}]}.
  63. cover_with_suite_test_() ->
  64. {"Ensure Cover runs with Tests in a test dir and a test suite",
  65. setup,
  66. fun() ->
  67. setup_cover_project_with_suite(),
  68. rebar("-v eunit suite=mysuite")
  69. end,
  70. fun teardown/1,
  71. [{"All cover reports are generated",
  72. assert_files_in("the temporary eunit directory",
  73. expected_cover_generated_files())},
  74. {"Only production modules get coverage reports",
  75. assert_files_not_in("the temporary eunit directory",
  76. [".eunit/myapp_mymod_tests.COVER.html",
  77. ".eunit/mysuite.COVER.html"])}]}.
  78. expected_cover_generated_files() ->
  79. [".eunit/index.html",
  80. ".eunit/myapp_app.COVER.html",
  81. ".eunit/myapp_mymod.COVER.html",
  82. ".eunit/myapp_sup.COVER.html"].
  83. cover_coverage_test_() ->
  84. {"Coverage is accurately calculated",
  85. setup, fun() -> setup_cover_project(), rebar("-v eunit") end,
  86. fun teardown/1,
  87. [{"Modules that include the EUnit header can still have 100% coverage",
  88. %% cover notices the implicit EUnit test/0 func that never gets
  89. %% called during eunit:test(TestRepresentation), so NotCounted
  90. %% needs to be decremented in this case.
  91. assert_full_coverage("myapp_mymod")}]}.
  92. %% ====================================================================
  93. %% Environment and Setup Tests
  94. %% ====================================================================
  95. environment_test_() ->
  96. {"Sanity check the testing environment",
  97. setup, fun make_tmp_dir/0, fun remove_tmp_dir/1,
  98. [{"Ensure a test project can be created",
  99. ?_assert(filelib:is_dir(?TMP_DIR))},
  100. {"Ensure the rebar script can be found, copied, and run",
  101. [?_assert(filelib:is_file(?REBAR_SCRIPT)),
  102. fun assert_rebar_runs/0]}]}.
  103. assert_rebar_runs() ->
  104. prepare_rebar_script(),
  105. ?assert(string:str(os:cmd("./" ++ ?TMP_DIR ++ "rebar"), "Usage: rebar") =/= 0).
  106. basic_setup_test_() ->
  107. {"Create a simple project with a 'test' directory, a test, and a module",
  108. setup, fun setup_basic_project/0, fun teardown/1,
  109. %% Test the setup function
  110. assert_dirs_in("Basic Project",
  111. ["src", "ebin", "test"]) ++
  112. assert_files_in("Basic Project",
  113. ["test/myapp_mymod_tests.erl", "src/myapp_mymod.erl"])}.
  114. %% ====================================================================
  115. %% Setup and Teardown
  116. %% ====================================================================
  117. -define(myapp_mymod,
  118. ["-module(myapp_mymod).\n",
  119. "-export([myfunc/0]).\n",
  120. "-include_lib(\"eunit/include/eunit.hrl\").\n",
  121. "myfunc() -> ok.\n",
  122. "myprivate_test() -> ?assert(true).\n"]).
  123. -define(myapp_mymod_tests,
  124. ["-module(myapp_mymod_tests).\n",
  125. "-compile([export_all]).\n",
  126. "-include_lib(\"eunit/include/eunit.hrl\").\n",
  127. "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n"]).
  128. -define(mysuite,
  129. ["-module(mysuite).\n",
  130. "-export([all_test_/0]).\n",
  131. "-include_lib(\"eunit/include/eunit.hrl\").\n",
  132. "all_test_() -> [myapp_mymod_defined_in_mysuite_tests].\n"]).
  133. -define(myapp_mymod_defined_in_mysuite_tests,
  134. ["-module(myapp_mymod_defined_in_mysuite_tests).\n",
  135. "-compile([export_all]).\n",
  136. "-include_lib(\"eunit/include/eunit.hrl\").\n",
  137. "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n"]).
  138. make_tmp_dir() ->
  139. file:make_dir(?TMP_DIR).
  140. setup_environment() ->
  141. make_tmp_dir(),
  142. prepare_rebar_script(),
  143. file:set_cwd(?TMP_DIR).
  144. setup_basic_project() ->
  145. setup_environment(),
  146. rebar("create-app appid=myapp"),
  147. file:make_dir("test"),
  148. file:write_file("test/myapp_mymod_tests.erl", ?myapp_mymod_tests),
  149. file:write_file("src/myapp_mymod.erl", ?myapp_mymod).
  150. setup_cover_project() ->
  151. setup_basic_project(),
  152. file:write_file("rebar.config", "{cover_enabled, true}.\n").
  153. setup_cover_project_with_suite() ->
  154. setup_cover_project(),
  155. file:write_file("test/mysuite.erl", ?mysuite),
  156. file:write_file("test/myapp_mymod_defined_in_mysuite_tests.erl",
  157. ?myapp_mymod_defined_in_mysuite_tests).
  158. teardown(_) ->
  159. file:set_cwd(".."),
  160. remove_tmp_dir(),
  161. ok.
  162. remove_tmp_dir() ->
  163. remove_tmp_dir(arg_for_eunit).
  164. remove_tmp_dir(_) ->
  165. case os:type() of
  166. {unix, _} ->
  167. os:cmd("rm -rf " ++ ?TMP_DIR ++ " 2>/dev/null");
  168. {win32, _} ->
  169. %% os:cmd("rmdir /S /Q " ++ ?TMP_DIR ++ " 2>NUL")
  170. exit("Windows is not supported yet.")
  171. end.
  172. %% ====================================================================
  173. %% Helper Functions
  174. %% ====================================================================
  175. prepare_rebar_script() ->
  176. {ok, _} = file:copy(?REBAR_SCRIPT, ?TMP_DIR ++ "rebar"),
  177. [] = os:cmd("chmod u+x " ++ ?TMP_DIR ++ "rebar").
  178. rebar() ->
  179. rebar([]).
  180. rebar(Args) when is_list(Args) ->
  181. Out = os:cmd("./rebar " ++ Args),
  182. %?debugMsg("**** Begin"), ?debugMsg(Out), ?debugMsg("**** End"),
  183. Out.
  184. assert_dirs_in(Name, [Dir|T]) ->
  185. [{Name ++ " has directory: " ++ Dir, ?_assert(filelib:is_dir(Dir))} |
  186. assert_dirs_in(Name, T)];
  187. assert_dirs_in(_, []) -> [].
  188. assert_files_in(Name, [File|T]) ->
  189. [{Name ++ " has file: " ++ File, ?_assert(filelib:is_file(File))} |
  190. assert_files_in(Name, T)];
  191. assert_files_in(_, []) -> [].
  192. assert_files_not_in(Name, [File|T]) ->
  193. [{Name ++ " does not have file: " ++ File, ?_assertNot(filelib:is_file(File))} |
  194. assert_files_not_in(Name, T)];
  195. assert_files_not_in(_, []) -> [].
  196. assert_full_coverage(Mod) ->
  197. fun() ->
  198. {ok, F} = file:read_file(".eunit/index.html"),
  199. Result = [X || X <- string:tokens(binary_to_list(F), "\n"),
  200. string:str(X, Mod) =/= 0,
  201. string:str(X, "100%") =/= 0],
  202. file:close(F),
  203. ?assert(length(Result) == 1)
  204. end.