Merge pull request #531 from ThrowTheSwitch/feature/better_arrays

Feature/better arrays
This commit is contained in:
Mark VanderVoord
2026-06-19 10:53:54 -04:00
committed by GitHub
20 changed files with 2093 additions and 366 deletions
+46 -7
View File
@@ -147,6 +147,27 @@ that they are pointing to the same memory address.
* `retval func(void)` => (nothing. In fact, an additional function is only generated if the params list contains pointers)
* `retval func(other, ptr* param)` => `void func_ExpectWithArrayAndReturn(other, ptr* param, int param_depth, retval_to_return)`
When the `:array_size_name` and `:array_size_type` options are configured, CMock
can recognize that a scalar parameter is the size of an adjacent pointer parameter
and pair them together. When a size parameter is paired with a pointer, the `_Expect`
call automatically uses it as the array depth, and `_ExpectWithArray` preserves
the original argument order without adding a separate depth argument.
When performing this type of automatic identification of arguments, CMock will also
generate an additional `_ExpectWithArrayExtended`, which accepts an explicit
depth for every pointer — allowing you to override the inferred depth when the
pairing heuristic guesses wrong:
* `void func(int size, ptr* buf)` =>
* `void func_ExpectWithArray(int size, ptr* buf)` _(depth inferred from `size`)_
* `void func_ExpectWithArrayExtended(int size, ptr* buf, int buf_Depth)` _(explicit override)_
`_ExpectWithArrayExtended` is only generated for functions where at least one
size parameter has been automatically identified. For all other functions the short
`_ExpectWithArray` already gives full depth control. This function can be used to correct
poor assumptions that CMock has made. It can also be used to separately verify a passed
length, but compare the actual contents for a DIFFERENT number of elements.
Ignore:
-------
@@ -722,11 +743,7 @@ from the defaults. We've tried to specify what the defaults are below.
* `void GoBananas(Banana * bananas, int num_bananas)`
* `int write_data(int fd, const uint8_t * data, uint32_t size)`
To recognize functions like these, CMock looks for a parameter list
containing a pointer (which could be an array) followed by something that
could be an array size. "Something", by default, means an `int` or `size_t`
parameter with a name containing "size" or "len".
* `void store_data(int buf_size, uint8_t * buf)`
`:array_size_type` is a list of additional types (besides `int` and `size_t`)
that could be used for an array size parameter. For example, to get CMock to
@@ -741,8 +758,30 @@ from the defaults. We've tried to specify what the defaults are below.
cfg[:array_size_name] = 'size|len|num_'
Parameters must match *both* `:array_size_type` and `:array_size_name` (and
must come right after a pointer parameter) to be treated as an array size.
A parameter must match *both* `:array_size_type` and `:array_size_name` to be
treated as an array size.
**Pairing heuristic:** CMock scores each candidate size parameter against each
pointer parameter using name similarity. It strips size-words (e.g. "size",
"len") from the size parameter's name to derive a root, then checks whether
that root matches the pointer's name exactly (score 10), as a prefix or suffix
(score 7), or as a substring (score 5). Adjacency in the argument list adds a
small bonus (score +2). The highest-scoring pairing wins. This means CMock
correctly pairs `buff_size` with `buffer` even when another pointer appears
adjacent to `buff_size`.
Size parameters may appear either **before or after** the pointer they describe.
CMock recognizes both orderings:
* Size after pointer: `void func(uint8_t* buf, int buf_size)` — the `_Expect`
call uses `buf_size` as the depth automatically. `_ExpectWithArray` adds an
explicit `buf_Depth` argument after `buf` for manual override.
* Size before pointer: `void func(int buf_size, uint8_t* buf)` — the `_Expect`
call again uses `buf_size` as the depth automatically, and `_ExpectWithArray`
keeps arguments in their original order with no extra depth argument added.
An additional `_ExpectWithArrayExtended` variant is generated that does accept
an explicit depth, allowing you to override the inferred value when needed.
Once you've told it how to recognize your arrays, CMock will give you `_Expect`
calls that work more like `_ExpectWithArray`, and compare an array of objects
+64 -14
View File
@@ -21,28 +21,66 @@ class CMockGeneratorPluginArray
def instance_typedefs(function)
function[:args].inject('') do |all, arg|
arg[:ptr?] ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
arg[:ptr?] || arg[:string?] ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
end
end
def mock_function_declarations(function)
return nil unless function[:contains_ptr?]
args_call_i = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : (m[:name]).to_s }.join(', ')
args_call_o = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, (#{m[:name]}_Depth)" : (m[:name]).to_s }.join(', ')
func_name = function[:name]
# C function signature: always explicit depth for every pointer/string arg
args_string = function[:args].map do |m|
type = @utils.arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
m[:ptr?] || m[:string?] ? "#{@utils.arg_declaration(m)}, int #{m[:name]}_Depth" : @utils.arg_declaration(m)
end.join(', ')
# Short macro params: paired ptrs (before OR after) omit _Depth (auto-filled from paired size arg)
# string? args always need an explicit _Depth
args_call_i = function[:args].map do |m|
(m[:ptr?] || m[:string?]) && !m[:array_size_name] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name].to_s
end.join(', ')
# Short macro call: paired ptrs pass paired size name as depth automatically
args_call_o = function[:args].map do |m|
if (m[:ptr?] || m[:string?]) && m[:array_size_name]
"#{m[:name]}, (#{m[:array_size_name]})"
elsif m[:ptr?] || m[:string?]
"#{m[:name]}, (#{m[:name]}_Depth)"
else
m[:name].to_s
end
end.join(', ')
# Extended macro params: every ptr/string gets an explicit _Depth
args_call_ext_i = function[:args].map do |m|
m[:ptr?] || m[:string?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name].to_s
end.join(', ')
# Extended macro call: every ptr/string passes (name_Depth)
args_call_ext_o = function[:args].map do |m|
m[:ptr?] || m[:string?] ? "#{m[:name]}, (#{m[:name]}_Depth)" : m[:name].to_s
end.join(', ')
has_paired = function[:args].any? { |m| m[:array_size_name] }
lines = ''
if function[:return][:void?]
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"
if @error_stubs
lines << "#define #{func_name}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) TEST_FAIL_MESSAGE(\"#{func_name} requires _ExpectWithArray (not AndReturn)\");\n"
lines << "#define #{func_name}_ExpectWithArrayExtendedAndReturn(#{args_call_ext_i}, cmock_retval) TEST_FAIL_MESSAGE(\"#{func_name} requires _ExpectWithArrayExtended (not AndReturn)\");\n" if has_paired
end
lines << "#define #{func_name}_ExpectWithArray(#{args_call_i}) #{func_name}_CMockExpectWithArray(__LINE__, #{args_call_o})\n"
lines << "#define #{func_name}_ExpectWithArrayExtended(#{args_call_ext_i}) #{func_name}_CMockExpectWithArray(__LINE__, #{args_call_ext_o})\n" if has_paired
lines << "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
else
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"
if @error_stubs
lines << "#define #{func_name}_ExpectWithArray(#{args_call_i}) TEST_FAIL_MESSAGE(\"#{func_name} requires _ExpectWithArrayAndReturn\");\n"
lines << "#define #{func_name}_ExpectWithArrayExtended(#{args_call_ext_i}) TEST_FAIL_MESSAGE(\"#{func_name} requires _ExpectWithArrayExtendedAndReturn\");\n" if has_paired
end
lines << "#define #{func_name}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) #{func_name}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call_o}, cmock_retval)\n"
lines << "#define #{func_name}_ExpectWithArrayExtendedAndReturn(#{args_call_ext_i}, cmock_retval) #{func_name}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call_ext_o}, cmock_retval)\n" if has_paired
lines << "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
end
lines
end
@@ -52,11 +90,18 @@ class CMockGeneratorPluginArray
lines = []
func_name = function[:name]
# C function: always explicit depth for every pointer/string arg
args_string = function[:args].map do |m|
type = @utils.arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
m[:ptr?] || m[:string?] ? "#{@utils.arg_declaration(m)}, int #{m[:name]}_Depth" : @utils.arg_declaration(m)
end.join(', ')
call_string = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name] }.join(', ')
# Call to CMockExpectParameters_: :before-paired ptrs pass only ptr name (their depth is set from paired size arg)
# string? args always pass their depth explicitly
call_string = function[:args].map do |m|
(m[:ptr?] || m[:string?]) && m[:array_size_order] != :before ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name]
end.join(', ')
lines << if function[:return][:void?]
"void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n"
else
@@ -65,6 +110,11 @@ class CMockGeneratorPluginArray
lines << "{\n"
lines << @utils.code_add_base_expectation(func_name)
lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n"
# Override depths for :before-paired pointers. CMockExpectParameters_ sets these from the paired
# size arg; the explicit _Depth param here allows _ExpectWithArrayExtended to override that value.
function[:args].each do |arg|
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if (arg[:ptr?] || arg[:string?]) && arg[:array_size_order] == :before
end
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless function[:return][:void?]
lines << "}\n\n"
end
@@ -56,7 +56,12 @@ class CMockGeneratorPluginReturnThruPtr
" #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n"
end
lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (cmock_len * sizeof(*#{arg[:name]})))\n"
array_elem_size = if arg[:array_dims] && (arg[:type][-1] == '*') && !void_pointer?(arg[:type][0..-2])
"sizeof(#{arg[:type][0..-2]})"
else
"sizeof(*#{arg[:name]})"
end
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (cmock_len * #{array_elem_size}))\n"
lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (cmock_size))\n"
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{ptr_to_const(arg[:type])} #{arg[:name]}, size_t cmock_size);\n"
+104 -17
View File
@@ -20,6 +20,7 @@ class CMockGeneratorUtils
@ignore = @config.plugins.include? :ignore
@ignore_stateless = @config.plugins.include? :ignore_stateless
@treat_as = @config.treat_as
@treat_as_void = (['void'] + (@config.respond_to?(:treat_as_void) ? @config.treat_as_void : [])).uniq
@helpers = helpers
end
@@ -36,6 +37,24 @@ class CMockGeneratorUtils
self.class.arg_type_with_const(arg)
end
def self.arg_declaration(arg)
if arg[:ptr_to_array?] && arg[:array_dims]
base_type = arg_type_with_const(arg).sub(/\*$/, '').strip
dims_str = arg[:array_dims].map { |d| "[#{d}]" }.join
"#{base_type} (*#{arg[:name]})#{dims_str}"
elsif arg[:array_dims]
base_type = arg_type_with_const(arg).sub(/\*$/, '').strip
dims_str = arg[:array_dims].map { |d| "[#{d}]" }.join
"#{base_type} #{arg[:name]}#{dims_str}"
else
"#{arg_type_with_const(arg)} #{arg[:name]}"
end
end
def arg_declaration(arg)
self.class.arg_declaration(arg)
end
def code_verify_an_arg_expectation(function, arg)
if @arrays
case @ptr_handling
@@ -64,7 +83,7 @@ class CMockGeneratorUtils
def code_add_an_arg_expectation(arg, depth = 1)
lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg)
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if @arrays && depth.instance_of?(String)
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{depth};\n" if @arrays && depth.instance_of?(String)
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if @ignore_arg
lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if @return_thru_ptr && ptr_or_str?(arg[:type]) && !(arg[:const?])
lines
@@ -72,7 +91,8 @@ class CMockGeneratorUtils
def code_assign_argument_quickly(dest, arg)
if arg[:ptr?] || @treat_as.include?(arg[:type])
" #{dest} = #{arg[:name]};\n"
cast = arg[:array_dims] ? "(#{arg[:type]})" : ''
" #{dest} = #{cast}#{arg[:name]};\n"
else
assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1"
comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */"
@@ -85,12 +105,27 @@ class CMockGeneratorUtils
if function[:args_string] != 'void'
if @arrays
args_string = function[:args].map do |m|
type = arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
if (m[:ptr?] || m[:string?]) && m[:array_size_order] == :before
arg_declaration(m)
elsif m[:ptr?] || m[:string?]
"#{arg_declaration(m)}, int #{m[:name]}_Depth"
else
arg_declaration(m)
end
end.join(', ')
body = function[:args].inject('') do |all, arg|
depth = if (arg[:ptr?] || arg[:string?]) && arg[:array_size_order] == :before
arg[:array_size_name]
elsif arg[:ptr?] || arg[:string?]
"#{arg[:name]}_Depth"
else
1
end
all + code_add_an_arg_expectation(arg, depth)
end
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string});\n" \
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" \
"#{function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1)) }}" \
"#{body}" \
"}\n\n"
else
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]});\n" \
@@ -106,10 +141,16 @@ class CMockGeneratorUtils
def code_call_argument_loader(function)
if function[:args_string] != 'void'
args = function[:args].map do |m|
if @arrays && m[:ptr?] && !(m[:array_data?])
if @arrays && (m[:ptr?] || m[:string?]) && m[:array_size_order] == :after
"#{m[:name]}, #{m[:array_size_name]}"
elsif @arrays && (m[:ptr?] || m[:string?]) && m[:array_size_order] == :before
m[:name]
elsif @arrays && m[:ptr?]
"#{m[:name]}, 1"
elsif @arrays && m[:string?]
"#{m[:name]}, 0"
elsif @arrays && m[:array_size?]
"#{m[:name]}, #{m[:name]}"
m[:name]
else
m[:name]
end
@@ -132,16 +173,46 @@ class CMockGeneratorUtils
arg_name = arg[:name]
expected = "cmock_call_instance->Expected_#{arg_name}"
ignore = "cmock_call_instance->IgnoreArg_#{arg_name}"
# Pointer-to-array args (e.g., char (*buf)[N]) always compare by memory contents
return [c_type, arg_name, expected, ignore, 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY', ''] if arg[:ptr_to_array?]
unity_func = if (arg[:ptr?]) && ((c_type =~ /\*\*/) || (@ptr_handling == :compare_ptr))
['UNITY_TEST_ASSERT_EQUAL_PTR', '']
elsif arg[:ptr?] && !@arrays && void_pointer_type?(c_type)
# void* cannot be safely dereferenced; without the array plugin there's no way
# to specify depth, so fall back to comparing the pointer value itself
['UNITY_TEST_ASSERT_EQUAL_PTR', '']
elsif arg[:ptr?] && @arrays && void_pointer_type?(c_type)
# With the array plugin, treat_as_void aliases not in treat_as would fall back to
# MEMORY_ARRAY with sizeof(void), which is illegal. Use HEX8_ARRAY (byte comparison)
# to match what literal void* gets from the default treat_as entry.
['UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY', '']
else
@helpers.nil? || @helpers[:unity_helper].nil? ? ['UNITY_TEST_ASSERT_EQUAL', ''] : @helpers[:unity_helper].get_helper(c_type)
end
[c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]]
end
def void_pointer_type?(c_type)
base = c_type.gsub(/\bconst\b/, '').gsub(/\s+/, '')
return false unless base.end_with?('*')
@treat_as_void.include?(base.chomp('*'))
end
def ptr_to_array_elem_size(arg, c_type)
# For pointer-to-array args (e.g., char (*buf)[10]), the element size is sizeof(base_type[dims])
if arg[:ptr_to_array?] && arg[:array_dims]
base_type = c_type.gsub(/\*+$/, '').strip
"sizeof(#{base_type}#{arg[:array_dims].map { |d| "[#{d}]" }.join})"
else
"sizeof(#{c_type.sub('*', '')})"
end
end
def code_verify_an_arg_expectation_with_no_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
elem_size = ptr_to_array_elem_size(arg, c_type)
lines = ''
lines << " if (!#{ignore})\n" if @ignore_arg
lines << " {\n"
@@ -152,12 +223,12 @@ class CMockGeneratorUtils
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
if pre == '&'
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n"
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, #{elem_size}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch); }\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, #{elem_size}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if pre == '&'
@@ -177,7 +248,8 @@ class CMockGeneratorUtils
def code_verify_an_arg_expectation_with_normal_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
depth_name = arg[:ptr?] || arg[:string?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
elem_size = ptr_to_array_elem_size(arg, c_type)
lines = ''
lines << " if (!#{ignore})\n" if @ignore_arg
lines << " {\n"
@@ -188,12 +260,12 @@ class CMockGeneratorUtils
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
if pre == '&'
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n"
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, #{elem_size}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(#{pre}#{expected}, #{pre}#{arg_name}, #{elem_size}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if pre == '&'
@@ -205,7 +277,14 @@ class CMockGeneratorUtils
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
if arg[:string?]
lines << " if (#{depth_name} == 0)\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((const void*)(#{pre}#{expected}), (const void*)(#{pre}#{arg_name}), (UNITY_UINT32)(#{depth_name}), cmock_line, CMockStringMismatch); }\n"
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
end
end
lines << " }\n"
lines
@@ -213,7 +292,8 @@ class CMockGeneratorUtils
def code_verify_an_arg_expectation_with_smart_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
depth_name = arg[:ptr?] || arg[:string?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
elem_size = ptr_to_array_elem_size(arg, c_type)
lines = ''
lines << " if (!#{ignore})\n" if @ignore_arg
lines << " {\n"
@@ -224,13 +304,13 @@ class CMockGeneratorUtils
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
if pre == '&'
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch);\n"
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(#{pre}#{expected}, #{pre}#{arg_name}, #{elem_size}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '')
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(#{pre}#{expected}, #{pre}#{arg_name}, sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(#{pre}#{expected}, #{pre}#{arg_name}, #{elem_size}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if pre == '&'
@@ -243,7 +323,14 @@ class CMockGeneratorUtils
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
if arg[:string?]
lines << " if (#{depth_name} == 0)\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((const void*)(#{pre}#{expected}), (const void*)(#{pre}#{arg_name}), (UNITY_UINT32)(#{depth_name}), cmock_line, CMockStringMismatch); }\n"
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
end
end
lines << " }\n"
lines
+106 -11
View File
@@ -408,7 +408,25 @@ class CMockHeaderParser
arg_info
end
def parse_args(arg_list)
def extract_array_dims(arg_list)
dims = {}
arg_list.scan(/(\w+)\s*((?:\s*\[[^\[\]]*\])+)/) do |name, all_dims|
dim_list = all_dims.scan(/\[([^\[\]]*)\]/).map { |d| d[0].strip }
dims[name] = dim_list
end
dims
end
def extract_ptr_to_array_dims(arg_list)
dims = {}
arg_list.scan(/\(\s*\*\s*(\w+)\s*\)((?:\s*\[[^\[\]]*\])+)/) do |name, all_dims|
dim_list = all_dims.scan(/\[([^\[\]]*)\]/).map { |d| d[0].strip }
dims[name] = dim_list
end
dims
end
def parse_args(arg_list, array_dims_by_name = {}, ptr_to_array_dims_by_name = {})
args = []
arg_list.split(',').each do |arg|
arg.strip!
@@ -418,6 +436,15 @@ class CMockHeaderParser
arg_info.delete(:modifier) # don't care about this
arg_info.delete(:c_calling_convention) # don't care about this
arg_info[:array_dims] = array_dims_by_name[arg_info[:name]] if array_dims_by_name.key?(arg_info[:name])
# Handle pointer-to-array args: (*name)[dims] was rewritten to * name before clean_args
if ptr_to_array_dims_by_name.key?(arg_info[:name])
arg_info[:array_dims] = ptr_to_array_dims_by_name[arg_info[:name]]
arg_info[:ptr_to_array?] = true
arg_info[:ptr?] = true # force true even for types like char* that divine_ptr would otherwise treat as strings
end
# in C, array arguments implicitly degrade to pointers
# make the translation explicit here to simplify later logic
if @treat_as_array[arg_info[:type]] && !(arg_info[:ptr?])
@@ -429,20 +456,61 @@ class CMockHeaderParser
args << arg_info
end
# Try to find array pair in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name>
args.each_with_index do |val, index|
next_index = index + 1
next unless args.length > next_index
# Try to find array pairs using name-affinity scoring.
# Pairs each size-candidate arg with the best-matching pointer arg.
# Score: 10=exact root match, 7=prefix match, 5=substring match, +2 adjacency bonus (ptr immediately precedes size).
# Falls back to adjacency alone (score 2) when no name affinity found, preserving original behavior.
size_candidate_indices = args.each_index.select do |i|
args[i][:name].match(@array_size_name) && @array_size_type.include?(args[i][:type])
end
if (val[:ptr?] == true) && args[next_index][:name].match(@array_size_name) && @array_size_type.include?(args[next_index][:type])
val[:array_data?] = true
args[next_index][:array_size?] = true
size_candidate_indices.each do |size_idx|
best_score = 0
best_ptr_idx = nil
args.each_with_index do |ptr_arg, ptr_idx|
next unless (ptr_arg[:ptr?] || ptr_arg[:string?]) && !ptr_arg[:array_data?]
score = array_size_name_affinity(ptr_arg[:name], args[size_idx][:name])
score += 2 if ptr_idx + 1 == size_idx
if score > best_score
best_score = score
best_ptr_idx = ptr_idx
end
end
next unless best_ptr_idx
args[best_ptr_idx][:array_size_name] = args[size_idx][:name]
args[best_ptr_idx][:array_size_order] = size_idx < best_ptr_idx ? :before : :after
args[size_idx][:array_size?] = true
end
args
end
def array_size_name_affinity(ptr_name, size_name)
size_words = @array_size_name.to_s.split('|').select { |w| w.match?(/^\w+$/) }
p_name = ptr_name.downcase
s_name = size_name.downcase
roots = size_words.flat_map do |word|
[
s_name.sub(/_#{Regexp.escape(word)}$/, ''),
s_name.sub(/^#{Regexp.escape(word)}_/, '')
]
end.uniq.reject { |r| r.empty? || r == s_name }
roots.each do |root|
return 10 if root == p_name
return 7 if p_name.start_with?(root) || root.start_with?(p_name)
return 5 if p_name.include?(root) || root.include?(p_name)
end
0
end
def divine_ptr(arg)
return false unless arg.include? '*'
# treat "const char *" and similar as a string, not a pointer
@@ -465,6 +533,7 @@ class CMockHeaderParser
divination = {}
divination[:ptr?] = divine_ptr(arg)
divination[:string?] = !divination[:ptr?] && (/(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg ? true : false)
divination[:const?] = divine_const(arg)
# an arg containing "const" after the last * is a constant pointer
@@ -591,12 +660,38 @@ class CMockHeaderParser
decl[:var_arg] = nil
end
# Extract pointer-to-array parameters (e.g., char (*buffer)[10]) and rewrite for normal processing
ptr_to_array_dims = extract_ptr_to_array_dims(args)
ptr_to_array_dims.each_key do |name|
args.gsub!(/\(\s*\*\s*#{Regexp.escape(name)}\s*\)((?:\s*\[[^\[\]]*\])+)/, "* #{name}")
end
# Extract array dimensions before cleaning converts them to pointer notation
array_dims_by_name = extract_array_dims(args)
# parse out and clean up the remainder of the arguments
args = clean_args(args, parse_project)
decl[:args_string] = args
decl[:args] = parse_args(args)
decl[:args] = parse_args(args, array_dims_by_name, ptr_to_array_dims)
# Rebuild args_string using original array notation where applicable
if args == 'void'
decl[:args_string] = args
else
arg_parts = args.split(/,\s*/)
decl[:args].each_with_index do |arg, i|
next unless arg[:array_dims]
base_type = arg[:type].sub(/\*$/, '').strip
dims_str = arg[:array_dims].map { |d| "[#{d}]" }.join
arg_parts[i] = if arg[:ptr_to_array?]
"#{base_type} (*#{arg[:name]})#{dims_str}"
else
"#{base_type} #{arg[:name]}#{dims_str}"
end
end
decl[:args_string] = arg_parts.join(', ')
end
decl[:args_call] = decl[:args].map { |a| a[:name] }.join(', ')
decl[:contains_ptr?] = decl[:args].inject(false) { |ptr, arg| arg[:ptr?] ? true : ptr }
decl[:contains_ptr?] = decl[:args].inject(false) { |ptr, arg| arg[:ptr?] || arg[:string?] ? true : ptr }
if decl[:return][:type].nil? || decl[:name].nil? || decl[:args].nil? ||
decl[:return][:type].empty? || decl[:name].empty?
+6 -1
View File
@@ -16,7 +16,12 @@ class CMockUnityHelperParser
def get_helper(ctype)
lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/, '\1\3\5\6').strip.gsub(/\s+/, '_')
return [@c_types[lookup], ''] if @c_types[lookup]
if @c_types[lookup]
# _ARRAY_ARRAY variants don't exist in Unity; use memory fallback instead
return [@fallback, ''] if @c_types[lookup].end_with?('_ARRAY_ARRAY')
return [@c_types[lookup], '']
end
if lookup =~ /\*$/
lookup = lookup.gsub(/\*$/, '')
+1 -1
View File
@@ -12,7 +12,7 @@
#define CMOCK_VERSION_MAJOR 2
#define CMOCK_VERSION_MINOR 6
#define CMOCK_VERSION_BUILD 3
#define CMOCK_VERSION_BUILD 4
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
/* should be big enough to index full range of CMOCK_MEM_MAX */
+5 -7
View File
@@ -44,6 +44,7 @@ module RakefileHelpers
def load_configuration(config_file, cmock_overlay = nil)
$cfg_file = config_file
cmock_overlay += '.yml' if cmock_overlay && cmock_overlay !~ /\.yml$/i
$proj = load_yaml('./project.yml')
unity_targets_dir = '../vendor/unity/test/targets'
@@ -89,7 +90,6 @@ module RakefileHelpers
def configure_toolchain(config_file = DEFAULT_CONFIG_FILE, cmock_overlay = nil)
config_file = config_file || DEFAULT_CONFIG_FILE
config_file += '.yml' unless config_file =~ /\.yml$/i
cmock_overlay += '.yml' if cmock_overlay && cmock_overlay !~ /\.yml$/i
load_configuration(config_file, cmock_overlay)
configure_clean
end
@@ -154,8 +154,7 @@ module RakefileHelpers
def unsupported_tests
result = ($cmock_cfg[:unsupported] || []) | ($unity_cfg[:unsupported] || [])
test_defs = $unity_cfg.dig(:defines, :test)
conf_defs = (test_defs.is_a?(Hash) ? test_defs['*'] : nil) || test_defs || []
conf_defs = all_defines
UNSUPPORTED_CRITERIA.each_pair do |name, crit|
result |= [name] if (crit[:defines] & conf_defs).empty?
end
@@ -343,7 +342,7 @@ module RakefileHelpers
SystemTestGenerator.new.generate_files(test_case_files)
load_configuration($cfg_file)
load_configuration($cfg_file, $cmock_test_overlay_file)
include_dirs = get_local_include_dirs
@@ -481,7 +480,7 @@ module RakefileHelpers
def run_system_test_compilations(mockables)
load '../lib/cmock.rb'
load_configuration($cfg_file)
load_configuration($cfg_file, $cmock_test_overlay_file)
unsupported = unsupported_tests
mockables = mockables.reject do |f|
@@ -510,7 +509,7 @@ module RakefileHelpers
def run_system_test_profiles(mockables)
load '../lib/cmock.rb'
load_configuration($cfg_file)
load_configuration($cfg_file, $cmock_test_overlay_file)
report "\n"
report "--------------------------\n"
@@ -561,7 +560,6 @@ module RakefileHelpers
total_tests = 0
total_failures = 0
total_ignored = 0
puts "DEBUG DIS #{$cmock_test_config_file}"
cfg_file = "#{($cmock_test_config_file =~ /[\\\/]/) ? '../' : ''}#{$cmock_test_config_file}"
# Determine which examples are valid for this platform
@@ -0,0 +1,758 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
---
:cmock:
:when_ptr: :smart
:array_size_name: 'size|len|count'
:plugins:
- :array
:systest:
:types: |
typedef struct {
int x;
int y;
} POINT_T;
typedef struct {
int id;
int value;
} SENSOR_T;
typedef enum {
STATUS_OK = 0,
STATUS_ERROR = 1,
STATUS_PENDING = 2
} STATUS_E;
typedef union {
int raw;
unsigned char bytes[4];
} SAMPLE_U;
#define ARRAY_A_SIZE (5)
:mockable: |
POINT_T* bar(void);
void fooa(POINT_T a[ARRAY_A_SIZE]);
void no_pointers(int a, const char* b);
int mixed(int a, int* b, int c);
void process_sensors(SENSOR_T sensors[], int count);
void process_statuses(STATUS_E statuses[], int count);
void process_samples(SAMPLE_U samples[], int count);
void fill_matrix(int matrix[13][4]);
void transform_grid(int grid[][4], int rows);
void write_buffer(char (*dest)[10]);
void read_buffers(int count, char (*buffers)[8]);
void process_handles(void *const handles[], int count);
void store_data(int *written_count, int buf_size, int *buf);
:source:
:header: |
void function_a(void);
int function_b(void);
void function_c(void);
void function_d(void);
void function_e(void);
void function_f(void);
void function_g(void);
void function_h(void);
void function_i(void);
void function_j(void);
void function_k(void);
:code: |
void function_a(void)
{
fooa(bar());
}
int function_b(void)
{
int test_list[] = {1, 2, 3, 4, 5};
no_pointers(1, "silly");
return mixed(6, test_list, 7);
}
void function_c(void)
{
SENSOR_T sensors[] = {{1, 100}, {2, 200}, {3, 300}};
process_sensors(sensors, 3);
}
void function_d(void)
{
STATUS_E statuses[] = {STATUS_OK, STATUS_ERROR, STATUS_PENDING};
process_statuses(statuses, 3);
}
void function_e(void)
{
SAMPLE_U samples[3];
samples[0].raw = 111;
samples[1].raw = 222;
samples[2].raw = 333;
process_samples(samples, 3);
}
void function_f(void)
{
int matrix[13][4];
int i, j;
for (i = 0; i < 13; i++)
for (j = 0; j < 4; j++)
matrix[i][j] = i * 4 + j;
fill_matrix(matrix);
}
void function_g(void)
{
int grid[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
transform_grid(grid, 3);
}
void function_h(void)
{
char buf[10] = {1,2,3,4,5,6,7,8,9,10};
write_buffer(&buf);
}
void function_i(void)
{
char bufs[3][8];
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 8; j++)
bufs[i][j] = (char)(i * 8 + j + 1);
read_buffers((int)3, bufs);
}
void function_j(void)
{
void *const ptrs[] = {(void*)1, (void*)2, (void*)3};
process_handles(ptrs, 3);
}
void function_k(void)
{
int count = 0;
int data[] = {10, 20, 30};
store_data(&count, 3, data);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'handle passing null to an array parameter'
:code: |
test()
{
bar_ExpectAndReturn(NULL);
fooa_Expect(NULL);
function_a();
}
- :pass: TRUE
:should: 'compare a single struct array element and pass'
:code: |
test()
{
POINT_T pt = {4, 8};
POINT_T ex = {4, 8};
bar_ExpectAndReturn(&pt);
fooa_Expect(&ex);
function_a();
}
- :pass: FALSE
:should: 'detect mismatch in single struct array element'
:code: |
test()
{
POINT_T pt = {4, 8};
POINT_T ex = {4, 9};
bar_ExpectAndReturn(&pt);
fooa_Expect(&ex);
function_a();
}
- :pass: FALSE
:should: 'detect when null array is passed but non-null was expected'
:code: |
test()
{
POINT_T pt = {4, 8};
bar_ExpectAndReturn(&pt);
fooa_Expect(NULL);
function_a();
}
- :pass: TRUE
:should: 'compare multiple struct array elements via ExpectWithArray and pass'
:code: |
test()
{
POINT_T pt[] = {{1, 2}, {3, 4}, {5, 6}};
POINT_T ex[] = {{1, 2}, {3, 4}, {5, 6}};
bar_ExpectAndReturn(pt);
fooa_ExpectWithArray(ex, 3);
function_a();
}
- :pass: FALSE
:should: 'detect mismatch in first struct array element via ExpectWithArray'
:code: |
test()
{
POINT_T pt[] = {{1, 2}, {3, 4}, {5, 6}};
POINT_T ex[] = {{9, 2}, {3, 4}, {5, 6}};
bar_ExpectAndReturn(pt);
fooa_ExpectWithArray(ex, 3);
function_a();
}
- :pass: FALSE
:should: 'detect mismatch in middle struct array element via ExpectWithArray'
:code: |
test()
{
POINT_T pt[] = {{1, 2}, {3, 4}, {5, 6}};
POINT_T ex[] = {{1, 2}, {3, 9}, {5, 6}};
bar_ExpectAndReturn(pt);
fooa_ExpectWithArray(ex, 3);
function_a();
}
- :pass: FALSE
:should: 'detect mismatch in last struct array element via ExpectWithArray'
:code: |
test()
{
POINT_T pt[] = {{1, 2}, {3, 4}, {5, 6}};
POINT_T ex[] = {{1, 2}, {3, 4}, {5, 9}};
bar_ExpectAndReturn(pt);
fooa_ExpectWithArray(ex, 3);
function_a();
}
- :pass: TRUE
:should: 'handle creating int array expects for mixed-argument function and pass'
:code: |
test()
{
int expect_list[] = {1, 9};
no_pointers_Expect(1, "silly");
mixed_ExpectAndReturn(6, expect_list, 7, 13);
TEST_ASSERT_EQUAL(13, function_b());
}
- :pass: FALSE
:should: 'detect mismatch in int array for mixed-argument function'
:code: |
test()
{
int expect_list[] = {9, 1};
no_pointers_Expect(1, "silly");
mixed_ExpectAndReturn(6, expect_list, 7, 13);
TEST_ASSERT_EQUAL(13, function_b());
}
- :pass: TRUE
:should: 'compare multiple int array elements for mixed-argument function and pass'
:code: |
test()
{
int expect_list[] = {1, 2, 3, 4, 6};
no_pointers_Expect(1, "silly");
mixed_ExpectWithArrayAndReturn(6, expect_list, 4, 7, 13);
TEST_ASSERT_EQUAL(13, function_b());
}
- :pass: FALSE
:should: 'detect mismatch when checking too many int array elements'
:code: |
test()
{
int expect_list[] = {1, 2, 3, 4, 6};
no_pointers_Expect(1, "silly");
mixed_ExpectWithArrayAndReturn(6, expect_list, 5, 7, 13);
TEST_ASSERT_EQUAL(13, function_b());
}
- :pass: TRUE
:should: 'compare an array of sensors (struct) and pass'
:code: |
test()
{
SENSOR_T expected[] = {{1, 100}, {2, 200}, {3, 300}};
process_sensors_Expect(expected, 3);
function_c();
}
- :pass: FALSE
:should: 'detect mismatch in sensor id field'
:code: |
test()
{
SENSOR_T expected[] = {{9, 100}, {2, 200}, {3, 300}};
process_sensors_Expect(expected, 3);
function_c();
}
- :pass: FALSE
:should: 'detect mismatch in sensor value field'
:code: |
test()
{
SENSOR_T expected[] = {{1, 100}, {2, 999}, {3, 300}};
process_sensors_Expect(expected, 3);
function_c();
}
- :pass: TRUE
:should: 'compare all sensor elements via collapsed ExpectWithArray and pass'
:code: |
test()
{
SENSOR_T expected[] = {{1, 100}, {2, 200}, {3, 300}};
process_sensors_ExpectWithArray(expected, 3);
function_c();
}
- :pass: TRUE
:should: 'compare a subset of sensor elements via ExpectWithArrayExtended and pass'
:code: |
test()
{
SENSOR_T expected[] = {{1, 100}, {2, 200}};
process_sensors_ExpectWithArrayExtended(expected, 2, 3);
function_c();
}
- :pass: FALSE
:should: 'detect mismatch when comparing sensor subset via ExpectWithArrayExtended'
:code: |
test()
{
SENSOR_T expected[] = {{1, 100}, {2, 999}};
process_sensors_ExpectWithArrayExtended(expected, 2, 3);
function_c();
}
- :pass: TRUE
:should: 'compare an array of statuses (enum) and pass'
:code: |
test()
{
STATUS_E expected[] = {STATUS_OK, STATUS_ERROR, STATUS_PENDING};
process_statuses_Expect(expected, 3);
function_d();
}
- :pass: FALSE
:should: 'detect mismatch in first status enum element'
:code: |
test()
{
STATUS_E expected[] = {STATUS_ERROR, STATUS_ERROR, STATUS_PENDING};
process_statuses_Expect(expected, 3);
function_d();
}
- :pass: FALSE
:should: 'detect mismatch in last status enum element'
:code: |
test()
{
STATUS_E expected[] = {STATUS_OK, STATUS_ERROR, STATUS_OK};
process_statuses_Expect(expected, 3);
function_d();
}
- :pass: TRUE
:should: 'compare a subset of status elements via ExpectWithArrayExtended and pass'
:code: |
test()
{
STATUS_E expected[] = {STATUS_OK, STATUS_ERROR};
process_statuses_ExpectWithArrayExtended(expected, 2, 3);
function_d();
}
- :pass: FALSE
:should: 'detect mismatch in status subset via ExpectWithArrayExtended'
:code: |
test()
{
STATUS_E expected[] = {STATUS_OK, STATUS_PENDING};
process_statuses_ExpectWithArrayExtended(expected, 2, 3);
function_d();
}
- :pass: TRUE
:should: 'compare an array of samples (union) and pass'
:code: |
test()
{
SAMPLE_U expected[3];
expected[0].raw = 111;
expected[1].raw = 222;
expected[2].raw = 333;
process_samples_Expect(expected, 3);
function_e();
}
- :pass: FALSE
:should: 'detect mismatch in first sample union element'
:code: |
test()
{
SAMPLE_U expected[3];
expected[0].raw = 999;
expected[1].raw = 222;
expected[2].raw = 333;
process_samples_Expect(expected, 3);
function_e();
}
- :pass: FALSE
:should: 'detect mismatch in last sample union element'
:code: |
test()
{
SAMPLE_U expected[3];
expected[0].raw = 111;
expected[1].raw = 222;
expected[2].raw = 999;
process_samples_Expect(expected, 3);
function_e();
}
- :pass: TRUE
:should: 'compare a subset of sample elements via ExpectWithArrayExtended and pass'
:code: |
test()
{
SAMPLE_U expected[3];
expected[0].raw = 111;
expected[1].raw = 222;
process_samples_ExpectWithArrayExtended(expected, 2, 3);
function_e();
}
- :pass: FALSE
:should: 'detect mismatch in sample subset via ExpectWithArrayExtended'
:code: |
test()
{
SAMPLE_U expected[3];
expected[0].raw = 111;
expected[1].raw = 999;
process_samples_ExpectWithArrayExtended(expected, 2, 3);
function_e();
}
- :pass: TRUE
:should: 'compare a fully-specified 2D matrix [13][4] and pass'
:code: |
test()
{
int expected[13][4];
int i, j;
for (i = 0; i < 13; i++)
for (j = 0; j < 4; j++)
expected[i][j] = i * 4 + j;
fill_matrix_ExpectWithArray(expected, 13*4);
function_f();
}
- :pass: FALSE
:should: 'detect mismatch in a fully-specified 2D matrix [13][4]'
:code: |
test()
{
int expected[13][4];
int i, j;
for (i = 0; i < 13; i++)
for (j = 0; j < 4; j++)
expected[i][j] = i * 4 + j;
expected[6][2] = 999;
fill_matrix_ExpectWithArray(expected, 13*4);
function_f();
}
- :pass: TRUE
:should: 'compare only the first row of a fully-specified 2D matrix [13][4]'
:code: |
test()
{
int expected[13][4] = {{0,1,2,3}};
fill_matrix_ExpectWithArray(expected, 4);
function_f();
}
- :pass: TRUE
:should: 'compare a partially-specified 2D grid [][4] and pass'
:code: |
test()
{
int expected[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
transform_grid_ExpectWithArray(expected, 3*4, 3);
function_g();
}
- :pass: FALSE
:should: 'detect mismatch in a partially-specified 2D grid [][4]'
:code: |
test()
{
int expected[3][4] = {{1,2,3,4},{5,6,7,99},{9,10,11,12}};
transform_grid_ExpectWithArray(expected, 3*4, 3);
function_g();
}
- :pass: TRUE
:should: 'compare only the first two rows of a partially-specified 2D grid [][4]'
:code: |
test()
{
int expected[3][4] = {{1,2,3,4},{5,6,7,8}};
transform_grid_ExpectWithArray(expected, 2*4, 3);
function_g();
}
- :pass: TRUE
:should: 'pass when pointer-to-array argument contents match'
:code: |
test()
{
char expected[10] = {1,2,3,4,5,6,7,8,9,10};
write_buffer_Expect(&expected);
function_h();
}
- :pass: FALSE
:should: 'detect mismatch in pointer-to-array argument contents'
:code: |
test()
{
char expected[10] = {1,2,3,4,5,6,7,8,9,99};
write_buffer_Expect(&expected);
function_h();
}
- :pass: TRUE
:should: 'pass when passing null to pointer-to-array parameter'
:code: |
test()
{
write_buffer_Expect(NULL);
write_buffer(NULL);
}
- :pass: TRUE
:should: 'compare multiple pointer-to-array elements via ExpectWithArray and pass'
:code: |
test()
{
char expected[3][8];
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 8; j++)
expected[i][j] = (char)(i * 8 + j + 1);
read_buffers_ExpectWithArray(3, expected, 3);
function_i();
}
- :pass: FALSE
:should: 'detect mismatch when comparing multiple pointer-to-array elements'
:code: |
test()
{
char expected[3][8];
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 8; j++)
expected[i][j] = (char)(i * 8 + j + 1);
expected[1][3] = 99;
read_buffers_ExpectWithArray(3, expected, 3);
function_i();
}
- :pass: TRUE
:should: 'pass when array of const void pointers matches expected'
:code: |
test()
{
void *const expected[] = {(void*)1, (void*)2, (void*)3};
process_handles_Expect(expected, 3);
function_j();
}
- :pass: FALSE
:should: 'detect mismatch in array of const void pointers'
:code: |
test()
{
void *const expected[] = {(void*)1, (void*)2, (void*)9};
process_handles_Expect(expected, 3);
function_j();
}
- :pass: TRUE
:should: 'pass when comparing subset of const void pointer array via ExpectWithArrayExtended'
:code: |
test()
{
void *const expected[] = {(void*)1, (void*)2};
process_handles_ExpectWithArrayExtended(expected, 2, 3);
function_j();
}
- :pass: TRUE
:should: 'pair buf_size with buf not written_count, and pass'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 20, 30};
store_data_Expect(&exp_count, 3, exp_data);
function_k();
}
- :pass: FALSE
:should: 'detect mismatch in buf array when buf_size is correctly paired with buf'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 20, 99};
store_data_Expect(&exp_count, 3, exp_data);
function_k();
}
- :pass: TRUE
:should: 'use ExpectWithArray with length before pointer order'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 20, 30};
store_data_ExpectWithArray(&exp_count, 1, 3, exp_data);
function_k();
}
- :pass: FALSE
:should: 'detect content mismatch in buf via ExpectWithArray'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 99, 30};
store_data_ExpectWithArray(&exp_count, 1, 3, exp_data);
function_k();
}
- :pass: TRUE
:should: 'pass using ExpectWithArrayExtended with explicit depth matching buf_size'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 20, 30};
store_data_ExpectWithArrayExtended(&exp_count, 1, 3, exp_data, 3);
function_k();
}
- :pass: FALSE
:should: 'detect content mismatch in buf via ExpectWithArrayExtended'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 99, 30};
store_data_ExpectWithArrayExtended(&exp_count, 1, 3, exp_data, 3);
function_k();
}
- :pass: TRUE
:should: 'pass using ExpectWithArrayExtended with depth override that skips mismatched last element'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 20, 99};
store_data_ExpectWithArrayExtended(&exp_count, 1, 3, exp_data, 2);
function_k();
}
- :pass: FALSE
:should: 'detect mismatch within overridden depth via ExpectWithArrayExtended'
:code: |
test()
{
int exp_count = 0;
int exp_data[] = {10, 99, 30};
store_data_ExpectWithArrayExtended(&exp_count, 1, 3, exp_data, 2);
function_k();
}
...
@@ -0,0 +1,113 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
---
:cmock:
:when_ptr: :smart
:plugins:
- :array
:systest:
:types: |
:mockable: |
void send_message(const char* msg);
int process_command(const char* cmd, int len);
:source:
:header: |
void function_a(void);
void function_b(void);
void function_c(void);
int function_d(void);
int function_e(void);
:code: |
void function_a(void)
{
send_message("hello");
}
void function_b(void)
{
send_message("hello");
}
void function_c(void)
{
send_message("hello");
}
int function_d(void)
{
return process_command("hello", 5);
}
int function_e(void)
{
return process_command("hello", 5);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'compare char* args as strings using Expect (strcmp) when array plugin active'
:code: |
test()
{
send_message_Expect("hello");
function_a();
}
- :pass: TRUE
:should: 'compare char* args as byte array using ExpectWithArray and pass when bytes match'
:code: |
test()
{
send_message_ExpectWithArray("hello", 5);
function_b();
}
- :pass: TRUE
:should: 'compare char* args as byte array using ExpectWithArray and pass when brief bytes match'
:code: |
test()
{
send_message_ExpectWithArray("heXXX", 2);
function_b();
}
- :pass: FALSE
:should: 'detect mismatch in char* via ExpectWithArray byte comparison'
:code: |
test()
{
send_message_ExpectWithArray("hXllo", 5);
function_c();
}
- :pass: TRUE
:should: 'compare char* with ExpectWithArrayAndReturn and pass when bytes match'
:code: |
test()
{
process_command_ExpectWithArrayAndReturn("hello", 5, 42);
TEST_ASSERT_EQUAL(42, function_d());
}
- :pass: FALSE
:should: 'detect mismatch in char* via ExpectWithArrayAndReturn byte comparison'
:code: |
test()
{
process_command_ExpectWithArrayAndReturn("world", 5, 42);
TEST_ASSERT_EQUAL(42, function_e());
}
@@ -7,7 +7,7 @@
---
:cmock:
:plugins: []
:plugins: [ignore, expect_any_args, array]
:treat_as:
custom_type: INT
@@ -21,6 +21,8 @@
:mockable: |
void foo(BIG_FAT_STRUCT_T a);
int get_result(void);
void process_data(int* data, int count);
:source:
:header: |
@@ -68,6 +70,7 @@
- :pass: FALSE
:should: 'should error out because we do not have eough memory to handle two of these structures'
:verify_error: 'CMock has run out of memory. Please allocate more.'
:code: |
test()
{
@@ -86,4 +89,41 @@
}
}
- :pass: FALSE
:should: 'should error out on ExpectAnyArgs when memory is exhausted'
:verify_error: 'CMock has run out of memory. Please allocate more.'
:code: |
test()
{
// Fill all available memory with ExpectAnyArgs call instances
while (CMock_Guts_MemBytesFree() > 0) {
foo_ExpectAnyArgs();
}
}
- :pass: FALSE
:should: 'should error out on IgnoreAndReturn when memory is exhausted'
:verify_error: 'CMock has run out of memory. Please allocate more.'
:code: |
test()
{
// Fill all available memory with IgnoreAndReturn call instances
while (CMock_Guts_MemBytesFree() > 0) {
get_result_IgnoreAndReturn(42);
}
}
- :pass: FALSE
:should: 'should error out on ExpectWithArray when memory is exhausted'
:verify_error: 'CMock has run out of memory. Please allocate more.'
:code: |
test()
{
int data = 0;
// Fill all available memory with ExpectWithArray call instances
while (CMock_Guts_MemBytesFree() > 0) {
process_data_ExpectWithArray(&data, 1, 1);
}
}
...
@@ -13,21 +13,32 @@
:systest:
:types: |
typedef struct _POINT_T {
typedef struct {
int x;
int y;
} POINT_T;
#define ARRAY_A_SIZE (5)
typedef enum {
RED = 0,
GREEN = 1,
BLUE = 2
} COLOR_E;
typedef union {
int as_int;
unsigned short as_shorts[2];
} RESULT_U;
:mockable: |
void foo(POINT_T* a);
POINT_T* bar(void);
void fooa(POINT_T a[ARRAY_A_SIZE+1-1]);
void foos(const char * a);
const char * bars(void);
void no_pointers(int a, const char* b);
int mixed(int a, int* b, int c);
void potential_packing_problem(short *a);
void foos(const char* a);
const char* bars(void);
void poke_color(COLOR_E* c);
COLOR_E* peek_color(void);
void poke_result(RESULT_U* r);
RESULT_U* peek_result(void);
void potential_packing_problem(short* a);
void voidpointerfunc(void* a);
:source:
@@ -35,7 +46,7 @@
void function_a(void);
void function_b(void);
void function_c(void);
int function_d(void);
void function_d(void);
void function_e(void);
void function_f(void);
@@ -45,26 +56,29 @@
foo(bar());
}
void function_b(void) {
fooa(bar());
}
void function_c(void) {
void function_b(void)
{
foos(bars());
}
int function_d(void) {
int test_list[] = { 1, 2, 3, 4, 5 };
no_pointers(1, "silly");
return mixed(6, test_list, 7);
void function_c(void)
{
poke_color(peek_color());
}
void function_e(void) {
void function_d(void)
{
poke_result(peek_result());
}
void function_e(void)
{
short test_list[] = {-1, -2, -3, -4};
potential_packing_problem(&test_list[1]);
}
void function_f(void) {
void function_f(void)
{
char arg[6] = "hello";
voidpointerfunc(arg);
}
@@ -76,7 +90,7 @@
:units:
- :pass: TRUE
:should: 'handle the situation where we pass nulls to pointers'
:should: 'handle null struct pointers in both directions'
:code: |
test()
{
@@ -87,7 +101,7 @@
}
- :pass: FALSE
:should: 'handle the situation where we expected nulls to pointers but did not get that'
:should: 'detect mismatch when expecting null struct pointer but receiving non-null'
:code: |
test()
{
@@ -99,7 +113,7 @@
}
- :pass: FALSE
:should: 'handle the situation where we did not expect nulls to pointers but got null'
:should: 'detect mismatch when expecting non-null struct pointer but receiving null'
:code: |
test()
{
@@ -111,7 +125,33 @@
}
- :pass: TRUE
:should: 'handle the situation where it falls back to pointers because you asked it to compare 0 elements'
:should: 'compare struct pointer contents and pass when contents match'
:code: |
test()
{
POINT_T pt = {3, 7};
POINT_T ex = {3, 7};
bar_ExpectAndReturn(&pt);
foo_Expect(&ex);
function_a();
}
- :pass: FALSE
:should: 'compare struct pointer contents and fail when contents differ'
:code: |
test()
{
POINT_T pt = {3, 7};
POINT_T ex = {3, 9};
bar_ExpectAndReturn(&pt);
foo_Expect(&ex);
function_a();
}
- :pass: TRUE
:should: 'fall back to pointer comparison when depth is zero and pointers match'
:code: |
test()
{
@@ -123,7 +163,7 @@
}
- :pass: FALSE
:should: 'handle the situation where it fails because you asked it to compare zero elements and the pointers do not match'
:should: 'fail pointer comparison when depth is zero and pointers differ'
:code: |
test()
{
@@ -136,59 +176,7 @@
}
- :pass: TRUE
:should: 'handle the situation where we pass single object with expect'
:code: |
test()
{
POINT_T pt = {1, 2};
POINT_T ex = {1, 2};
bar_ExpectAndReturn(&pt);
foo_Expect(&ex);
function_a();
}
- :pass: FALSE
:should: 'handle the situation where we pass single object with expect and it is wrong'
:code: |
test()
{
POINT_T pt = {1, 2};
POINT_T ex = {1, 3};
bar_ExpectAndReturn(&pt);
foo_Expect(&ex);
function_a();
}
- :pass: TRUE
:should: 'handle the situation where we pass single object with expect and use array handler'
:code: |
test()
{
POINT_T pt = {1, 2};
POINT_T ex = {1, 2};
bar_ExpectAndReturn(&pt);
foo_ExpectWithArray(&ex, 1);
function_a();
}
- :pass: FALSE
:should: 'handle the situation where we pass single object with expect and use array handler and it is wrong'
:code: |
test()
{
POINT_T pt = {1, 2};
POINT_T ex = {1, 3};
bar_ExpectAndReturn(&pt);
foo_ExpectWithArray(&ex, 1);
function_a();
}
- :pass: TRUE
:should: 'handle the situation where we pass multiple objects with expect and use array handler'
:should: 'compare multiple struct elements via ExpectWithArray and pass'
:code: |
test()
{
@@ -201,7 +189,7 @@
}
- :pass: FALSE
:should: 'handle the situation where we pass multiple objects with expect and use array handler and it is wrong at start'
:should: 'detect mismatch in first element of struct array comparison'
:code: |
test()
{
@@ -214,20 +202,7 @@
}
- :pass: FALSE
:should: 'handle the situation where we pass multiple objects with expect and use array handler and it is wrong at end'
:code: |
test()
{
POINT_T pt[] = {{1, 2}, {3, 4}, {5, 6}};
POINT_T ex[] = {{1, 2}, {3, 4}, {5, 9}};
bar_ExpectAndReturn(pt);
foo_ExpectWithArray(ex, 3);
function_a();
}
- :pass: FALSE
:should: 'handle the situation where we pass multiple objects with expect and use array handler and it is wrong in middle'
:should: 'detect mismatch in middle element of struct array comparison'
:code: |
test()
{
@@ -240,68 +215,20 @@
}
- :pass: FALSE
:should: 'handle the situation where we pass nulls to pointers and fail'
:should: 'detect mismatch in last element of struct array comparison'
:code: |
test()
{
POINT_T pt = {1, 2};
bar_ExpectAndReturn(&pt);
foo_Expect(NULL);
POINT_T pt[] = {{1, 2}, {3, 4}, {5, 6}};
POINT_T ex[] = {{1, 2}, {3, 4}, {5, 9}};
bar_ExpectAndReturn(pt);
foo_ExpectWithArray(ex, 3);
function_a();
}
- :pass: TRUE
:should: 'handle the situation where we pass nulls to arrays'
:code: |
test()
{
bar_ExpectAndReturn(NULL);
fooa_Expect(NULL);
function_b();
}
- :pass: TRUE
:should: 'handle the situation where we pass single array element with expect'
:code: |
test()
{
POINT_T pt = {1, 2};
POINT_T ex = {1, 2};
bar_ExpectAndReturn(&pt);
fooa_Expect(&ex);
function_b();
}
- :pass: FALSE
:should: 'handle the situation where we pass single array element with expect and it is wrong'
:code: |
test()
{
POINT_T pt = {1, 2};
POINT_T ex = {1, 3};
bar_ExpectAndReturn(&pt);
fooa_Expect(&ex);
function_b();
}
- :pass: FALSE
:should: 'handle the situation where we pass nulls to arrays and fail'
:code: |
test()
{
POINT_T pt = {1, 2};
bar_ExpectAndReturn(&pt);
fooa_Expect(NULL);
function_b();
}
- :pass: TRUE
:should: 'handle standard c string as null terminated on not do crappy memory compares of a byte, passing'
:should: 'handle string pointer matching on null-terminated content'
:code: |
test()
{
@@ -309,11 +236,11 @@
bars_ExpectAndReturn((char*)retval);
foos_Expect("This is a\0 wacky string");
function_c();
function_b();
}
- :pass: FALSE
:should: 'handle standard c string as null terminated on not do crappy memory compares of a byte, finding failures'
:should: 'detect string pointer mismatch on content'
:code: |
test()
{
@@ -321,81 +248,167 @@
bars_ExpectAndReturn((char*)retval);
foos_Expect("This is a wacky string");
function_b();
}
- :pass: TRUE
:should: 'handle null enum pointers in both directions'
:code: |
test()
{
peek_color_ExpectAndReturn(NULL);
poke_color_Expect(NULL);
function_c();
}
- :pass: TRUE
:should: 'handle creating array expects when we have mixed arguments for single object'
:should: 'compare enum pointer contents and pass when contents match'
:code: |
test()
{
int expect_list[] = { 1, 9 };
no_pointers_Expect(1, "silly");
mixed_ExpectAndReturn(6, expect_list, 7, 13);
COLOR_E actual = GREEN;
COLOR_E expected = GREEN;
peek_color_ExpectAndReturn(&actual);
poke_color_Expect(&expected);
TEST_ASSERT_EQUAL(13, function_d());
function_c();
}
- :pass: FALSE
:should: 'handle creating array expects when we have mixed arguments and handle failures for single object'
:should: 'detect mismatch in enum pointer contents'
:code: |
test()
{
int expect_list[] = { 9, 1 };
no_pointers_Expect(1, "silly");
mixed_ExpectAndReturn(6, expect_list, 7, 13);
COLOR_E actual = GREEN;
COLOR_E expected = BLUE;
peek_color_ExpectAndReturn(&actual);
poke_color_Expect(&expected);
TEST_ASSERT_EQUAL(13, function_d());
function_c();
}
- :pass: TRUE
:should: 'handle creating array expects when we have mixed arguments for multiple objects'
:should: 'compare multiple enum elements via ExpectWithArray and pass'
:code: |
test()
{
int expect_list[] = { 1, 2, 3, 4, 6 };
no_pointers_Expect(1, "silly");
mixed_ExpectWithArrayAndReturn(6, expect_list, 4, 7, 13);
COLOR_E actual[] = {RED, GREEN, BLUE};
COLOR_E expected[] = {RED, GREEN, BLUE};
peek_color_ExpectAndReturn(actual);
poke_color_ExpectWithArray(expected, 3);
TEST_ASSERT_EQUAL(13, function_d());
function_c();
}
- :pass: FALSE
:should: 'handle creating array expects when we have mixed arguments and handle failures for multiple objects'
:should: 'detect mismatch when comparing multiple enum elements'
:code: |
test()
{
int expect_list[] = { 1, 2, 3, 4, 6 };
no_pointers_Expect(1, "silly");
mixed_ExpectWithArrayAndReturn(6, expect_list, 5, 7, 13);
COLOR_E actual[] = {RED, GREEN, BLUE};
COLOR_E expected[] = {RED, BLUE, BLUE};
peek_color_ExpectAndReturn(actual);
poke_color_ExpectWithArray(expected, 3);
TEST_ASSERT_EQUAL(13, function_d());
function_c();
}
- :pass: TRUE
:should: 'handle a passing version of a potential packing problem (particularly try with ARM simulators)'
:should: 'handle null union pointers in both directions'
:code: |
test()
{
short expect_list[] = { -2, -3, -4 };
peek_result_ExpectAndReturn(NULL);
poke_result_Expect(NULL);
function_d();
}
- :pass: TRUE
:should: 'compare union pointer contents and pass when contents match'
:code: |
test()
{
RESULT_U actual;
RESULT_U expected;
actual.as_int = 42;
expected.as_int = 42;
peek_result_ExpectAndReturn(&actual);
poke_result_Expect(&expected);
function_d();
}
- :pass: FALSE
:should: 'detect mismatch in union pointer contents'
:code: |
test()
{
RESULT_U actual;
RESULT_U expected;
actual.as_int = 42;
expected.as_int = 99;
peek_result_ExpectAndReturn(&actual);
poke_result_Expect(&expected);
function_d();
}
- :pass: TRUE
:should: 'compare multiple union elements via ExpectWithArray and pass'
:code: |
test()
{
RESULT_U actual[3];
RESULT_U expected[3];
actual[0].as_int = 1; actual[1].as_int = 2; actual[2].as_int = 3;
expected[0].as_int = 1; expected[1].as_int = 2; expected[2].as_int = 3;
peek_result_ExpectAndReturn(actual);
poke_result_ExpectWithArray(expected, 3);
function_d();
}
- :pass: FALSE
:should: 'detect mismatch when comparing multiple union elements'
:code: |
test()
{
RESULT_U actual[3];
RESULT_U expected[3];
actual[0].as_int = 1; actual[1].as_int = 2; actual[2].as_int = 3;
expected[0].as_int = 1; expected[1].as_int = 9; expected[2].as_int = 3;
peek_result_ExpectAndReturn(actual);
poke_result_ExpectWithArray(expected, 3);
function_d();
}
- :pass: TRUE
:should: 'handle a passing packing problem comparison'
:code: |
test()
{
short expect_list[] = {-2, -3, -4};
potential_packing_problem_ExpectWithArray(expect_list, 3);
function_e();
}
- :pass: FALSE
:should: 'handle a failing version of a potential packing problem (particularly try with ARM simulators)'
:should: 'detect a failing packing problem comparison'
:code: |
test()
{
short expect_list[] = { -2, -3, 4 };
short expect_list[] = {-2, -3, 4};
potential_packing_problem_ExpectWithArray(expect_list, 3);
function_e();
}
- :pass: TRUE
:should: 'handle a void pointers as arguments and still be able to use the array plugin'
:should: 'handle void pointer with array comparison passing'
:code: |
test()
{
@@ -406,7 +419,7 @@
}
- :pass: TRUE
:should: 'handle a void pointers as arguments and still be able to use the array plugin (short)'
:should: 'handle void pointer with partial array comparison passing'
:code: |
test()
{
@@ -417,7 +430,7 @@
}
- :pass: FALSE
:should: 'handle a void pointers as arguments and still be able to use the array plugin (fail)'
:should: 'detect void pointer content mismatch with array comparison'
:code: |
test()
{
@@ -428,7 +441,7 @@
}
- :pass: TRUE
:should: 'handle a void pointer with a standard expectation (pass)'
:should: 'handle void pointer with standard expect passing'
:code: |
test()
{
@@ -439,7 +452,7 @@
}
- :pass: FALSE
:should: 'handle a void pointer with a standard expectation (fail)'
:should: 'detect void pointer mismatch with standard expect'
:code: |
test()
{
@@ -449,5 +462,4 @@
function_f();
}
...
@@ -15,7 +15,7 @@
:when_ptr: :smart
:plugins:
- :array
- :ignore_arg
- :expect_any_args
- :return_thru_ptr
:systest:
@@ -106,11 +106,10 @@
:code: |
test()
{
int r = 1, s = 2;
int s = 2;
int res = 4;
ptr_ret_int_Expect(&r);
ptr_ret_int_IgnoreArg_r();
ptr_ret_int_ExpectAnyArgs();
ptr_ret_int_ReturnThruPtr_r(&res);
ptr_ret_int(&s);
TEST_ASSERT_EQUAL(4, s);
@@ -124,8 +123,7 @@
int r = 1;
int res = 4;
ptr_ret_int_Expect(NULL);
ptr_ret_int_IgnoreArg_r();
ptr_ret_int_ExpectAnyArgs();
ptr_ret_int_ReturnThruPtr_r(&res);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(4, r);
@@ -230,13 +228,11 @@
}
- :pass: TRUE
:should: "generate IgnoreArg definitions"
:should: "generate ExpectAnyArgs definitions"
:code: |
test()
{
#if !defined(ptr_ret_array_IgnoreArg_r) \
|| !defined(ptr_ret_array_IgnoreArg_len) \
|| !defined(ptr_ret_const_int_IgnoreArg_s)
TEST_FAIL_MESSAGE("IgnoreArg not defined for an argument.");
#if !defined(ptr_ret_array_ExpectAnyArgs)
TEST_FAIL_MESSAGE("ExpectAnyArgs not defined for an argument.");
#endif
}
@@ -15,7 +15,7 @@
:when_ptr: :smart
:plugins:
- :array
- :expect_any_args
- :ignore_arg
- :return_thru_ptr
:systest:
@@ -106,10 +106,11 @@
:code: |
test()
{
int s = 2;
int r = 1, s = 2;
int res = 4;
ptr_ret_int_ExpectAnyArgs();
ptr_ret_int_Expect(&r);
ptr_ret_int_IgnoreArg_r();
ptr_ret_int_ReturnThruPtr_r(&res);
ptr_ret_int(&s);
TEST_ASSERT_EQUAL(4, s);
@@ -123,7 +124,8 @@
int r = 1;
int res = 4;
ptr_ret_int_ExpectAnyArgs();
ptr_ret_int_Expect(NULL);
ptr_ret_int_IgnoreArg_r();
ptr_ret_int_ReturnThruPtr_r(&res);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(4, r);
@@ -228,11 +230,13 @@
}
- :pass: TRUE
:should: "generate ExpectAnyArgs definitions"
:should: "generate IgnoreArg definitions"
:code: |
test()
{
#if !defined(ptr_ret_array_ExpectAnyArgs)
TEST_FAIL_MESSAGE("ExpectAnyArgs not defined for an argument.");
#if !defined(ptr_ret_array_IgnoreArg_r) \
|| !defined(ptr_ret_array_IgnoreArg_len) \
|| !defined(ptr_ret_const_int_IgnoreArg_s)
TEST_FAIL_MESSAGE("IgnoreArg not defined for an argument.");
#endif
}
@@ -0,0 +1,133 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
---
#The purpose of this test is to verify that void* arguments use pointer
#comparison (not byte dereferencing) when the array plugin is not active.
#Dereferencing void* is illegal in C, so the mock must fall back to
#comparing pointer values via UNITY_TEST_ASSERT_EQUAL_PTR.
:cmock:
:plugins: []
:treat_as_void:
- MY_VOID
:systest:
:types: |
typedef void MY_VOID;
:mockable: |
void get_v_ptr(void* ptr);
void get_const_v_ptr(const void* ptr);
void get_my_void_ptr(MY_VOID* ptr);
:source:
:header: |
void function_a(void* arg);
void function_b(const void* arg);
void function_c(MY_VOID* arg);
:code: |
void function_a(void* arg) {
get_v_ptr(arg);
}
void function_b(const void* arg) {
get_const_v_ptr(arg);
}
void function_c(MY_VOID* arg) {
get_my_void_ptr(arg);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'handle void pointer expect passing when same pointer used'
:code: |
test()
{
char* a = "Hello";
get_v_ptr_Expect(a);
function_a(a);
}
- :pass: FALSE
:should: 'detect void pointer mismatch when different pointers used even with same content'
:code: |
test()
{
static char a[] = "Hello";
static char b[] = "Hello";
get_v_ptr_Expect(a);
function_a(b);
}
- :pass: TRUE
:should: 'handle null void pointer expect passing'
:code: |
test()
{
get_v_ptr_Expect(NULL);
function_a(NULL);
}
- :pass: FALSE
:should: 'detect null vs non-null void pointer mismatch'
:code: |
test()
{
char* a = "Hello";
get_v_ptr_Expect(NULL);
function_a(a);
}
- :pass: TRUE
:should: 'handle const void pointer expect passing when same pointer used'
:code: |
test()
{
char* a = "Hello";
get_const_v_ptr_Expect(a);
function_b(a);
}
- :pass: FALSE
:should: 'detect const void pointer mismatch when different pointers used'
:code: |
test()
{
static char a[] = "Hello";
static char b[] = "Hello";
get_const_v_ptr_Expect(a);
function_b(b);
}
- :pass: TRUE
:should: 'handle treat_as_void alias pointer expect passing when same pointer used'
:code: |
test()
{
char* a = "Hello";
get_my_void_ptr_Expect(a);
function_c(a);
}
- :pass: FALSE
:should: 'detect treat_as_void alias pointer mismatch when different pointers used'
:code: |
test()
{
static char a[] = "Hello";
static char b[] = "Hello";
get_my_void_ptr_Expect(a);
function_c(b);
}
...
@@ -0,0 +1,102 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
---
#The purpose of this test is to verify that pointers to treat_as_void alias types
#(e.g. MY_VOID*) use HEX8_ARRAY byte comparison when the array plugin is active,
#rather than falling through to MEMORY_ARRAY which would emit sizeof(void) — illegal C.
:cmock:
:plugins:
- :array
:when_ptr: :smart
:treat_as_void:
- MY_VOID
:systest:
:types: |
typedef void MY_VOID;
:mockable: |
void get_my_void_ptr(MY_VOID* ptr);
:source:
:header: |
void function_a(MY_VOID* arg);
:code: |
void function_a(MY_VOID* arg) {
get_my_void_ptr(arg);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'handle treat_as_void pointer with same pointer using standard expect'
:code: |
test()
{
char* a = "Hello";
get_my_void_ptr_Expect(a);
function_a(a);
}
- :pass: TRUE
:should: 'handle treat_as_void pointer with same content using ExpectWithArray'
:code: |
test()
{
char* a = "Hello";
char* b = "Hello";
get_my_void_ptr_ExpectWithArray(a, 5);
function_a(b);
}
- :pass: FALSE
:should: 'detect treat_as_void pointer content mismatch with ExpectWithArray'
:code: |
test()
{
char* a = "Hello";
char* b = "Jello";
get_my_void_ptr_ExpectWithArray(a, 5);
function_a(b);
}
- :pass: TRUE
:should: 'handle null treat_as_void pointer comparison'
:code: |
test()
{
get_my_void_ptr_Expect(NULL);
function_a(NULL);
}
- :pass: TRUE
:should: 'handle treat_as_void pointer comparison with depth 0 using smart ptr comparison'
:code: |
test()
{
char* a = "Hello";
get_my_void_ptr_ExpectWithArray(a, 0);
function_a(a);
}
- :pass: FALSE
:should: 'detect treat_as_void pointer value mismatch with depth 0 in smart mode'
:code: |
test()
{
static char a[] = "Hello";
static char b[] = "Hello";
get_my_void_ptr_ExpectWithArray(a, 0);
function_a(b);
}
...
@@ -16,6 +16,9 @@ class UtilsStub
def arg_type_with_const(arg)
CMockGeneratorUtils.arg_type_with_const(arg)
end
def arg_declaration(arg)
CMockGeneratorUtils.arg_declaration(arg)
end
def code_add_base_expectation(func)
"mock_retval_0"
end
@@ -16,6 +16,9 @@ class UtilsStub
def arg_type_with_const(arg)
CMockGeneratorUtils.arg_type_with_const(arg)
end
def arg_declaration(arg)
CMockGeneratorUtils.arg_declaration(arg)
end
def code_add_base_expectation(func)
"mock_retval_0"
end
@@ -115,6 +118,42 @@ describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do
assert_equal(expected, returned)
end
it "add mock function declarations for functions with size arg after pointer, short macro auto-fills depth" do
function = {:name => "Birch",
:args => [
{ :type => "int*", :name => "sensors", :ptr? => true, :array_size_order => :after, :array_size_name => "count" },
{ :type => "int", :name => "count", :ptr? => false, :array_size? => true }
],
:return => test_return[:void],
:contains_ptr? => true }
expected = "#define Birch_ExpectWithArrayAndReturn(sensors, count, cmock_retval) TEST_FAIL_MESSAGE(\"Birch requires _ExpectWithArray (not AndReturn)\");\n" +
"#define Birch_ExpectWithArrayExtendedAndReturn(sensors, sensors_Depth, count, cmock_retval) TEST_FAIL_MESSAGE(\"Birch requires _ExpectWithArrayExtended (not AndReturn)\");\n" +
"#define Birch_ExpectWithArray(sensors, count) Birch_CMockExpectWithArray(__LINE__, sensors, (count), count)\n" +
"#define Birch_ExpectWithArrayExtended(sensors, sensors_Depth, count) Birch_CMockExpectWithArray(__LINE__, sensors, (sensors_Depth), count)\n" +
"void Birch_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, int* sensors, int sensors_Depth, int count);\n"
returned = @cmock_generator_plugin_array.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "add mock function declarations for functions with size arg before pointer, short macro auto-fills depth" do
function = {:name => "Willow",
:args => [
{ :type => "int", :name => "buf_size", :ptr? => false, :array_size? => true },
{ :type => "int*", :name => "buf", :ptr? => true, :array_size_order => :before, :array_size_name => "buf_size" }
],
:return => test_return[:void],
:contains_ptr? => true }
expected = "#define Willow_ExpectWithArrayAndReturn(buf_size, buf, cmock_retval) TEST_FAIL_MESSAGE(\"Willow requires _ExpectWithArray (not AndReturn)\");\n" +
"#define Willow_ExpectWithArrayExtendedAndReturn(buf_size, buf, buf_Depth, cmock_retval) TEST_FAIL_MESSAGE(\"Willow requires _ExpectWithArrayExtended (not AndReturn)\");\n" +
"#define Willow_ExpectWithArray(buf_size, buf) Willow_CMockExpectWithArray(__LINE__, buf_size, buf, (buf_size))\n" +
"#define Willow_ExpectWithArrayExtended(buf_size, buf, buf_Depth) Willow_CMockExpectWithArray(__LINE__, buf_size, buf, (buf_Depth))\n" +
"void Willow_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, int buf_size, int* buf, int buf_Depth);\n"
returned = @cmock_generator_plugin_array.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "not have a mock function implementation" do
assert(!@cmock_generator_plugin_array.respond_to?(:mock_implementation))
end
@@ -143,4 +182,25 @@ describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do
assert_equal(expected, returned)
end
it "add mock interfaces with depth override line for :before-paired pointer" do
function = {:name => "Willow",
:args => [
{ :type => "int", :name => "buf_size", :ptr? => false, :array_size? => true },
{ :type => "int*", :name => "buf", :ptr? => true, :array_size_order => :before, :array_size_name => "buf_size" }
],
:args_string => "int buf_size, int* buf",
:return => test_return[:void],
:contains_ptr? => true }
expected = ["void Willow_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, int buf_size, int* buf, int buf_Depth)\n",
"{\n",
"mock_retval_0",
" CMockExpectParameters_Willow(cmock_call_instance, buf_size, buf);\n",
" cmock_call_instance->Expected_buf_Depth = buf_Depth;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_array.mock_interfaces(function).join
assert_equal(expected, returned)
end
end
+109 -2
View File
@@ -98,6 +98,46 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
assert_equal(expected, output)
end
it "add code for a base expectation with expect_any_args plugin" do
config = create_stub(
:when_ptr => :smart,
:enforce_strict_ordering => false,
:plugins => [:expect_any_args],
:treat_as => {},
:respond_to? => false
)
utils = CMockGeneratorUtils.new(config, {})
expected =
" CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_Apple_CALL_INSTANCE));\n" +
" CMOCK_Apple_CALL_INSTANCE* cmock_call_instance = (CMOCK_Apple_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n" +
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" +
" memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" +
" Mock.Apple_CallInstance = CMock_Guts_MemChain(Mock.Apple_CallInstance, cmock_guts_index);\n" +
" cmock_call_instance->LineNumber = cmock_line;\n" +
" cmock_call_instance->ExpectAnyArgsBool = (char)0;\n"
assert_equal(expected, utils.code_add_base_expectation("Apple"))
end
it "add code for a base expectation with ignore_stateless plugin (without ignore)" do
config = create_stub(
:when_ptr => :smart,
:enforce_strict_ordering => false,
:plugins => [:ignore_stateless],
:treat_as => {},
:respond_to? => false
)
utils = CMockGeneratorUtils.new(config, {})
expected =
" CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_Apple_CALL_INSTANCE));\n" +
" CMOCK_Apple_CALL_INSTANCE* cmock_call_instance = (CMOCK_Apple_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n" +
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" +
" memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" +
" Mock.Apple_CallInstance = CMock_Guts_MemChain(Mock.Apple_CallInstance, cmock_guts_index);\n" +
" Mock.Apple_IgnoreBool = (char)0;\n" +
" cmock_call_instance->LineNumber = cmock_line;\n"
assert_equal(expected, utils.code_add_base_expectation("Apple"))
end
it "add argument expectations for values when no array plugin" do
arg1 = { :name => "Orange", :const? => false, :type => 'int', :ptr? => false }
expected1 = " cmock_call_instance->Expected_Orange = Orange;\n"
@@ -130,7 +170,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
arg3 = { :name => "Kiwi", :const? => false, :type => 'KIWI_T*', :ptr? => true }
expected3 = " cmock_call_instance->Expected_Kiwi = Kiwi;\n" +
" cmock_call_instance->Expected_Kiwi_Depth = Kiwi_Depth;\n" +
" cmock_call_instance->Expected_Kiwi_Depth = Mango_Depth;\n" +
" cmock_call_instance->IgnoreArg_Kiwi = 0;\n" +
" cmock_call_instance->ReturnThruPtr_Kiwi_Used = 0;\n"
@@ -141,7 +181,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
assert_equal(expected1, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg1))
assert_equal(expected2, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg2, 'Lemon_Depth'))
assert_equal(expected3, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg3, 'Lemon_Depth'))
assert_equal(expected3, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg3, 'Mango_Depth'))
assert_equal(expected4, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg4))
end
@@ -401,4 +441,71 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
@unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_MY_TYPE_ARRAY', '&'], ['MY_TYPE']
assert_equal(expected, @cmock_generator_utils_complex.code_verify_an_arg_expectation(function, arg))
end
# void* tests without array plugin (when_ptr: :compare_data) - these must use pointer
# comparison because dereferencing void* is illegal in C
it 'handle void pointer comparison without array plugin by using pointer comparison' do
config_stub = create_stub({
when_ptr: :compare_data,
enforce_strict_ordering: false,
plugins: [],
treat_as: {'void*' => 'HEX8_ARRAY', 'void const*' => 'HEX8_ARRAY', 'const void*' => 'HEX8_ARRAY'},
treat_as_void: []
})
utils = CMockGeneratorUtils.new(config_stub, {:unity_helper => @unity_helper})
function = { :name => 'Pear' }
[
{:type => "void*", :name => 'MyVoidPtr', :ptr? => true, :const? => false, :const_ptr? => false},
{:type => "const void*", :name => 'MyConstVoidPtr', :ptr? => true, :const? => true, :const_ptr? => false},
{:type => "void const*", :name => 'MyVoidConstPtr', :ptr? => true, :const? => false, :const_ptr? => true},
].each do |arg|
expected = " {\n" +
" UNITY_SET_DETAILS(CMockString_Pear,CMockString_#{arg[:name]});\n" +
" UNITY_TEST_ASSERT_EQUAL_PTR(cmock_call_instance->Expected_#{arg[:name]}, #{arg[:name]}, cmock_line, CMockStringMismatch);\n" +
" }\n"
assert_equal(expected, utils.code_verify_an_arg_expectation(function, arg))
end
end
it 'handle treat_as_void alias pointer comparison without array plugin by using pointer comparison' do
config_stub = create_stub({
when_ptr: :compare_data,
enforce_strict_ordering: false,
plugins: [],
treat_as: {'MY_VOID*' => 'HEX8_ARRAY'},
treat_as_void: ['MY_VOID']
})
utils = CMockGeneratorUtils.new(config_stub, {:unity_helper => @unity_helper})
function = { :name => 'Pear' }
arg = {:type => "MY_VOID*", :name => 'MyVoidAliasPtr', :ptr? => true, :const? => false, :const_ptr? => false}
expected = " {\n" +
" UNITY_SET_DETAILS(CMockString_Pear,CMockString_MyVoidAliasPtr);\n" +
" UNITY_TEST_ASSERT_EQUAL_PTR(cmock_call_instance->Expected_MyVoidAliasPtr, MyVoidAliasPtr, cmock_line, CMockStringMismatch);\n" +
" }\n"
assert_equal(expected, utils.code_verify_an_arg_expectation(function, arg))
end
it 'handle treat_as_void alias pointer with array plugin using HEX8_ARRAY to avoid sizeof(void)' do
config_stub = create_stub({
when_ptr: :compare_data,
enforce_strict_ordering: false,
plugins: [:array],
treat_as: {},
treat_as_void: ['MY_VOID']
})
utils = CMockGeneratorUtils.new(config_stub, {:unity_helper => @unity_helper})
function = { :name => 'Pear' }
arg = {:type => "MY_VOID*", :name => 'MyVoidAliasPtr', :ptr? => true, :const? => false, :const_ptr? => false}
expected = " {\n" +
" UNITY_SET_DETAILS(CMockString_Pear,CMockString_MyVoidAliasPtr);\n" +
" if (cmock_call_instance->Expected_MyVoidAliasPtr == NULL)\n" +
" { UNITY_TEST_ASSERT_NULL(MyVoidAliasPtr, cmock_line, CMockStringExpNULL); }\n" +
" else\n" +
" { UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(cmock_call_instance->Expected_MyVoidAliasPtr, MyVoidAliasPtr, cmock_call_instance->Expected_MyVoidAliasPtr_Depth, cmock_line, CMockStringMismatch); }\n" +
" }\n"
assert_equal(expected, utils.code_verify_an_arg_expectation(function, arg))
end
end
+227 -107
View File
@@ -597,7 +597,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
},
:modifier=>"",
:contains_ptr? => false,
:args=>[{:type=>"int", :name=>"a", :ptr? => false, :const? => false, :const_ptr? => false}],
:args=>[{:type=>"int", :name=>"a", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}],
:args_string=>"int a",
:args_call=>"a"}
assert_equal(expected, @parser.parse_declaration(@test_project, source))
@@ -643,7 +643,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
},
:modifier=>"",
:contains_ptr? => true,
:args=>[{:type=>"MY_FUNKY_VOID*", :name=>"bluh", :ptr? => true, :const? => false, :const_ptr? => false}],
:args=>[{:type=>"MY_FUNKY_VOID*", :name=>"bluh", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}],
:args_string=>"MY_FUNKY_VOID* bluh",
:args_call=>"bluh" }
assert_equal(expected, @parser.parse_declaration(@test_project, source))
@@ -745,8 +745,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
},
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"a", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int", :name=>"b", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"a", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int", :name=>"b", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int a, unsigned int b",
:args_call=>"a, b" }
@@ -771,9 +771,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"uint", :name=>"la", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"de", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"bool", :name=>"da", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"uint", :name=>"la", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"de", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"bool", :name=>"da", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"uint la, int de, bool da",
:args_call=>"la, de, da" }
@@ -822,8 +822,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"const",
:contains_ptr? => true,
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Trinity, unsigned int* Neo",
:args_call=>"Trinity, Neo" }
@@ -849,8 +849,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:modifier=>"const",
:c_calling_convention=>"__stdcall",
:contains_ptr? => true,
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Trinity, unsigned int* Neo",
:args_call=>"Trinity, Neo" }
@@ -874,8 +874,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
},
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"a", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int", :name=>"b", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"a", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int", :name=>"b", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int a, unsigned int b",
:args_call=>"a, b" }
@@ -902,8 +902,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"const",
:contains_ptr? => true,
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Trinity, unsigned int* Neo",
:args_call=>"Trinity, Neo" },
@@ -922,8 +922,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"int", :name=>"cmock_arg1", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"cmock_arg2", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"cmock_arg1", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"cmock_arg2", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int cmock_arg1, unsigned int* cmock_arg2",
:args_call=>"cmock_arg1, cmock_arg2"
@@ -951,8 +951,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
},
:modifier=>"const",
:contains_ptr? => true,
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned int*", :name=>"Neo", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Trinity, unsigned int* Neo",
:args_call=>"Trinity, Neo"
@@ -1070,14 +1070,14 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:var_arg => nil,
:args_string => "int const* cmock_arg1, int* const cmock_arg2, const int* cmock_arg3, const int* const cmock_arg4, " +
"int const* const cmock_arg5, int* cmock_arg6, int cmock_arg7, const int cmock_arg8",
:args => [{ :type=>"int const*", :name => "cmock_arg1", :ptr? => true, :const? => true, :const_ptr? => false },
{ :type=>"int*", :name => "cmock_arg2", :ptr? => true, :const? => false, :const_ptr? => true },
{ :type=>"const int*", :name => "cmock_arg3", :ptr? => true, :const? => true, :const_ptr? => false },
{ :type=>"const int*", :name => "cmock_arg4", :ptr? => true, :const? => true, :const_ptr? => true },
{ :type=>"int const*", :name => "cmock_arg5", :ptr? => true, :const? => true, :const_ptr? => true },
{ :type=>"int*", :name => "cmock_arg6", :ptr? => true, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "cmock_arg7", :ptr? => false, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "cmock_arg8", :ptr? => false, :const? => true, :const_ptr? => false }],
:args => [{ :type=>"int const*", :name => "cmock_arg1", :ptr? => true, :string? => false, :const? => true, :const_ptr? => false },
{ :type=>"int*", :name => "cmock_arg2", :ptr? => true, :string? => false, :const? => false, :const_ptr? => true },
{ :type=>"const int*", :name => "cmock_arg3", :ptr? => true, :string? => false, :const? => true, :const_ptr? => false },
{ :type=>"const int*", :name => "cmock_arg4", :ptr? => true, :string? => false, :const? => true, :const_ptr? => true },
{ :type=>"int const*", :name => "cmock_arg5", :ptr? => true, :string? => false, :const? => true, :const_ptr? => true },
{ :type=>"int*", :name => "cmock_arg6", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "cmock_arg7", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "cmock_arg8", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false }],
:args_call => "cmock_arg1, cmock_arg2, cmock_arg3, cmock_arg4, cmock_arg5, cmock_arg6, cmock_arg7, cmock_arg8",
:contains_ptr? => true
}]
@@ -1105,14 +1105,14 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:var_arg => nil,
:args_string => "int const* param1, int* const param2, const int* param3, const int* const param4, " +
"int const* const param5, int* param6, int param7, const int param8",
:args => [{ :type=>"int const*", :name => "param1", :ptr? => true, :const? => true, :const_ptr? => false },
{ :type=>"int*", :name => "param2", :ptr? => true, :const? => false, :const_ptr? => true },
{ :type=>"const int*", :name => "param3", :ptr? => true, :const? => true, :const_ptr? => false },
{ :type=>"const int*", :name => "param4", :ptr? => true, :const? => true, :const_ptr? => true },
{ :type=>"int const*", :name => "param5", :ptr? => true, :const? => true, :const_ptr? => true },
{ :type=>"int*", :name => "param6", :ptr? => true, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "param7", :ptr? => false, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "param8", :ptr? => false, :const? => true, :const_ptr? => false }],
:args => [{ :type=>"int const*", :name => "param1", :ptr? => true, :string? => false, :const? => true, :const_ptr? => false },
{ :type=>"int*", :name => "param2", :ptr? => true, :string? => false, :const? => false, :const_ptr? => true },
{ :type=>"const int*", :name => "param3", :ptr? => true, :string? => false, :const? => true, :const_ptr? => false },
{ :type=>"const int*", :name => "param4", :ptr? => true, :string? => false, :const? => true, :const_ptr? => true },
{ :type=>"int const*", :name => "param5", :ptr? => true, :string? => false, :const? => true, :const_ptr? => true },
{ :type=>"int*", :name => "param6", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "param7", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false },
{ :type=>"int", :name => "param8", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false }],
:args_call => "param1, param2, param3, param4, param5, param6, param7, param8",
:contains_ptr? => true
}].freeze
@@ -1137,8 +1137,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:const_ptr? => false
},
:var_arg => nil,
:args => [{ :type => "Page*", :name => "book", :ptr? => true, :const? => false, :const_ptr? => false },
{ :type => "const int*", :name => "values", :ptr? => true, :const? => true, :const_ptr? => false }],
:args => [{ :type => "Page*", :name => "book", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false },
{ :type => "const int*", :name => "values", :ptr? => true, :string? => false, :const? => true, :const_ptr? => false }],
:args_string => "Book book, const IntArray values",
:args_call => "book, values",
:contains_ptr? => true
@@ -1170,7 +1170,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
},
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"SingAlong", :ptr? => false, :const? => false, :const_ptr? => false} ],
:args=>[ {:type=>"int", :name=>"SingAlong", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false} ],
:args_string=>"int SingAlong",
:args_call=>"SingAlong"
},
@@ -1217,7 +1217,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"struct SingAlong", :name=>"Blog", :ptr? => false, :const? => false, :const_ptr? => false} ],
:args=>[ {:type=>"struct SingAlong", :name=>"Blog", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false} ],
:args_string=>"struct SingAlong Blog",
:args_call=>"Blog"
},
@@ -1236,7 +1236,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"struct const _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :const? => true, :const_ptr? => true} ],
:args=>[ {:type=>"struct const _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :string? => false, :const? => true, :const_ptr? => true} ],
:args_string=>"struct const _KeepYourHeadUp_* const BillyBuddy",
:args_call=>"BillyBuddy"
},
@@ -1279,8 +1279,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"union STARS_AND_STRIPES*", :name=>"a", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"union AFL_CIO", :name=>"b", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"union STARS_AND_STRIPES*", :name=>"a", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"union AFL_CIO", :name=>"b", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"union STARS_AND_STRIPES* a, union AFL_CIO b",
:args_call=>"a, b" }]
@@ -1305,11 +1305,11 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=> "unsigned int", :name=>"const_param", :ptr? => false, :const? => true, :const_ptr? => false},
{:type=>"int", :name=>"int_param", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"integer", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"char", :name=>"character", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int*", :name=>"constant", :ptr? => true, :const? => false, :const_ptr? => true}
:args=>[ {:type=> "unsigned int", :name=>"const_param", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false},
{:type=>"int", :name=>"int_param", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"integer", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"char", :name=>"character", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int*", :name=>"constant", :ptr? => true, :string? => false, :const? => false, :const_ptr? => true}
],
:args_string=>"const unsigned int const_param, int int_param, int integer, char character, int* const constant",
:args_call=>"const_param, int_param, integer, character, constant" }]
@@ -1334,11 +1334,11 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"integer", :name=>"param", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"character", :name=>"thing", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"longint*", :name=>"junk", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"constant", :name=>"value", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int32_t", :name=>"number", :ptr? => false, :const? => true, :const_ptr? => false}
:args=>[ {:type=>"integer", :name=>"param", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"character", :name=>"thing", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"longint*", :name=>"junk", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"constant", :name=>"value", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int32_t", :name=>"number", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false}
],
:args_string=>"integer param, character thing, longint* junk, constant value, int32_t const number",
:args_call=>"param, thing, junk, value, number" }]
@@ -1363,10 +1363,10 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"signed char", :name=>"abc", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned long int", :name=>"xyz_123", :ptr? => false, :const? => true, :const_ptr? => false},
{:type=>"unsigned int", :name=>"abc_123", :ptr? => false, :const? => true, :const_ptr? => false},
{:type=>"long long", :name=>"arm_of_the_law", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"signed char", :name=>"abc", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned long int", :name=>"xyz_123", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false},
{:type=>"unsigned int", :name=>"abc_123", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false},
{:type=>"long long", :name=>"arm_of_the_law", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"signed char abc, const unsigned long int xyz_123, unsigned int const abc_123, long long arm_of_the_law",
:args_call=>"abc, xyz_123, abc_123, arm_of_the_law" }]
@@ -1391,10 +1391,10 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"CUSTOM_TYPE", :name=>"abc", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"CUSTOM_TYPE*", :name=>"xyz_123", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"CUSTOM_TYPE", :name=>"abcxyz", :ptr? => false, :const? => true, :const_ptr? => false},
{:type=>"struct CUSTOM_TYPE const*", :name=>"abc123", :ptr? => true, :const? => true, :const_ptr? => true}
:args=>[ {:type=>"CUSTOM_TYPE", :name=>"abc", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"CUSTOM_TYPE*", :name=>"xyz_123", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"CUSTOM_TYPE", :name=>"abcxyz", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false},
{:type=>"struct CUSTOM_TYPE const*", :name=>"abc123", :ptr? => true, :string? => false, :const? => true, :const_ptr? => true}
],
:args_string=>"CUSTOM_TYPE abc, CUSTOM_TYPE* xyz_123, CUSTOM_TYPE const abcxyz, struct CUSTOM_TYPE const* const abc123",
:args_call=>"abc, xyz_123, abcxyz, abc123" }]
@@ -1406,13 +1406,11 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
source = 'void KeyOperated(CUSTOM_TYPE thing1[], int thing2 [ ], ' \
'char thing3 [][2 ][ 3], int* thing4[4], u8 thing5[((u8)((5 + 5*2)/3))])'
expected_args = [
{ type: 'CUSTOM_TYPE*', name: 'thing1', ptr?: true, const?: false, const_ptr?: false },
{ type: 'int*', name: 'thing2', ptr?: true, const?: false, const_ptr?: false },
# this one will likely change in the future when we improve multidimensional array support
{ type: 'char*', name: 'thing3', ptr?: false, const?: false, const_ptr?: false },
# this one will likely change in the future when we improve multidimensional array support
{ type: 'int**', name: 'thing4', ptr?: true, const?: false, const_ptr?: false },
{ type: 'u8*', name: 'thing5', ptr?: true, const?: false, const_ptr?: false }
{ type: 'CUSTOM_TYPE*', name: 'thing1', ptr?: true, string?: false, const?: false, const_ptr?: false, array_dims: [''] },
{ type: 'int*', name: 'thing2', ptr?: true, string?: false, const?: false, const_ptr?: false, array_dims: [''] },
{ type: 'char*', name: 'thing3', ptr?: false, string?: true, const?: false, const_ptr?: false, array_dims: ['', '2', '3'] },
{ type: 'int**', name: 'thing4', ptr?: true, string?: false, const?: false, const_ptr?: false, array_dims: ['4'] },
{ type: 'u8*', name: 'thing5', ptr?: true, string?: false, const?: false, const_ptr?: false, array_dims: ['((u8)((5 + 5*2)/3))'] }
]
expected = [{:var_arg=>nil,
:return=>{ :type => "void",
@@ -1430,8 +1428,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:modifier=>"",
:contains_ptr? => true,
:args => expected_args,
:args_string => 'CUSTOM_TYPE* thing1, int* thing2, ' \
'char* thing3, int** thing4, u8* thing5',
:args_string => 'CUSTOM_TYPE thing1[], int thing2[], char thing3[][2][3], int* thing4[4], u8 thing5[((u8)((5 + 5*2)/3))]',
:args_call => 'thing1, thing2, thing3, thing4, thing5' }]
result = @parser.parse("module", source)
assert_equal(expected, result[:functions])
@@ -1454,9 +1451,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"unsigned CUSTOM_TYPE", :name=>"abc", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned", :name=>"xyz", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"CUSTOM_TYPE1 CUSTOM_TYPE2", :name=>"pdq", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"unsigned CUSTOM_TYPE", :name=>"abc", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"unsigned", :name=>"xyz", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"CUSTOM_TYPE1 CUSTOM_TYPE2", :name=>"pdq", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"unsigned CUSTOM_TYPE abc, unsigned xyz, CUSTOM_TYPE1 CUSTOM_TYPE2 pdq",
:args_call=>"abc, xyz, pdq" }]
@@ -1481,7 +1478,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 func_ptr",
:args_call=>"func_ptr" }]
@@ -1508,7 +1505,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 func_ptr",
:args_call=>"func_ptr" }]
@@ -1535,7 +1532,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 func_ptr",
:args_call=>"func_ptr" }]
@@ -1562,7 +1559,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 func_ptr",
:args_call=>"func_ptr" }]
@@ -1589,7 +1586,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => true, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 const func_ptr",
:args_call=>"func_ptr" }]
@@ -1604,7 +1601,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
# expected = [{ :var_arg=>nil,
# :return=>{ :type => "void",
# :name => 'cmock_to_return',
# :ptr? => false,
# :ptr? => false, :string? => false,
# :const? => false,
# :const_ptr? => false,
# :str => "void cmock_to_return",
@@ -1616,7 +1613,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
# :class=>nil,
# :modifier=>"",
# :contains_ptr? => false,
# :args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
# :args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
# ],
# :args_string=>"cmock_module_func_ptr1 func_ptr",
# :args_call=>"func_ptr" }]
@@ -1643,8 +1640,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr1", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"cmock_module_func_ptr2", :name=>"func_ptr2", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr1", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"cmock_module_func_ptr2", :name=>"func_ptr2", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 func_ptr1, cmock_module_func_ptr2 func_ptr2",
:args_call=>"func_ptr1, func_ptr2" }]
@@ -1671,9 +1668,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"uint16_t", :name=>"num1", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"uint16_t", :name=>"num2", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"cmock_module_func_ptr1", :name=>"func_ptr1", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"uint16_t", :name=>"num1", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"uint16_t", :name=>"num2", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"cmock_module_func_ptr1", :name=>"func_ptr1", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"uint16_t num1, uint16_t num2, cmock_module_func_ptr1 func_ptr1",
:args_call=>"num1, num2, func_ptr1" }]
@@ -1700,7 +1697,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"cmock_arg1", :ptr? => false, :const? => true, :const_ptr? => false}
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"cmock_arg1", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false}
],
:args_string=>"cmock_module_func_ptr1 const cmock_arg1",
:args_call=>"cmock_arg1" }]
@@ -1727,7 +1724,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"char", :name=>"op_code", :ptr? => false, :const? => true, :const_ptr? => false}
:args=>[ {:type=>"char", :name=>"op_code", :ptr? => false, :string? => false, :const? => true, :const_ptr? => false}
],
:args_string=>"const char op_code",
:args_call=>"op_code" }]
@@ -1806,8 +1803,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"double*", :name=>"foo", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"THING*", :name=>"bar", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"double*", :name=>"foo", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"THING*", :name=>"bar", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"double* foo, THING* bar",
:args_call=>"foo, bar" }]
@@ -1834,11 +1831,11 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"SQLITE_API",
:contains_ptr? => true,
:args=>[ {:type=>"sqlite3_stmt*", :name=>"cmock_arg2", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"cmock_arg3", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"const char*", :name=>"cmock_arg4", :ptr? => false, :const? => true, :const_ptr? => false},
{:type=>"int", :name=>"n", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"cmock_module_func_ptr1", :name=>"cmock_arg1", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"sqlite3_stmt*", :name=>"cmock_arg2", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"cmock_arg3", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"const char*", :name=>"cmock_arg4", :ptr? => false, :string? => true, :const? => true, :const_ptr? => false},
{:type=>"int", :name=>"n", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"cmock_module_func_ptr1", :name=>"cmock_arg1", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"sqlite3_stmt* cmock_arg2, int cmock_arg3, const char* cmock_arg4, int n, cmock_module_func_ptr1 cmock_arg1",
:args_call=>"cmock_arg2, cmock_arg3, cmock_arg4, n, cmock_arg1" }]
@@ -1865,8 +1862,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"Scully", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Mulder", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Scully", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Mulder", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Scully, int Mulder",
:args_call=>"Scully, Mulder"
@@ -1891,7 +1888,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"void*", :name=>"stuff", :ptr? => true, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"void*", :name=>"stuff", :ptr? => true, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"void* stuff",
:args_call=>"stuff"
@@ -1916,8 +1913,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"Lenny", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Squiggy", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Lenny", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Squiggy", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Lenny, int Squiggy",
:args_call=>"Lenny, Squiggy"
@@ -1942,8 +1939,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"Cliff", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Claire", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Cliff", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Claire", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Cliff, int Claire",
:args_call=>"Cliff, Claire"
@@ -1981,7 +1978,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(@parser.divine_ptr(entry[0]), entry[1])
assert_equal(@parser.divine_const(entry[0]), entry[2])
assert_equal(@parser.divine_ptr_and_const(entry[0]),
{ ptr?: entry[1], const?: entry[2], const_ptr?: entry[3] })
{ ptr?: entry[1], string?: false, const?: entry[2], const_ptr?: entry[3] })
end
end
@@ -2348,8 +2345,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:class=>nil,
:modifier=>"",
:contains_ptr? => false,
:args=>[ {:type=>"int", :name=>"Lenny", :ptr? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Squiggy", :ptr? => false, :const? => false, :const_ptr? => false}
:args=>[ {:type=>"int", :name=>"Lenny", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false},
{:type=>"int", :name=>"Squiggy", :ptr? => false, :string? => false, :const? => false, :const_ptr? => false}
],
:args_string=>"int Lenny, int Squiggy",
:args_call=>"Lenny, Squiggy"
@@ -2592,7 +2589,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:var_arg => nil,
:args_string => "int a",
:args => [
{ :ptr? => false,
{ :ptr? => false, :string? => false,
:const? => false,
:const_ptr? => false,
:name => "a",
@@ -2615,7 +2612,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:var_arg => nil,
:args_string => "int* a",
:args => [
{ :ptr? => true,
{ :ptr? => true, :string? => false,
:const? => false,
:const_ptr? => false,
:name => "a",
@@ -2664,7 +2661,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:var_arg => nil,
:args_string => "int a",
:args => [
{ :ptr? => false,
{ :ptr? => false, :string? => false,
:const? => false,
:const_ptr? => false,
:name => "a",
@@ -2687,7 +2684,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:var_arg => nil,
:args_string => "int* a",
:args => [
{ :ptr? => true,
{ :ptr? => true, :string? => false,
:const? => false,
:const_ptr? => false,
:name => "a",
@@ -2882,5 +2879,128 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, @parser.transform_inline_functions(source))
end
it "pairs size arg with adjacent pointer when no name affinity exists" do
source = "void process(int *data, int size)"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
data_arg = args.find { |a| a[:name] == 'data' }
size_arg = args.find { |a| a[:name] == 'size' }
assert_equal(:after, data_arg[:array_size_order], "data should be paired with size (after)")
assert_equal(true, size_arg[:array_size?], "size should be marked as array_size?")
end
it "pairs size arg with the pointer whose name it matches, even when a different pointer is adjacent" do
# buf_size is adjacent to status, but 'buf' root matches 'buf' exactly
source = "void store(int *status, int buf_size, int *buf)"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
status_arg = args.find { |a| a[:name] == 'status' }
buf_size_arg = args.find { |a| a[:name] == 'buf_size' }
buf_arg = args.find { |a| a[:name] == 'buf' }
assert_nil(status_arg[:array_size_order], "status should NOT be paired")
assert_equal(:before, buf_arg[:array_size_order], "buf should be paired with size (before)")
assert_equal(true, buf_size_arg[:array_size?], "buf_size should be marked as array_size?")
end
it "pairs size arg with pointer that comes after it when name affinity is stronger than adjacency" do
# buff_size is adjacent to bytes_to_read, but 'buff' root is a prefix of 'buffer'
source = "void read_interface(size_t *bytes_to_read, size_t buff_size, char **buffer)"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
bytes_arg = args.find { |a| a[:name] == 'bytes_to_read' }
buff_size_arg = args.find { |a| a[:name] == 'buff_size' }
buffer_arg = args.find { |a| a[:name] == 'buffer' }
assert_nil(bytes_arg[:array_size_order], "bytes_to_read should NOT be paired")
assert_equal(:before, buffer_arg[:array_size_order], "buffer should be paired with size (before)")
assert_equal(true, buff_size_arg[:array_size?], "buff_size should be marked as array_size?")
end
it "pairs multiple size args each with their best-matched pointer" do
source = "void copy(int *dst, int dst_len, int *src, int src_len)"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
dst_arg = args.find { |a| a[:name] == 'dst' }
dst_len_arg = args.find { |a| a[:name] == 'dst_len' }
src_arg = args.find { |a| a[:name] == 'src' }
src_len_arg = args.find { |a| a[:name] == 'src_len' }
assert_equal(:after, dst_arg[:array_size_order], "dst should be paired with size (after)")
assert_equal(true, dst_len_arg[:array_size?], "dst_len should be marked as array_size?")
assert_equal(:after, src_arg[:array_size_order], "src should be paired with size (after)")
assert_equal(true, src_len_arg[:array_size?], "src_len should be marked as array_size?")
end
it "pairs size arg with adjacent array when no name affinity exists" do
source = "void process(int data[], int size)"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
data_arg = args.find { |a| a[:name] == 'data' }
size_arg = args.find { |a| a[:name] == 'size' }
assert_equal(:after, data_arg[:array_size_order], "data should be paired with size (after)")
assert_equal(true, size_arg[:array_size?], "size should be marked as array_size?")
end
it "pairs size arg with the array whose name it matches, even when a different pointer is adjacent" do
# buf_size is adjacent to status, but 'buf' root matches 'buf' exactly
source = "void store(int status[], int buf_size, int buf[])"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
status_arg = args.find { |a| a[:name] == 'status' }
buf_size_arg = args.find { |a| a[:name] == 'buf_size' }
buf_arg = args.find { |a| a[:name] == 'buf' }
assert_nil(status_arg[:array_size_order], "status should NOT be paired")
assert_equal(:before, buf_arg[:array_size_order], "buf should be paired with size (before)")
assert_equal(true, buf_size_arg[:array_size?], "buf_size should be marked as array_size?")
end
it "pairs size arg with array that comes after it when name affinity is stronger than adjacency" do
# buff_size is adjacent to bytes_to_read, but 'buff' root is a prefix of 'buffer'
source = "void read_interface(size_t bytes_to_read[], size_t buff_size, char *buffer[])"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
bytes_arg = args.find { |a| a[:name] == 'bytes_to_read' }
buff_size_arg = args.find { |a| a[:name] == 'buff_size' }
buffer_arg = args.find { |a| a[:name] == 'buffer' }
assert_nil(bytes_arg[:array_size_order], "bytes_to_read should NOT be paired")
assert_equal(:before, buffer_arg[:array_size_order], "buffer should be paired with size (before)")
assert_equal(true, buff_size_arg[:array_size?], "buff_size should be marked as array_size?")
end
it "pairs multiple size args each with their best-matched array" do
source = "void copy(int dst[], int dst_len, int src[], int src_len)"
result = @parser.parse("module", source)
args = result[:functions].first[:args]
dst_arg = args.find { |a| a[:name] == 'dst' }
dst_len_arg = args.find { |a| a[:name] == 'dst_len' }
src_arg = args.find { |a| a[:name] == 'src' }
src_len_arg = args.find { |a| a[:name] == 'src_len' }
assert_equal(:after, dst_arg[:array_size_order], "dst should be paired with size (after)")
assert_equal(true, dst_len_arg[:array_size?], "dst_len should be marked as array_size?")
assert_equal(:after, src_arg[:array_size_order], "src should be paired with size (after)")
assert_equal(true, src_len_arg[:array_size?], "src_len should be marked as array_size?")
end
end