Skip to content
8 changes: 4 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[submodule "vendor/unity"]
path = vendor/unity
url = https://github.com/throwtheswitch/unity.git
branch = master
[submodule "vendor/c_exception"]
path = vendor/c_exception
url = https://github.com/throwtheswitch/cexception.git
branch = master
[submodule "vendor/unity"]
path = vendor/unity
url = https://github.com/throwtheswitch/unity.git
branch = master
27 changes: 24 additions & 3 deletions docs/CMock_Summary.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CMock: A Summary
================

*[ThrowTheSwitch.org](http://throwtheswitch.org)*
*[ThrowTheSwitch.org](http://throwtheswitch.org)*

*This documentation is released under a Creative Commons 3.0 Attribution Share-Alike License*

Expand Down Expand Up @@ -138,7 +138,7 @@ that resembles a pointer or array, it breaks the argument into TWO arguments.
The first is the original pointer. The second specify the number of elements
it is to verify of that array. If you specify 1, it'll check one object. If 2,
it'll assume your pointer is pointing at the first of two elements in an array.
If you specify zero elements and `UNITY_COMPARE_PTRS_ON_ZERO_ARRAY` is defined,
If you specify zero elements and `UNITY_COMPARE_PTRS_ON_ZERO_ARRAY` is defined,
then this assertion can also be used to directly compare the pointers to verify
that they are pointing to the same memory address.

Expand Down Expand Up @@ -420,6 +420,27 @@ from the defaults. We've tried to specify what the defaults are below.

* default: *nil*

* `:create_error_stubs`:
New users of CMock sometimes struggle with the concept that CMock is
generating differently named interface functions for a mock depending
on whether a function to be mocked has a return value or not (see
description of the plugins `:Expect`, `:ExpectAnyArgs`, `:Array`, `:Ignore`,
`:IgnoreStateless` above). They are looking e.g. for a function `func_Expect()`
while CMock generated the function `func_ExpectAndReturn()` instead.
This has proven to be a significant hurdle, because it is not easy to
spot the slightly different named function within the generated mock.
Therefore CMock (v2.6.0 and newer) is generating *both* functions
per default, although one of them has only a "stub" functionality:
on call it will always fail the test emitting a helpful error message
pointing towards the correct function.

Experienced CMock users on the other hand might prefer the original
behavior, where no additional error stubs are generated - e.g. to
ensure code completion offers only "real" functionality of the mock.
In this case, the option `:create_error_stubs` can be set to false.

* default: true

* `:enforce_strict_ordering`:
CMock always enforces the order that you call a particular function,
so if you expect GrabNabber(int size) to be called three times, it
Expand Down Expand Up @@ -637,7 +658,7 @@ from the defaults. We've tried to specify what the defaults are below.
for the test code to also see the newly generated header ,and not
the old header with inline functions, the build system has to add
the mock folder to the include paths.

Furthermore, we need to keep the order of include paths in mind. We
have to set the mock folder before the other includes to avoid the
test code including the original header instead of the newly
Expand Down
1 change: 1 addition & 0 deletions lib/cmock_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class CMockConfig
:array_size_name => 'size|len',
:skeleton => false,
:exclude_setjmp_h => false,
:create_error_stubs => true,

# Format to look for inline functions.
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
Expand Down
15 changes: 9 additions & 6 deletions lib/cmock_generator_plugin_array.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(config, utils)
@config = config
@ptr_handling = @config.when_ptr
@ordered = @config.enforce_strict_ordering
@error_stubs = @config.create_error_stubs
@utils = utils
@unity_helper = @utils.helpers[:unity_helper]
@priority = 8
Expand All @@ -33,15 +34,17 @@ def mock_function_declarations(function)
type = @utils.arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
end.join(', ')
lines = ''
if function[:return][:void?]
"#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArray (not AndReturn)\");\n" \
"#define #{function[:name]}_ExpectWithArray(#{args_call_i}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call_o})\n" \
"void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
lines << "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArray (not AndReturn)\");\n" if @error_stubs
lines << "#define #{function[:name]}_ExpectWithArray(#{args_call_i}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call_o})\n"
lines << "void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
else
"#define #{function[:name]}_ExpectWithArray(#{args_call_i}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArrayAndReturn\");\n" \
"#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call_o}, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
lines << "#define #{function[:name]}_ExpectWithArray(#{args_call_i}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArrayAndReturn\");\n" if @error_stubs
lines << "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call_o}, cmock_retval)\n"
lines << "void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
end
lines
end

def mock_interfaces(function)
Expand Down
27 changes: 15 additions & 12 deletions lib/cmock_generator_plugin_expect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(config, utils)
@config = config
@ptr_handling = @config.when_ptr
@ordered = @config.enforce_strict_ordering
@error_stubs = @config.create_error_stubs
@utils = utils
@unity_helper = @utils.helpers[:unity_helper]
@priority = 5
Expand All @@ -35,25 +36,27 @@ def instance_typedefs(function)
end

def mock_function_declarations(function)
lines = ''
if function[:args].empty?
if function[:return][:void?]
"#define #{function[:name]}_ExpectAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" \
"#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n"
lines << "#define #{function[:name]}_ExpectAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" if @error_stubs
lines << "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n"
lines << "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n"
else
"#define #{function[:name]}_Expect() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\n" \
"#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
lines << "#define #{function[:name]}_Expect() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\n" if @error_stubs
lines << "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n"
lines << "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
elsif function[:return][:void?]
"#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" \
"#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" \
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
lines << "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" if @error_stubs
lines << "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n"
lines << "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
else
"#define #{function[:name]}_Expect(#{function[:args_call]}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\n" \
"#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
lines << "#define #{function[:name]}_Expect(#{function[:args_call]}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\n" if @error_stubs
lines << "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n"
lines << "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
end
lines
end

def mock_implementation_always_check_args(function)
Expand Down
17 changes: 10 additions & 7 deletions lib/cmock_generator_plugin_expect_any_args.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class CMockGeneratorPluginExpectAnyArgs

def initialize(config, utils)
@config = config
@error_stubs = @config.create_error_stubs
@utils = utils
@priority = 3
end
Expand All @@ -19,17 +20,19 @@ def instance_typedefs(_function)
end

def mock_function_declarations(function)
lines = ''
if function[:args].empty?
''
lines << ''
elsif function[:return][:void?]
"#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAnyArgs (not AndReturn)\");\n" \
"#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" \
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
lines << "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAnyArgs (not AndReturn)\");\n" if @error_stubs
lines << "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n"
lines << "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
else
"#define #{function[:name]}_ExpectAnyArgs() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAnyArgsAndReturn\");\n" \
"#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
lines << "#define #{function[:name]}_ExpectAnyArgs() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAnyArgsAndReturn\");\n" if @error_stubs
lines << "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n"
lines << "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
lines
end

def mock_interfaces(function)
Expand Down
20 changes: 11 additions & 9 deletions lib/cmock_generator_plugin_ignore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class CMockGeneratorPluginIgnore

def initialize(config, utils)
@config = config
@error_stubs = @config.create_error_stubs
@utils = utils
@priority = 2
end
Expand All @@ -23,15 +24,16 @@ def instance_structure(function)
end

def mock_function_declarations(function)
lines = if function[:return][:void?]
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Ignore (not AndReturn)\");\n" \
"#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \
"void #{function[:name]}_CMockIgnore(void);\n"
else
"#define #{function[:name]}_Ignore() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _IgnoreAndReturn\");\n" \
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" \
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
lines = ''
if function[:return][:void?]
lines << "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Ignore (not AndReturn)\");\n" if @error_stubs
lines << "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n"
lines << "void #{function[:name]}_CMockIgnore(void);\n"
else
lines << "#define #{function[:name]}_Ignore() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _IgnoreAndReturn\");\n" if @error_stubs
lines << "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n"
lines << "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end

# Add stop ignore function. it does not matter if there are any args
lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \
Expand Down
20 changes: 11 additions & 9 deletions lib/cmock_generator_plugin_ignore_stateless.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class CMockGeneratorPluginIgnoreStateless

def initialize(config, utils)
@config = config
@error_stubs = @config.create_error_stubs
@utils = utils
@priority = 2
end
Expand All @@ -23,15 +24,16 @@ def instance_structure(function)
end

def mock_function_declarations(function)
lines = if function[:return][:void?]
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Ignore (not AndReturn)\");\n" \
"#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \
"void #{function[:name]}_CMockIgnore(void);\n"
else
"#define #{function[:name]}_Ignore() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _IgnoreAndReturn\");\n" \
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" \
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"
end
lines = ''
if function[:return][:void?]
lines << "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Ignore (not AndReturn)\");\n" if @error_stubs
lines << "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n"
lines << "void #{function[:name]}_CMockIgnore(void);\n"
else
lines << "#define #{function[:name]}_Ignore() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _IgnoreAndReturn\");\n" if @error_stubs
lines << "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n"
lines << "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"
end

# Add stop ignore function. it does not matter if there are any args
lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \
Expand Down
87 changes: 87 additions & 0 deletions test/unit/cmock_generator_no_error_stubs_plugin_array_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================

require File.expand_path(File.dirname(__FILE__)) + "/../test_helper"
require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_plugin_array'
require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_utils'

class UtilsStub
def helpers
{}
end
def arg_type_with_const(arg)
CMockGeneratorUtils.arg_type_with_const(arg)
end
def code_add_base_expectation(func)
"mock_retval_0"
end
end

describe CMockGeneratorPluginArray, "Verify Generation Of Mock Function Declarations Without Error Stubs By CMockPGeneratorluginArray Module" do
before do
#no strict ordering
@config = create_stub(
:when_ptr => :compare_data,
:enforce_strict_ordering => false,
:respond_to? => true,
:create_error_stubs => false)

@utils = UtilsStub.new

@cmock_generator_plugin_array = CMockGeneratorPluginArray.new(@config, @utils)
end

after do
end

it "add another mock function declaration for functions of style 'void func(int* tofu)'" do
function = {:name => "Pine",
:args => [{ :type => "int*",
:name => "tofu",
:ptr? => true,
}],
:return => test_return[:void],
:contains_ptr? => true }

expected = "#define #{function[:name]}_ExpectWithArray(tofu, tofu_Depth) #{function[:name]}_CMockExpectWithArray(__LINE__, tofu, (tofu_Depth))\n" +
"void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, int* tofu, int tofu_Depth);\n"
returned = @cmock_generator_plugin_array.mock_function_declarations(function)
assert_equal(expected, returned)
end

it "add another mock function declaration for functions of style 'const char* func(int* tofu)'" do
function = {:name => "Pine",
:args => [{ :type => "int*",
:name => "tofu",
:ptr? => true,
}],
:return => test_return[:string],
:contains_ptr? => true }

expected = "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, tofu, (tofu_Depth), cmock_retval)\n" +
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, int* tofu, int tofu_Depth, const char* cmock_to_return);\n"
returned = @cmock_generator_plugin_array.mock_function_declarations(function)
assert_equal(expected, returned)
end

it "add another mock function declaration for functions of style 'const char* func(const int* tofu)'" do
function = {:name => "Pine",
:args => [{ :type => "const int*",
:name => "tofu",
:ptr? => true,
:const? => true,
}],
:return => test_return[:string],
:contains_ptr? => true }

expected = "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, tofu, (tofu_Depth), cmock_retval)\n" +
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, const int* tofu, int tofu_Depth, const char* cmock_to_return);\n"
returned = @cmock_generator_plugin_array.mock_function_declarations(function)
assert_equal(expected, returned)
end

end
Loading