Browse Source

Add more tests for load tag and related options (fixes #100, relates #137)

Andreas Stenius 11 years ago
parent
commit
c0af31f3b0

+ 4 - 4
src/erlydtl_beam_compiler.erl

@@ -92,13 +92,13 @@ format_error({write_file, Error}) ->
 format_error(compile_beam) ->
     "Failed to compile template to BEAM code";
 format_error({unknown_filter, Name, Arity}) ->
-    io_lib:format("Unknown filter '~s' (arity ~p)", [Name, Arity]);
+    io_lib:format("Unknown filter '~p' (arity ~p)", [Name, Arity]);
 format_error({filter_args, Name, {Mod, Fun}, Arity}) ->
-    io_lib:format("Wrong number of arguments to filter '~s' (~p:~p): ~p", [Name, Mod, Fun, Arity]);
+    io_lib:format("Wrong number of arguments to filter '~p' (~p:~p): ~p", [Name, Mod, Fun, Arity]);
 format_error({missing_tag, Name, {Mod, Fun}}) ->
-    io_lib:format("Custom tag '~s' not exported (~p:~p)", [Name, Mod, Fun]);
+    io_lib:format("Custom tag '~p' not exported (~p:~p)", [Name, Mod, Fun]);
 format_error({bad_tag, Name, {Mod, Fun}, Arity}) ->
-    io_lib:format("Invalid tag '~s' (~p:~p/~p)", [Name, Mod, Fun, Arity]);
+    io_lib:format("Invalid tag '~p' (~p:~p/~p)", [Name, Mod, Fun, Arity]);
 format_error({load_code, Error}) ->
     io_lib:format("Failed to load BEAM code: ~p", [Error]);
 format_error(Error) ->

+ 34 - 20
src/erlydtl_compiler_utils.erl

@@ -251,19 +251,26 @@ reset_parse_trail(ParseTrail, Context) ->
 load_library(Lib, Context) -> load_library(none, Lib, [], Context).
 load_library(Pos, Lib, Context) -> load_library(Pos, Lib, [], Context).
 
-load_library(Pos, Lib, Accept, #treewalker{ context=Context }=TreeWalker) ->
-    TreeWalker#treewalker{ context=load_library(Pos, Lib, Accept, Context) };
-load_library(Pos, Lib, Accept, Context) ->
+load_library(Pos, Lib, Which, #treewalker{ context=Context }=TreeWalker) ->
+    TreeWalker#treewalker{ context=load_library(Pos, Lib, Which, Context) };
+load_library(Pos, Lib, Which, Context) ->
     case lib_module(Lib, Context) of
         {ok, Mod} ->
             ?LOG_DEBUG(
                "~s: Load library '~s' from ~s ~p~n",
-               [get_current_file(Context), Lib, Mod, Accept], Context),
-            add_filters(
-              read_library(Mod, filters, Accept),
-              add_tags(
-                read_library(Mod, tags, Accept),
-                Context));
+               [get_current_file(Context), Lib, Mod, Which], Context),
+            Filters = read_library(Mod, filters, Which),
+            Tags = read_library(Mod, tags, Which),
+            Found = Filters ++ Tags,
+            Missing = lists:filter(
+                        fun (W) -> lists:keyfind(W, 1, Found) == false end,
+                        Which),
+            add_tags(
+              Tags,
+              add_filters(
+                Filters,
+                warn_missing(
+                  Missing, {Pos, Lib, Mod}, Context)));
         Error ->
             ?WARN({Pos, Error}, Context)
     end.
@@ -277,13 +284,14 @@ add_tags(Load, #dtl_context{ tags=Tags }=Context) ->
     Context#dtl_context{ tags=Load ++ Tags }.
 
 format_error({load_library, Name, Mod, Reason}) ->
-    io_lib:format("Failed to load library '~s' from '~s' (~s)", [Name, Mod, Reason]);
-format_error({library_version, Name, Mod, Version}) ->
-    io_lib:format("Unknown library version for '~s' from '~s': ~p", [Name, Mod, Version]);
+    io_lib:format("Failed to load library '~p' (~p): ~p", [Name, Mod, Reason]);
+format_error({load_from, Name, Mod, Tag}) ->
+    io_lib:format("'~p' not in library '~p' (~p)", [Tag, Name, Mod]);
 format_error({unknown_extension, Tag}) ->
     io_lib:format("Unhandled extension: ~p", [Tag]);
 format_error(Other) ->
-    io_lib:format("## Error description for ~p not implemented.", [Other]).
+    io_lib:format("## Sorry, error description for ~p not yet implemented.~n"
+                  "## Please report this so we can fix it.", [Other]).
 
 
 %%====================================================================
@@ -331,7 +339,7 @@ compose_error_desc({{Line, Col}=Pos, ErrorDesc}, Module)
   when is_integer(Line), is_integer(Col), is_atom(Module) ->
     {Pos, Module, ErrorDesc};
 compose_error_desc({Line, ErrorDesc}, Module)
-  when is_integer(Line) ->
+  when is_integer(Line); Line =:= none ->
     {Line, Module, ErrorDesc};
 compose_error_desc({{Line, Col}, Module, _}=ErrorDesc, _)
   when is_integer(Line), is_integer(Col), is_atom(Module) ->
@@ -339,6 +347,9 @@ compose_error_desc({{Line, Col}, Module, _}=ErrorDesc, _)
 compose_error_desc({Line, Module, _}=ErrorDesc, _)
   when is_integer(Line), is_atom(Module) ->
     ErrorDesc;
+compose_error_desc({none, Module, _}=ErrorDesc, _)
+  when is_atom(Module) ->
+    ErrorDesc;
 compose_error_desc({_, InfoList}=ErrorDesc, _)
   when is_list(InfoList) -> ErrorDesc;
 compose_error_desc(ErrorDesc, Module) ->
@@ -429,24 +440,27 @@ lib_module(Name, #dtl_context{ libraries=Libs }) ->
             if IsLib ->
                     case Mod:version() of
                         ?LIB_VERSION -> {ok, Mod};
-                        V -> {library_version, Name, Mod, V}
+                        V -> {load_library, Name, Mod, {version, V}}
                     end;
-               true -> {load_library, Name, Mod, "not a library"}
+               true -> {load_library, Name, Mod, behaviour}
             end;
         {error, Reason} ->
             {load_library, Name, Mod, Reason}
     end.
 
-read_library(Mod, Section, Accept) ->
+read_library(Mod, Section, Which) ->
     [{Name, lib_function(Mod, Fun)}
      || {Name, Fun} <- read_inventory(Mod, Section),
-        Accept =:= [] orelse lists:member(Name, Accept)
-    ].
+        Which =:= [] orelse lists:member(Name, Which)].
+
+warn_missing([], _, Context) -> Context;
+warn_missing([X|Xs], {Pos, Lib, Mod}=Info, Context) ->
+    warn_missing(Xs, Info, ?WARN({Pos, {load_from, Lib, Mod, X}}, Context)).
 
 lib_function(_, {Mod, Fun}) ->
     lib_function(Mod, Fun);
 lib_function(Mod, Fun) ->
-    %% TODO: we can check for lib function availability here.. (sanity check)
+    %% we could check for lib function availability here.. (sanity check)
     {Mod, Fun}.
 
 read_inventory(Mod, Section) ->

+ 9 - 0
tests/src/erlydtl_lib_testversion.erl

@@ -0,0 +1,9 @@
+-module(erlydtl_lib_testversion).
+-behaviour(erlydtl_library).
+
+-export([version/0, inventory/1]).
+
+version() -> invalid.
+
+inventory(filters) -> [];
+inventory(tags) -> [].

+ 89 - 28
tests/src/erlydtl_unittests.erl

@@ -1306,15 +1306,13 @@ tests() ->
       [{"no out dir warning",
         <<"foo bar">>,
         [], [], %% Vars, RenderOpts
-        %%[report], %% CompilerOpts
-        ?GRP_ERROR_REPORTING_COMPILER_OPTS,
+        ?GRP_ERROR_REPORTING_COMPILER_OPTS, %% CompilerOpts
         <<"foo bar">>, %% Output
         [error_info([no_out_dir])] %% Warnings
        },
        {"warnings as errors",
         <<"foo bar">>,
         [], [],
-        %%[report, warnings_as_errors],
         [warnings_as_errors|?GRP_ERROR_REPORTING_COMPILER_OPTS],
         {error, %% Output...
          [error_info([no_out_dir])], %% Errors
@@ -1324,13 +1322,11 @@ tests() ->
        {"illegal character",
         <<"{{{">>,
         [], [],
-        %%[report],
         ?GRP_ERROR_REPORTING_COMPILER_OPTS,
         {error,
          [error_info(
             [{{1,3},erlydtl_scanner,{illegal_char, ${}}] )],
-         []
-        }
+         []}
        },
        {"unexpected end of file - in code",
         <<"{{">>,
@@ -1339,8 +1335,7 @@ tests() ->
         {error,
          [error_info(
             [{{1,3},erlydtl_scanner,{eof, in_code}}] )],
-         []
-        }
+         []}
        },
        {"unexpected end of file - in comment",
         <<"{#">>,
@@ -1349,15 +1344,74 @@ tests() ->
         {error,
          [error_info(
             [{{1,3},erlydtl_scanner,{eof, in_comment}}] )],
-         []
-        }
+         []}
+       },
+       {"unknown library",
+        <<"{% load foo %}">>, [], [],
+        ?GRP_ERROR_REPORTING_COMPILER_OPTS,
+        <<>>,
+        [error_info(
+           [no_out_dir,
+            {{1,9},erlydtl_compiler_utils,{load_library,foo,foo,nofile}}
+           ])]
+       },
+       {"not a library",
+        <<"{% load foo %}">>, [], [],
+        [{libraries, [{foo, ?MODULE}]}|?GRP_ERROR_REPORTING_COMPILER_OPTS],
+        <<>>,
+        [error_info(
+           [no_out_dir,
+            {{1,9},erlydtl_compiler_utils,{load_library,foo,?MODULE,behaviour}}
+           ])]
+       },
+       {"library version",
+        <<"{% load foo %}">>, [], [],
+        [{libraries, [{foo, erlydtl_lib_testversion}]}|?GRP_ERROR_REPORTING_COMPILER_OPTS],
+        <<>>,
+        [error_info(
+           [no_out_dir,
+            {{1,9},erlydtl_compiler_utils,{load_library,foo,erlydtl_lib_testversion,{version,invalid}}}
+           ])]
+       },
+       {"not in library",
+        <<"{% load foo bar from test1 %}\n{{ \"w00t\"|reverse }}">>, [], [],
+        [{libraries, [{test1, erlydtl_lib_test1}]}|?GRP_ERROR_REPORTING_COMPILER_OPTS],
+        <<"\n">>,
+        [error_info(
+           [no_out_dir,
+            {{2,11},erlydtl_beam_compiler,{unknown_filter,reverse,1}},
+            {{1,22},erlydtl_compiler_utils,{load_from,test1,erlydtl_lib_test1,foo}},
+            {{1,22},erlydtl_compiler_utils,{load_from,test1,erlydtl_lib_test1,bar}}
+           ])]
+       },
+       {"pre load unknown library",
+        <<"{{ '123'|reverse }}">>, [], [],
+        [{default_libraries, [test1]}],
+        <<"">>,
+        [error_info(
+           [no_out_dir,
+            {{1,10},erlydtl_beam_compiler,{unknown_filter,reverse,1}},
+            {none,erlydtl_compiler_utils,{load_library,test1,test1,nofile}}
+           ])]
        }
       ]},
      {"load",
       [{"filter",
-        <<"{% load test1 %}{{ \"w00t\"|reverse }}">>, [], [],
+        <<"{% load test1 %}{{ \"1234\"|reverse }}">>, [], [],
+        [{libraries, [{test1, erlydtl_lib_test1}]}],
+        <<"4321">>
+       },
+       {"named",
+        <<"{% load reverse from test1 %}{{ \"abcd\"|reverse }}">>, [], [],
         [{libraries, [{test1, erlydtl_lib_test1}]}],
-        <<"t00w">>}
+        <<"dcba">>
+       },
+       {"pre loaded",
+        <<"{{ QWER|reverse }}">>, [{'QWER', "Qwerty"}], [],
+        [{default_libraries, [test1]},
+         {libraries, [{test1, erlydtl_lib_test1}]}],
+        <<"ytrewQ">>
+       }
       ]}
     ].
 
@@ -1474,24 +1528,24 @@ process_unit_test({Name, DTL, Vars, RenderOpts, CompilerOpts, Output, Warnings})
                                 {Output, Unexpected} ->
                                     test_fail(
                                       Name,
-                                      "Unexpected result with binary variables: ~n"
-                                      "Expected: ~p~n"
-                                      "Actual: ~p",
+                                      "Unexpected result with binary variables:~n"
+                                      "    Expected: ~p~n"
+                                      "    Actual  : ~p",
                                       [Output, Unexpected], TrB);
                                 {Unexpected, Output} ->
                                     test_fail(
                                       Name,
-                                      "Unexpected result with list variables: ~n"
-                                      "Expected: ~p~n"
-                                      "Actual: ~p",
+                                      "Unexpected result with list variables:~n"
+                                      "    Expected: ~p~n"
+                                      "    Actual  : ~p",
                                       [Output, Unexpected], TrB);
                                 {Unexpected1, Unexpected2} ->
                                     test_fail(
                                       Name,
-                                      "Unexpected result: ~n"
-                                      "Expected: ~p~n"
-                                      "Actual (list): ~p~n"
-                                      "Actual (binary): ~p",
+                                      "Unexpected result:~n"
+                                      "    Expected       : ~p~n"
+                                      "    Actual (list)  : ~p~n"
+                                      "    Actual (binary): ~p",
                                       [Output, Unexpected1, Unexpected2], TrB)
                             end;
                         {TrenderB, Output} ->
