Implemented estap:test_dir().
authorStanislaw Klekot <dozzie@jarowit.net>
Tue, 16 Jun 2015 01:14:21 +0000 (03:14 +0200)
committerStanislaw Klekot <dozzie@jarowit.net>
Tue, 16 Jun 2015 01:14:21 +0000 (03:14 +0200)
src/estap.erl
src/estap_file.erl
src/estap_test.erl

index 0d8d7ed..ddc50f5 100644 (file)
@@ -223,17 +223,24 @@ all_ok() ->
 
 %% @doc Get a directory containing this test script.
 %%
-%% @TODO Implement this function.
+%%   <b>NOTE</b>: This function doesn't work in processes spawned from test
+%%   function. You need to get the directory in parent process and pass it as
+%%   an argument.
 
 test_dir() ->
-  'TODO'.
+  case get(test_dir) of
+    undefined -> erlang:error({undefined, test_dir});
+    Directory -> Directory
+  end.
 
 %% @doc Get a subdirectory of the directory containing this test script.
 %%
-%% @TODO Implement this function.
+%%   <b>NOTE</b>: This function doesn't work in processes spawned from test
+%%   function. You need to get the directory in parent process and pass it as
+%%   an argument.
 
-test_dir(_Subdir) ->
-  'TODO'.
+test_dir(Subdir) ->
+  filename:join(test_dir(), Subdir).
 
 %%%---------------------------------------------------------------------------
 
index c64e93e..794b2c6 100644 (file)
@@ -138,26 +138,52 @@ parse_file(File, Source, IncludePath) ->
       % replace name of the file `epp:parse_file()' actually read with the
       % name of source file, so any possible stack traces mention this source,
       % not a temporary file
-      NewForms = lists:map(
-        fun
-          ({attribute,N1,file,{_File,N2}}) -> {attribute,N1,file,{Source,N2}};
-          (Form) -> Form
-        end,
-        Forms
-      ),
-      case [M || {attribute, _, module, M} <- Forms] of
-        % in case of two `-module()' entries let the `compile:forms()' raise
-        % an error
-        [ModuleName | _] ->
-          {ok, {ModuleName, NewForms}};
-        [] ->
-          ModuleName = list_to_atom(filename:rootname(filename:basename(File))),
-          {ok, {ModuleName, [{attribute, 0, module, ModuleName} | NewForms]}}
-      end;
+      {ModuleName, FixedForms} = adjust_forms(Source, Forms),
+      {ok, {ModuleName, FixedForms}};
     {error, Reason} ->
       {error, Reason}
   end.
 
+%% @doc Adjust ABFs from the test file so they can be safely compiled to
+%%   a binary module.
+%%
+%%   Adjusting consists of setting source file to `SourceFile' (instead of
+%%   a temporary file it was read from), adding module declaration if it was
+%%   missing, and adding `test_dir' attribute to
+%%   `filename:dirname(SourceFile)' (necessary step for
+%%   {@link estap:test_dir/0} to work).
+
+-spec adjust_forms(file:name(), [erl_parse:abstract_form()]) ->
+  {module(), [erl_parse:abstract_form()]}.
+
+adjust_forms(SourceFile, Forms) ->
+  {BeforeModuleForms, AfterModuleForms} = lists:splitwith(
+    fun({attribute,_,module,_}) -> false; (_) -> true end,
+    Forms
+  ),
+  {ModuleName, FormsWithModuleAndDir} = case AfterModuleForms of
+    [{attribute, _, module, Module} = ModForm | Rest] ->
+      % add `test_dir' attribute just after the module declaration
+      DirAttr = {attribute, 0, test_dir, filename:dirname(SourceFile)},
+      {Module, BeforeModuleForms ++ [ModForm, DirAttr | Rest]};
+    [] ->
+      % add module declaration and `test_dir' attribute
+      Module = list_to_atom(filename:rootname(filename:basename(SourceFile))),
+      ModForm = {attribute, 0, module, Module},
+      DirAttr = {attribute, 0, test_dir, filename:dirname(SourceFile)},
+      {Module, [ModForm, DirAttr | BeforeModuleForms]}
+  end,
+  FormsWithProperSourcefile = lists:map(
+    fun
+      ({attribute, N1, file, {_File, N2}}) ->
+        {attribute, N1, file, {SourceFile, N2}};
+      (Form) ->
+        Form
+    end,
+    FormsWithModuleAndDir
+  ),
+  {ModuleName, FormsWithProperSourcefile}.
+
 %% }}}
 %%----------------------------------------------------------
 %% ABF handling functions {{{
index 1ab7d4a..254cb95 100644 (file)
@@ -95,6 +95,14 @@ test({Mod, Func} = _TestFunSpec) ->
   ok.
 
 call({Pid, Ref} = _ResultTo, Mod, Fun, Args) ->
+  % XXX: putting `test_dir' to proc dict is an important thing for
+  % `estap:test_dir()' function
+  ModuleAttrs = Mod:module_info(attributes),
+  case proplists:get_value(test_dir, ModuleAttrs) of
+    [DirName] -> put(test_dir, DirName);
+    DirName when is_list(DirName) -> put(test_dir, DirName);
+    _ -> ok
+  end,
   TestResult = try
     success_or_failure(apply(Mod, Fun, Args))
   catch