Browse Source

Add tests for `compile_dir` (fixes #146)

The compile_dir functionality was broken (again).
This test case was very much over due..
Andreas Stenius 11 years ago
parent
commit
76736d8377

+ 21 - 15
src/erlydtl.erl

@@ -135,28 +135,34 @@ compile_dir(DirectoryPath, Module, Options) ->
 %% --------------------------------------------------------------------
 
 %% keep for backwards compatibility, with a tuple-twist to ease migration / offer alternative path..
--spec compile(FileOrBinary, atom()) -> {ok, Module::atom()} | error
-                                           when FileOrBinary :: string() | binary()
+-spec compile(FileOrTemplate, atom()) -> {ok, Module::atom()} | error
+                                           when FileOrTemplate :: string() | binary()
                                                               | {file, filename()}
-                                                              | {template, iodata()}.
+                                                              | {template, iodata()}
+                                                              | {dir, filename()}.
 compile({file, File}, Module) ->
     compile_file(File, Module);
 compile({template, Template}, Module) ->
     compile_template(Template, Module);
-compile(FileOrBinary, Module) when is_binary(FileOrBinary) ->
-    compile_template(FileOrBinary, Module);
-compile(FileOrBinary, Module) ->
-    compile_file(FileOrBinary, Module).
-
--spec compile(FileOrBinary, atom(), compile_options() ) -> ok_ret() | err_ret()
-                                                               when FileOrBinary :: string() | binary()
+compile({dir, Directory}, Module) ->
+    compile_dir(Directory, Module);
+compile(FileOrTemplate, Module) when is_binary(FileOrTemplate) ->
+    compile_template(FileOrTemplate, Module);
+compile(FileOrTemplate, Module) ->
+    compile_file(FileOrTemplate, Module).
+
+-spec compile(FileOrTemplate, atom(), compile_options() ) -> ok_ret() | err_ret()
+                                                               when FileOrTemplate :: string() | binary()
                                                                                   | {file, filename()}
-                                                                                  | {template, iodata()}.
+                                                                                  | {template, iodata()}
+                                                                                  | {dir, filename()}.
 compile({file, File}, Module, Options) ->
     compile_file(File, Module, Options);
 compile({template, Template}, Module, Options) ->
     compile_template(Template, Module, Options);
-compile(FileOrBinary, Module, Options) when is_binary(FileOrBinary) ->
-    compile_template(FileOrBinary, Module, Options);
-compile(FileOrBinary, Module, Options) ->
-    compile_file(FileOrBinary, Module, Options).
+compile({dir, Directory}, Module, Options) ->
+    compile_dir(Directory, Module, Options);
+compile(FileOrTemplate, Module, Options) when is_binary(FileOrTemplate) ->
+    compile_template(FileOrTemplate, Module, Options);
+compile(FileOrTemplate, Module, Options) ->
+    compile_file(FileOrTemplate, Module, Options).

+ 14 - 13
src/erlydtl_beam_compiler.erl

@@ -130,7 +130,7 @@ do_compile_dir(Dir, Context) ->
                                     case parse_file(FilePath, Ctx) of
                                         up_to_date -> {ResultAcc, Ctx};
                                         {ok, DjangoParseTree, CheckSum} ->
-                                            {[{File, DjangoParseTree, CheckSum}|ResultAcc], Ctx};
+                                            {[{FilePath, DjangoParseTree, CheckSum}|ResultAcc], Ctx};
                                         {error, Reason} -> {ResultAcc, ?ERR(Reason, Ctx)}
                                     end
                             end
@@ -161,15 +161,16 @@ compile_multiple_to_binary(Dir, ParserResults, Context) ->
                                                              {FilePath, CheckSum},
                                                              body_ast(DjangoParseTree, TreeWalker)),
                       FunctionName = filename:rootname(filename:basename(File)),
