如何模拟头文件中的函数?
How to mock functions in headerfiles?
我在做什么:
我正在使用 cmocka 运行 对大型嵌入式项目进行单元测试。
嵌入式项目是用arm-gcc-compiler
编译的。
单元测试是使用嵌入式代码片段和 cmocka 库使用正常 gcc
编译的。
通常cmocka推荐使用-Wl,--wrap=functionName
标志来mock(替换)一些不需要的子函数。这个效果不错。
问题:
好吧,在我的嵌入式代码中有一个头文件 (foo.h
),其中包含一些函数(声明为内联)。其中一个函数包含 arm-gcc-compiler
的一些汇编代码,当然 gcc
.
无法编译这些代码
愚蠢的是,wrap
-flag 似乎不适用于放置在头文件中的函数。
问题:
如何在头文件中模拟这个函数?
我是如何尝试解决问题的:
我想插入一些 #idef
宏来排除提到的汇编器部分。但这是不可能的,因为这个文件属于一个许可的库,我不能更改它的内容。
我可以将我的待测函数提取到其他文件中,这样 foo.h
就不再需要包含了。但这会混淆嵌入式源代码结构。
问题的确切行数
确切的代码放在第233行的freeRtos的portmacro.h中:
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
其中 portFORCE_INLINE
定义为:
#define portFORCE_INLINE inline __attribute__(( always_inline))
Stupidly the wrap-flag seems not to work on functions
which are placed in header files.
这不是 wrap
的错,该函数已被编译器内联,因此链接器无能为力。
How to mock this function in the headerfile away?
一种选择是使用 sed
自动修补有问题的代码,然后再将其传递给 gcc。例如。改变
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
...
}
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void )
{
uint32_t ulNewBASEPRI;
...
}
从你的例子到
portFORCE_INLINE static void vPortRaiseBASEPRI( void );
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void );
做
cat tmp.c | sed '/inline\|INLINE/,/^}$/{ s/^\(.*\(inline\|INLINE\).*\)/;/; /inline\|INLINE/!d }'
正则表达式非常草率,它依赖于 header 中的所有定义都将具有 INLINE
标记这一事实,但在您的情况下应该足够了。
您可以将以上命令嵌入到您的 Makefile 中以在临时文件夹中生成自定义 header,然后使用 -Ipath/to/temp/folder
标志覆盖默认 header。
我没有使用过 cmocka,所以我不确定框架内是否已经有管理它的方法。
但是,cmock 使用一种方法,其中 header 被复制到测试构建的包含层次结构中更高的位置(并且只有测试构建,该位置甚至不包含在发布版本中。
然后可以编辑此 header 的副本,使函数声明简单地变为 port void vPortRaiseBASEPRI( void );
。然后当生成模拟时,就像在任何其他情况下一样,为此(以及同一 header 中的其他函数声明)生成模拟。因为正在生成 hte 模拟,所以没有匹配的函数源代码定义(即 .c
文件)并不重要。
请参阅 https://dmitryfrank.com/articles/unit_testing_embedded_c_applications
中的 "Dealing with compiler-specific stuff" 部分
还有我的类似问题以及我是如何解决的:Unit test C with compiler specific keywords
我在做什么:
我正在使用 cmocka 运行 对大型嵌入式项目进行单元测试。
嵌入式项目是用arm-gcc-compiler
编译的。
单元测试是使用嵌入式代码片段和 cmocka 库使用正常 gcc
编译的。
通常cmocka推荐使用-Wl,--wrap=functionName
标志来mock(替换)一些不需要的子函数。这个效果不错。
问题:
好吧,在我的嵌入式代码中有一个头文件 (foo.h
),其中包含一些函数(声明为内联)。其中一个函数包含 arm-gcc-compiler
的一些汇编代码,当然 gcc
.
愚蠢的是,wrap
-flag 似乎不适用于放置在头文件中的函数。
问题:
如何在头文件中模拟这个函数?
我是如何尝试解决问题的:
我想插入一些 #idef
宏来排除提到的汇编器部分。但这是不可能的,因为这个文件属于一个许可的库,我不能更改它的内容。
我可以将我的待测函数提取到其他文件中,这样 foo.h
就不再需要包含了。但这会混淆嵌入式源代码结构。
问题的确切行数
确切的代码放在第233行的freeRtos的portmacro.h中:
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
其中 portFORCE_INLINE
定义为:
#define portFORCE_INLINE inline __attribute__(( always_inline))
Stupidly the wrap-flag seems not to work on functions which are placed in header files.
这不是 wrap
的错,该函数已被编译器内联,因此链接器无能为力。
How to mock this function in the headerfile away?
一种选择是使用 sed
自动修补有问题的代码,然后再将其传递给 gcc。例如。改变
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
...
}
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void )
{
uint32_t ulNewBASEPRI;
...
}
从你的例子到
portFORCE_INLINE static void vPortRaiseBASEPRI( void );
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void );
做
cat tmp.c | sed '/inline\|INLINE/,/^}$/{ s/^\(.*\(inline\|INLINE\).*\)/;/; /inline\|INLINE/!d }'
正则表达式非常草率,它依赖于 header 中的所有定义都将具有 INLINE
标记这一事实,但在您的情况下应该足够了。
您可以将以上命令嵌入到您的 Makefile 中以在临时文件夹中生成自定义 header,然后使用 -Ipath/to/temp/folder
标志覆盖默认 header。
我没有使用过 cmocka,所以我不确定框架内是否已经有管理它的方法。
但是,cmock 使用一种方法,其中 header 被复制到测试构建的包含层次结构中更高的位置(并且只有测试构建,该位置甚至不包含在发布版本中。
然后可以编辑此 header 的副本,使函数声明简单地变为 port void vPortRaiseBASEPRI( void );
。然后当生成模拟时,就像在任何其他情况下一样,为此(以及同一 header 中的其他函数声明)生成模拟。因为正在生成 hte 模拟,所以没有匹配的函数源代码定义(即 .c
文件)并不重要。
请参阅 https://dmitryfrank.com/articles/unit_testing_embedded_c_applications
中的 "Dealing with compiler-specific stuff" 部分还有我的类似问题以及我是如何解决的:Unit test C with compiler specific keywords