throwtheswitch / cmock Goto Github PK
View Code? Open in Web Editor NEWCMock - Mock/stub generator for C
Home Page: http://throwtheswitch.org
License: MIT License
CMock - Mock/stub generator for C
Home Page: http://throwtheswitch.org
License: MIT License
Mocking the following function:
void foo(void __stdcall * bar(int arg0));
creates the mock:
void foo(void __stdcall* bar(int arg0))
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_foo_CALL_INSTANCE* cmock_call_instance = (CMOCK_foo_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.foo_CallInstance);
Mock.foo_CallInstance = CMock_Guts_MemNext(Mock.foo_CallInstance);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "Function 'foo' called more times than expected.");
cmock_line = cmock_call_instance->LineNumber;
{
UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_arg0)), (void*)(&arg0)), sizeof(void __stdcall* bar(int), cmock_line, "Function 'foo' called with unexpected value for argument 'arg0)'.");
}
}
The line
UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_arg0)), (void*)(&arg0)), sizeof(void __stdcall* bar(int), cmock_line, "Function 'foo' called with unexpected value for argument 'arg0)'.");
Seems to have a misplaced paren, as the open/close match ends at UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(&cmock_call_instance->Expected_arg0))
.
I'm new to github, so not really sure if it's a right place to propose ideas and new functionality here, but still...
It would be really nice to have a configurable option that defines a prefix name for the generated mock functions. Say, the original function is "int foo(int a)", then CMock would generate a mock with slightly changed name as "int prefixfoo(int a)". It would be a neat feature to use it together with the GNU linker --wrap option, which would make it possible to generate a wrapper mock with CMock, like "int __wrap_foo(int a)". Then, in a unit test, one could define a callback for the mock and from that callback call the original (being mocked) function as __real_foo().
Thanks!
When calling the <mock_name>_StubWithCallback(cb)
, I have to manually do another call <mock_name>_StubWithCallback(NULL)
to be able to run my next ExpectAndReturn
.
In some cases I use the stub as a special case for when I want to check for behavior specific to a single case, then switch back to regular, generated mocks. The regular Expect-functions will not be executed unless I disable the callback with the NULL-call, which seems a bit counter intuitive.
I think it makes sense to implicitly disable the callback if you call an expect or ignore function, is there any counter-argument I'm missing?
Declarations with constant pointers generate mock definitions for pointers to constant data.
int * const func(void);
leads to
const int* func(void) { ... }
Similar to #75
It would be nice to be able to ignore calls to a function after the initial call. Something like:
TestFunction_Expect(...)
TestFunction_Ignore()
CodeUnderTestCall() <-- calls 'TestFunction' twice.
This would allow the testing of individual parts in some functions. The ignore_args module already does something very similar. I am able to add a second 'expect', then just ignore all of the args. It's just ugly.
Hi,
At line 116 of cmock_header_oarser.rb, I had to remove the extern keyword (and even the else branch) because it was not possible to mock something like:
extern void my_api(args...)
The above prototype is usually used when hardware/software I/F are provided and avoid linking unused API.
In my opinion, it is worth mocking extern functions.
Best regards;
Johan
The returnThruPtr
plugin generates the corresponding _ReturnThruPtr_
function for thins kind of prototype:
void my_func(my_type_t *param);
but does not for this
void my_func(const my_type_t *param);
nor this
void my_func(my_type_t *const param);
In the const my_type_t *
case it seems right not to generate the mock function, since param
is clearly not an output parameter. But the my_type_t *const
case is different. Here we express the fact that the function cannot modify param
, but it can modify *param
, thus making it an output parameter.
Hello,
I guess, I'm missing something. Lets suppose I have a function
void ToTest(void)
{
char string[512] = "";
for (int i = 0; i < 100; i++)
{
sprintf(string, "String%d", i);
Function(string);
}
}
that I want to test. It calls a function int Function(char* string)
that I have to mock.
Then, back in the testcase, I use Function_ExpectAndReturn(..)
to enter the expected strings. As long as I enter hardcoded strings here (Function_ExpectAndReturn("String1")
) everything is fine (by chance, I guess). Not the string is passed (in terms of strcpy/memcpy) but only the address. That means, if I want to enter all 100 strings with a loop, only the last string is placed at the address and the test fails.
Is that a bug or a feature? :) Is there a way to overcome this issue?
All the best,
Oliver
This seems to be a ruby issue related to 1.9, my version:
ruby -v
ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]
Error output when I try to run the mocking process:
tools/Cmock/lib/cmock_header_parser.rb:53:in `scan': invalid byte sequence in UTF-8 (ArgumentError)
from [snip]/tools/Cmock/lib/cmock_header_parser.rb:53:in `import_source'
from [snip]/tools/Cmock/lib/cmock_header_parser.rb:32:in `parse'
from tools/Cmock/lib/cmock.rb:40:in `generate_mock'
from tools/Cmock/lib/cmock.rb:31:in `block in setup_mocks'
from tools/Cmock/lib/cmock.rb:30:in `each'
from tools/Cmock/lib/cmock.rb:30:in `setup_mocks'
from tools/Cmock/lib/cmock.rb:64:in `<main>'
Regards
Well, I tried with 1.8.7 and 1.9.3 from http://rubyinstaller.org/downloads/
I first ran:
gem install rake
gem install bundler
I skipped the git checkout because I don't have git installed. I just downloaded CMock and Unity and put Unity in the vendor/unity folder.
I then run (and get as output)
C:\cmock>bundle install rake
ERROR: "bundle install" was called with arguments ["rake"]
Usage: "bundle install [OPTIONS]"
C:\cmock>bundle install
Using rake 10.4.2
Using constructor 2.0.0
Using diy 1.1.2
Using minitest 5.5.0
Using require_all 1.3.2
Using bundler 1.7.9
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
C:\cmock>bundle exec rake
mkdir -p C:/cmock/test/system/generated
mkdir -p C:/cmock/test/system/build
C:/Ruby187/bin/ruby.exe -I"lib" -I"C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib" "C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/unit/*_test.rb"
C:/cmock/test/unit/cmock_config_test.rb:8:in `require': C:/cmock/test/unit/../test_helper.rb:19: syntax error, unexpected '=', expecting '|' (SyntaxError)
stub.define_singleton_method(k) {|unused=nil| return v }
^
C:/cmock/test/unit/../test_helper.rb:19: void value expression
stub.define_singleton_method(k) {|unused=nil| return v }
^
C:/cmock/test/unit/../test_helper.rb:19: syntax error, unexpected tIDENTIFIER, expecting kEND
stub.define_singleton_method(k) {|unused=nil| return v }
^
C:/cmock/test/unit/../test_helper.rb:42: syntax error, unexpected $end, expecting kEND
from C:/cmock/test/unit/cmock_config_test.rb:8
from C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib/rake/rake_test_loader.rb:15:in `require'
from C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib/rake/rake_test_loader.rb:15
from C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib/rake/rake_test_loader.rb:4:in `select'
from C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib/rake/rake_test_loader.rb:4
rake aborted!
Command failed with status (1): [ruby -I"lib" -I"C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib" "C:/Ruby187/lib/ruby/gems/1.8/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/unit/*_test.rb" ]
Tasks: TOP => default => test => test:units
(See full trace by running task with --trace)
C:\cmock>
How do I solve this? I am no rubyguru (first time ever using it to be honest).
Any help is appreciated.
When I gave CMock a header file named cmock-bug.h with the contents:
#ifndef CMOCK_BUG_H
#define CMOCK_BUG_H
void cmock_bug(void);
#endif /* !CMOCK_BUG_H */
It created this Mockcmock-bug.h:
#ifndef _MOCKCMOCK-BUG_H
#define _MOCKCMOCK-BUG_H
#include "cmock-bug.h"
void Mockcmock-bug_Init(void);
void Mockcmock-bug_Destroy(void);
void Mockcmock-bug_Verify(void);
#define cmock_bug_Expect() cmock_bug_CMockExpect(__LINE__)
void cmock_bug_CMockExpect(UNITY_LINE_TYPE cmock_line);
#endif
This mock header file won't compile because of the dashes in the guard macro and function names.
Dashes are pretty common in C file names, particularly in GNU and Gnome source code. This seems like a use case CMock would want to support.
rake test:system starts failing at Unity commit ThrowTheSwitch/Unity@5fbc23e
It looks like this commit just made a simple formatting change to the output of Unity which CMock's test suite hasn't been updated to account for.
Hi,
I think I stumbled upon a bug in CMock which can occurs when the memory alignment is not 1 byte.
In the CMock_Guts_MemNew function, access to CMock_Guts_Buffer is done by first adding CMock_Guts_FreePtr (which is 4 initially), and then casting it to a (in my case) an 32bit unsigned int pointer. CMock_Guts_Buffer currently is defined as a char array, and thus does not have to be aligned. So if the CMock_Guts_Buffer is not allocated to a 32 bit aligned location, CMock will crash the system on the first call to CMock_Guts_MemNew. (Assuming unaligned access is not supported ofcourse.)
Suggested syntax:
#include "foo/bar/mock_baz.h"
Produces a set of mocked files pulled in by the statement:
#include <foo/bar/baz.h>
or
#include "foo/bar/baz.h"
The primary motivation for this is to support stubbing out architecture interface header files for testing.
Hello,
I've downloaded the most recent version of CMock from the origin/master branch with SHA-1 f341e3f650ffa2b301768b5a1acbea0264999db2
and then I've tried to play with it a little bit. I've encountered a problem when I was trying to generate mocks for function which argument is of incomplete struct type, please find my modified foo.c, foo.h and test_foo.c files:
[https://gist.github.com/a-d-v-e-n-t-u-r-o-u-s/1089367da8f2ba7af39caf900400c062]
Here is also console output:
build/test/mocks/mock_foo.c: In function ‘foo_attach’:
build/test/mocks/mock_foo.c:140:107: error: invalid application of ‘sizeof’ to incomplete type ‘struct FOO_handle_t’
UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(cmock_call_instance->Expected_handle), (void*)(handle), sizeof(struct FOO_handle_t), cmock_line, CMockStringMismatch);
^
/home/babula/Documents/source/github/cmock/vendor/unity/src/unity_internals.h:670:191: note: in definition of macro ‘UNITY_TEST_ASSERT_EQUAL_MEMORY’
ITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), 1, (m
^
build/test/MakefileTestSupport:59: recipe for target 'build/test/mocks/mock_foo.o' failed
Can you please advise is there some magic switch in the order to turn off those error messages ? Currently the simplest solution would be moving structure definition to the header file.
The first time running cmock, I got this error:
:> cmock spi.h
Creating mock for spi...
../lib/cmock_file_writer.rb:26:in `initialize': No such file or directory @ rb_sysopen - mocks/Mockspi.h.new (Errno::ENOENT)
Once I create the mocks
directory then everything works fine. However the above error message is a bit cryptic, especially for new users. Can we either:
a) Create the mocks
dir by default
b) have a better warning message prompting the user to create or configure the mocks directory
Any preference?
Hi all,
I get the following error when CMock attempts to parse a particular header file.
rake aborted!
invalid byte sequence in UTF-8
CMock/lib/cmock_header_parser.rb:51:in scan' CMock/lib/cmock_header_parser.rb:51:in
import_source'
CMock/lib/cmock_header_parser.rb:30:in parse' CMock/lib/cmock.rb:40:in
generate_mock'
CMock/lib/cmock.rb:31:in block in setup_mocks' CMock/lib/cmock.rb:30:in
each'
CMock/lib/cmock.rb:30:in `setup_mocks'
I am using Ruby 1.9.3 and Ubuntu Linux. Surprisingly, the problem does not occur on a Windows machine.
Any ideas?
Not sure if this is the same as #26
If I substitute the _IgnoreAndReturn for _ExpectAndReturn(blah), the behavior is as expected: I have to fullfill the N calls.
I have the following header file { http://pastebin.com/Pcbi6hYQ } . I want to mock it using cmock so that i can write unit test for 'Server.c' that uses the methods in the header file. But while compiling, i get the following message :
/tmp/ccGINIbW.o: In function `redisLibuvAttach':
TestServer.c:(.text+0x378): multiple definition of `redisLibuvAttach'
/tmp/cc1dEQsm.o:MockStore.c:(.text+0x229): first defined here
collect2: error: ld returned 1 exit status
make: *** [default] Error 1
'TestServer.c' is file that contains that unit tests. 'MockStore.c' is the file generated by cmock. I searched 'MockStore.c' for 'redisLibuvAttach', but found nothing by that name.
Mocking the following function:
typedef void * __stdcall foofn (void);
void bar(foofn * arg0);
Will generate this
void bar(foofn* arg0)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_bar_CALL_INSTANCE* cmock_call_instance = (CMOCK_bar_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.bar_CallInstance);
Mock.bar_CallInstance = CMock_Guts_MemNext(Mock.bar_CallInstance);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "Function 'bar' called more times than expected.");
cmock_line = cmock_call_instance->LineNumber;
{
UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(cmock_call_instance->Expected_arg0), (void*)(arg0), sizeof(foofn), cmock_line, "Function 'bar' called with unexpected value for argument 'arg0'.");
}
}
which casts a function pointer to a data pointer during the operation (void*)(arg0)
.
$ ruby lib/cmock.rb examples/src/AdcConductor.h
lib/cmock.rb:14:in require': /sandbox/kyleh/workspace/cmock/lib/cmock_header_parser.rb:51: syntax error, unexpected ':', expecting ')' (SyntaxError) ...9-1").encode("utf-8", replace: nil) if ($QUICK_RUBY_VERSION ... ^ from lib/cmock.rb:14 from lib/cmock.rb:7:in
each'
from lib/cmock.rb:7
Hi,
After the following commit:
May 6, 8bd739e
Fixed 'unused variable `cmock_line' compiler warning. Warning was produced by generated code for functions without args.
CMock no longer creates compilable code for Armcc v5.04 (using uVision 5 IDE, similar to IAR workbench):
bool init_module(..)
{
UNITY_LINE_TYPE cmock_line;
cmock_line = TEST_LINE_NUM;
CMOCK_init_module_CALL_INSTANCE* cmock_call_instance = ...
error: (): error: #268: declaration may not appear after executable statement in block.
A fix for this would be to either solve the compiler warning in a different way (e.g. prefixing variable with (void)), or to move the statement "cmock_line = TEST_LINE_NUM;" after all variable declarations in the mocked function.
I enabled Return_Thru_Ptr and ran into an instance where a mock generated a memory protection exception. The problem appears to be that the cmock_call_instance data (setup in _CMockExpect) was not cleared resulting in the mock attempting to memcpy from a random location with a random length when called. This was fixed by editing the generated mock code and adding the line commented "/*added by CWS */" below:
X_CMockExpect(UNITY_LINE_TYPE cmock_line, , ...)
{
CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_CC_Execute_CALL_INSTANCE));
CMOCK_CC_Execute_CALL_INSTANCE* cmock_call_instance = (CMOCK_CC_Execute_CALL_INSTANCE_)CMock_Guts_GetAddressFor(cmock_guts_index);
/_added by CWS */ memset(cmock_call_instance, 0, sizeof(CMOCK_CC_Execute_CALL_INSTANCE));
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "CMock has run out of memory. Please allocate more.");
Mock.CC_Execute_CallInstance = CMock_Guts_MemChain(Mock.CC_Execute_CallInstance, cmock_guts_index);
Mock.CC_Execute_IgnoreBool = (int)0;
cmock_call_instance->LineNumber = cmock_line;
cmock_call_instance->CallOrder = ++GlobalExpectCount;
CMockExpectParameters_CC_Execute(cmock_call_instance, ...);
}
When trying to generate a mock form a header file I am getting a runtime error. The header file uses a macro to generate function declarations.
Header file:
#define DECLARE_FUNCTION(ID) int Test##ID();
DECLARE_FUNCTION(55)
CMock error:
cmock/lib/cmock_header_parser.rb:263:in `parse_declaration': Failed Parsing Declaration Prototype! (RuntimeError)
declaration: 'DECLARE_FUNCTION(55)'
modifier: ''
return: {:type => '', :name => 'cmock_to_return', :ptr? => false, :const? => false, :str => ' cmock_to_return', :void? => false}
function: 'DECLARE_FUNCTION'
args: [{:type => '55', :name => 'cmock_arg1', :ptr? => false, :const? => false}]
from cmock/lib/cmock_header_parser.rb:33:in `block in parse'
from cmock/lib/cmock_header_parser.rb:32:in `map'
from cmock/lib/cmock_header_parser.rb:32:in `parse'
from cmock/lib/cmock.rb:43:in `generate_mock'
from cmock/lib/cmock.rb:34:in `block in setup_mocks'
from cmock/lib/cmock.rb:33:in `each'
from cmock/lib/cmock.rb:33:in `setup_mocks'
from cmock/lib/cmock.rb:88:in `<main>'
This header causes no problems for the compiler (gcc). Running it through the preprocessor results in the following which CMock will correctly generate a mock from.
int Test55();
The generated mock of the following syntactically correct function generates a compiler warning C4034 :
typedef void SOMETHING;
void foo(SOMETHING* arg0);
The offending generated function looks like this:
void foo(SOMETHING* arg0)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_foo_CALL_INSTANCE* cmock_call_instance = (CMOCK_foo_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.foo_CallInstance);
Mock.foo_CallInstance = CMock_Guts_MemNext(Mock.foo_CallInstance);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "Function 'foo' called more times than expected.");
cmock_line = cmock_call_instance->LineNumber;
{
UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(cmock_call_instance->Expected_arg0), (void*)(arg0), sizeof(SOMETHING), cmock_line, "Function 'foo' called with unexpected value for argument 'arg0'.");
}
}
As you can see, calling sizeof(SOMETHING)
is essentially sizeof(void)
and may result in 0.
I have a function that I would like to mock
void my_third_function(int * p_arg);
But in a test case:
...
int retval = 10;
my_third_function_Ignore();
my_third_function_ReturnThruPtr_p_arg(&retval);
...
I will get this
ReturnThruPtr called before Expect on 'my_third_function'..
The problem is in the generated code, which does not set up the call instance correctly:
void my_third_function_CMockIgnore(void)
{
Mock.my_third_function_IgnoreBool = (int)1;
}
I have a function I'm testing that calls a mocked function lots of times. I tried using Expect in a loop, but I get an error that CMock has run out of memory. Consider the following code:
for(;;)
{
mocked_function_Expect();
mocked_function();
}
I would expect the mocked_function_Expect()
call to use some memory, but I expected that to be freed when the actual function is called. However, it looks like the memory is only freed after the entire test is finished. Is that actually true, and if so, why does it work like that?
Of course, in the example above, the Expect doesn't seem useful, but in my actual test there is also a ReturnThruPtr, so it becomes necessary.
Hello,
First, thank you for providing such wonderful development tools.
I am having a odd issue that has been driving me bonkers for days. I'll start with my environment:
Here is a helper function that will set up the mocks for writing a CRC16 value into my external flash chip:
void setupMocksForWritingFullStageImageCrc( uint16_t expectedCrc )
{
//uint16_t crcValue = expectedCrc;
uint16_t crcValue = 0xDEAD;
flash_sectorErase_ExpectAndReturn( ADDRESS_FW_IMAGE_CRC_SECTOR, eFlash_Success );
flash_writeDataBytes_ExpectAndReturn( crcAddress, sizeof( uint16_t ), (uint8_t *)&crcValue, eFlash_Success );
}
So I am expecting a flash sector erase then a call to write the CRC value to the external flash with a value of 0xDEAD. I hard-coded it to make sure I wasn't going crazy.
Here is the test summary output:
------------------------ FAILED UNIT TEST SUMMARY ------------------------ [test_FirmwareInit.c] Test: testInitBacksUpImageIfCrcCheckFails At line (113): "Element 0 Expected 0xC340 Was 0xDEAD. Function 'flash_writeDataBytes' called with unexpected value for argument 'data'."
As you can see, the function is being called and sending the correct value to the mock. But, even though I told it to expect 0xDEAD, it expects 0xC340 instead.
I should mention that I manually modified the mock function for flash_writeDataBytes to UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY instead of UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY and the data depth from 1 to 2 so that it will display the entire hex value.
I am going crazy here. Any help would be appreciated.
Thank you,
Alvin
Whenever I place the cmock functions function_Ignore, function_expect, etc. before my function call where the function is called gcc does a core dump. Please help.
I hit to an issue that mock generation misses the first function in the header in case there is declaration
extern "C"{ in the beginning.
It seems that the parser requires whitespace between the " and {. The below patch fixed the issue for me.
Index: lib/cmock_header_parser.rb
===================================================================
--- lib/cmock_header_parser.rb (revision 4699)
+++ lib/cmock_header_parser.rb (working copy)
@@ -71,7 +71,7 @@
# remove preprocessor statements and extern "C"
source.gsub!(/^\s*#.*/, '')
- source.gsub!(/extern\s+\"C\"\s+\{/, '')
+ source.gsub!(/extern\s+\"C\"\s*\{/, '')
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
There seems to be a bug for recreating the original header file name from the cmock header in line 67 of lib/cmock_generator.rb
orig_filename = filename.gsub(@config.mock_prefix, "")
If the original file name contains @config.mock_prefix, the attempt to recreate the original file name in this line creates a wrong name where @config.mock_prefix is removed at all occurrences not just at the beginning.
Suggested replacement:
orig_filename = filename[@config.mock_prefix.size..-1]
The cmock_header_parser.rb script has some serious problems parsing nested braces, and it's causing some issues with inline functions:
If I declare an inline function with internal control blocks surrounded by braces (see below), then call a function from within the inline function, the parser crashes at cmock_header_parser.rb:264, as it can't resolve the type of the return.
To reproduce:
Run cmock on the following header file:
#ifndef TEST_H__
#define TEST_H__
static inline void test(int arg1, int arg2)
{
if (arg1 == arg2)
{
return;
}
test_func2(arg1, arg2);
}
#endif
This triggers the exception at cmock_header_parser.rb:264 with the following output:
declaration: 'test_func2(arg1, arg2)'
modifier: ''
return: {:type => '', :name => 'cmock_to_return', :ptr? => false, :const? => false, :str => ' cmock_to_return', :void? => false}
function: 'test_func2'
args: [
{:type => 'arg1', :name => 'cmock_arg1', :ptr? => false, :const? => false}
{:type => 'arg2', :name => 'cmock_arg2', :ptr? => false, :const? => false}
]
from cmock/lib/cmock_header_parser.rb:33:in `block in parse'
from cmock/lib/cmock_header_parser.rb:32:in `map'
from cmock/lib/cmock_header_parser.rb:32:in `parse'
from cmock/lib/cmock.rb:43:in `generate_mock'
from cmock/lib/cmock.rb:34:in `block in setup_mocks'
from cmock/lib/cmock.rb:33:in `each'
from cmock/lib/cmock.rb:33:in `setup_mocks'
from cmock/lib/cmock.rb:88:in `<main>'
The regexes in the cmock_header_parser.rb function import_source(source)
are quite sloppy in general, mostly because they don't handle nested braces very well, and it relies on the functions after it to clean up. This particular issue could be solved by checking each potential function declaration for returns in parse_functions(source)
, or ignoring functions violating the conditional at L262, but that just seems like a work-around.
I must be missing something trivial here. I'd appreciate any help.
I reduced my test file to this:
#include <unity.h>
#include <stdbool.h>
#include "uart.h"
#include "mock_assert.h"
bool ASSERT_EXPECTED;
void setUp(void)
{
ASSERT_EXPECTED = false;
}
void tearDown(void)
{
}
void _assert_Callback(const char* file, int line, int cmock_num_calls)
{
TEST_ASSERT_EQUAL(true, ASSERT_EXPECTED);
}
void test_Verify_Init_With_NULL_Reference(void)
{
_assert_StubWithCallback(_assert_Callback);
ASSERT_EXPECTED = true;
uart_init(0);
}
I'm using Ceedling and when I do "rake test:all", I receive the message:
ERROR: Test executable "test_uart.out" failed.
Produced no output to $stdout.
And then likely crashed.
This is often a symptom of a bad memory access in source or test code.
My tests were running OK, until I tried to use CMock to mock my _assert function.
ASSERT_EXPECTED has global scope. I may be missing something here but I don't see why it would not be acessible from those functions.
The crazy thing is:
if I set the ASSERT_EXPECTED to falsein the test_Verify_Init_With_NULL_Reference, the test runs and then fails correctly.
So I tried this two situations inside _assert_Callback:
1- TEST_ASSERT_EQUAL(true, false) - test runs and fails as expected
2= TEST_ASSERT_EQUAL(true,true) - test fails with above message
Any idea what may be causing this?
I run bundle exec rake from Windows and get the following. It appears to try and access a non-existent file.
C:\>bundle install --gemfile Gemfile
Using rake 10.5.0
Using constructor 2.0.0
Using minitest 5.8.4
Using require_all 1.3.3
Using bundler 1.11.2
Using diy 1.1.2
Bundle complete! 6 Gemfile dependencies, 6 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
C:\> bundle exec rake
....
....
C:/Ruby22/bin/ruby.exe -I"lib" -I"C:/Ruby22/lib/ruby/gems/2.2.0/gems/rake-10.5.0/lib" "C:/Ruby22/lib/ruby/gems/2.2.0/gems/rake-10.5.0/lib/rake/rake_test_loader.rb" "test/unit/*_test.rb"
Run options: --seed 49888
# Running:
.........................................................................................................................................................................................................................................
Finished in 0.112229s, 2076.1060 runs/s, 2833.4837 assertions/s.
233 runs, 318 assertions, 0 failures, 0 errors, 0 skips
----------------
UNIT TEST C CODE
----------------
Testing test/c/TestCMockC
(TEST, CMOCK_MEM_STATIC, CMOCK_MEM_SIZE=128, CMOCK_MEM_ALIGN=2, CMOCK_MEM_INDEX_TYPE=int)
rake aborted!
Errno::ENOENT: No such file or directory - gcc -DCMOCK -DUNITY_SUPPORT_64 -DCMOCK_MEM_INDEX_TYPE=int -DCMOCK_MEM_ALIGN=2 -DCMOCK_MEM_SIZE=128 -DCMOCK_MEM_STATIC -DTEST -c -Wall -Wextra -Wunused-parameter -Wno-address -Wno-invalid-token-paste -std=c99 -pedantic -O0 -Itest/system/generated/ -Iexamples/test/ -Itest/system/generated/ -Isrc/ -Ivendor/unity/src/ -Ivendor/c_exception/lib/ -Itest/system/test_compilation/ -Itest/ src/cmock.c -otest/system/build/cmock.o
....
....
....
Tasks: TOP => default => test => test:c
(See full trace by running task with --trace)
As discussed at http://throwtheswitch.org/white-papers/cmock-pointers-and-structs.html, CMock doesn't provide a way for mocks to modify the data pointed to by pointer arguments. This makes it impossible to mock functions that return data through pointers. That article discusses workarounds, but they all assume that you have control over the API of the function in question. Sometimes, you don't.
I've developed a patch to add this ability to CMock: [EDIT: Link removed due to bugs. In a later comment I posted a link to a fixed version with additional features]
The patch adds a plugin, return_thru_ptr
. When this plugin is enabled, additional macros are generated for each function's pointer arguments which allow you to specify data to be copied onto the target of that pointer by the mock. For example, for a function with the prototype void ptr_ret_int(int *r)
, the following macros are created:
void ptr_ret_int_ReturnThruPtr_r(int *r)
void ptr_ret_int_ReturnArrayThruPtr_r(int *r, int len)
void ptr_ret_int_ReturnMemThruPtr_r(int *r, int size)
These functions can be called after one of the Expect
family of calls to give the most recently defined expectation a value to return through a pointer argument.
ReturnThruPtr
arranges for a single value to be copied onto the target of the pointer argument.
ReturnArrayThruPtr
arranges for an array of values, with a length specified by len
, to be copied.
ReturnMemThruPtr
arranges for a memory buffer, with a size
specified in bytes, to be copied.
Here is an example of a test that exercises ReturnThruPtr
for a function void ptr_ret_ints(int *r, int *s)
:
{
int r, s = 0x0880AA55;
int r_res = 4;
int s_res = 6;
Mock_ptr_ret_Init();
ptr_ret_ints_Expect(&r, &s);
ptr_ret_ints_ReturnThruPtr_r(&r_res);
ptr_ret_ints_ReturnThruPtr_s(&s_res);
ptr_ret_ints(&r, &s);
Mock_ptr_ret_Verify();
TEST_ASSERT_EQUAL(4, r);
TEST_ASSERT_EQUAL(6, s);
}
Usage Notes
The expectation object created by these calls only stores a pointer to the memory to be copied, so it's important that the memory, in this case r_res
and s_res
, not be modified between the calls to ReturnThruPtr
and the call to the mocked function.
ReturnThruPtr
functions must be called after the Expect
calls they modify. A ReturnThruPtr
call before any Expect
calls will result in undefined behavior.
return_thru_ptr
doesn't work with the ignore
plugin. It only properly returns through pointer arguments when the expectation was created with an Expect
call.
Implementation Notes
The CMock plugin architecture isn't quite flexible enough to support implementing this feature entirely within the plugin class file. Since there's no structured way to add additional constructor code to expectations, I had to hack cm_utils.code_add_argument_loader
to detect the presence of the return_thru_ptr
plugin and add initialization of the ReturnThruPtr_..._Used
fields, using the same technique that code_add_argument_loader
already used to hack in support for the array
plugin.
While incomplete types won't prevent mocks from being generated or compiled with return_thru_ptr
enabled, they will present an obstacle for anyone wanting to actually use the plugin to pass data through an incompletely typed argument. This can be worked around with ReturnMemThruPtr
but requires hard-coding the size of the abstract type, which is very dangerous and brittle. A better solution is to use preprocessor magic to make sure that the type is complete when compiling the test harness.
Hi
When having the same issue as handled in assert fix #24 (committed to master in 31ae10b, March 9 2014) I found that this fix - which seems to work as expected in my code - have been removed from the master (commit fcc6a40, March 17 2014) with the comment "resolved conflicts".
My questions is:
Thanks.
/Steven
On one of my projects I am using IAR for ARM with the following :tools:
configuration for the compiler:
:tools:
:test_compiler:
:executable: iccarm.exe
:name: 'IAR-ARM C/C++ Compiler'
:stderr_redirect: :win #inform Ceedling what model of $stderr capture to use
:arguments:
- -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE #expands to -I search paths
- -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR #expands to -I search paths
- -D$: COLLECTION_DEFINES_TEST_AND_VENDOR #expands to all -D defined symbols
- --silent --use_unix_directory_separators --no_wrap_diagnostics #Configure output
- --diag_suppress=Pa050 # Ignore warning about non-native line-ends
- --no_cse --no_unroll --no_inline --no_code_motion --no_tbaa --no_clustering --no_scheduling
- --endian=little --cpu=Cortex-M4 --fpu=VFPv4_sp
- --debug
- -Ol --dlib_config
- "#{'\"'}#{`type iar-path.inc`}#{'/arm/inc/c/DLib_Config_Normal.h'}#{'\"'}"
- ${1} #source code input file (Ruby method call param list sub)
- -o ${2} #object file output (Ruby method call param list sub)
And I get the following warning:
Warning[Pe161]: unrecognized #pragma
Looking into the MockMyFile.h I see this:
/* Ignore the following warnings, since we are copying code */
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#pragma GCC diagnostic ignored "-Wpragmas"
#endif
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wduplicate-decl-specifier"
It's those lower two #pragmas that are being used even though I'm not using GCC. I can fix this by ignoring Pe161 but other compilers might fail with an error so please fix this. Thank you!
I have a header with this function prototype (all others have been commented out) and the error persists:
I2C_AO_REQ_RET pubRequestI2C(unsigned char addr, unsigned char *data, uint32_t length, I2C_DIRECTION dir, QActive *requesting_AO);
This configuration works fine:
:cmock:
:verbosity: 3
:mock_prefix: mock_
:when_no_prototypes: :warn
:enforce_strict_ordering: TRUE
:when_ptr: smart
:plugins:
- :ignore
- :callback
- :ignore_arg
:treat_as:
uint8: HEX8
uint16: HEX16
uint32: UINT32
int8: INT8
bool: UINT8
However when I add :array
I get the following error output:
vagrant@vagrant-ubuntu-trusty-64:/vagrant$ ceedling test:all
Test 'test_temp_humid.c'
------------------------
Creating mock for i2c...
rake aborted!
TypeError: can't convert nil into String
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb:60:in `block in mock_implementation
_always_check_args'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb:59:in `each'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb:59:in `mock_implementation_always_c
heck_args'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb:33:in `block in run'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb:33:in `collect'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb:33:in `run'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb:225:in `create_mock_implementation'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb:79:in `block (2 levels) in create_mock_source_fil
e'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb:78:in `each'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb:78:in `block in create_mock_source_file'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb:31:in `block in create_file'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb:30:in `open'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb:30:in `create_file'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb:71:in `create_mock_source_file'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb:47:in `create_mock'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock.rb:43:in `generate_mock'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock.rb:34:in `block in setup_mocks'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock.rb:33:in `each'
/vagrant/vendor/ceedling/vendor/cmock/lib/cmock.rb:33:in `setup_mocks'
/vagrant/vendor/ceedling/lib/ceedling/generator.rb:49:in `generate_mock'
/vagrant/vendor/ceedling/lib/ceedling/rules_cmock.rake:8:in `block in <top (required)>'
/vagrant/vendor/ceedling/lib/ceedling/task_invoker.rb:49:in `block in invoke_test_mocks'
/vagrant/vendor/ceedling/lib/ceedling/task_invoker.rb:49:in `invoke_test_mocks'
/vagrant/vendor/ceedling/lib/ceedling/preprocessinator.rb:23:in `preprocess_test_and_invoke_test_mocks'
/vagrant/vendor/ceedling/lib/ceedling/test_invoker.rb:42:in `block in setup_and_invoke'
/vagrant/vendor/ceedling/lib/ceedling/test_invoker.rb:32:in `setup_and_invoke'
/vagrant/vendor/ceedling/lib/ceedling/tasks_tests.rake:8:in `block (2 levels) in <top (required)>'
/var/lib/gems/1.9.1/gems/rake-11.2.2/exe/rake:27:in `<top (required)>'
Tasks: TOP => build/test/mocks/mock_i2c.c
(See full trace by running task with --trace)
--------------------
OVERALL TEST SUMMARY
--------------------
No tests executed.
vagrant@vagrant-ubuntu-trusty-64:/vagrant$
This was a tricky one! I was performing some very basic tests to make sure that a deInit() function was being cascaded from a top-layer module down to the layers below. CMock provided the lower-layer deInit() functions.
In my Unity tearDown() routine, I accidentally called "ExpectAndReturn" on the wrong functions (init instead of deInit) and provided a return value.
The test executable seg-faulted in one of the mocked deInit() functions, at the line:
cmock_line = cmock_call_instance->LineNumber;
gdb reported the value of cmock_call_instance was 0, so the mock was trying to dereference a null pointer.
While I'm still not certain exactly what in my test configuration caused CMock_Guts_GetAddressFor() to return null, and the segfault stopped once I started Expect-ing the correct functions, it strikes me that the cmock_call_instance should at least be null checked to return an error code instead of causing a segmentation fault.
Possible clue: The test only segfaulted when the incorrect expectations occurred in the tearDown() function. Moving the identical lines of code to the end of a unit test did not cause a segfault.
Compiling CMock with GCC and the following warnings throws strict-aliasing warning.
gcc -g -O0 -Wall -Werror -Wextra -Wcast-align -Wcast-qual -Wconversion -Wdisabled-optimization -Wdouble-promotion -Wflo
at-equal -Wformat=2 -Winit-self -Winline -Winvalid-pch -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wmiss
ing-prototypes -Wnonnull -Wpacked -Wpointer-arith -Wredundant-decls -Wswitch-default -Wstrict-aliasing -Wstrict-overflow
=5 -Wsuggest-attribute=const -Wuninitialized -Wmaybe-uninitialized -Wunused -Wunreachable-code -Wreturn-type -Wshadow -W
undef -Wwrite-strings -Wno-missing-declarations -Wno-missing-prototypes -Wno-nested-externs -Wno-redundant-decls -Wno-un
used-parameter -Wno-variadic-macros -fms-extensions -fno-omit-frame-pointer -ffloat-store -fno-common -fstrict-aliasing
-std=gnu99 -Wbad-function-cast -o obj/cmock.o -ICMock/ -c cmock.c
cmock.c: In function 'CMock_Guts_MemNew':
cmock.c:77:3: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
cc1.exe: all warnings being treated as errors
Compilation of cmock.c failed!
Running the install instructions in the Readme.md, bundle exec rake failes when executing the first compiled C test on Windows, with MinGW and GCC 4.8.1. Forcing rakefile_helper.rb to output generated gcc commands renders the following (relevant) output:
----------------
UNIT TEST C CODE
----------------
Testing test/c/TestCMockC
(TEST, CMOCK_MEM_SIZE=128, CMOCK_MEM_ALIGN=2, CMOCK_MEM_INDEX_TYPE=int)
gcc -DUNITY_SUPPORT_64 -DCMOCK_MEM_INDEX_TYPE=int -DCMOCK_MEM_ALIGN=2 -DCMOCK_MEM_SIZE=128 -DTEST -c -Wall -Wextra -Wunused-parameter -Wno-address -std=c99 -pedantic -O0 -g3 -Itest/system/generated/ -Iexamples/test/ -Itest/system/generated/ -Isrc/ -Ivendor/unity/src/ -Ivendor/c_exception/lib/ -Itest/system/test_compilation/ -Itest/ src/cmock.c -otest/system/build/cmock.o
gcc -DUNITY_SUPPORT_64 -DCMOCK_MEM_INDEX_TYPE=int -DCMOCK_MEM_ALIGN=2 -DCMOCK_MEM_SIZE=128 -DTEST -c -Wall -Wextra -Wunused-parameter -Wno-address -std=c99 -pedantic -O0 -g3 -Itest/system/generated/ -Iexamples/test/ -Itest/system/generated/ -Isrc/ -Ivendor/unity/src/ -Ivendor/c_exception/lib/ -Itest/system/test_compilation/ -Itest/ test/c/TestCMockC.c -otest/system/build/TestCMockC.o
gcc -DUNITY_SUPPORT_64 -DCMOCK_MEM_INDEX_TYPE=int -DCMOCK_MEM_ALIGN=2 -DCMOCK_MEM_SIZE=128 -DTEST -c -Wall -Wextra -Wunused-parameter -Wno-address -std=c99 -pedantic -O0 -g3 -Itest/system/generated/ -Iexamples/test/ -Itest/system/generated/ -Isrc/ -Ivendor/unity/src/ -Ivendor/c_exception/lib/ -Itest/system/test_compilation/ -Itest/ test/c/TestCMockC_Runner.c -otest/system/build/TestCMockC_Runner.o
gcc -DUNITY_SUPPORT_64 -DCMOCK_MEM_INDEX_TYPE=int -DCMOCK_MEM_ALIGN=2 -DCMOCK_MEM_SIZE=128 -DTEST -c -Wall -Wextra -Wunused-parameter -Wno-address -std=c99 -pedantic -O0 -g3 -Itest/system/generated/ -Iexamples/test/ -Itest/system/generated/ -Isrc/ -Ivendor/unity/src/ -Ivendor/c_exception/lib/ -Itest/system/test_compilation/ -Itest/ vendor/unity/src/unity.c -otest/system/build/unity.o
gcc -lm test/system/build/cmock.o test/system/build/TestCMockC.o test/system/build/TestCMockC_Runner.o test/system/build/unity.o -lm -o test/system/build/TestCMockC.exe
rake aborted!
test/system/build/TestCMockC.exe failed. (Returned )
c:/Users/Brad/Dropbox/Dev/cmock/rakefile_helper.rb:148:in `execute'
c:/Users/Brad/Dropbox/Dev/cmock/rakefile_helper.rb:367:in `block in build_and_test_c_files'
c:/Users/Brad/Dropbox/Dev/cmock/rakefile_helper.rb:359:in `build_and_test_c_files'
c:/Users/Brad/Dropbox/Dev/cmock/Rakefile:65:in `block (2 levels) in <top (required)>'
Tasks: TOP => default => test => test:c
(See full trace by running task with --trace)
Looking at the objdump, or stepping through with GDB, the code appears to fail at the first call to setUp(), which calls into nowhere code:
if (TEST_PROTECT())
40503e: c7 04 24 f8 1a 41 00 movl $0x411af8,(%esp)
405045: e8 d6 70 00 00 call 40c120 <__setjmp>
40504a: 85 c0 test %eax,%eax
40504c: 75 0a jne 405058 <_UnityDefaultTestRun+0x53
>
{
setUp();
40504e: e8 c3 a6 ff ff call 3ff716 <__size_of_stack_reserve__
+0x1ff716>
Func();
405053: 8b 45 08 mov 0x8(%ebp),%eax
405056: ff d0 call *%eax
}
On an Ubuntu VM, for example, the following disassembly is generated:
if (TEST_PROTECT())
4031f8: bf 60 51 60 00 mov $0x605160,%edi
4031fd: e8 ae d2 ff ff callq 4004b0 <_setjmp@plt>
403202: 85 c0 test %eax,%eax
403204: 75 0b jne 403211 <UnityDefaultTestRun+0x55>
{
setUp();
403206: e8 0b d6 ff ff callq 400816 <setUp>
Func();
40320b: 48 8b 45 f8 mov -0x8(%rbp),%rax
40320f: ff d0 callq *%rax
}
I'm.. Kinda at a loss here. I really suspect the toolchain, except that I've been able to compile other non-trivially large projects with this same toolchain, and haven't seen any weirdness, and my google-fu has failed. Appreciate any insights.
I have a function that I would like to mock
void my_third_function(int * p_arg);
But in a test case:
...
int retval = 10;
int expected = 11;
my_third_function_Expect(&expected);
my_third_function_ReturnThruPtr_p_arg(&retval);
...
I will get this
Element 0 Expected 11 Was 10. Function 'my_third_function' called with unexpected value for argument 'p_arg'.
If I change
int retval = 10;
to
int retval = 11;
The case will work.
The problem is in the generated code (UNITY_TEST_ASSERT_EQUAL_INT_ARRAY is done after memcpy, which will over write the checked argument):
...
if (cmock_call_instance->ReturnThruPtr_p_arg_Used)
{
memcpy(p_arg, cmock_call_instance->ReturnThruPtr_p_arg_Val,
cmock_call_instance->ReturnThruPtr_p_arg_Size);
}
{
if (cmock_call_instance->Expected_p_arg == NULL)
{ UNITY_TEST_ASSERT_NULL(p_arg, cmock_line, "Expected NULL. Function 'my_third_function' called with unexpected value for argument 'p_arg'."); }
else
{ UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(cmock_call_instance->Expected_p_arg, p_arg, 1, cmock_line, "Function 'my_third_function' called with unexpected value for argument 'p_arg'."); }
}
...
Hi,
I'm using build version 2.0, build info 212 and I have the following yaml file:
:cmock:
:verbosity: 3
:plugins:
- 'ignore'
- 'ignore_arg'
- 'expect_any_args'
:includes:
- 'unity_fixture.h'
:mock_prefix: mock_
:mock_path: test/mocks
:treat_as_void: []
My test looks like this:
TEST_SETUP(some_group)
{
mock_foo_Init();
}
TEST_TEAR_DOWN(some_group)
{
mock_foo_Verify();
mock_foo_Destroy();
}
TEST(some_group, init_foo_not_called)
{
init_foo_IgnoreAndReturn(true);
}
TEST(some_group, init_foo_called_once)
{
init_foo_IgnoreAndReturn(true);
init_foo();
}
TEST(some_group, init_foo_called_twice)
{
init_foo_IgnoreAndReturn(true);
init_foo();
init_foo();
}
Results:
init_foo_not_called:FAIL: Function 'init_foo' called less times than expected.
init_foo_called_once -> PASS
init_foo_called_twice -> PASS
I'm looking for a way where 0 calls to init_foo() also passes the test.
Is this a bug, or do I need to do something else?
I am trying to mock a piece of code that has a function that returns a struct directly (not via a pointer). The problem is that CMock generates a function that returns the value, but casts the return which causes a compile error.
So I have the following example code in myHeader.h
:
typedef struct
{
uint8 x;
uint8 y;
uint8 z;
} tMyStruct;
tMyStruct myFunc( void );
This generates the following mocked function:
tMyStruct myFunc(void)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_myFunc_CALL_INSTANCE* cmock_call_instance = (CMOCK_myFunc_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.myFunc_CallInstance);
Mock.myFunc_CallInstance = CMock_Guts_MemNext(Mock.myFunc_CallInstance);
if (Mock.myFunc_IgnoreBool)
{
if (cmock_call_instance == NULL)
return (tMyStruct)Mock.myFunc_FinalReturn;
memcpy(&Mock.myFunc_FinalReturn, &cmock_call_instance->ReturnVal, sizeof(tMyStruct));
return (tMyStruct)cmock_call_instance->ReturnVal;
}
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "Function 'myFunc' called more times than expected.");
cmock_line = cmock_call_instance->LineNumber;
return cmock_call_instance->ReturnVal;
}
This will fail to compile in IAR with the error cast to type "tMyStruct" is not allowed
.
Oddly it seems that the mocks structures contain the correct type for the return value anyway so don't actually need to be cast. I can get around the error in fact by removing the cast from the offending code. Does the cast need to be done at all?
Putting a token after the ) of a function definition causes cmock to fail to detect the signature, even if the token is listed in :attributes:
. For example
void my_function(void) SUFFIX;
with this cmock.yml:
:cmock:
:attributes:
- SUFFIX
causes WARNING: No function prototypes found!
. This is a problem since GCC attribute((...))'s are often placed after the function signature.
By looking at the code I discovered that adding SUFFIX to :strippables:
does the trick, but it's not documented so I'm not sure if that is a supported use. Possibly the documentation just needs improvement to clarify what exactly attributes
and strippables
are for.
This is a copy of an issue from the closed cmock-forum.
I mocked printf and used IgnoreAndReturn. Since then the test loops and never finishs.
Every time I stop the execution in gdb it is somewhere in CMock_Guts_MemChain.
Program received signal SIGINT, Interrupt.
0x0000000000423728 in CMock_Guts_MemChain (root_index=8, obj_index=272)
at /home/sschwarz/dev/COR4114/tools/Cmock/src/cmock.c:116
116 index = (CMOCK_MEM_INDEX_TYPE)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
(gdb) where
#0 0x0000000000423728 in CMock_Guts_MemChain (root_index=8, obj_index=272)
at /home/sschwarz/dev/COR4114/tools/Cmock/src/cmock.c:116
#1 0x000000000040db0c in dbg_printf_CMockIgnoreAndReturn (cmock_line=55,
cmock_to_return=0 '\000')
(version is 2.0.203)
thx
Wow. that's a new one.
Can you post the function prototype you are using for printf (that is getting fed into the mock) and also the generated mock code? Out of curiosity, is that 32-bit or 64-it gcc? native?
Thanks
Mark
Hi Mark,
the prototype is:
uint8_t dbg_printf(const char* format, ...);
In my code I use macros like this to call it:
The generated code is:
/* AUTOGENERATED FILE. DO NOT EDIT. */
typedef struct _CMOCK_dbg_setup_CALL_INSTANCE
{
UNITY_LINE_TYPE LineNumber;
int ReturnVal;
} CMOCK_dbg_setup_CALL_INSTANCE;
typedef struct _CMOCK_dbg_printf_CALL_INSTANCE
{
UNITY_LINE_TYPE LineNumber;
uint8_t ReturnVal;
char* Expected_format;
} CMOCK_dbg_printf_CALL_INSTANCE;
static struct MockdebugInstance
{
int dbg_setup_IgnoreBool;
int dbg_setup_FinalReturn;
CMOCK_dbg_setup_CALLBACK dbg_setup_CallbackFunctionPointer;
int dbg_setup_CallbackCalls;
CMOCK_MEM_INDEX_TYPE dbg_setup_CallInstance;
int dbg_printf_IgnoreBool;
uint8_t dbg_printf_FinalReturn;
CMOCK_dbg_printf_CALLBACK dbg_printf_CallbackFunctionPointer;
int dbg_printf_CallbackCalls;
CMOCK_MEM_INDEX_TYPE dbg_printf_CallInstance;
} Mock;
extern jmp_buf AbortFrame;
void Mockdebug_Verify(void)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
if (Mock.dbg_setup_IgnoreBool)
Mock.dbg_setup_CallInstance = CMOCK_GUTS_NONE;
UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.dbg_setup_CallInstance, cmock_line, "Function 'dbg_setup' called less times than expected.");
if (Mock.dbg_setup_CallbackFunctionPointer != NULL)
Mock.dbg_setup_CallInstance = CMOCK_GUTS_NONE;
if (Mock.dbg_printf_IgnoreBool)
Mock.dbg_printf_CallInstance = CMOCK_GUTS_NONE;
UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.dbg_printf_CallInstance, cmock_line, "Function 'dbg_printf' called less times than expected.");
if (Mock.dbg_printf_CallbackFunctionPointer != NULL)
Mock.dbg_printf_CallInstance = CMOCK_GUTS_NONE;
}
void Mockdebug_Init(void)
{
Mockdebug_Destroy();
}
void Mockdebug_Destroy(void)
{
CMock_Guts_MemFreeAll();
memset(&Mock, 0, sizeof(Mock));
Mock.dbg_setup_CallbackFunctionPointer = NULL;
Mock.dbg_setup_CallbackCalls = 0;
Mock.dbg_printf_CallbackFunctionPointer = NULL;
Mock.dbg_printf_CallbackCalls = 0;
}
int dbg_setup(void)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_dbg_setup_CALL_INSTANCE* cmock_call_instance = (CMOCK_dbg_setup_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.dbg_setup_CallInstance);
Mock.dbg_setup_CallInstance = CMock_Guts_MemNext(Mock.dbg_setup_CallInstance);
if (Mock.dbg_setup_IgnoreBool)
{
if (cmock_call_instance == NULL)
return Mock.dbg_setup_FinalReturn;
Mock.dbg_setup_FinalReturn = cmock_call_instance->ReturnVal;
return cmock_call_instance->ReturnVal;
}
if (Mock.dbg_setup_CallbackFunctionPointer != NULL)
{
return Mock.dbg_setup_CallbackFunctionPointer(Mock.dbg_setup_CallbackCalls++);
}
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "Function 'dbg_setup' called more times than expected.");
cmock_line = cmock_call_instance->LineNumber;
return cmock_call_instance->ReturnVal;
}
void dbg_setup_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return)
{
CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_dbg_setup_CALL_INSTANCE));
CMOCK_dbg_setup_CALL_INSTANCE* cmock_call_instance = (CMOCK_dbg_setup_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "CMock has run out of memory. Please allocate more.");
Mock.dbg_setup_CallInstance = CMock_Guts_MemChain(Mock.dbg_setup_CallInstance, cmock_guts_index);
cmock_call_instance->LineNumber = cmock_line;
cmock_call_instance->ReturnVal = cmock_to_return;
Mock.dbg_setup_IgnoreBool = (int)1;
}
void dbg_setup_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return)
{
CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_dbg_setup_CALL_INSTANCE));
CMOCK_dbg_setup_CALL_INSTANCE* cmock_call_instance = (CMOCK_dbg_setup_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "CMock has run out of memory. Please allocate more.");
Mock.dbg_setup_CallInstance = CMock_Guts_MemChain(Mock.dbg_setup_CallInstance, cmock_guts_index);
cmock_call_instance->LineNumber = cmock_line;
cmock_call_instance->ReturnVal = cmock_to_return;
}
void dbg_setup_StubWithCallback(CMOCK_dbg_setup_CALLBACK Callback)
{
Mock.dbg_setup_CallbackFunctionPointer = Callback;
}
uint8_t dbg_printf(const char* format, ...)
{
UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;
CMOCK_dbg_printf_CALL_INSTANCE* cmock_call_instance = (CMOCK_dbg_printf_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.dbg_printf_CallInstance);
Mock.dbg_printf_CallInstance = CMock_Guts_MemNext(Mock.dbg_printf_CallInstance);
if (Mock.dbg_printf_IgnoreBool)
{
if (cmock_call_instance == NULL)
return Mock.dbg_printf_FinalReturn;
Mock.dbg_printf_FinalReturn = cmock_call_instance->ReturnVal;
return cmock_call_instance->ReturnVal;
}
if (Mock.dbg_printf_CallbackFunctionPointer != NULL)
{
return Mock.dbg_printf_CallbackFunctionPointer(format, Mock.dbg_printf_CallbackCalls++);
}
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "Function 'dbg_printf' called more times than expected.");
cmock_line = cmock_call_instance->LineNumber;
UNITY_TEST_ASSERT_EQUAL_STRING(cmock_call_instance->Expected_format, format, cmock_line, "Function 'dbg_printf' called with unexpected value for argument 'format'.");
return cmock_call_instance->ReturnVal;
}
void CMockExpectParameters_dbg_printf(CMOCK_dbg_printf_CALL_INSTANCE* cmock_call_instance, const char* format)
{
cmock_call_instance->Expected_format = (char*)format;
}
void dbg_printf_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, uint8_t cmock_to_return)
{
CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_dbg_printf_CALL_INSTANCE));
CMOCK_dbg_printf_CALL_INSTANCE* cmock_call_instance = (CMOCK_dbg_printf_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "CMock has run out of memory. Please allocate more.");
Mock.dbg_printf_CallInstance = CMock_Guts_MemChain(Mock.dbg_printf_CallInstance, cmock_guts_index);
cmock_call_instance->LineNumber = cmock_line;
cmock_call_instance->ReturnVal = cmock_to_return;
Mock.dbg_printf_IgnoreBool = (int)1;
}
void dbg_printf_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, const char* format, uint8_t cmock_to_return)
{
CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_dbg_printf_CALL_INSTANCE));
CMOCK_dbg_printf_CALL_INSTANCE* cmock_call_instance = (CMOCK_dbg_printf_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);
UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, "CMock has run out of memory. Please allocate more.");
Mock.dbg_printf_CallInstance = CMock_Guts_MemChain(Mock.dbg_printf_CallInstance, cmock_guts_index);
cmock_call_instance->LineNumber = cmock_line;
CMockExpectParameters_dbg_printf(cmock_call_instance, format);
cmock_call_instance->ReturnVal = cmock_to_return;
}
void dbg_printf_StubWithCallback(CMOCK_dbg_printf_CALLBACK Callback)
{
Mock.dbg_printf_CallbackFunctionPointer = Callback;
}
And the header:
/* AUTOGENERATED FILE. DO NOT EDIT. */
void Mockdebug_Init(void);
void Mockdebug_Destroy(void);
void Mockdebug_Verify(void);
void dbg_setup_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return);
void dbg_setup_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return);
typedef int (* CMOCK_dbg_setup_CALLBACK)(int cmock_num_calls);
void dbg_setup_StubWithCallback(CMOCK_dbg_setup_CALLBACK Callback);
void dbg_printf_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, uint8_t cmock_to_return);
void dbg_printf_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, const char* format, uint8_t cmock_to_return);
typedef uint8_t (* CMOCK_dbg_printf_CALLBACK)(const char* format, int cmock_num_calls);
void dbg_printf_StubWithCallback(CMOCK_dbg_printf_CALLBACK Callback);
It's 64bit:
gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)
Hmmm... That code looks right. Are you using the ruby scripts to generate a test runner for you? Can you verify that it is calling CMock_Init() and that function is calling Mockdebug_Init? I'm wondering if the Mock structure isn't getting cleared so that it's just following random memory locations or something? It seems unlikely, but maybe?
It's interesting that it's a function with a vararg that is giving you headaches, but at this point CMock just ignores the extra arguments (someday it will mock them... but not yet). Have you tried a different function in the same module? Does your dbg_setup have the same problem?
Thanks... sorry that I don't have any quick answers... hopefully we can work through this together.
Mark
I was in vacation last week - sorry for the delay. Answer to your last post will follow soon.
For the following function declaration ...
void func(int array[2][3]);
... CMock generates the following mock function definition ...
void func(int* array) {...}
... which leads to a error: conflicting types for ‘func’
compiler error (gcc 4.9.2).
Say you have a function under test like this:
void foo(){
DoThing(1,2);
DoThing(3,4);
}
and then you write a test like this:
void test_foo_should_do_the_first_thing()
{
DoThing_Expect(500, 600);
DoThing_Ignore();
foo();
}
the test passes. Even though the expect has the wrong parameters. In my cmock settings I have the :ignore
property set to :args_only
. Apparently, including one call to xxx_Ignore(), causes the arguments to be ignored to every call made to that function. But that is quite unintuitive. It's dangerous because It looks like I have an expectation in place but that expect is begin ignored completely. However, If I delete the line DoThing_Expect(500, 600);
from the test, the test fails! So behind the scene, the expect seems to be getting replaced with an ignore, making the test quite useless.
When trying to create a mock, this happened:
/CMock/lib/cmock_header_parser.rb:252:in `parse_declaration': Failed Parsing Declaration Prototype! (RuntimeError)
declaration: 'void(wakeup)(uint16_t ev, struct pico_socket *s)'
modifier: ''
return: {:type => '', :name => 'cmock_to_return', :ptr? => false, :const? => false, :str => ' cmock_to_return', :void? => false}
function: 'void'
args: [
{:type => ' wakeup)(uint16_t', :name => 'ev', :ptr? => true, :const? => false}
{:type => 'struct pico_socket*', :name => 's', :ptr? => true, :const? => false}
]
from /home/x/Projects/CMock/lib/cmock_header_parser.rb:33:in `block in parse'
from /home/x/Projects/CMock/lib/cmock_header_parser.rb:32:in `map'
from /home/x/Projects/CMock/lib/cmock_header_parser.rb:32:in `parse'
from ../../../CMock/lib/cmock.rb:40:in `generate_mock'
from ../../../CMock/lib/cmock.rb:31:in `block in setup_mocks'
from ../../../CMock/lib/cmock.rb:30:in `each'
from ../../../CMock/lib/cmock.rb:30:in `setup_mocks'
from ../../../CMock/lib/cmock.rb:85:in `<main>'
The header i used to mock was pico_socket.h from the picotcp repo (https://github.com/tass-belgium/picotcp)
It's failing on a function pointer declaration. Is CMock not able yet to handle function pointers?
Hi all,
We have configured CMock to use dynamic memory in our environment because it ran out of memory when executing some tests in our codebase.
We are now running our unit tests under Valgrind (on Linux) and it always picks up an error like so -
==24766== HEAP SUMMARY:
==24766== in use at exit: 32,784 bytes in 1 blocks
==24766== total heap usage: 1 allocs, 0 frees, 32,784 bytes allocated
==24766==
==24766== 32,784 bytes in 1 blocks are still reachable in loss record 1 of 1
==24766== at 0x402BE18: malloc (vg_replace_malloc.c:270)
==24766== by 0x402BF9E: realloc (vg_replace_malloc.c:662)
==24766== by 0x804B839: CMock_Guts_MemNew (cmock.c:72)
Any idea why this could be happening?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.