%% @author Bob Ippolito %% @copyright 2010 Mochi Media, Inc. %% %% Permission is hereby granted, free of charge, to any person obtaining a %% copy of this software and associated documentation files (the "Software"), %% to deal in the Software without restriction, including without limitation %% the rights to use, copy, modify, merge, publish, distribute, sublicense, %% and/or sell copies of the Software, and to permit persons to whom the %% Software is furnished to do so, subject to the following conditions: %% %% The above copyright notice and this permission notice shall be included in %% all copies or substantial portions of the Software. %% %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL %% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING %% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER %% DEALINGS IN THE SOFTWARE. %% @doc Workarounds for various cover deficiencies. -module(xpath_cover). -export([get_beam/1, get_abstract_code/1, get_clauses/2, clause_lookup_table/1]). -export([clause_lookup_table/2]). %% Internal get_beam(Module) -> {Module, Beam, _Path} = code:get_object_code(Module), Beam. get_abstract_code(Beam) -> {ok, {_Module, [{abstract_code, {raw_abstract_v1, L}}]}} = beam_lib:chunks(Beam, [abstract_code]), L. get_clauses(Function, Code) -> [L] = [Clauses || {function, _, FName, _, Clauses} <- Code, FName =:= Function], L. clause_lookup_table(Module, Function) -> clause_lookup_table( get_clauses(Function, get_abstract_code(get_beam(Module)))). clause_lookup_table(Clauses) -> lists:foldr(fun clause_fold/2, [], Clauses). clause_fold({clause, _, [InTerm], _Guards=[], [OutTerm]}, Acc) -> try [{erl_parse:normalise(InTerm), erl_parse:normalise(OutTerm)} | Acc] catch error:_ -> Acc end; clause_fold(_, Acc) -> Acc. %% %% Tests %% -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). foo_table(a) -> b; foo_table("a") -> <<"b">>; foo_table(123) -> {4, 3, 2}; foo_table([list]) -> []; foo_table([list1, list2]) -> [list1, list2, list3]; foo_table(ignored) -> some, code, ignored; foo_table(Var) -> Var. foo_table_test() -> T = clause_lookup_table(?MODULE, foo_table), [?assertEqual(V, foo_table(K)) || {K, V} <- T]. clause_lookup_table_test() -> ?assertEqual(b, foo_table(a)), ?assertEqual(ignored, foo_table(ignored)), ?assertEqual('Var', foo_table('Var')), ?assertEqual( [{a, b}, {"a", <<"b">>}, {123, {4, 3, 2}}, {[list], []}, {[list1, list2], [list1, list2, list3]}], clause_lookup_table(?MODULE, foo_table)). -endif.