Usage

Command line

Before we integrate it into the build chain of your choice it is a good idea to call it on the command line in order to gather more understanding what it does and what it needs.

Let’s call hammocking without any arguments:

$ python -m hammocking
usage: hammocking [-h] (--symbols SYMBOLS [SYMBOLS ...] | --plink PLINK) --outdir OUTDIR --sources SOURCES [SOURCES ...] [--except EXCLUDES ...]
hammocking: error: the following arguments are required: --outdir/-o, --sources

hammocking needs …

  • –sources: The list of paths to source files which represent your item-under test. (In classic unittest it is just one)

  • Either …
    • –symbols*: comma seperated list of symbol names which are to mock or

    • –plink: path to the object file which contains the unresolved symbols to mock

  • –outdir: An existing directory where to write code files containing mockup code.

  • –except: if a symbol is found in a header of these directories, it will not be mocked. Use this to exclude symbols from mocking that will be provided by libraries in the linking process. (Defaults to /usr/include for system headers)

One compilation unit

We show this scenario for explanation purpose only. The next chapter shows the common way and covers the one compilation unit as well.

In a simple scenario your

_images/usage_one_compile_unit_only.uxf.svg

Make

 1 .SUFFIXES:
 2 
 3 CC := gcc -c
 4 LD := gcc 
 5 
 6 CC_OPTS := -g
 7 LD_OPTS :=
 8 
 9 .PHONY: a_test
10 a_test: a_test.exe
11         ./a_test.exe
12 
13 a_test.exe: a.c.obj a_test.c.obj mockup.c.obj
14         $(LD) $(LD_OPTS) $(CC_OPTS) -o $@ $^
15 
16 
17 -include $(patsubst %.c,%.c.d,$(wildcard *.c))
18 %.c.obj: %.c
19         $(CC) $(CC_OPTS) -MMD -o $@ $<
20 
21 
22 
23 
24 a_test.c.obj: mockup.c
25 
26 mockup.c: a.c.obj
27         python -m hammocking --source a.c --plink a.c.obj --style plain_c --outdir . $(CC_OPTS)
28 
29 .PHONY: clean
30 clean:
31         rm -rf a_test.exe *.obj *.d mockup.c mockup.h
32 

CMake

One or more compilation units

_images/usage_one_or_more_compile_units.uxf.svg

Make

 1 .SUFFIXES:
 2 
 3 CC := gcc -c
 4 LD := gcc 
 5 
 6 CC_OPTS := -g
 7 LD_OPTS :=
 8 
 9 .PHONY: a_test
10 a_test: a_test.exe
11         ./a_test.exe
12 
13 a_test.exe: a_1.c.obj a_2.c.obj a_test.c.obj mockup.c.obj
14         $(LD) $(LD_OPTS) $(CC_OPTS) -o $@ $^
15 
16 
17 -include $(patsubst %.c,%.c.d,$(wildcard *.c))
18 %.c.obj: %.c
19         $(CC) $(CC_OPTS) -MMD -o $@ $<
20 
21 a.obj: a_1.c.obj a_2.c.obj
22         $(LD) $(LD_OPTS) -r -nostdlib -o $@ $^
23 
24 a_test.c.obj: mockup.c
25 
26 mockup.c: a.obj
27         python -m hammocking --source a_1.c a_2.c --plink a.obj --style plain_c --outdir . $(CC_OPTS)
28 
29 .PHONY: clean
30 clean:
31         rm -rf a_test.exe *.obj *.d mockup.c mockup.h
32 

CMake

Usage with GoogleTest and GoogleMocks

https://google.github.io/googletest/reference/mocking.html

 1 # cmake project definition
 2 cmake_minimum_required(VERSION 3.20.0)
 3 
 4 set(CMAKE_C_COMPILER clang CACHE STRING "C Compiler")
 5 set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ Compiler")
 6 set(CMAKE_C_COMPILER clang CACHE STRING "C Compiler")
 7 set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ Compiler")
 8 project(mini_c)
 9 
10 # GTEST + GMOCK STUFF ####################################
11 # GoogleTest requires at least C++14
12 set(CMAKE_CXX_STANDARD 14)
13 
14 include(FetchContent)
15 FetchContent_Declare(
16     googletest
17     GIT_REPOSITORY https://github.com/google/googletest.git
18     GIT_TAG release-1.12.1
19 )
20 
21 if(WIN32)
22     # Prevent overriding the parent project's compiler/linker
23     # settings on Windows
24     set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
25 endif()
26 
27 FetchContent_MakeAvailable(googletest)
28 
29 include(GoogleTest)
30 
31 find_package(Threads REQUIRED)
32 
33 enable_testing()
34 # END OF GTEST + GMOCK STUFF #############################
35 
36 set(PROD_SRC b.c)
37 set(MOCK_SRC mockup.cc)
38 set(TEST_SRC b_test.cc)
39 set(PROD_PARTIAL_LINK prod.obj)
40 
41 include_directories("includes")
42 
43 # One command to mock them all!
44 set(HAMMOCK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../hammocking)
45 add_custom_command(
46     OUTPUT ${MOCK_SRC}
47     BYPRODUCTS mockup.h
48     WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
49     COMMAND_EXPAND_LISTS
50     COMMAND python ${HAMMOCK_DIR}/hammocking.py --sources ${PROD_SRC} --plink ${CMAKE_CURRENT_BINARY_DIR}/${PROD_PARTIAL_LINK} --outdir ${CMAKE_CURRENT_BINARY_DIR} "-I$<JOIN:$<TARGET_PROPERTY:prodlib,INCLUDE_DIRECTORIES>,;-I>"
51     DEPENDS
52     ${HAMMOCK_DIR}/hammocking.py
53     ${PROD_PARTIAL_LINK}
54 )
55 
56 add_library(prodlib OBJECT ${PROD_SRC})
57 
58 add_custom_command(
59     OUTPUT ${PROD_PARTIAL_LINK}
60     COMMAND ${CMAKE_CXX_COMPILER} -r -nostdlib -o ${PROD_PARTIAL_LINK} $<TARGET_OBJECTS:prodlib>
61     COMMAND_EXPAND_LISTS
62     VERBATIM
63     DEPENDS $<TARGET_OBJECTS:prodlib>
64 )
65 
66 add_executable(
67     ${PROJECT_NAME}
68     ${MOCK_SRC}
69     ${TEST_SRC}
70 )
71 
72 target_include_directories(
73     ${PROJECT_NAME}
74     PRIVATE
75     ${CMAKE_CURRENT_BINARY_DIR}
76     ${CMAKE_CURRENT_LIST_DIR}
77 )
78 
79 target_link_libraries(
80     ${PROJECT_NAME}
81     prodlib
82     GTest::gtest_main
83     GTest::gmock_main
84     Threads::Threads
85 )
86 
87 gtest_discover_tests(${PROJECT_NAME})
88 
89 add_custom_command(
90     TARGET ${PROJECT_NAME}
91     POST_BUILD
92     COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
93 )