Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Including "standard headers" in mock files. #804

Open
informatimago opened this issue Aug 10, 2023 · 3 comments · May be fixed by ThrowTheSwitch/CMock#454
Open

Including "standard headers" in mock files. #804

informatimago opened this issue Aug 10, 2023 · 3 comments · May be fixed by ThrowTheSwitch/CMock#454

Comments

@informatimago
Copy link

informatimago commented Aug 10, 2023

When mocking a file, the cmock_generator includes first <string.h>, <stdlib.h> and possibly <setjmp.h> and then "cmock.h" and the mocked headers, etc.

/* Source File: src/nkern/common/core/nktypes.h */
/* AUTOGENERATED FILE. DO NOT EDIT. */
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include "cmock.h"
#include "mock_nktypes.h"

This causes problems with our project. We're working on low-level, kernel/hypervisor software, and we define our own standard header files, since libc or a unix kernel is not available. I'd guess that's the case for most microcontroller code: there are libraries providing their own headers.

But in this particular case, we are mocking parts of the hypervisor itself, which provides the string.h and stdlib.h, etc.

So what happens, is that string.h includes amongst other files, src/nkern/common/core/nktypes.h itself; therefore when we include the mocked version, mock_nktypes.h, we get duplicate declarations (no problem they're compatible), but in case of inlines, we get duplicate definitions!

> Shell executed command:
'/build/pbourguignon/clang/src.devel/vlm-x86-linux-android-clang/bin/clang -target aarch64-linux-android -mcpu=cortex-a53 -Wno-gnu-variable-sized-type-not-at-end -Wno-initializer-overrides -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-implicit-function-declaration -H --sysroot=/home/pbourguignon/src/android/sysroot -idirafter src/nkern/common/stdc -DUNITY_OUTPUT_CHAR\(a\)=printf\(\"%c\",\(a\)\) -UUNITY_OUTPUT_CHAR_HEADER_DECLARATION -DUNITY_OUTPUT_FLUSH\(\)=do\{\}while\(0\) -UUNITY_OUTPUT_FLUSH_HEADER_DECLARATION -include "fixups.h" -g -fprofile-instr-generate -fcoverage-mapping -fprofile-arcs -ftest-coverage -I"/build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/unity/src" -I"/build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/c_exception/lib" -I"/build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/bsp" -I"test/bsp/cpu" -I"test/bsp/cpu/arm" -I"test/bsp/cpu/arm64" -I"test/bsp/framework" -I"test/bsp/framework/vbridge" -I"test/bsp/monitoring" -I"test/bsp/pcie" -I"test/bsp/pcie/designware" -I"test/bsp/pcie/ecam" -I"test/bsp/svec" -I"test/bsp/virtio" -I"test/bsp/vpcie" -I"test/nkern" -I"test/nkern/arm" -I"test/nkern/arm/vdev" -I"test/nkern/arm64" -I"test/nkern/arm64/core" -I"test/nkern/arm64/vdev" -I"test/nkern/common" -I"test/nkern/common/boot" -I"test/nkern/common/boot/dtb-iter" -I"test/nkern/common/core" -I"test/nkern/common/core/vram" -I"test/nkern/common/dbg" -I"test/nkern/common/dev" -I"test/nkern/common/stdc" -I"test/nkern/common/vdev" -I"test/support/dtb" -I"test/support/dtb-iter" -I"test/support/vgic-v3-its-vlpi" -I"test/support/vpcie-ep-swmsi" -I"test/support/vram" -I"test/support" -I"." -I"test" -I"test/nkern" -I"test/nkern/common" -I"test/nkern/common/core" -I"test/nkern/common/core/vram" -I"test/nkern/common/boot" -I"test/nkern/common/boot/dtb-iter" -I"test/nkern/common/vdev" -I"test/nkern/common/dev" -I"test/nkern/common/dbg" -I"test/nkern/arm" -I"test/nkern/arm/vdev" -I"test/nkern/arm64" -I"test/nkern/arm64/core" -I"test/nkern/arm64/vdev" -I"test/support/dtb" -I"test/support/vram" -I"test/support/dtb-iter" -I"test/support/vgic-v3-its-vlpi" -I"test/support/vpcie-ep-swmsi" -I"test/bsp" -I"test/bsp/virtio" -I"test/bsp/pcie" -I"test/bsp/pcie/ecam" -I"test/bsp/pcie/designware" -I"test/bsp/vpcie" -I"test/bsp/monitoring" -I"test/bsp/svec" -I"test/bsp/cpu" -I"test/bsp/cpu/arm" -I"test/bsp/cpu/arm64" -I"test/bsp/framework" -I"test/bsp/framework/vbridge" -I"test/support" -I"src" -I"src/nkern" -I"src/arm-arch" -I"src/arm" -I"src/sys" -I"src/ext" -I"src/hyp-dist" -I"src/arch" -I"src/bsp" -I"src/hyp-dist/include" -I"src/nkern/common/core" -I"src/nkern/common/dbg" -I"src/nkern/common/hal" -I"src/nkern/common/vdev" -I"src/nkern/common/assets" -I"src/nkern/common/nk" -I"src/nkern/common/boot" -I"src/nkern/common/dev" -I"src/nkern/common/balloon" -I"src/bsp/virtio" -I"src/bsp/pcie" -I"src/bsp/pcie/ecam" -I"src/bsp/pcie/designware" -I"src/bsp/vpcie" -I"src/bsp/monitoring" -I"src/bsp/svec" -I"src/bsp/soc" -I"src/bsp/soc/armltd" -I"src/bsp/soc/armltd/vexpress64" -I"src/bsp/soc/armltd/vexpress" -I"src/bsp/cpu" -I"src/bsp/cpu/arm" -I"src/bsp/cpu/ia32" -I"src/bsp/cpu/ia" -I"src/bsp/cpu/ia64" -I"src/bsp/cpu/arm64" -I"src/bsp/cpu/arm32" -I"src/bsp/framework" -I"src/bsp/framework/vbridge" -I"src/bsp/uart" -I"src/bsp/smmu" -I"src/bsp/smmu/arm" -I"src/bsp/smmu/ia" -I"src/bsp/board" -I"src/bsp/board/vexpress" -I"src/bsp/board/vexpress/fvp" -I"src/bsp/board/vexpress/vetc2" -I"src/bsp/board/vexpress/juno" -I"src/bsp/vdt" -I"src/bsp/vdt/common" -I"src/bsp/vdt/vcarautosar" -I"src/bsp/vdt/vcar" -I"src/bsp/vdt/htf" -I"src/bsp/vdt/true" -I"src/bsp/vdt/test" -I"src/hyp-dist/nkern" -I"src/hyp-dist/nkern/common" -I"src/hyp-dist/nkern/common/boot" -I"src/hyp-dist/nkern/common/core" -I"src/hyp-dist/nkern/common/vdev" -I"src/hyp-dist/nkern/arch" -I"src/hyp-dist/nkern/arm-arch" -I"src/hyp-dist/nkern/arm" -I"src/hyp-dist/nkern/arm/core" -I"src/hyp-dist/nkern/arm64" -I"src/hyp-dist/nkern/arm64/core" -I"src/hyp-dist/obj" -I"src/hyp-dist/var" -I"src/hyp-dist/lib" -I"src/hyp-dist/include/nkern" -I"src/hyp-dist/include/nkern/arm-arch" -I"src/hyp-dist/include/nkern/arm" -I"src/hyp-dist/include/nkern/arch" -I"src/hyp-dist/include/nkern/arm64" -I"src/nkern/arm" -I"src/nkern/arm/core" -I"src/nkern/arm/vdev" -I"src/nkern/arm/nk" -I"src/nkern/arm/dbg" -I"src/nkern/arm/dbg/kdb" -I"src/nkern/arm64/core" -I"src/nkern/arm64/vdev" -I"src/nkern/common/utils" -DPARAM_ARMV8 -DTEST -DUNITY_EXCLUDE_MATH_H -DUNITY_EXCLUDE_STDINT_H -DUNITY_EXCLUDE_LIMITS_H -DUNITY_EXCLUDE_TIME_H -DUNITY_EXCLUDE_STDLIB_H -DUNITY_SUPPORT_64 -DCMOCK_MEM_SIZE=131072 -DGCOV_COMPILER -DPASS=2 -c "build/test/mocks/mock_nktypes.c" -o "build/gcov/out/mock_nktypes.o" 2>&1'
> Produced output:
. src/sys/string.h
.. src/nkern/common/stdc/stdio.h
... src/nkern/common/core/nktypes.h
.... src/nkern/common/nk/nktypes.h
.... src/nkern/common/nk/nkvcpuregs.h
..... src/arch/nk/nkvcpuregs.h
...... src/arm-arch/nk/nkvcpuregs.h
.... src/nkern/common/nk/nkvlink.h
.... src/nkern/common/nk/nktiming.h
.... src/nkern/common/nk/nkmpboot.h
.... src/nkern/common/nk/nkbootvars.h
..... src/nkern/common/nk/nkvdt.h
.... src/nkern/common/nk/nkvcpumap.h
.... src/nkern/common/core/macro.h
..... src/nkern/common/core/macro-asm.h
... src/nkern/common/stdc/stdarg.h
. src/sys/stdlib.h
. src/sys/setjmp.h
. /build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/cmock/src/cmock.h
.. /build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/cmock/src/cmock_internals.h
... /build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/unity/src/unity.h
.... /build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/unity/src/unity_internals.h
..... src/sys/setjmp.h
..... /build/pbourguignon/clang/src.devel/vlm-clang-prebuilts-android/clang-r450784d/lib64/clang/14.0.6/include/stddef.h
...... /build/pbourguignon/clang/src.devel/vlm-clang-prebuilts-android/clang-r450784d/lib64/clang/14.0.6/include/__stddef_max_align_t.h
..... /build/pbourguignon/clang/src.devel/vlm-clang-prebuilts-android/clang-r450784d/lib64/clang/14.0.6/include/stdnoreturn.h
.. /build/pbourguignon/clang/src.devel/vlm-clang-prebuilts-android/clang-r450784d/lib64/clang/14.0.6/include/stddef.h
. build/test/mocks/mock_nktypes.h
.. /build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/unity/src/unity.h
.. build/test/mocks/nktypes.h
.. /build/pbourguignon/clang/work/build.devel/utest-nkernel/vendor/ceedling/vendor/c_exception/lib/CException.h
... src/sys/setjmp.h
build/test/mocks/mock_nktypes.c:135:8: error: redefinition of 'vmid_is_valid'
bool_t vmid_is_valid(vm_id_t vmid)
       ^
src/nkern/common/core/nktypes.h:112:1: note: previous definition is here
vmid_is_valid(vm_id_t vmid)
^

First, I would object on principle on the need for string.h and stdlib.h in the generated mock code. Even setjmp.h should not be directly needed by the mock code (it's used in the unity module to implement tests for noreturn functions).
The only occurence I see, is memset. A mock_memset could be provided by cmock.h.

But more fundamentally, as mentionned above, in a lot of projects, standard libraries don't come from libc and an underlying posix kernel. If they're available, they're not the host (the testing host) libraries. So this should preclude their use entirely in the generated mock code.

@informatimago
Copy link
Author

Oops, I attached this Issue to Ceedling instead of CMock. Please, move it over.

@mvandervoord
Copy link
Member

Originally neither Unity nor CMock had lib dependencies other than setjmp/longjmp and that was intentional. Over time, some of the basic standard library usage has crept its way into both projects.

In Unity, we've been very careful to make sure that there is always an alternative way to do it (Each standard library include is optional in Unity, including setjmp/longjmp. The effect of disabling a standard header just comes with additional steps the person building the test environment is responsible for. We feel like this is a good way to run things... where people can take advantage of the options when they're around, but still make good use of the tool when they're not.

This has been the goal for CMock, but (as you've notice) we haven't been as effective in keeping up with the "optional" portion of this. I agree we should get back to that. Specifically (and this is partially notes for myself or whoever tackles this issue soon):

  • The setjmp include should be disabled with Unity's UNITY_EXCLUDE_SETJMP. If Unity's not using it, CMock doesn't need it for anything.
  • The stdlib include should only be enabled with CMOCK_MEM_DYNAMIC or better: we can reimplement basic memset
  • The string include can be handled be reimplementing memcpy

@informatimago
Copy link
Author

  • The string include can be handled be reimplementing memcpy

I've updated my PR and added tests: ThrowTheSwitch/CMock#454

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants