summaryrefslogtreecommitdiff
path: root/FreeRTOS/Test/CMock/testdir.mk
blob: 139cae80ab92d855ce81249c693fedc2beed48c6 (plain)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# Indent with spaces
.RECIPEPREFIX := $(.RECIPEPREFIX) $(.RECIPEPREFIX)

# define the name for this test's output files
ifdef SUITE
EXEC_PREFIX     :=  $(PROJECT)_$(SUITE)
else
EXEC_PREFIX     :=  $(PROJECT)
endif

# Define directory paths

ifdef SUITE
PROJECT_DIR     :=  $(abspath ../)
else
PROJECT_DIR     :=  $(abspath .)
endif

SUITE_DIR       :=  $(abspath .)

ifdef SUITE
SCRATCH_DIR     :=  $(GENERATED_DIR)/$(PROJECT)/$(SUITE)
else
SCRATCH_DIR     :=  $(GENERATED_DIR)/$(PROJECT)
endif

MOCKS_DIR       :=  $(SCRATCH_DIR)/mocks
PROJ_DIR        :=  $(SCRATCH_DIR)/proj

# Define mock details
MOCK_FILES      :=  $(notdir $(MOCK_FILES_FP))
MOCK_HDR        :=  $(addprefix mock_,$(MOCK_FILES))
MOCK_SRC        :=  $(addprefix mock_,$(MOCK_FILES:.h=.c))
MOCK_OBJ        :=  $(addprefix mock_,$(MOCK_FILES:.h=.o))
MOCK_HDR_LIST   :=  $(addprefix $(MOCKS_DIR)/,$(MOCK_HDR))
MOCK_SRC_LIST   :=  $(addprefix $(MOCKS_DIR)/,$(MOCK_SRC))
MOCK_OBJ_LIST   :=  $(addprefix $(SCRATCH_DIR)/,$(MOCK_OBJ))
CFLAGS          +=  -I$(MOCKS_DIR)

# Kernel files under test
PROJ_SRC_LIST   :=  $(addprefix $(KERNEL_DIR)/,$(PROJECT_SRC))
PROJ_PP_LIST    :=  $(addprefix $(PROJ_DIR)/,$(PROJECT_SRC:.c=.i))
PROJ_OBJ_LIST   :=  $(addprefix $(PROJ_DIR)/,$(PROJECT_SRC:.c=.o))
PROJ_GCDA_LIST  :=  $(PROJ_OBJ_LIST:.o=.gcda)

# Unit test files
SUITE_OBJ_LIST  :=  $(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:.c=.o))
RUNNER_SRC_LIST :=  $(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:_utest.c=_utest_runner.c))
RUNNER_OBJ_LIST :=  $(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:_utest.c=_utest_runner.o))

# Support files
SF_OBJ_LIST     :=  $(addprefix $(SCRATCH_DIR)/sf_,$(SUITE_SUPPORT_SRC:.c=.o))
DEPS_OBJ_LIST   :=  $(addprefix $(SCRATCH_DIR)/dep_,$(PROJECT_DEPS_SRC:.c=.o))
EXECS           :=  $(addprefix $(EXEC_PREFIX)_,$(SUITE_UT_SRC:.c=))
EXEC_LIST       :=  $(addprefix $(BIN_DIR)/,$(EXECS))
LCOV_LIST       :=  $(addsuffix .info,$(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:.c=)))
COVINFO_INITIAL :=  $(SCRATCH_DIR)/$(EXEC_PREFIX)_initial.info
COVINFO_COMBINE :=  $(SCRATCH_DIR)/$(EXEC_PREFIX)_combined.info
COVINFO         :=  $(abspath $(SCRATCH_DIR)/..)/$(EXEC_PREFIX).info
LIBS_LIST       :=  $(foreach lib, $(LIBS), $(LIB_DIR)/$(lib).so)

# Coverage related options
GCC_COV_OPTS    :=  -fprofile-arcs -ftest-coverage -fprofile-generate
GCOV_OPTS       :=  --unconditional-branches --branch-probabilities
COV_REPORT_DIR  :=  $(SCRATCH_DIR)/coverage

.PHONY: all clean run gcov bin lcov lcovhtml libs

# Prevent deletion of intermediate files
NO_DELETE : $(MOCK_HDR_LIST) $(MOCK_SRC_LIST) $(MOCK_OBJ_LIST)      \
            $(DEPS_OBJ_LIST) $(SF_OBJ_LIST) $(EXEC_LIST)            \
            $(PROJ_PP_LIST) $(PROJ_OBJ_LIST) $(PROJ_GCDA_LIST)      \
            $(SUITE_OBJ_LIST) $(RUNNER_SRC_LIST) $(RUNNER_OBJ_LIST) \
            $(COVINFO) $(LCOV_LIST)

# Cases that run test binaries cannot be run in parallel.
.NOTPARALLEL : $(COVINFO) $(LCOV_LIST) $(PROJ_GCDA_LIST)

.DEFAULT_GOAL := run

# Generate gcov files by default
run : gcov

gcov : $(PROJ_GCDA_LIST)

clean:
    rm -rf $(SCRATCH_DIR)
    rm -rf $(EXEC_LIST)
    rm -rf $(COVINFO)

$(LIBS_LIST) :
    make -C $(UT_ROOT_DIR) libs

define run-test
$(1)

endef

