libpayload: Add unit-tests framework and first test case
This commit adds a unit-tests framework ported from coreboot, and test for drivers/speaker. Usage of the unit-tests framework is same as for the coreboot one. Change-Id: Iaa94ee4dcdc3f74af830113813df0e8fb0b31e4f Signed-off-by: Jakub Czapiga <jacz@semihalf.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/58242 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org> Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
		
				
					committed by
					
						 Felix Held
						Felix Held
					
				
			
			
				
	
			
			
			
						parent
						
							e8b6b07bfc
						
					
				
				
					commit
					12ae850dfc
				
			| @@ -114,18 +114,36 @@ ARCH-$(CONFIG_LP_ARCH_ARM64)   := arm64 | ||||
| ARCH-$(CONFIG_LP_ARCH_X86)     := x86_32 | ||||
| ARCH-$(CONFIG_LP_ARCH_MOCK)    := mock | ||||
|  | ||||
| # Three cases where we don't need fully populated $(obj) lists: | ||||
| # Five cases where we don't need fully populated $(obj) lists: | ||||
| # 1. when no .config exists | ||||
| # 2. when make config (in any flavour) is run | ||||
| # 3. when make distclean is run | ||||
| # 4. when make help% or make clean% is run | ||||
| # 5. when make %-test or make %-tests or make %coverage-report is run | ||||
| # Don't waste time on reading all Makefile.incs in these cases | ||||
| ifeq ($(strip $(HAVE_DOTCONFIG)),) | ||||
| NOCOMPILE := 1 | ||||
| endif | ||||
| ifneq ($(MAKECMDGOALS),) | ||||
| ifneq ($(filter %config %clean,$(MAKECMDGOALS)),) | ||||
| ifneq ($(filter %config %clean clean-% help%,$(MAKECMDGOALS)),) | ||||
| NOCOMPILE := 1 | ||||
| endif | ||||
| ifneq ($(filter %clean help% clean%, $(MAKECMDGOALS)),) | ||||
| UNIT_TEST := 1 | ||||
| endif | ||||
| endif | ||||
|  | ||||
| ifneq ($(filter help%, $(MAKECMDGOALS)),) | ||||
| NOCOMPILE := 1 | ||||
| UNIT_TEST := 1 | ||||
| else | ||||
| ifneq ($(filter %-test %-tests %coverage-report, $(MAKECMDGOALS)),) | ||||
| ifneq ($(filter-out %-test %-tests %coverage-report, $(MAKECMDGOALS)),) | ||||
| $(error Cannot mix unit-tests targets with other targets) | ||||
| endif | ||||
| NOCOMPILE := | ||||
| UNIT_TEST := 1 | ||||
| endif | ||||
| endif | ||||
|  | ||||
| xcompile ?= $(obj)/xcompile | ||||
| @@ -135,6 +153,7 @@ $(xcompile): $(top)/../../util/xcompile/xcompile | ||||
|  | ||||
| ifeq ($(NOCOMPILE),1) | ||||
| include $(TOPLEVEL)/Makefile.inc | ||||
| include $(TOPLEVEL)/tests/Makefile.inc | ||||
| real-all: config | ||||
|  | ||||
| else | ||||
| @@ -283,9 +302,13 @@ evaluate_subdirs= \ | ||||
| 		$(eval $(call includemakefiles,$(dir)/Makefile.inc))) \ | ||||
| 	$(if $(subdirs),$(eval $(call evaluate_subdirs))) | ||||
|  | ||||
| # collect all object files eligible for building | ||||
| # collect all object files eligible for building or run unit-tests | ||||
| ifneq ($(UNIT_TEST),1) | ||||
| subdirs:=$(TOPLEVEL) | ||||
| $(eval $(call evaluate_subdirs)) | ||||
| else | ||||
| include $(TOPLEVEL)/tests/Makefile.inc | ||||
| endif | ||||
|  | ||||
| src-to-obj=$(addsuffix .$(1).o, $(basename $(addprefix $(obj)/, $($(1)-srcs)))) | ||||
| $(foreach class,$(classes),$(eval $(class)-objs:=$(call src-to-obj,$(class)))) | ||||
|   | ||||
| @@ -135,7 +135,7 @@ prepare: | ||||
|  | ||||
| junit.xml: | ||||
| 	echo '<?xml version="1.0" encoding="utf-8"?><testsuite>' > $@.tmp | ||||
| 	for i in $(filter-out %.old,$(wildcard configs/*)); do \ | ||||
| 	for i in $(filter-out %.old %.unit-tests,$(wildcard configs/*)); do \ | ||||
| 		$(MAKE) clean; \ | ||||
| 		echo "Building libpayload for $$i"; \ | ||||
| 		cp "$$i" junit_config; \ | ||||
| @@ -158,7 +158,7 @@ junit.xml: | ||||
| 	mv $@.tmp $@ | ||||
|  | ||||
| test-configs: | ||||
| 	for config in $(filter-out %.old,$(wildcard configs/*)); do \ | ||||
| 	for config in $(filter-out %.old %.unit-tests,$(wildcard configs/*)); do \ | ||||
| 		$(MAKE) clean; \ | ||||
| 		cp "$$config" test_config; \ | ||||
| 		echo "*** Making libpayload config $$config ***"; \ | ||||
|   | ||||
							
								
								
									
										2
									
								
								payloads/libpayload/configs/config.unit-tests
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								payloads/libpayload/configs/config.unit-tests
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| CONFIG_LP_ARCH_MOCK=y | ||||
| CONFIG_LP_ARCH_BIG_ENDIAN=n | ||||
							
								
								
									
										277
									
								
								payloads/libpayload/tests/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								payloads/libpayload/tests/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,277 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only | ||||
|  | ||||
| testsrc := $(top)/tests | ||||
|  | ||||
| # Place the build output in one of two places depending on COV, so that code | ||||
| # built with code coverage never mixes with code built without code coverage. | ||||
| ifeq ($(COV),1) | ||||
| testobj := $(obj)/coverage | ||||
| else | ||||
| testobj := $(obj)/tests | ||||
| endif | ||||
| coverage-dir := $(testobj)/coverage_reports | ||||
|  | ||||
| coreboottop := ../../ | ||||
|  | ||||
| cmockasrc := $(coreboottop)/3rdparty/cmocka | ||||
| cmockaobj := $(objutil)/cmocka | ||||
| CMOCKA_LIB := $(cmockaobj)/src/libcmocka.so | ||||
|  | ||||
| CMAKE := cmake | ||||
|  | ||||
| TEST_DEFAULT_CONFIG := $(top)/configs/config.unit-tests | ||||
| TEST_DOTCONFIG := $(testobj)/.config | ||||
| TEST_KCONFIG_AUTOHEADER := $(testobj)/libpayload-config.src.h | ||||
| TEST_KCONFIG_AUTOCONFIG := $(testobj)/auto.conf | ||||
| TEST_KCONFIG_DEPENDENCIES := $(testobj)/auto.conf.cmd | ||||
| TEST_KCONFIG_SPLITCONFIG := $(testobj)/config/ | ||||
| TEST_KCONFIG_TRISTATE := $(testobj)/tristate.conf | ||||
| TEST_KCONFIG_NEGATIVES := 1 | ||||
| TEST_KBUILD_KCONFIG := $(top)/Kconfig | ||||
| TEST_CONFIG_ := CONFIG_LP_ | ||||
|  | ||||
|  | ||||
| # Default includes | ||||
| TEST_CFLAGS := -include include/kconfig.h -include include/compiler.h | ||||
| TEST_CFLAGS += -Iinclude -Iinclude/mock | ||||
| TEST_CFLAGS += -I$(dir $(TEST_KCONFIG_AUTOHEADER)) | ||||
|  | ||||
| # Test specific includes | ||||
| TEST_CFLAGS += -I$(testsrc)/include -I$(testsrc)/include/mocks | ||||
| TEST_CFLAGS += -I$(cmockasrc)/include | ||||
|  | ||||
| # Minimal subset of warnings and errors. Tests can be less strict than actual build. | ||||
| TEST_CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wvla | ||||
| TEST_CFLAGS += -Wwrite-strings -Wno-trigraphs -Wimplicit-fallthrough | ||||
| TEST_CFLAGS += -Wstrict-aliasing -Wshadow -Werror | ||||
|  | ||||
| TEST_CFLAGS += -std=gnu11 -Os -ffunction-sections -fdata-sections -fno-builtin | ||||
|  | ||||
| # Make unit-tests detectable by the code | ||||
| TEST_CFLAGS += -D__TEST__ | ||||
|  | ||||
| # Link against CMocka | ||||
| TEST_LDFLAGS := -L$(dir $(CMOCKA_LIB)) -lcmocka -Wl,-rpath=$(dir $(CMOCKA_LIB)) | ||||
|  | ||||
| TEST_LDFLAGS += -Wl,--gc-sections | ||||
|  | ||||
| # Disable userspace relocations | ||||
| TEST_CFLAGS += -fno-pie -fno-pic | ||||
| TEST_LDFLAGS += -no-pie | ||||
|  | ||||
| ifeq ($(COV),1) | ||||
| TEST_CFLAGS += --coverage | ||||
| TEST_LDFLAGS += --coverage | ||||
| endif | ||||
|  | ||||
|  | ||||
| # Extra attributes for unit tests. Declated per each test. Only `srcs` is required. | ||||
| attributes := cflags config mocks srcs | ||||
|  | ||||
| alltests := | ||||
| subdirs := tests/crypto tests/curses tests/drivers tests/gdb tests/libc tests/libcbfs | ||||
| subdirs += tests/liblz4 tests/liblzma tests/libpci | ||||
|  | ||||
| define tests-handler | ||||
| alltests += $(1)$(2) | ||||
| $(foreach attribute,$(attributes), \ | ||||
| 	$(eval $(1)$(2)-$(attribute) += $($(2)-$(attribute)))) | ||||
| $(foreach attribute,$(attributes), \ | ||||
| 	$(eval $(2)-$(attribute) := )) | ||||
| endef | ||||
|  | ||||
| # Copy attributes of one test to another | ||||
| # $1 - input test name | ||||
| # $2 - output test name | ||||
| copy-test = $(foreach attribute,$(attributes), \ | ||||
| 		$(eval $(strip $(2))-$(attribute) := $($(strip $(1))-$(attribute)))) | ||||
|  | ||||
| $(call add-special-class,tests) | ||||
| $(call evaluate_subdirs) | ||||
|  | ||||
| # Create actual targets for unit test binaries | ||||
| # $1 - test name | ||||
| define TEST_CC_template | ||||
|  | ||||
| # Generate custom config.h redefining given config symbols, and declaring mocked | ||||
| # functions weak. It is important that the compiler already sees that they are | ||||
| # weak (and they aren't just turned weak at a later stage) to prevent certain | ||||
| # optimizations that would break if the function gets replaced. (For clang this | ||||
| # file needs to be marked `system_header` to prevent it from warning about | ||||
| # `#pragma weak` entries without a matching function declaration, since there is | ||||
| # no -Wno-xxx commandline for that.) | ||||
| $(1)-config-file := $(testobj)/$(1)/libpayload-config.h | ||||
| $$($(1)-config-file): $(TEST_KCONFIG_AUTOHEADER) | ||||
| 	mkdir -p $$(dir $$@); | ||||
| 	printf '// File generated by tests/Makefile.inc\n// Do not change\n' > $$@; | ||||
| 	printf '#ifndef TEST_LIBPAYLOAD_CONFIG_H_\n' >> $$@; | ||||
| 	printf '#define TEST_LIBPAYLOAD_CONFIG_H_\n' >> $$@; | ||||
| 	printf '#include <%s>\n\n' "$(notdir $(TEST_KCONFIG_AUTOHEADER))" >> $$@; | ||||
| 	for kv in $$($(1)-config); do \ | ||||
| 		key="`echo $$$$kv | cut -d '=' -f -1`"; \ | ||||
| 		value="`echo $$$$kv | cut -d '=' -f 2-`"; \ | ||||
| 		printf '#undef %s\n' "$$$$key" >> $$@; \ | ||||
| 		printf '#define %s %s\n\n' "$$$$key" "$$$$value" >> $$@; \ | ||||
| 	done | ||||
| 	printf '#ifdef __clang__\n' >> $$@; | ||||
| 	printf '#pragma clang system_header\n' >> $$@; | ||||
| 	printf '#endif\n\n' >> $$@; | ||||
| 	printf '#ifdef __TEST_SRCOBJ__\n' >> $$@; | ||||
| 	for m in $$($(1)-mocks); do \ | ||||
| 		printf '#pragma weak %s\n' "$$$$m" >> $$@; \ | ||||
| 	done | ||||
| 	printf '#endif\n\n' >> $$@; | ||||
| 	printf '#endif\n' >> $$@; | ||||
|  | ||||
| $($(1)-objs): TEST_CFLAGS += -I$$(dir $$($(1)-config-file)) \ | ||||
| 	-D__TEST_NAME__=\"$(subst /,_,$(1))\" | ||||
|  | ||||
| # Give us a way to distinguish between libpayload source files and test files in the code. | ||||
| $($(1)-srcobjs): TEST_CFLAGS += -D__TEST_SRCOBJ__ | ||||
|  | ||||
| # Compile sources and apply mocking/wrapping for selected symbols. | ||||
| # For each listed mock add new symbol with prefix `__real_`, | ||||
| # pointing to the same section:address. This will keep original | ||||
| # function accessible if required. | ||||
| $($(1)-objs): $(testobj)/$(1)/%.o: $$$$*.c $$($(1)-config-file) | ||||
| 	mkdir -p $$(dir $$@) | ||||
| 	$(HOSTCC) $$(TEST_CFLAGS) $($(1)-cflags) -MMD \ | ||||
| 		-MF $$(basename $$@).d -MT $$@ -c $$< -o $$@.orig | ||||
| 	objcopy_wrap_flags=''; \ | ||||
| 	for sym in $$($(1)-mocks); do \ | ||||
| 		sym_line="$$$$($(HOSTOBJDUMP) -t $$@.orig \ | ||||
| 			| grep -E \"[0-9a-fA-F]+\\s+w\\s+F\\s+.*\\s$$$$sym$$$$\")"; \ | ||||
| 		if [ ! -z "$$$$sym_line" ] ; then \ | ||||
| 			addr="$$$$(echo \"$$$$sym_line\" | awk '{ print $$$$1 }')"; \ | ||||
| 			section="$$$$(echo \"$$$$sym_line\" | awk '{ print $$$$(NF - 2) }')"; \ | ||||
| 			objcopy_wrap_flags="$$$$objcopy_wrap_flags --add-symbol __real_$$$${sym}=$$$${section}:0x$$$${addr},function,global"; \ | ||||
| 		fi \ | ||||
| 	done ; \ | ||||
| 	$(HOSTOBJCOPY) $$@.orig $$$$objcopy_wrap_flags $$@ | ||||
|  | ||||
| $($(1)-bin): $($(1)-objs) $(CMOCKA_LIB) | ||||
| 	$(HOSTCC) $$^ $($(1)-cflags) $$(TEST_LDFLAGS) -o $$@ | ||||
|  | ||||
| endef | ||||
|  | ||||
| $(foreach test,$(alltests), \ | ||||
| 	$(eval $(test)-srcobjs := $(addprefix $(testobj)/$(test)/, \ | ||||
| 		$(patsubst %.c,%.o,$(filter-out tests/%,$($(test)-srcs))))) \ | ||||
| 	$(eval $(test)-objs := $(addprefix $(testobj)/$(test)/, \ | ||||
| 		$(patsubst %.c,%.o,$($(test)-srcs)))) \ | ||||
| 	$(eval $(test)-bin := $(testobj)/$(test)/run)) | ||||
| $(foreach test,$(alltests), \ | ||||
| 	$(eval $(call TEST_CC_template,$(test)))) | ||||
| $(foreach test,$(alltests), \ | ||||
| 	$(eval all-test-objs += $($(test)-objs)) \ | ||||
| 	$(eval test-bins += $($(test)-bin))) | ||||
|  | ||||
| DEPENDENCIES += $(addsuffix .d,$(basename $(all-test-objs))) | ||||
| -include $(DEPENDENCIES) | ||||
|  | ||||
| # Build CMocka | ||||
| $(CMOCKA_LIB): | ||||
| 	echo "*** Building CMOCKA ***" | ||||
| 	mkdir -p $(cmockaobj) | ||||
| 	cd $(cmockaobj) && $(CMAKE) $(abspath $(cmockasrc)) | ||||
| 	$(MAKE) -C $(cmockaobj) | ||||
|  | ||||
| # Kconfig targets | ||||
| $(TEST_DOTCONFIG): | ||||
| 	mkdir -p $(dir $@) | ||||
| 	cp $(TEST_DEFAULT_CONFIG) $(TEST_DOTCONFIG) | ||||
|  | ||||
| $(TEST_KCONFIG_AUTOHEADER): TEST_KCONFIG_FLAGS := DOTCONFIG=$(TEST_DOTCONFIG) \ | ||||
| 	KCONFIG_AUTOHEADER=$(TEST_KCONFIG_AUTOHEADER) \ | ||||
| 	KCONFIG_AUTOCONFIG=$(TEST_KCONFIG_AUTOCONFIG) \ | ||||
| 	KCONFIG_DEPENDENCIES=$(TEST_KCONFIG_DEPENDENCIES) \ | ||||
| 	KCONFIG_SPLITCONFIG=$(TEST_KCONFIG_SPLITCONFIG) \ | ||||
| 	KCONFIG_TRISTATE=$(TEST_KCONFIG_TRISTATE) \ | ||||
| 	KCONFIG_NEGATIVES=$(TEST_KCONFIG_NEGATIVES) \ | ||||
| 	KBUILD_KCONFIG=$(TEST_KBUILD_KCONFIG) \ | ||||
| 	KBUILD_DEFCONFIG=$(TEST_DEFAULT_CONFIG) \ | ||||
| 	CONFIG_=$(TEST_CONFIG_) | ||||
|  | ||||
| $(TEST_KCONFIG_AUTOHEADER): $(TEST_DOTCONFIG) $(objk)/conf | ||||
| 	mkdir -p $(dir $@) | ||||
| 	$(MAKE) $(TEST_KCONFIG_FLAGS) olddefconfig V=$(V) | ||||
| 	$(MAKE) $(TEST_KCONFIG_FLAGS) syncconfig V=$(V) | ||||
|  | ||||
| $(TEST_KCONFIG_AUTOCONFIG): $(TEST_KCONFIG_AUTOHEADER) | ||||
| 	true | ||||
|  | ||||
| .PHONY: $(alltests) $(addprefix clean-,$(alltests)) | ||||
| .PHONY: unit-tests build-unit-tests run-unit-tests clean-unit-tests | ||||
|  | ||||
| ifeq ($(JUNIT_OUTPUT),y) | ||||
| $(alltests): export CMOCKA_MESSAGE_OUTPUT=xml | ||||
| $(alltests): export CMOCKA_XML_FILE=$(testobj)/junit-%g.xml | ||||
| endif | ||||
|  | ||||
| $(alltests): $$($$(@)-bin) | ||||
| 	rm -f $(testobj)/junit-libpayload-$(subst /,_,$(patsubst $(testobj)/%/,%,$(dir $^)))\(*\).xml | ||||
| 	rm -f $(testobj)/$(subst /,_,$^).failed | ||||
| 	-$^ || echo failed > $(testobj)/$(subst /,_,$^).failed | ||||
|  | ||||
| # Build a code coverage report by collecting all the gcov files into a single | ||||
| # report. If COV is not set, this might be a user error, and they're trying | ||||
| # to generate a coverage report without first having built and run the code | ||||
| # with code coverage. absence of COV=1 will be corrected. | ||||
|  | ||||
| .PHONY: coverage-report clean-coverage-report | ||||
|  | ||||
| ifeq ($(COV),1) | ||||
| coverage-report: | ||||
| 	lcov -o $(testobj)/tests.info -c -d $(testobj) --exclude '$(testsrc)/*' | ||||
| 	genhtml -q -o $(coverage-dir) -t "coreboot unit tests" -s $(testobj)/tests.info | ||||
|  | ||||
| clean-coverage-report: | ||||
| 	rm -Rf $(coverage-dir) | ||||
| else | ||||
| coverage-report: | ||||
| 	COV=1 V=$(V) $(MAKE) coverage-report | ||||
|  | ||||
| clean-coverage-report: | ||||
| 	COV=1 V=$(V) $(MAKE) clean-coverage-report | ||||
| endif | ||||
|  | ||||
| unit-tests: build-unit-tests run-unit-tests | ||||
|  | ||||
| build-unit-tests: $(test-bins) | ||||
|  | ||||
| run-unit-tests: $(alltests) | ||||
| 	if [ `find $(testobj) -name '*.failed' | wc -l` -gt 0 ]; then \ | ||||
| 		echo "**********************"; \ | ||||
| 		echo "     TESTS FAILED"; \ | ||||
| 		echo "**********************"; \ | ||||
| 		exit 1; \ | ||||
| 	else \ | ||||
| 		echo "**********************"; \ | ||||
| 		echo "   ALL TESTS PASSED"; \ | ||||
| 		echo "**********************"; \ | ||||
| 		exit 0; \ | ||||
| 	fi | ||||
|  | ||||
| $(addprefix clean-,$(alltests)): clean-% | ||||
| 	rm -rf $(testobj)/$* | ||||
|  | ||||
| clean-unit-tests: | ||||
| 	rm -rf $(testobj) | ||||
|  | ||||
| list-unit-tests: | ||||
| 	@echo "unit-tests:" | ||||
| 	for t in $(sort $(alltests)); do \ | ||||
| 		echo "  $$t"; \ | ||||
| 	done | ||||
|  | ||||
| help-unit-tests help:: | ||||
| 	@echo  '*** libpayload unit-tests targets ***' | ||||
| 	@echo  '  Use "COV=1 make [target]" to enable code coverage for unit tests' | ||||
| 	@echo  '  unit-tests            - Run all unit-tests from tests/' | ||||
| 	@echo  '  clean-unit-tests      - Remove unit-tests build artifacts' | ||||
| 	@echo  '  list-unit-tests       - List all unit-tests' | ||||
| 	@echo  '  <unit-test>           - Build and run single unit-test' | ||||
| 	@echo  '  clean-<unit-test>     - Remove single unit-test build artifacts' | ||||
| 	@echo  '  coverage-report       - Generate a code coverage report' | ||||
| 	@echo  '  clean-coverage-report - Remove the code coverage report' | ||||
| 	@echo | ||||
							
								
								
									
										9
									
								
								payloads/libpayload/tests/drivers/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								payloads/libpayload/tests/drivers/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only | ||||
|  | ||||
| tests-y += speaker-test | ||||
|  | ||||
| speaker-test-srcs += tests/drivers/speaker-test.c | ||||
| speaker-test-mocks += inb | ||||
| speaker-test-mocks += outb | ||||
| speaker-test-mocks += arch_ndelay | ||||
| speaker-test-cflags += -include $(testsrc)/include/mocks/x86_io.h | ||||
							
								
								
									
										148
									
								
								payloads/libpayload/tests/drivers/speaker-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								payloads/libpayload/tests/drivers/speaker-test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #include <libpayload.h> | ||||
| #include <mocks/x86_io.h> | ||||
|  | ||||
| /* Include source to gain access to private defines */ | ||||
| #include "../drivers/speaker.c" | ||||
|  | ||||
| #include <tests/test.h> | ||||
|  | ||||
| void outb(unsigned char val, int port) | ||||
| { | ||||
| 	check_expected(val); | ||||
| 	check_expected(port); | ||||
| } | ||||
|  | ||||
| unsigned char inb(int port) | ||||
| { | ||||
| 	check_expected(port); | ||||
| 	return mock_type(unsigned char); | ||||
| } | ||||
|  | ||||
| static void setup_speaker_enable_calls(u16 freq, u8 port_val) | ||||
| { | ||||
| 	/* Minimal correct value should be at leaset 256. For values lowe than that, | ||||
| 	   counter will have an incorrect value. Regardless, there is  */ | ||||
| 	u16 reg16 = 1193180 / freq; | ||||
|  | ||||
| 	/* Select counter 2 */ | ||||
| 	expect_value(outb, val, 0xb6); | ||||
| 	expect_value(outb, port, I82C54_CONTROL_WORD_REGISTER); | ||||
|  | ||||
| 	/* Write freq. [LSB, MSB] */ | ||||
| 	expect_value(outb, val, (u8)(reg16 & 0xff)); | ||||
| 	expect_value(outb, port, I82C54_COUNTER2); | ||||
| 	expect_value(outb, val, (u8)(reg16 >> 8)); | ||||
| 	expect_value(outb, port, I82C54_COUNTER2); | ||||
|  | ||||
| 	/* Enable PC speaker */ | ||||
| 	expect_value(inb, port, PC_SPEAKER_PORT); | ||||
| 	will_return(inb, port_val); | ||||
| 	expect_value(outb, val, port_val | 0x3); | ||||
| 	expect_value(outb, port, PC_SPEAKER_PORT); | ||||
| } | ||||
|  | ||||
| static void test_speaker_enable(void **state) | ||||
| { | ||||
| 	setup_speaker_enable_calls(1, 0); | ||||
| 	speaker_enable(1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(1, 0xff); | ||||
| 	speaker_enable(1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(1, 123); | ||||
| 	speaker_enable(1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(1, -1); | ||||
| 	speaker_enable(1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(-1, 0); | ||||
| 	speaker_enable(-1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(-1, 0xff); | ||||
| 	speaker_enable(-1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(-1, 222); | ||||
| 	speaker_enable(-1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(-1, -1); | ||||
| 	speaker_enable(-1); | ||||
|  | ||||
| 	setup_speaker_enable_calls(10000, 0); | ||||
| 	speaker_enable(10000); | ||||
|  | ||||
| 	setup_speaker_enable_calls(10000, 0xff); | ||||
| 	speaker_enable(10000); | ||||
|  | ||||
| 	setup_speaker_enable_calls(10000, 91); | ||||
| 	speaker_enable(10000); | ||||
|  | ||||
| 	setup_speaker_enable_calls(10000, -1); | ||||
| 	speaker_enable(10000); | ||||
| } | ||||
|  | ||||
| static void setup_speaker_disable_calls(u8 value) | ||||
| { | ||||
| 	expect_value(inb, port, PC_SPEAKER_PORT); | ||||
| 	will_return(inb, value); | ||||
| 	expect_value(outb, val, value & 0xfc); | ||||
| 	expect_value(outb, port, PC_SPEAKER_PORT); | ||||
| } | ||||
|  | ||||
| static void test_speaker_disable(void **state) | ||||
| { | ||||
| 	setup_speaker_disable_calls(0); | ||||
| 	speaker_disable(); | ||||
|  | ||||
| 	setup_speaker_disable_calls(0xfc); | ||||
| 	speaker_disable(); | ||||
|  | ||||
| 	setup_speaker_disable_calls(0xff); | ||||
| 	speaker_disable(); | ||||
|  | ||||
| 	setup_speaker_disable_calls(0xff - 0xfc); | ||||
| 	speaker_disable(); | ||||
| } | ||||
|  | ||||
| void arch_ndelay(uint64_t ns) | ||||
| { | ||||
| 	check_expected(ns); | ||||
| } | ||||
|  | ||||
| static void setup_speaker_tone_calls(u16 freq, unsigned int duration) | ||||
| { | ||||
| 	setup_speaker_enable_calls(freq, ~freq & 0xff); | ||||
| 	expect_value(arch_ndelay, ns, (uint64_t)duration * NSECS_PER_MSEC); | ||||
| 	setup_speaker_disable_calls(0xff); | ||||
| 	expect_any(arch_ndelay, ns); | ||||
| } | ||||
|  | ||||
| static void test_speaker_tone(void **state) | ||||
| { | ||||
| 	setup_speaker_tone_calls(500, 100); | ||||
| 	speaker_tone(500, 100); | ||||
|  | ||||
| 	setup_speaker_tone_calls(4321, 0); | ||||
| 	speaker_tone(4321, 0); | ||||
|  | ||||
| 	setup_speaker_tone_calls(-1, -1); | ||||
| 	speaker_tone(-1, -1); | ||||
|  | ||||
| 	setup_speaker_tone_calls(10000, 1000); | ||||
| 	speaker_tone(10000, 1000); | ||||
|  | ||||
| 	setup_speaker_tone_calls(433, 890); | ||||
| 	speaker_tone(433, 890); | ||||
| } | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
| 	const struct CMUnitTest tests[] = { | ||||
| 		cmocka_unit_test(test_speaker_enable), | ||||
| 		cmocka_unit_test(test_speaker_disable), | ||||
| 		cmocka_unit_test(test_speaker_tone), | ||||
| 	}; | ||||
|  | ||||
| 	return lp_run_group_tests(tests, NULL, NULL); | ||||
| } | ||||
							
								
								
									
										30
									
								
								payloads/libpayload/tests/include/mocks/x86_io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								payloads/libpayload/tests/include/mocks/x86_io.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #ifndef TESTS_MOCKS_X86_IO_H_ | ||||
| #define TESTS_MOCKS_X86_IO_H_ | ||||
|  | ||||
| unsigned int inl(int port); | ||||
|  | ||||
| unsigned short inw(int port); | ||||
|  | ||||
| unsigned char inb(int port); | ||||
|  | ||||
| void outl(unsigned int val, int port); | ||||
|  | ||||
| void outw(unsigned short val, int port); | ||||
|  | ||||
| void outb(unsigned char val, int port); | ||||
|  | ||||
| void outsl(int port, const void *addr, unsigned long count); | ||||
|  | ||||
| void outsw(int port, const void *addr, unsigned long count); | ||||
|  | ||||
| void outsb(int port, const void *addr, unsigned long count); | ||||
|  | ||||
| void insl(int port, void *addr, unsigned long count); | ||||
|  | ||||
| void insw(int port, void *addr, unsigned long count); | ||||
|  | ||||
| void insb(int port, void *addr, unsigned long count); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										52
									
								
								payloads/libpayload/tests/include/tests/test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								payloads/libpayload/tests/include/tests/test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #ifndef _TESTS_TEST_H | ||||
| #define _TESTS_TEST_H | ||||
|  | ||||
| /* | ||||
|  * Standard test header that should be included in all tests. For now it just encapsulates the | ||||
|  * include dependencies for Cmocka. Test-specific APIs that are so generic we would want them | ||||
|  * available everywhere could also be added here. | ||||
|  */ | ||||
|  | ||||
| #include <arch/types.h> | ||||
| #include <stdarg.h> | ||||
| #include <stddef.h> | ||||
| #include <setjmp.h> | ||||
| #include <cmocka.h> | ||||
|  | ||||
| /* Helper macro to aviud checkpatch errors for some macros */ | ||||
| #define EMPTY_WRAP(...) __VA_ARGS__ | ||||
|  | ||||
| /* | ||||
|  * Set symbol value and make it global. | ||||
|  */ | ||||
| #define TEST_SYMBOL(symbol, value) asm(".set " #symbol ", " #value "\n\t.globl " #symbol) | ||||
|  | ||||
| /* | ||||
|  * Define memory region for testing purpose. | ||||
|  * | ||||
|  * Create buffer with specified name and size. | ||||
|  * Create end symbol for it. | ||||
|  */ | ||||
| #define TEST_REGION(region, size) uint8_t _##region[size];                                     \ | ||||
| 	TEST_SYMBOL(_e##region, _##region + size);                                             \ | ||||
| 	TEST_SYMBOL(_##region##_size, size) | ||||
|  | ||||
| /* | ||||
|  * Set start, end and size symbols describing region without allocating memory for it. | ||||
|  */ | ||||
| #define TEST_REGION_UNALLOCATED(region, start, size) EMPTY_WRAP(                               \ | ||||
| 	TEST_SYMBOL(_##region, start);                                                         \ | ||||
| 	TEST_SYMBOL(_e##region, _##region + size);                                             \ | ||||
| 	TEST_SYMBOL(_##region##_size, size)                                                    \ | ||||
| ) | ||||
|  | ||||
| /* Wrapper for running cmocka test groups using name provided by build system in __TEST_NAME__ | ||||
|    This should be used instead of cmocka_run_group_tests(). If there is a need to use custom | ||||
|    group name, then please use cmocka_run_group_tests_name(). */ | ||||
| #define lp_run_group_tests(group_tests, group_setup, group_teardown)                           \ | ||||
| 	cmocka_run_group_tests_name((__TEST_NAME__ "(" #group_tests ")"), group_tests,         \ | ||||
| 				    group_setup, group_teardown) | ||||
|  | ||||
| #endif /* _TESTS_TEST_H */ | ||||
| @@ -97,6 +97,7 @@ endif | ||||
| 	$(MAKE) CPUS=$(CPUS) V=$(V) Q=$(Q) BLD_DIR=src/soc/nvidia/tegra124/lp0 BLD=tegra124_lp0 MFLAGS= MAKEFLAGS=xcompile=$(COREBOOT_BUILD_DIR)/xcompile MAKETARGET=all junit.xml | ||||
| 	$(MAKE) CPUS=$(CPUS) V=$(V) Q=$(Q) BLD_DIR=src/soc/nvidia/tegra210/lp0 BLD=tegra120_lp0 MFLAGS= MAKEFLAGS=xcompile=$(COREBOOT_BUILD_DIR)/xcompile MAKETARGET=all junit.xml | ||||
| 	$(MAKE) unit-tests JUNIT_OUTPUT=y | ||||
| 	(cd payloads/libpayload; unset COREBOOT_BUILD_DIR; $(MAKE) unit-tests JUNIT_OUTPUT=y) | ||||
|  | ||||
| test-basic: test-lint test-tools test-abuild test-payloads test-cleanup | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user