@@ -1509,13 +1563,17 @@ process_unit_test({Name, DTL, Vars, RenderOpts, CompilerOpts, Output, Warnings})
         {Tcompile, {ok, _, ActualWarnings}} ->
             test_fail(
               Name,
-              "Unexpected warnings: ~p~n"
-              "Expected: ~p",
-              [ActualWarnings, Warnings], [{compile, Tcompile}]);
+              "Unexpected warnings:~n"
+              "    Expected: ~p~n"
+              "    Actual  : ~p",
+              [Warnings, ActualWarnings], [{compile, Tcompile}]);
         {Tcompile, Output} -> test_pass([{compile, Tcompile}]);
         {Tcompile, Err} ->
-            test_fail(Name, "Compile error: ~p~nExpected: ~p",
-                      [Err, Output], [{compile, Tcompile}])
+            test_fail(Name,
+                      "Compile error:~n"
+                      "    Expected: ~p~n"
+                      "    Actual  : ~p",
+                      [Output, Err], [{compile, Tcompile}])
     end.
 
 
@@ -1560,11 +1618,14 @@ error_info(File, Ws, Mod) ->
     {File, [error_info(W, Mod) || W <- Ws]}.
 
 error_info({Line, ErrorDesc}, Mod)
-  when is_integer(Line) ->
+  when is_integer(Line); Line =:= none ->
   {Line, Mod, ErrorDesc};
 error_info({Line, Module, _}=ErrorDesc, _Mod)
   when is_integer(Line), is_atom(Module) ->
     ErrorDesc;
+error_info({none, Module, _}=ErrorDesc, _Mod)
+  when is_atom(Module) ->
+    ErrorDesc;
 error_info({{Line, Col}, Module, _}=ErrorDesc, _Mod)
   when is_integer(Line), is_integer(Col), is_atom(Module) ->
     ErrorDesc;