-                      Function1 = ?Q("'@FunctionName@'(Variables) -> _@FunctionName@(Variables, [])."),
-                      Function2 = ?Q(["'@FunctionName@'(Variables, RenderOptions) ->",
-                                      "  try _@MatchAst, _@body of",
-                                      "    Val -> {ok, Val}",
-                                      "  catch",
-                                      "    Err -> {error, Err}",
-                                      "  end."],
-                                     [{body, stringify(BodyAst, Ctx)}]),
-                      {{FunctionName, Function1, Function2}, {merge_info(AstInfo, BodyInfo), TreeWalker1}}
+                      FunctionDefs = ?Q(["'@func'(Variables) -> _@func(Variables, []).",
+                                         "'@func'(_Variables, RenderOptions) ->",
+                                         "  try _@MatchAst, _@body of",
+                                         "    Val -> {ok, Val}",
+                                         "  catch",
+                                         "    Err -> {error, Err}",
+                                         "  end."],
+                                        [{func, erl_syntax:atom(FunctionName)},
+                                         {body, stringify(BodyAst, Ctx)}]),
+                      {{FunctionName, FunctionDefs}, {merge_info(AstInfo, BodyInfo), TreeWalker1}}
                   catch
                       throw:Error ->
                           {error, {AstInfo, TreeWalker#treewalker{ context=?ERR(Error, Ctx) }}}
@@ -437,20 +438,20 @@ custom_forms(Dir, Module, Functions, AstInfo) ->
                 erl_syntax:arity_qualifier(erl_syntax:atom(dependencies), erl_syntax:integer(0)),
                 erl_syntax:arity_qualifier(erl_syntax:atom(translatable_strings), erl_syntax:integer(0))
                 | lists:foldl(
-                    fun({FunctionName, _, _}, Acc) ->
+                    fun({FunctionName, _}, Acc) ->
                             [erl_syntax:arity_qualifier(erl_syntax:atom(FunctionName), erl_syntax:integer(1)),
                              erl_syntax:arity_qualifier(erl_syntax:atom(FunctionName), erl_syntax:integer(2))
                              |Acc]
                     end, [], Functions)
                ],
     ModuleAst = ?Q("-module('@Module@')."),
-    ExportAst = ?Q("-export(['@_Exported'/1])"),
+    ExportAst = ?Q("-export(['@_Exported'/1])."),
 
     SourceFunctionAst = ?Q("source_dir() -> _@Dir@."),
 
     DependenciesFunctionAst = dependencies_function(AstInfo#ast_info.dependencies),
     TranslatableStringsFunctionAst = translatable_strings_function(AstInfo#ast_info.translatable_strings),
-    FunctionAsts = lists:foldl(fun({_, Function1, Function2}, Acc) -> [Function1, Function2 | Acc] end, [], Functions),
+    FunctionAsts = lists:foldl(fun({_, FunctionDefs}, Acc) -> FunctionDefs ++ Acc end, [], Functions),
 
     [erl_syntax:revert(X)
      || X <- [ModuleAst, ExportAst, SourceFunctionAst, DependenciesFunctionAst, TranslatableStringsFunctionAst

+ 9 - 8
src/erlydtl_compiler.erl

@@ -52,7 +52,7 @@
 
 -import(erlydtl_compiler_utils,
          [add_filters/2, add_tags/2, call_extension/3,
-         load_library/2, shorten_filename/1]).
+         load_library/2, shorten_filename/1, get_current_file/1]).
 
 -include("erlydtl_ext.hrl").
 
@@ -242,7 +242,7 @@ init_context(ParseTrail, DefDir, Module, Options) ->
            binary_strings = proplists:get_value(binary_strings, Options, Ctx#dtl_context.binary_strings),
            force_recompile = proplists:get_bool(force_recompile, Options),
            verbose = length(proplists:get_all_values(verbose, Options)),
-           is_compiling_dir = ParseTrail == [],
+           is_compiling_dir = if ParseTrail == [] -> DefDir; true -> false end,
            extension_module = proplists:get_value(extension_module, Options, Ctx#dtl_context.extension_module),
            scanner_module = proplists:get_value(scanner_module, Options, Ctx#dtl_context.scanner_module),
            record_info = [{R, lists:zip(I, lists:seq(2, length(I) + 1))}
@@ -427,12 +427,13 @@ collect_error_info([], Rest, Acc) ->
     end.
 
 
-do_compile(#dtl_context{ is_compiling_dir=true, parse_trail=[Dir] }=Context) ->
-    erlydtl_beam_compiler:compile_dir(Dir, Context);
-do_compile(#dtl_context{ bin=undefined, parse_trail=[File] }=Context) ->
-    compile_output(parse_file(File, Context), Context);
-do_compile(#dtl_context{ bin=Template }=Context) ->
-    compile_output(parse_template(Template, Context), Context).
+do_compile(#dtl_context{ is_compiling_dir=false, bin=undefined }=Context) ->
+    compile_output(parse_file(get_current_file(Context), Context), Context);
+do_compile(#dtl_context{ is_compiling_dir=false, bin=Template }=Context) ->
+    compile_output(parse_template(Template, Context), Context);
+do_compile(#dtl_context{ is_compiling_dir=Dir }=Context) ->
+    erlydtl_beam_compiler:compile_dir(Dir, Context).
+
 
 compile_output(up_to_date, Context) -> Context;
 compile_output({ok, DjangoParseTree, CheckSum}, Context) ->

+ 1 - 0
src/erlydtl_compiler_utils.erl

@@ -113,6 +113,7 @@ print(_Verbosity, _Fmt, _Args, _Context) ->
 get_current_file(#treewalker{ context=Context }) ->
     get_current_file(Context);
 get_current_file(#dtl_context{ parse_trail=[File|_] }) -> File;
+get_current_file(#dtl_context{ is_compiling_dir=Dir }) when Dir =/= false -> Dir;
 get_current_file(#dtl_context{ doc_root=Root }) -> Root.
 
 add_error(Module, Error, #treewalker{ context=Context }=TreeWalker) ->

+ 7 - 2
test/erlydtl_eunit_testrunner.erl

@@ -60,8 +60,13 @@ run_compile(T) ->
             error_ok
     end.
 
-run_render(T) ->    
-    case (T#test.module):render(T#test.render_vars, T#test.render_opts) of
+run_render(#test{ renderer=Renderer }=T) ->
+    Output = if is_atom(Renderer) ->
+                     (T#test.module):Renderer(T#test.render_vars, T#test.render_opts);
+                is_function(Renderer) ->
+                     Renderer(T)
+             end,
+    case Output of
         {ok, O} ->
             B = iolist_to_binary(O),
             case T#test.output of

+ 28 - 3
test/erlydtl_test_defs.erl

@@ -1422,6 +1422,20 @@ all_test_defs() ->
                 "extends_path2", "trans", "extends2", "extends3",
                 "recursive_block", "extend_recursive_block", "missing",
                 "block_super"]
+      ]},
+     {"compile_dir",
+      [setup_compile(T)
+       || T <- [#test{
+                   title = "non-existing dir",
+                   source = {dir, "non-existing-made-up-dir"},
+                   renderer = fun(#test{ source={dir, Dir} }) -> Dir end,
+                   output = "non-existing-made-up-dir"
+                  },
+                #test{
+                   title = "path1",
+                   source = {dir, template_file(input, "path1")},
+                   renderer = base1
+                  }]
       ]}
     ].
 
@@ -1570,12 +1584,22 @@ setup_compile(_) ->
 
 
 expected(File) ->
-    case file:read_file(template_file(expect, File)) of
+    Filename = template_file(expect, File),
+    case file:read_file(Filename) of
         {ok, Data} -> Data;
-        _ -> fun (Data) -> file:write_file(template_file(expect, File), Data) end
+        _ -> fun (Data) ->
+                     ok = file:write_file(Filename, Data),
+                     io:format(
+                       user,
+                       "## Saved expected output for test ~p to ~p.~n"
+                       "   Verify the contents, as it is used to pass the test on subsequent test runs.~n"
+                       "~n",
+                       [File, Filename]),
+                     throw({verify_new_expected_output, Filename})
+             end
     end.
 
-setup(#test{ title = F }=T) ->
+setup(#test{ title = F, output=undefined }=T) ->
     {Vars, Opts, Result} =
         case setup(F) of
             {ok, V} -> {V, [], expected(F)};
@@ -1588,6 +1612,7 @@ setup(#test{ title = F }=T) ->
       render_opts = Opts,
       output = Result
      };
+setup(#test{}=T) -> T;
 setup("autoescape") ->
     RenderVars = [{var1, "<b>bold</b>"}],
     {ok, RenderVars};

+ 1 - 0
test/testrunner.hrl

@@ -6,6 +6,7 @@
           title = "<no title>",
           module = erly_test,
           source,
+          renderer = render,
           output,
           compile_opts = [report, return, {auto_escape, false}, force_recompile, {out_dir, false}],
           compile_vars = [],