1 # SPDX-License-Identifier: GPL-2.0-only
3 testsrc
:= $(top
)/tests
5 # Place the build output in one of two places depending on COV, so that code
6 # built with code coverage never mixes with code built without code coverage.
8 testobj
:= $(obj
)/coverage
10 testobj
:= $(obj
)/tests
12 coverage-dir
:= $(testobj
)/coverage_reports
14 cmockasrc
:= $(coreboottop
)/3rdparty
/cmocka
15 cmockaobj
:= $(objutil
)/cmocka
16 CMOCKA_LIB
:= $(cmockaobj
)/src
/libcmocka.so
20 TEST_DEFAULT_CONFIG
:= $(top
)/configs
/config.unit-tests
21 TEST_DOTCONFIG
:= $(testobj
)/.config
22 TEST_KCONFIG_AUTOHEADER
:= $(testobj
)/libpayload-config.src.h
23 TEST_KCONFIG_AUTOCONFIG
:= $(testobj
)/auto.conf
24 TEST_KCONFIG_DEPENDENCIES
:= $(testobj
)/auto.conf.cmd
25 TEST_KCONFIG_SPLITCONFIG
:= $(testobj
)/config
/
26 TEST_KCONFIG_TRISTATE
:= $(testobj
)/tristate.conf
27 TEST_KCONFIG_NEGATIVES
:= 1
28 TEST_KBUILD_KCONFIG
:= $(top
)/Kconfig
29 TEST_CONFIG_
:= CONFIG_LP_
33 TEST_CFLAGS
:= -include include/kconfig.h
34 TEST_CFLAGS
+= -include $(coreboottop
)/src
/commonlib
/bsd
/include/commonlib
/bsd
/compiler.h
35 TEST_CFLAGS
+= -Iinclude
-Iinclude
/mock
36 TEST_CFLAGS
+= -I
$(coreboottop
)/src
/commonlib
/bsd
/include
37 TEST_CFLAGS
+= -I
$(coreboottop
)/src
/commonlib
/include
38 TEST_CFLAGS
+= -I
$(dir $(TEST_KCONFIG_AUTOHEADER
))
39 TEST_CFLAGS
+= -I
$(VBOOT_SOURCE
)/firmware
/include
41 # Test specific includes
42 TEST_CFLAGS
+= -I
$(testsrc
)/include
43 TEST_CFLAGS
+= -I
$(cmockasrc
)/include
45 # Minimal subset of warnings and errors. Tests can be less strict than actual build.
46 TEST_CFLAGS
+= -Wall
-Wundef
-Wstrict-prototypes
-Wvla
47 TEST_CFLAGS
+= -Wwrite-strings
-Wno-trigraphs
-Wimplicit-fallthrough
48 TEST_CFLAGS
+= -Wstrict-aliasing
-Wshadow
-Werror
49 TEST_CFLAGS
+= -Wno-unknown-warning-option
-Wno-source-mgr
-Wno-main-return-type
51 TEST_CFLAGS
+= -std
=gnu11
-ffunction-sections
-fdata-sections
-fno-builtin
53 ifneq ($(filter-out 0,$(DEBUG
)),)
54 TEST_CFLAGS
+= -Og
-ggdb3
59 # Make unit-tests detectable by the code
60 TEST_CFLAGS
+= -D__TEST__
63 TEST_LDFLAGS
:= -L
$(dir $(CMOCKA_LIB
)) -lcmocka
-Wl
,-rpath
=$(dir $(CMOCKA_LIB
))
65 TEST_LDFLAGS
+= -Wl
,--gc-sections
67 # Disable userspace relocations
68 TEST_CFLAGS
+= -fno-pie
-fno-pic
69 TEST_LDFLAGS
+= -no-pie
72 TEST_CFLAGS
+= --coverage
73 TEST_LDFLAGS
+= --coverage
77 # Extra attributes for unit tests. Declated per each test. Only `srcs` is required.
78 attributes
:= cflags config mocks srcs
81 subdirs
:= tests
/crypto tests
/curses tests
/drivers tests
/gdb tests
/libc tests
/libcbfs
82 subdirs
+= tests
/liblz4 tests
/liblzma tests
/libpci
86 $(foreach attribute
,$(attributes
), \
87 $(eval
$(1)$(2)-$(attribute
) += $($(2)-$(attribute
))))
88 $(foreach attribute
,$(attributes
), \
89 $(eval
$(2)-$(attribute
) := ))
92 # Copy attributes of one test to another
93 # $1 - input test name
94 # $2 - output test name
95 copy-test
= $(foreach attribute
,$(attributes
), \
96 $(eval
$(strip $(2))-$(attribute
) := $($(strip $(1))-$(attribute
))))
98 $(call add-special-class
,tests
)
99 $(call evaluate_subdirs
)
101 # Create actual targets for unit test binaries
103 define TEST_CC_template
105 # Generate custom config.h redefining given config symbols, and declaring mocked
106 # functions weak. It is important that the compiler already sees that they are
107 # weak (and they aren't just turned weak at a later stage) to prevent certain
108 # optimizations that would break if the function gets replaced. (For clang this
109 # file needs to be marked `system_header` to prevent it from warning about
110 # `#pragma weak` entries without a matching function declaration, since there is
111 # no -Wno-xxx commandline for that.)
112 $(1)-config-file
:= $(testobj
)/$(1)/libpayload-config.h
113 $$($(1)-config-file
): $(TEST_KCONFIG_AUTOHEADER
)
114 mkdir
-p
$$(dir $$@
);
115 printf
'// File generated by tests/Makefile.mk\n// Do not change\n' > $$@
;
116 printf
'#ifndef TEST_LIBPAYLOAD_CONFIG_H_\n' >> $$@
;
117 printf
'#define TEST_LIBPAYLOAD_CONFIG_H_\n' >> $$@
;
118 printf
'#include <%s>\n\n' "$(notdir $(TEST_KCONFIG_AUTOHEADER))" >> $$@
;
119 for kv in
$$($(1)-config
); do \
120 key
="`echo $$$$kv | cut -d '=' -f -1`"; \
121 value
="`echo $$$$kv | cut -d '=' -f 2-`"; \
122 printf
'#undef %s\n' "$$$$key" >> $$@
; \
123 printf
'#define %s %s\n\n' "$$$$key" "$$$$value" >> $$@
; \
125 printf
'#ifdef __clang__\n' >> $$@
;
126 printf
'#pragma clang system_header\n' >> $$@
;
127 printf
'#endif\n\n' >> $$@
;
128 printf
'#ifdef __TEST_SRCOBJ__\n' >> $$@
;
129 for m in
$$($(1)-mocks
); do \
130 printf
'#pragma weak %s\n' "$$$$m" >> $$@
; \
132 printf
'#endif\n\n' >> $$@
;
133 printf
'#endif\n' >> $$@
;
135 $($(1)-objs
): TEST_CFLAGS
+= -I
$$(dir $$($(1)-config-file
)) \
136 -D__TEST_NAME__
=\"$(subst /,_
,$(1))\"
138 # Give us a way to distinguish between libpayload source files and test files in the code.
139 $($(1)-srcobjs
): TEST_CFLAGS
+= -D__TEST_SRCOBJ__
141 # Compile sources and apply mocking/wrapping for selected symbols.
142 # For each listed mock add new symbol with prefix `__real_`,
143 # pointing to the same section:address. This will keep original
144 # function accessible if required.
145 $($(1)-objs
): $(testobj
)/$(1)/%.o
: $$$$*.c
$$($(1)-config-file
)
147 $(HOSTCC
) $$(TEST_CFLAGS
) $($(1)-cflags) -MMD \
148 -MF
$$(basename $$@
).d
-MT
$$@
-c
$$< -o
$$@.orig
149 objcopy_wrap_flags
=''; \
150 for sym in
$$($(1)-mocks
); do \
151 sym_line
="$$$$($(HOSTOBJDUMP) -t $$@.orig \
152 | grep -E "[0-9a-fA-F
]+\\s
+w
\\s
+F
\\s
+.
*\\s
+$$$$sym$$$$")"; \
153 if
[ ! -z
"$$$$sym_line" ] ; then \
154 addr
="$$$$(echo "$$$$sym_line" | awk '{ print $$$$1 }')"; \
155 section
="$$$$(echo "$$$$sym_line" | awk '{ print $$$$(NF - 2) }')"; \
156 objcopy_wrap_flags
="$$$$objcopy_wrap_flags --add-symbol __real_$$$${sym}=$$$${section}:0x$$$${addr},function,global"; \
159 $(HOSTOBJCOPY
) $$@.orig
$$$$objcopy_wrap_flags $$@
161 $($(1)-bin
): $($(1)-objs
) $(CMOCKA_LIB
)
162 $(HOSTCC
) $$^
$($(1)-cflags) $$(TEST_LDFLAGS
) -o
$$@
166 $(foreach test,$(alltests
), \
167 $(eval
$(test)-srcobjs
:= $(addprefix $(testobj
)/$(test)/, \
168 $(patsubst %.c
,%.o
,$(filter-out tests
/%,$($(test)-srcs
))))) \
169 $(eval
$(test)-objs
:= $(addprefix $(testobj
)/$(test)/, \
170 $(patsubst %.c
,%.o
,$($(test)-srcs
)))) \
171 $(eval
$(test)-bin
:= $(testobj
)/$(test)/run
))
172 $(foreach test,$(alltests
), \
173 $(eval
$(call TEST_CC_template
,$(test))))
174 $(foreach test,$(alltests
), \
175 $(eval all-test-objs
+= $($(test)-objs
)) \
176 $(eval test-bins
+= $($(test)-bin
)))
178 DEPENDENCIES
+= $(addsuffix .d
,$(basename $(all-test-objs
)))
179 -include $(DEPENDENCIES
)
183 echo
"*** Building CMOCKA ***"
184 mkdir
-p
$(cmockaobj
)
185 cd
$(cmockaobj
) && $(CMAKE
) $(abspath
$(cmockasrc
))
186 $(MAKE
) -C
$(cmockaobj
)
191 cp
$(TEST_DEFAULT_CONFIG
) $(TEST_DOTCONFIG
)
193 $(TEST_KCONFIG_AUTOHEADER
): TEST_KCONFIG_FLAGS
:= DOTCONFIG
=$(TEST_DOTCONFIG
) \
194 KCONFIG_AUTOHEADER
=$(TEST_KCONFIG_AUTOHEADER
) \
195 KCONFIG_AUTOCONFIG
=$(TEST_KCONFIG_AUTOCONFIG
) \
196 KCONFIG_DEPENDENCIES
=$(TEST_KCONFIG_DEPENDENCIES
) \
197 KCONFIG_SPLITCONFIG
=$(TEST_KCONFIG_SPLITCONFIG
) \
198 KCONFIG_TRISTATE
=$(TEST_KCONFIG_TRISTATE
) \
199 KCONFIG_NEGATIVES
=$(TEST_KCONFIG_NEGATIVES
) \
200 KBUILD_KCONFIG
=$(TEST_KBUILD_KCONFIG
) \
201 KBUILD_DEFCONFIG
=$(TEST_DEFAULT_CONFIG
) \
202 CONFIG_
=$(TEST_CONFIG_
)
204 $(TEST_KCONFIG_AUTOHEADER
): $(TEST_DOTCONFIG
) $(objk
)/conf
206 $(MAKE
) $(TEST_KCONFIG_FLAGS
) olddefconfig V
=$(V
)
207 $(MAKE
) $(TEST_KCONFIG_FLAGS
) syncconfig V
=$(V
)
209 $(TEST_KCONFIG_AUTOCONFIG
): $(TEST_KCONFIG_AUTOHEADER
)
212 .PHONY
: $(alltests
) $(addprefix clean-
,$(alltests
)) $(addprefix try-
,$(alltests
))
213 .PHONY
: $(addprefix build-
,$(alltests
)) $(addprefix run-
,$(alltests
))
214 .PHONY
: unit-tests build-unit-tests run-unit-tests clean-unit-tests
215 .PHONY
: junit.xml-unit-tests clean-junit.xml-unit-tests
217 ifeq ($(JUNIT_OUTPUT
),y
)
218 $(addprefix run-
,$(alltests
)): export CMOCKA_MESSAGE_OUTPUT
=xml
219 $(addprefix run-
,$(alltests
)): export CMOCKA_XML_FILE
=$(testobj
)/junit-libpayload-
%g.xml
222 $(addprefix run-
,$(alltests
)): run-
%: $$(%-bin
)
223 rm -f
$(testobj
)/junit-libpayload-
$(subst /,_
,$(patsubst $(testobj
)/%/,%,$(dir $^
)))\
(*\
).xml
224 rm -f
$(testobj
)/$(subst /,_
,$^
).failed
225 -$^ || echo failed
> $(testobj
)/$(subst /,_
,$^
).failed
227 $(addprefix build-
,$(alltests
)): build-
%: $$(%-bin
)
229 $(alltests
): run-
$$(@
)
231 $(addprefix try-
,$(alltests
)): try-
%: clean-
% $(CMOCKA_LIB
) $(TEST_KCONFIG_AUTOCONFIG
)
232 mkdir
-p
$(testobj
)/$*
233 echo
"<testcase classname='libpayload_build_unit_test' name='$*'>" >> $(testobj
)/$*.tmp
; \
234 $(MAKE
) V
=$(V
) Q
=$(Q
) COV
=$(COV
) JUNIT_OUTPUT
=y
"build-$*" >> $(testobj
)/$*.tmp
.2 2>&1 \
235 && type
="system-out" || type
="failure"; \
236 if
[ $$type = "failure" ]; then \
237 echo
"<failure type='buildFailed'>" >> $(testobj
)/$*.tmp
; \
239 echo
"<$$type>" >> $(testobj
)/$*.tmp
; \
241 echo
'<![CDATA[' >> $(testobj
)/$*.tmp
; \
242 cat
$(testobj
)/$*.tmp
.2 >> $(testobj
)/$*.tmp
; \
243 echo
"]]></$$type>" >> $(testobj
)/$*.tmp
; \
244 rm -f
$(testobj
)/$*.tmp
.2; \
245 echo
"</testcase>" >> $(testobj
)/$*.tmp
; \
246 if
[ $$type != 'failure' ]; then \
247 $(MAKE
) V
=$(V
) Q
=$(Q
) COV
=$(COV
) JUNIT_OUTPUT
=y
"run-$*"; \
251 TESTS_BUILD_XML_FILE
:= $(testobj
)/junit-libpayload-tests-build.xml
253 $(TESTS_BUILD_XML_FILE
): clean-junit.xml-unit-tests
$(addprefix try-
,$(alltests
))
255 echo
'<?xml version="1.0" encoding="utf-8"?><testsuite>' > $@
256 for tst in
$(alltests
); do \
257 cat
$(testobj
)/$$tst.tmp
>> $@
; \
259 echo
"</testsuite>" >> $@
261 junit.xml-unit-tests
: $(TESTS_BUILD_XML_FILE
)
263 clean-junit.xml-unit-tests
:
264 rm -f
$(TESTS_BUILD_XML_FILE
)
267 # Build a code coverage report by collecting all the gcov files into a single
268 # report. If COV is not set, this might be a user error, and they're trying
269 # to generate a coverage report without first having built and run the code
270 # with code coverage. absence of COV=1 will be corrected.
272 .PHONY
: coverage-report clean-coverage-report
276 lcov
-o
$(testobj
)/tests.
info -c
-d
$(testobj
) --exclude
'$(testsrc)/*'
277 genhtml
-q
-o
$(coverage-dir
) -t
"coreboot unit tests" -s
$(testobj
)/tests.
info
279 clean-coverage-report
:
280 rm -Rf
$(coverage-dir
)
283 COV
=1 V
=$(V
) $(MAKE
) coverage-report
285 clean-coverage-report
:
286 COV
=1 V
=$(V
) $(MAKE
) clean-coverage-report
289 unit-tests
: build-unit-tests run-unit-tests
291 build-unit-tests
: $(test-bins
)
293 run-unit-tests
: $(alltests
)
294 if
[ `find $(testobj) -name '*.failed' | wc -l` -gt
0 ]; then \
295 echo
"**********************"; \
296 echo
" TESTS FAILED"; \
297 echo
"**********************"; \
300 echo
"**********************"; \
301 echo
" ALL TESTS PASSED"; \
302 echo
"**********************"; \
306 $(addprefix clean-
,$(alltests
)): clean-
%:
314 for t in
$(sort $(alltests
)); do \
318 help-unit-tests help
::
319 @echo
'*** libpayload unit-tests targets ***'
320 @echo
' Use "COV=1 make [target]" to enable code coverage for unit tests'
321 @echo
' unit-tests - Run all unit-tests from tests/'
322 @echo
' clean-unit-tests - Remove unit-tests build artifacts'
323 @echo
' list-unit-tests - List all unit-tests'
324 @echo
' <unit-test> - Build and run single unit-test'
325 @echo
' clean-<unit-test> - Remove single unit-test build artifacts'
326 @echo
' coverage-report - Generate a code coverage report'
327 @echo
' clean-coverage-report - Remove the code coverage report'