# Run and append to gcov data files
$(PROJ_GCDA_LIST) : $(EXEC_LIST)
    rm -f $(PROJ_DIR)/*.gcda
    mkdir -p $(BIN_DIR)
    # run each test case
    $(foreach bin,$^,$(call run-test,$(bin)))

# Run and generate lcov
lcov: $(COVINFO)

lcovhtml : $(COVINFO)
    mkdir -p $(COV_REPORT_DIR)
    genhtml $(COVINFO) $(LCOV_OPTS) --output-directory $(COV_REPORT_DIR)

bin: $(EXEC_LIST)

# Generate _mock.c / .h files
$(MOCK_HDR_LIST) $(MOCK_SRC_LIST) : $(PROJECT_DIR)/$(PROJECT).yml $(MOCK_FILES_FP)
    mkdir -p $(SCRATCH_DIR) $(MOCKS_DIR)
    cd $(SCRATCH_DIR) && \
        ruby $(CMOCK_EXEC_DIR)/cmock.rb -o$(PROJECT_DIR)/$(PROJECT).yml \
        $(MOCK_FILES_FP)

# Generate callgraph for coverage filtering
$(PROJ_DIR)/callgraph.json : $(PROJ_SRC_LIST)
    mkdir -p $(PROJ_DIR)
    python3 $(UT_ROOT_DIR)/tools/callgraph.py --out $@ $^

# preprocess proj files to expand macros for coverage
$(PROJ_DIR)/%.i : $(KERNEL_DIR)/%.c
    mkdir -p $(PROJ_DIR)
    $(CC) -E $< $(CPPFLAGS) $(CFLAGS) -o $@

# compile the project objects with coverage instrumented
$(PROJ_DIR)/%.o : $(PROJ_DIR)/%.i
    $(CC) -c $< $(CPPFLAGS) $(CFLAGS) $(INCLUDE_DIR) $(GCC_COV_OPTS) -o $@

# Build mock objects
$(SCRATCH_DIR)/mock_%.o : $(MOCKS_DIR)/mock_%.c
    $(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@

# compile unit tests
$(SCRATCH_DIR)/%_utest.o : $(SUITE_DIR)/%_utest.c $(MOCK_HDR_LIST) $(LIBS_LIST)
    mkdir -p $(SCRATCH_DIR)
    $(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@

# compile support files
$(SCRATCH_DIR)/sf_%.o : $(PROJECT_DIR)/%.c $(MOCK_HDR_LIST)
    mkdir -p $(SCRATCH_DIR)
    $(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@

# compile c files that are needed by PROJ but not mocked
$(SCRATCH_DIR)/dep_%.o : $(KERNEL_DIR)/%.c
    mkdir -p $(SCRATCH_DIR)
    $(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@

# generate a test runner for each test file
$(SCRATCH_DIR)/%_utest_runner.c : $(SUITE_DIR)/%_utest.c
    mkdir -p $(SCRATCH_DIR)
    ruby $(UNITY_BIN_DIR)/generate_test_runner.rb\
        $(PROJECT_DIR)/$(PROJECT).yml $< $@

# compile test runner
$(SCRATCH_DIR)/%_utest_runner.o : $(SCRATCH_DIR)/%_utest_runner.c
    mkdir -p $(SCRATCH_DIR)
    $(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@

# Link the _utest binary
$(EXEC_LIST) : $(BIN_DIR)/$(EXEC_PREFIX)_%_utest : $(SCRATCH_DIR)/%_utest.o         \
                                                   $(SCRATCH_DIR)/%_utest_runner.o  \
                                                   $(SF_OBJ_LIST) $(MOCK_OBJ_LIST)  \
                                                   $(PROJ_OBJ_LIST) $(LIBS_LIST)    \
                                                   $(DEPS_OBJ_LIST)
    mkdir -p $(BIN_DIR)
    $(CC) $< $(subst .o,_runner.o,$<) $(SF_OBJ_LIST) $(DEPS_OBJ_LIST) \
        $(MOCK_OBJ_LIST) $(PROJ_OBJ_LIST) $(LDFLAGS) -o $@

# Generate baseline inital coverage data from .gcno file
$(SCRATCH_DIR)/$(EXEC_PREFIX)_initial.info : $(PROJ_OBJ_LIST)
    lcov $(LCOV_OPTS) --capture --initial --directory $(PROJ_DIR) -o $@

# Run the test runner and genrate a filtered gcov.json.gz file
$(SCRATCH_DIR)/%_utest.info : $(BIN_DIR)/$(EXEC_PREFIX)_%_utest \
                              $(PROJ_DIR)/callgraph.json
    # Remove any existing coverage data
    rm -f $(PROJ_DIR)/*.gcda

    # run the testrunner
    $<

    # Gather coverage into a json.gz file
    gcov $(GCOV_OPTS) $(foreach src,$(PROJECT_SRC),$(PROJ_DIR)/$(src:.c=.gcda)) \
         --json-format --stdout | gzip > $(subst .info,.json.gz,$@)

    # Filter coverage based on tags in unit test file
    $(TOOLS_DIR)/filtercov.py --in $(subst .info,.json.gz,$@)   \
                              --map $(PROJ_DIR)/callgraph.json  \
                              --test $(SUITE_DIR)/$*_utest.c    \
                              --format lcov                     \
                              --out $@
    -lcov $(LCOV_OPTS) --summary $@

    # Remove temporary files
    rm -f $(subst .info,.json.gz,$@)
    rm -f $(PROJ_GCDA_LIST)

# Combine lcov from each test bin into one lcov info file for the suite
$(COVINFO_COMBINE) : $(LCOV_LIST)
    lcov $(LCOV_OPTS) -o $@ $(foreach cov,$(LCOV_LIST),--add-tracefile $(cov) )

# Add baseline / initial coverage generated by gcc to point out untagged functions
$(COVINFO) : $(COVINFO_COMBINE) $(COVINFO_INITIAL)
    lcov $(LCOV_OPTS) -o $@ --add-tracefile $(COVINFO_INITIAL) --add-tracefile $(COVINFO_COMBINE)