summaryrefslogtreecommitdiff
path: root/deps/meck/src/meck_cover.erl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/meck/src/meck_cover.erl')
-rw-r--r--deps/meck/src/meck_cover.erl110
1 files changed, 110 insertions, 0 deletions
diff --git a/deps/meck/src/meck_cover.erl b/deps/meck/src/meck_cover.erl
new file mode 100644
index 00000000..da8888c8
--- /dev/null
+++ b/deps/meck/src/meck_cover.erl
@@ -0,0 +1,110 @@
+%%==============================================================================
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+
+%% @doc Module containing functions needed by meck to integrate with cover.
+
+-module(meck_cover).
+
+%% Interface exports
+-export([compile_beam/2]).
+-export([rename_module/2]).
+
+%%==============================================================================
+%% Interface exports
+%%==============================================================================
+
+%% @doc Enabled cover on `<name>_meck_original'.
+compile_beam(OriginalMod, Bin) ->
+ alter_cover(),
+ {ok, _} = cover:compile_beam(OriginalMod, Bin).
+
+%% @doc Given a cover file `File' exported by `cover:export' overwrite
+%% the module name with `Name'.
+rename_module(File, Name) ->
+ NewTerms = change_cover_mod_name(read_cover_file(File), Name),
+ write_terms(File, NewTerms),
+ ok.
+
+%%==============================================================================
+%% Internal functions
+%%==============================================================================
+
+%% @private
+%%
+%% @doc Alter the cover BEAM module to export some of it's private
+%% functions. This is done for two reasons:
+%%
+%% 1. Meck needs to alter the export analysis data on disk and
+%% therefore needs to understand this format. This is why `get_term'
+%% and `write' are exposed.
+%%
+%% 2. In order to avoid creating temporary files meck needs direct
+%% access to `compile_beam/2' which allows passing a binary.
+alter_cover() ->
+ case lists:member({compile_beam,2}, cover:module_info(exports)) of
+ true ->
+ ok;
+ false ->
+ Beam = meck_mod:beam_file(cover),
+ AbsCode = meck_mod:abstract_code(Beam),
+ Exports = [{compile_beam, 2}, {get_term, 1}, {write, 2}],
+ AbsCode2 = meck_mod:add_exports(Exports, AbsCode),
+ _Bin = meck_mod:compile_and_load_forms(AbsCode2),
+ ok
+ end.
+
+change_cover_mod_name(CoverTerms, Name) ->
+ {_, Terms} = lists:foldl(fun change_name_in_term/2, {Name,[]}, CoverTerms),
+ Terms.
+
+change_name_in_term({file, Mod, File}, {Name, Terms}) ->
+ Term2 = {file, Name, replace_string(File, Mod, Name)},
+ {Name, [Term2|Terms]};
+change_name_in_term({Bump={bump,_,_,_,_,_},_}=Term, {Name, Terms}) ->
+ Bump2 = setelement(2, Bump, Name),
+ Term2 = setelement(1, Term, Bump2),
+ {Name, [Term2|Terms]};
+change_name_in_term({_Mod,Clauses}, {Name, Terms}) ->
+ Clauses2 = lists:foldl(fun change_name_in_clause/2, {Name, []}, Clauses),
+ Term2 = {Name, Clauses2},
+ {Name, [Term2|Terms]}.
+
+change_name_in_clause(Clause, {Name, NewClauses}) ->
+ {Name, [setelement(1, Clause, Name)|NewClauses]}.
+
+replace_string(File, Old, New) ->
+ Old2 = atom_to_list(Old),
+ New2 = atom_to_list(New),
+ re:replace(File, Old2, New2, [{return, list}]).
+
+read_cover_file(File) ->
+ {ok, Fd} = file:open(File, [read, binary, raw]),
+ Terms = get_terms(Fd, []),
+ ok = file:close(Fd),
+ Terms.
+
+get_terms(Fd, Terms) ->
+ case cover:get_term(Fd) of
+ eof -> Terms;
+ Term -> get_terms(Fd, [Term|Terms])
+ end.
+
+write_terms(File, Terms) ->
+ {ok, Fd} = file:open(File, [write, binary, raw]),
+ lists:foreach(write_term(Fd), Terms),
+ ok.
+
+write_term(Fd) ->
+ fun(Term) -> cover:write(Term, Fd) end.
+