1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
%% @author Bob Ippolito <bob@mochimedia.com>
%% @copyright 2010 Mochi Media, Inc.
%% @doc Workarounds for various cover deficiencies.
-module(mochiweb_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
%%
-include_lib("eunit/include/eunit.hrl").
-ifdef(TEST).
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.
|