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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
# Copyright 2015, Viktor Söderqvist <[email protected]>
# This file is part of erlang.mk and subject to the terms of the ISC License.
COVER_REPORT_DIR = cover
# utility variables for representing special symbols
empty :=
space := $(empty) $(empty)
comma := ,
# Hook in coverage to eunit
ifdef COVER
ifdef EUNIT_RUN
EUNIT_RUN_BEFORE += -eval \
'case cover:compile_beam_directory("ebin") of \
{error, _} -> halt(1); \
_ -> ok \
end.'
EUNIT_RUN_AFTER += -eval 'cover:export("eunit.coverdata").'
endif
endif
# Hook in coverage to ct
ifdef COVER
ifdef CT_RUN
# All modules in 'ebin'
COVER_MODS = $(notdir $(basename $(shell echo ebin/*.beam)))
test-build:: $(TEST_DIR)/ct.cover.spec
$(TEST_DIR)/ct.cover.spec:
@echo Cover mods: $(COVER_MODS)
$(gen_verbose) printf "%s\n" \
'{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \
'{export,"$(CURDIR)/ct.coverdata"}.' > $@
CT_RUN += -cover $(TEST_DIR)/ct.cover.spec
endif
endif
# Core targets
ifdef COVER
ifneq ($(COVER_REPORT_DIR),)
tests::
@$(MAKE) make --no-print-directory cover-report
endif
endif
clean:: coverdata-clean
ifneq ($(COVER_REPORT_DIR),)
distclean:: cover-report-clean
endif
help::
@printf "%s\n" "" \
"Cover targets:" \
" cover-report Generate a HTML coverage report from previously collected" \
" cover data." \
" all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \
"" \
"If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \
"target tests additionally generates a HTML coverage report from the combined" \
"coverdata files from each of these testing tools. HTML reports can be disabled" \
"by setting COVER_REPORT_DIR to empty."
# Plugin specific targets
COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata))
.PHONY: coverdata-clean
coverdata-clean:
$(gen_verbose) rm -f *.coverdata ct.cover.spec
# Merge all coverdata files into one.
all.coverdata: $(COVERDATA)
$(gen_verbose) $(ERL) -eval ' \
$(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \
cover:export("$@"), halt(0).'
# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to
# empty if you want the coverdata files but not the HTML report.
ifneq ($(COVER_REPORT_DIR),)
.PHONY: cover-report-clean cover-report
cover-report-clean:
$(gen_verbose) rm -rf $(COVER_REPORT_DIR)
ifeq ($(COVERDATA),)
cover-report:
else
# Modules which include eunit.hrl always contain one line without coverage
# because eunit defines test/0 which is never called. We compensate for this.
EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \
grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \
| sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq))
define cover_report.erl
$(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),)
Ms = cover:imported_modules(),
[cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M)
++ ".COVER.html", [html]) || M <- Ms],
Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms],
EunitHrlMods = [$(EUNIT_HRL_MODS)],
Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of
true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report],
TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]),
TotalN = lists:sum([N || {_, {_, N}} <- Report1]),
TotalPerc = round(100 * TotalY / (TotalY + TotalN)),
{ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]),
io:format(F, "<!DOCTYPE html><html>~n"
"<head><meta charset=\"UTF-8\">~n"
"<title>Coverage report</title></head>~n"
"<body>~n", []),
io:format(F, "<h1>Coverage</h1>~n<p>Total: ~p%</p>~n", [TotalPerc]),
io:format(F, "<table><tr><th>Module</th><th>Coverage</th></tr>~n", []),
[io:format(F, "<tr><td><a href=\"~p.COVER.html\">~p</a></td>"
"<td>~p%</td></tr>~n",
[M, M, round(100 * Y / (Y + N))]) || {M, {Y, N}} <- Report1],
How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))",
Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")",
io:format(F, "</table>~n"
"<p>Generated using ~s and erlang.mk on ~s.</p>~n"
"</body></html>", [How, Date]),
halt().
endef
cover-report:
$(gen_verbose) mkdir -p $(COVER_REPORT_DIR)
$(gen_verbose) $(call erlang,$(cover_report.erl))
endif
endif # ifneq ($(COVER_REPORT_DIR),)
|