28 Commits

Author SHA1 Message Date
Mark VanderVoord d482f56066 Protect against more function-looking macros (Fixes#502) 2026-06-19 15:58:08 -04:00
Mark VanderVoord 1ef72ca854 Protect against function-looking structs (Fixes #513) 2026-06-19 15:10:14 -04:00
Mark VanderVoord 85058d1407 Fixed skeleton path handling, etc (#488) 2026-06-19 14:42:09 -04:00
Mark VanderVoord 411f6852f9 Add documentation to avoid problems like #518 and #521. 2026-06-19 13:50:21 -04:00
Mark VanderVoord 383c43246c Merge pull request #531 from ThrowTheSwitch/feature/better_arrays
Feature/better arrays
2026-06-19 10:53:54 -04:00
Mark VanderVoord 990954c548 Made the last two features actually cooperate. 2026-06-18 20:25:31 -04:00
Mark VanderVoord de4e53cd7b The array plugin can now compare strings as byte arrays, even though they are treated like strings everywhere else. (Fixes #262 and #177) 2026-06-18 19:56:22 -04:00
Mark VanderVoord 84705b2e84 Rename some misnamed tests. 2026-06-18 19:41:35 -04:00
Mark VanderVoord 336a52bf57 Verify #463 isn't currently an error, and won't return. 2026-06-18 18:49:03 -04:00
Mark VanderVoord aaf9559a57 Finish better identification of array pointer/len pairs.
Add fallback _ExpectWithArrayExtended when this happens for flexibility.
Fixes issue #520
2026-06-18 16:34:24 -04:00
Mark VanderVoord 8c1f88fb82 Improve the automatic detection of argument pairs related to arrays/pointers and lengths 2026-06-18 12:50:29 -04:00
Mark VanderVoord a0207f3800 void* handling within the array plugin defaults to bytes. 2026-06-16 21:41:07 -04:00
Mark VanderVoord bad95c5f54 Handle void pointers as pointer comparisons unless the array plugin gives more information. (Fixes #400) 2026-06-16 21:34:32 -04:00
Mark VanderVoord f756eeaf55 Fix handling of array of pointers (Fixes issue #450) 2026-06-16 18:14:51 -04:00
Mark VanderVoord 82ef7e53cf Fix handling of variable-length-arrays (fixed issue #479) 2026-06-16 17:39:40 -04:00
Mark VanderVoord af610445b3 flesh out tests for arrays and pointers and separate. 2026-06-16 17:02:56 -04:00
Mark VanderVoord a0de150635 Improve the array handling by making the public interfaces still use arrays. 2026-06-16 16:18:22 -04:00
Mark VanderVoord 3d4ddfdc4c Fix const pointer handling in return values 2026-06-16 15:37:14 -04:00
Mark VanderVoord 29ef16e54b Tidy handling of system tests to depend more on the defines involved then separate tracking.
Remove yml files that are no longer needed.
2026-06-16 15:20:21 -04:00
Mark VanderVoord 725e2d90ef cleanup the way defines are handled in tests. 2026-05-29 16:28:57 -04:00
Mark VanderVoord c06bbe791c run examples fully and pass optional yaml file to them.
begin to automatically reject tests based on criteria.
2026-05-29 16:09:22 -04:00
Mark VanderVoord c40a6e08c6 Refactored self-tests to use ceedling-formatted tools files 2026-05-28 16:48:53 -04:00
Mark VanderVoord 5f0296eb0a Fix naming to avoid that extra colon for parsing. 2026-05-22 14:41:22 -04:00
Mark VanderVoord 165de30b7d Bump to latest Unity 2026-05-22 14:17:29 -04:00
Mark VanderVoord 04b5b21ffd Give system tests more verbose output during testing. 2026-05-22 13:35:09 -04:00
Mark VanderVoord f20c59b029 Make the output more verbose for self-tests. 2026-05-22 11:41:00 -04:00
Mark VanderVoord 6a9e3afe14 update the create_makefile script to be independent and not require pointless middleware scripts. 2026-05-18 17:41:21 -04:00
Mark VanderVoord 13da43dc95 Merge pull request #530 from ThrowTheSwitch/refactor/inherit_targets
Refactor/inherit targets
2026-05-18 16:42:41 -04:00
45 changed files with 2627 additions and 776 deletions
+63 -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:
-------
@@ -357,6 +378,23 @@ generate a skeleton instead:
ruby cmock.rb --skeleton ../create/c/for/this.h
```
Using CMock Without Ceedling
----------------------------
CMock depends on the Unity test framework, but it does not *require* Ceedling. You can use the
generated mocks directly with the Unity test framework in whatever build system you prefer. One
important thing to remember when doing this is that you will need to call the `_Init` function
for each of your mocks BEFORE the tests and the `_Verify` function for each mock AFTER each test.
This allows CMock to perform all of its internal accounting. If you're running into problems where
some errors aren't getting caught, this is likely what you are missing.
There are many ways to accomplish this. Any is valid:
- These actions can be performed as part of `setUp` and `tearDown` in each test file
- You can hand-write your own RUN_TEST macro. If so, protect `_Verify` calls in `TEST_PROTECT`
- You can use Unity's test runner generator and it will automatically take care of this for you.
- You can use Ceedling and it will automatically take care of this for you.
Config Options:
---------------
@@ -722,11 +760,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 +775,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
+1 -1
View File
@@ -14,7 +14,7 @@ all: setup test ${BUILD_DIR}/main run
setup:
mkdir -p ${BUILD_DIR}
mkdir -p ${OBJ}
ruby ../../scripts/create_makefile.rb --silent
ruby ../../scripts/create_makefile.rb
clean:
rm -rf ${BUILD_DIR}
+1 -1
View File
@@ -6,7 +6,7 @@
========================================================================= */
#include "unity.h"
#include "mock_foo.h"
#include "Mockfoo.h"
void setUp(void)
{
+1 -1
View File
@@ -28,7 +28,7 @@
:executable: '.exe'
:defines:
:common:
:test:
- __monitor
- UNITY_SUPPORT_64
+37 -12
View File
@@ -39,24 +39,38 @@ module RakefileHelpers
$cfg_file = config_file
$proj = load_yaml(File.read('./project.yml'))
unity_target = "../../vendor/unity/test/targets/#{$cfg_file}"
unity_targets_dir = '../../vendor/unity/test/targets'
cmock_targets_dir = '../../test/targets'
config_basename = File.basename(config_file)
path_specified = File.dirname(config_file) != '.'
# Resolve the target file location:
# - path specified → use only that location
# - no path → check current directory first, then vendor unity targets
unity_target = if path_specified
config_file
elsif File.exist?("./#{config_file}")
"./#{config_file}"
else
"#{unity_targets_dir}/#{config_file}"
end
if File.exist?(unity_target)
puts "Loading Unity target: #{unity_target}"
$unity_cfg = load_yaml(File.read(unity_target))
cmock_file = cmock_overlay || find_cmock_target(cmock_targets_dir, $cfg_file)
cmock_file = cmock_overlay || find_cmock_target(cmock_targets_dir, config_basename)
if cmock_file
puts "Loading CMock overlay: #{cmock_targets_dir}/#{cmock_file}"
$cmock_cfg = load_yaml(File.read("#{cmock_targets_dir}/#{cmock_file}"))
else
puts "No CMock overlay found for #{$cfg_file}"
puts "No CMock overlay found for #{config_file}"
$cmock_cfg = {}
end
else
puts "Loading CMock-only target: #{cmock_targets_dir}/#{$cfg_file}"
$unity_cfg = load_yaml(File.read("#{cmock_targets_dir}/#{$cfg_file}"))
# CMock-only target (no Unity equivalent); it uses Unity format directly
puts "Loading CMock-only target: #{cmock_targets_dir}/#{config_basename}"
$unity_cfg = load_yaml(File.read("#{cmock_targets_dir}/#{config_basename}"))
$cmock_cfg = {}
end
@@ -118,7 +132,7 @@ module RakefileHelpers
# All defines: project common + Unity target + CMock overlay + any extras
def all_defines(extra = [])
(($proj[:defines][:common] || []) +
(($proj[:defines][:test] || []) +
($unity_cfg[:defines][:test] || []) +
(($cmock_cfg[:defines] || {})[:test] || []) +
extra).uniq
@@ -133,12 +147,23 @@ module RakefileHelpers
end
end
# Resolve Unity's argument template tokens into a flat argument string.
# Resolve argument template tokens into a flat argument string.
# Supports Ceedling-style positional tokens and legacy Unity COLLECTION_* tokens.
# ${5} → expands to one arg per include path (toolchain paths + project paths combined)
# ${6} → expands to one arg per define
# ${1} → input file(s)
# ${2} → output file
def build_argument_list(raw_args, toolchain_paths, project_paths, defines, input, output)
result = []
raw_args.each do |arg|
if arg.is_a?(Array)
result << arg.join
elsif arg.include?('${5}')
(toolchain_paths + project_paths).each do |p|
result << arg.gsub('${5}', p.is_a?(Array) ? p.join : p.to_s)
end
elsif arg.include?('${6}')
defines.each { |d| result << arg.gsub('${6}', d) }
elsif arg.include?('COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE')
toolchain_paths.each { |p| result << "-I\"#{p.is_a?(Array) ? p.join : p}\"" }
elsif arg.include?('COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR')
@@ -154,8 +179,8 @@ module RakefileHelpers
def compile(file, extra_defines = [])
tool = $unity_cfg[:tools][:test_compiler]
ext = $unity_cfg[:extension][:object]
build_root = $proj[:project][:build_root]
ext = $unity_cfg[:extension][:object] || '.o'
build_root = $proj[:project][:build_root] || 'build/'
obj_file = build_root + File.basename(file, C_EXTENSION) + ext
cmd_str = "#{tackit(tool[:executable])} #{
@@ -170,8 +195,8 @@ module RakefileHelpers
def link_it(exe_name, obj_list)
tool = $unity_cfg[:tools][:test_linker]
ext = $unity_cfg[:extension][:executable]
build_root = $proj[:project][:build_root]
ext = $unity_cfg[:extension][:executable] || ''
build_root = $proj[:project][:build_root] || 'build/'
input_files = obj_list.uniq.map { |obj| build_root + obj }.join(' ')
output_file = build_root + exe_name + ext
@@ -263,7 +288,7 @@ module RakefileHelpers
# Execute unit test and generate results file
simulator = build_simulator_fields
build_root = $proj[:project][:build_root]
executable = build_root + test_base + $unity_cfg[:extension][:executable]
executable = build_root + test_base + ($unity_cfg[:extension][:executable] || '')
cmd_str = if simulator.nil?
executable
else
+37
View File
@@ -16,6 +16,17 @@ class CMockFileWriter
require 'fileutils'
FileUtils.mkdir_p "#{@config.mock_path}/" unless Dir.exist?("#{@config.mock_path}/")
FileUtils.mkdir_p "#{@config.mock_path}/#{"#{subdir}/" if subdir}" if subdir && !Dir.exist?("#{@config.mock_path}/#{"#{subdir}/" if subdir}")
rescue SystemCallError => e
raise "Unable to create mock output directory: #{e.message}. Check :mock_path ('#{@config.mock_path}') configuration."
end
def create_skeleton_subdir(subdir)
require 'fileutils'
base = effective_skeleton_path
FileUtils.mkdir_p base
FileUtils.mkdir_p "#{base}/#{subdir}" if subdir
rescue SystemCallError => e
raise "Unable to create skeleton output directory: #{e.message}. Check :skeleton_path ('#{base}') configuration."
end
def create_file(filename, subdir)
@@ -27,6 +38,27 @@ class CMockFileWriter
yield(file, filename)
end
update_file(full_file_name_done, full_file_name_temp)
rescue SystemCallError => e
raise "Unable to write mock file '#{full_file_name_done}': #{e.message}. Check :mock_path ('#{@config.mock_path}') and :subdir ('#{subdir}') configuration."
end
def create_skeleton_file(filename, subdir)
raise "Where's the block of data to create?" unless block_given?
base = effective_skeleton_path
full_file_name_temp = "#{base}/#{"#{subdir}/" if subdir}#{filename}.new"
full_file_name_done = "#{base}/#{"#{subdir}/" if subdir}#{filename}"
File.open(full_file_name_temp, 'w') do |file|
yield(file, filename)
end
update_file(full_file_name_done, full_file_name_temp)
rescue SystemCallError => e
raise "Unable to write skeleton file '#{full_file_name_done}': #{e.message}. Check :skeleton_path ('#{base}') and :subdir ('#{subdir}') configuration."
end
def skeleton_file_path(filename, subdir)
base = effective_skeleton_path
"#{base}/#{"#{subdir}/" if subdir}#{filename}"
end
def append_file(filename, subdir)
@@ -40,6 +72,11 @@ class CMockFileWriter
private ###################################
def effective_skeleton_path
path = @config.skeleton_path
path.nil? || path.empty? ? @config.mock_path : path
end
def update_file(dest, src)
require 'fileutils'
FileUtils.rm(dest, :force => true)
+40 -26
View File
@@ -85,6 +85,7 @@ class CMockGenerator
:skeleton => true
}
@file_writer.create_skeleton_subdir(@subdir)
create_skeleton_source_file(mock_project)
end
@@ -133,9 +134,9 @@ class CMockGenerator
end
def create_skeleton_source_file(mock_project)
filename = "#{@config.mock_path}/#{"#{@subdir}/" if @subdir}#{mock_project[:module_name]}.c"
filename = @file_writer.skeleton_file_path("#{mock_project[:module_name]}.c", @subdir)
existing = File.exist?(filename) ? File.read(filename) : ''
@file_writer.create_file("#{mock_project[:module_name]}.c", @subdir) do |file, fullname|
@file_writer.create_skeleton_file("#{mock_project[:module_name]}.c", @subdir) do |file, fullname|
blank_project = mock_project.clone
blank_project[:parsed_stuff] = { :functions => [] }
if existing.empty?
@@ -210,24 +211,30 @@ class CMockGenerator
def create_source_header_section(file, filename, mock_project)
header_file = (mock_project[:folder] || '') + filename.sub(/.*\K\.c/, mock_project[:module_ext])
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty?
file << "#include <string.h>\n"
file << "#include <stdlib.h>\n"
unless @exclude_setjmp_h
file << "#include <setjmp.h>\n"
end
file << "#include \"cmock.h\"\n"
@includes_c_pre_header.each { |inc| file << "#include #{inc}\n" }
file << "#include \"#{header_file}\"\n"
@includes_c_post_header.each { |inc| file << "#include #{inc}\n" }
file << "\n"
strs = []
mock_project[:parsed_stuff][:functions].each do |func|
strs << func[:name]
func[:args].each { |arg| strs << arg[:name] }
end
strs.uniq.sort.each do |str|
file << "static const char* CMockString_#{str} = \"#{str}\";\n"
if mock_project[:skeleton]
@includes_c_pre_header.each { |inc| file << "#include #{inc}\n" }
file << "#include \"#{header_file}\"\n"
@includes_c_post_header.each { |inc| file << "#include #{inc}\n" }
else
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty?
file << "#include <string.h>\n"
file << "#include <stdlib.h>\n"
unless @exclude_setjmp_h
file << "#include <setjmp.h>\n"
end
file << "#include \"cmock.h\"\n"
@includes_c_pre_header.each { |inc| file << "#include #{inc}\n" }
file << "#include \"#{header_file}\"\n"
@includes_c_post_header.each { |inc| file << "#include #{inc}\n" }
file << "\n"
strs = []
mock_project[:parsed_stuff][:functions].each do |func|
strs << func[:name]
func[:args].each { |arg| strs << arg[:name] }
end
strs.uniq.sort.each do |str|
file << "static const char* CMockString_#{str} = \"#{str}\";\n"
end
end
file << "\n"
end
@@ -296,11 +303,20 @@ class CMockGenerator
file << "}\n\n"
end
def function_return_type(function)
# When const_ptr? is true, the "const" in :modifier belongs after the asterisk (e.g. "int* const"),
# not as a prefix (which would incorrectly produce "const int*").
ret = if function[:return][:const_ptr?]
"#{function[:return][:type]} const"
else
(function[:modifier].empty? ? '' : "#{function[:modifier]} ") + function[:return][:type]
end
ret + (function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
end
def create_mock_implementation(file, function)
# prepare return value and arguments
function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") +
(function[:return][:type]) +
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
function_mod_and_rettype = function_return_type(function)
args_string = function[:args_string]
args_string += ", #{function[:var_arg]}" unless function[:var_arg].nil?
@@ -359,9 +375,7 @@ class CMockGenerator
def create_function_skeleton(file, function, existing)
# prepare return value and arguments
function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") +
(function[:return][:type]) +
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
function_mod_and_rettype = function_return_type(function)
args_string = function[:args_string]
args_string += ", #{function[:var_arg]}" unless function[:var_arg].nil?
+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
+121 -13
View File
@@ -253,12 +253,23 @@ class CMockHeaderParser
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
source.gsub!(/^[\w\s]*struct[^;{}()]+;/m, '') # remove forward declared structs
source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^}]+\}[\w\s*,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s()]*\{[^}]+\}[\w\s*,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
# remove problem keywords
source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2')
source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp
source.gsub!(/\s*=\s*['"a-zA-Z0-9_.]+\s*/, '') # remove default value statements from argument lists
# strip macro decorator patterns that cannot be C function prototypes.
# must run after default-value removal so "= \"str\"" doesn't trigger string detection.
# neutralize string literals (never valid in C prototype args), eliminating any parentheses
# inside string content (e.g. "msg()") that would fool subsequent brace-matching.
source.gsub!(/"[^"]*"/, '""')
# strip WORD("") -- any call with a string literal arg cannot be a C function prototype
source.gsub!(/\b\w+\s*\([^)]*""[^)]*\)/, '')
# strip WORD(N...) -- any call whose first arg starts with a digit cannot be a C prototype
source.gsub!(/\b\w+\s*\(\s*\d[^)]*\)/, '')
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
@@ -408,7 +419,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 +447,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 +467,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 +544,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
@@ -567,9 +647,11 @@ class CMockHeaderParser
rettype = parsed[:type]
rettype = 'void' if @local_as_void.include?(rettype.strip)
rettype = 'void' if rettype.empty? && !(@standards + @local_as_void).include?(parsed[:name]) # all return-type tokens were stripped (e.g. bare decorator macros)
retstr = parsed[:const_ptr?] ? "#{rettype} const" : rettype
decl[:return] = { :type => rettype,
:name => 'cmock_to_return',
:str => "#{rettype} cmock_to_return",
:str => "#{retstr} cmock_to_return",
:void? => (rettype == 'void'),
:ptr? => parsed[:ptr?] || false,
:const? => parsed[:const?] || false,
@@ -590,12 +672,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(/\*$/, '')
+6 -4
View File
@@ -24,10 +24,12 @@ CMOCK_OBJ = File.join(OBJ_DIR, 'cmock.o')
RUNNERS_DIR = File.join(TEST_BUILD_DIR, 'runners')
MOCKS_DIR = File.join(TEST_BUILD_DIR, 'mocks')
TEST_BIN_DIR = TEST_BUILD_DIR
MOCK_PREFIX = ENV.fetch('TEST_MOCK_PREFIX', 'mock_')
MOCK_PREFIX = ENV.fetch('TEST_MOCK_PREFIX', 'Mock')
MOCK_SUFFIX = ENV.fetch('TEST_MOCK_SUFFIX', '')
TEST_MAKEFILE = ENV.fetch('TEST_MAKEFILE', File.join(TEST_BUILD_DIR, 'MakefileTestSupport'))
MOCK_MATCHER = /#{MOCK_PREFIX}[A-Za-z_][A-Za-z0-9_\-.]+#{MOCK_SUFFIX}/
OPTION_FILE = ENV.fetch('TEST_OPTION_YML_FILE', '')
OPTION_FILE_FLAG = OPTION_FILE.empty? ? '' : "-o#{OPTION_FILE}"
[TEST_BUILD_DIR, OBJ_DIR, RUNNERS_DIR, MOCKS_DIR, TEST_BIN_DIR].each do |dir|
FileUtils.mkdir_p dir
@@ -126,7 +128,7 @@ File.open(TEST_MAKEFILE, 'w') do |mkfile|
# Create runners
mkfile.puts "#{runner_source}: #{test}"
mkfile.puts "\t@UNITY_DIR=${UNITY_DIR} ruby ${CMOCK_DIR}/scripts/create_runner.rb #{test} #{runner_source}"
mkfile.puts "\truby #{UNITY_DIR}/auto/generate_test_runner.rb #{OPTION_FILE} #{test} #{runner_source}"
mkfile.puts ''
# Build runner
@@ -189,7 +191,7 @@ File.open(TEST_MAKEFILE, 'w') do |mkfile|
mock_obj = File.join(MOCKS_DIR, "#{mock_name}.o")
mkfile.puts "#{mock_src}: #{hdr}"
mkfile.puts "\t@CMOCK_DIR=${CMOCK_DIR} ruby ${CMOCK_DIR}/scripts/create_mock.rb #{hdr}"
mkfile.puts "\truby #{CMOCK_DIR}/lib/cmock.rb #{hdr} --mock_path=#{MOCKS_DIR} #{OPTION_FILE_FLAG}"
mkfile.puts ''
mkfile.puts "#{mock_obj}: #{mock_src} #{mock_header}"
@@ -199,7 +201,7 @@ File.open(TEST_MAKEFILE, 'w') do |mkfile|
# Create test summary task
mkfile.puts 'test_summary:'
mkfile.puts "\t@UNITY_DIR=${UNITY_DIR} ruby ${CMOCK_DIR}/scripts/test_summary.rb #{suppress_error ? '--silent' : ''}"
mkfile.puts "\truby #{UNITY_DIR}/auto/unity_test_summary.rb #{suppress_error ? '--silent' : ''} #{TEST_BUILD_DIR}"
mkfile.puts ''
mkfile.puts '.PHONY: test_summary'
mkfile.puts ''
-15
View File
@@ -1,15 +0,0 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
require "#{ENV['CMOCK_DIR']}/lib/cmock"
raise 'Header file to mock must be specified!' unless ARGV.length >= 1
mock_out = ENV.fetch('MOCK_OUT', './build/test/mocks')
mock_prefix = ENV.fetch('MOCK_PREFIX', 'mock_')
cmock = CMock.new(:plugins => %i[ignore return_thru_ptr], :mock_prefix => mock_prefix, :mock_path => mock_out)
cmock.setup_mocks(ARGV[0])
-25
View File
@@ -1,25 +0,0 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
if $0 == __FILE__
# make sure there is at least one parameter left (the input file)
if ARGV.length < 2
puts ["\nusage: ruby #{__FILE__} input_test_file (output)",
'',
' input_test_file - this is the C file you want to create a runner for',
' output - this is the name of the runner file to generate',
' defaults to (input_test_file)_Runner'].join("\n")
exit 1
end
require "#{ENV['UNITY_DIR']}/auto/generate_test_runner"
test = ARGV[0]
runner = ARGV[1]
UnityTestRunnerGenerator.new.run(test, runner)
end
-25
View File
@@ -1,25 +0,0 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
suppress_error = !ARGV.nil? && !ARGV.empty? && (ARGV[0].casecmp('--SILENT') == 0)
begin
require "#{ENV['UNITY_DIR']}/auto/unity_test_summary.rb"
build_dir = ENV.fetch('BUILD_DIR', './build')
test_build_dir = ENV.fetch('TEST_BUILD_DIR', File.join(build_dir, 'test'))
results = Dir["#{test_build_dir}/*.testresult"]
parser = UnityTestSummary.new
parser.targets = results
parser.run
puts parser.report
rescue StandardError => e
raise e unless suppress_error
end
exit(parser.failures) unless suppress_error
+119 -117
View File
@@ -22,14 +22,14 @@ const char* CMockStringMismatch = "Function called with unexpected argument v
/* private variables */
#ifdef CMOCK_MEM_DYNAMIC
static unsigned char* CMock_Guts_Buffer = NULL;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
static unsigned char* CMock_Guts_Buffer = NULL;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
#else
static long long CMock_Guts_Space[(CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE + sizeof(long long) - 1) / sizeof(long long)];
static unsigned char* CMock_Guts_Buffer = (unsigned char *)CMock_Guts_Space;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE;//sizeof(CMock_Guts_Space);
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
static long long CMock_Guts_Space[(CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE + sizeof(long long) - 1) / sizeof(long long)];
static unsigned char* CMock_Guts_Buffer = (unsigned char*)CMock_Guts_Space;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE;//sizeof(CMock_Guts_Space);
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
#endif
/*-------------------------------------------------------
@@ -37,41 +37,41 @@ static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
{
CMOCK_MEM_INDEX_TYPE index;
CMOCK_MEM_INDEX_TYPE index;
/* verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) */
if (size < 1)
{
return CMOCK_GUTS_NONE;
}
/* verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) */
if (size < 1)
{
return CMOCK_GUTS_NONE;
}
/* verify we have enough room */
size = size + CMOCK_MEM_INDEX_SIZE;
if (size & CMOCK_MEM_ALIGN_MASK)
{
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
}
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
{
/* verify we have enough room */
size = size + CMOCK_MEM_INDEX_SIZE;
if (size & CMOCK_MEM_ALIGN_MASK)
{
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
}
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
{
#ifndef CMOCK_MEM_DYNAMIC
return CMOCK_GUTS_NONE; /* nothing we can do; our static buffer is out of memory */
return CMOCK_GUTS_NONE; /* nothing we can do; our static buffer is out of memory */
#else
/* our dynamic buffer does not have enough room; request more via realloc() */
CMOCK_MEM_INDEX_TYPE new_buffersize = CMock_Guts_BufferSize + CMOCK_MEM_SIZE + size;
unsigned char* new_buffer = realloc(CMock_Guts_Buffer, (size_t)new_buffersize);
if (new_buffer == NULL)
return CMOCK_GUTS_NONE; /* realloc() failed; out of memory */
CMock_Guts_Buffer = new_buffer;
CMock_Guts_BufferSize = new_buffersize;
/* our dynamic buffer does not have enough room; request more via realloc() */
CMOCK_MEM_INDEX_TYPE new_buffersize = CMock_Guts_BufferSize + CMOCK_MEM_SIZE + size;
unsigned char* new_buffer = realloc(CMock_Guts_Buffer, (size_t)new_buffersize);
if (new_buffer == NULL)
return CMOCK_GUTS_NONE; /* realloc() failed; out of memory */
CMock_Guts_Buffer = new_buffer;
CMock_Guts_BufferSize = new_buffersize;
#endif
}
}
/* determine where we're putting this new block, and init its pointer to be the end of the line */
index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE;
*(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE;
CMock_Guts_FreePtr += size;
/* determine where we're putting this new block, and init its pointer to be the end of the line */
index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE;
*(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE;
CMock_Guts_FreePtr += size;
return index;
return index;
}
/*-------------------------------------------------------
@@ -79,47 +79,49 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index)
{
CMOCK_MEM_INDEX_TYPE index;
void* root;
void* obj;
void* next;
CMOCK_MEM_INDEX_TYPE index;
void* root;
void* obj;
void* next;
if (root_index == CMOCK_GUTS_NONE)
{
/* if there is no root currently, we return this object as the root of the chain */
return obj_index;
}
else
{
/* reject illegal nodes */
if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr))
if (root_index == CMOCK_GUTS_NONE)
{
return CMOCK_GUTS_NONE;
/* if there is no root currently, we return this object as the root of the chain */
return obj_index;
}
if ((obj_index < CMOCK_MEM_ALIGN_SIZE) || (obj_index >= CMock_Guts_FreePtr))
else
{
return CMOCK_GUTS_NONE;
/* reject illegal nodes */
if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr))
{
return CMOCK_GUTS_NONE;
}
if ((obj_index < CMOCK_MEM_ALIGN_SIZE) || (obj_index >= CMock_Guts_FreePtr))
{
return CMOCK_GUTS_NONE;
}
root = (void*)(&CMock_Guts_Buffer[root_index]);
obj = (void*)(&CMock_Guts_Buffer[obj_index]);
/* find the end of the existing chain and add us */
next = root;
do
{
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
if (index >= CMock_Guts_FreePtr)
{
return CMOCK_GUTS_NONE;
}
if (index > 0)
{
next = (void*)(&CMock_Guts_Buffer[index]);
}
}
while (index > 0);
*(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE) = (CMOCK_MEM_INDEX_TYPE)((CMOCK_MEM_PTR_AS_INT)obj - (CMOCK_MEM_PTR_AS_INT)CMock_Guts_Buffer);
return root_index;
}
root = (void*)(&CMock_Guts_Buffer[root_index]);
obj = (void*)(&CMock_Guts_Buffer[obj_index]);
/* find the end of the existing chain and add us */
next = root;
do {
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
if (index >= CMock_Guts_FreePtr)
{
return CMOCK_GUTS_NONE;
}
if (index > 0)
{
next = (void*)(&CMock_Guts_Buffer[index]);
}
} while (index > 0);
*(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE) = (CMOCK_MEM_INDEX_TYPE)((CMOCK_MEM_PTR_AS_INT)obj - (CMOCK_MEM_PTR_AS_INT)CMock_Guts_Buffer);
return root_index;
}
}
/*-------------------------------------------------------
@@ -127,27 +129,27 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
{
CMOCK_MEM_INDEX_TYPE index;
void* previous_item;
CMOCK_MEM_INDEX_TYPE index;
void* previous_item;
/* There is nothing "next" if the pointer isn't from our buffer */
if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr))
{
return CMOCK_GUTS_NONE;
}
previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]);
/* There is nothing "next" if the pointer isn't from our buffer */
if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr))
{
return CMOCK_GUTS_NONE;
}
previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]);
/* if the pointer is good, then use it to look up the next index
* (we know the first element always goes in zero, so NEXT must always be > 1) */
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE);
if ((index > 1) && (index < CMock_Guts_FreePtr))
{
return index;
}
else
{
return CMOCK_GUTS_NONE;
}
/* if the pointer is good, then use it to look up the next index
* (we know the first element always goes in zero, so NEXT must always be > 1) */
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE);
if ((index > 1) && (index < CMock_Guts_FreePtr))
{
return index;
}
else
{
return CMOCK_GUTS_NONE;
}
}
/*-------------------------------------------------------
@@ -155,17 +157,17 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
{
CMOCK_MEM_INDEX_TYPE index = root_index;
CMOCK_MEM_INDEX_TYPE next_index;
CMOCK_MEM_INDEX_TYPE index = root_index;
CMOCK_MEM_INDEX_TYPE next_index;
for (next_index = root_index;
next_index != CMOCK_GUTS_NONE;
next_index = CMock_Guts_MemNext(index))
{
index = next_index;
}
for (next_index = root_index;
next_index != CMOCK_GUTS_NONE;
next_index = CMock_Guts_MemNext(index))
{
index = next_index;
}
return index;
return index;
}
/*-------------------------------------------------------
@@ -173,14 +175,14 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
*-------------------------------------------------------*/
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
{
if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr))
{
return (void*)(&CMock_Guts_Buffer[index]);
}
else
{
return NULL;
}
if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr))
{
return (void*)(&CMock_Guts_Buffer[index]);
}
else
{
return NULL;
}
}
/*-------------------------------------------------------
@@ -188,7 +190,7 @@ void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
{
return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE);
return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE);
}
/*-------------------------------------------------------
@@ -196,7 +198,7 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
{
return CMock_Guts_BufferSize - CMock_Guts_FreePtr;
return CMock_Guts_BufferSize - CMock_Guts_FreePtr;
}
/*-------------------------------------------------------
@@ -204,7 +206,7 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
{
return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE;
return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE;
}
/*-------------------------------------------------------
@@ -212,7 +214,7 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
*-------------------------------------------------------*/
void CMock_Guts_MemFreeAll(void)
{
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; /* skip the very beginning */
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; /* skip the very beginning */
}
/*-------------------------------------------------------
@@ -220,13 +222,13 @@ void CMock_Guts_MemFreeAll(void)
*-------------------------------------------------------*/
void CMock_Guts_MemFreeFinal(void)
{
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
#ifdef CMOCK_MEM_DYNAMIC
if (CMock_Guts_Buffer)
{
free(CMock_Guts_Buffer);
CMock_Guts_Buffer = NULL;
}
if (CMock_Guts_Buffer)
{
free(CMock_Guts_Buffer);
CMock_Guts_Buffer = NULL;
}
#endif
}
+6 -6
View File
@@ -12,21 +12,21 @@
#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 */
#ifndef CMOCK_MEM_INDEX_TYPE
#include <stddef.h>
#define CMOCK_MEM_INDEX_TYPE size_t
#include <stddef.h>
#define CMOCK_MEM_INDEX_TYPE size_t
#endif
#define CMOCK_GUTS_NONE (0)
#if defined __GNUC__
# define CMOCK_FUNCTION_ATTR(a) __attribute__((a))
#define CMOCK_FUNCTION_ATTR(a) __attribute__((a))
#else
# define CMOCK_FUNCTION_ATTR(a) /* ignore */
#define CMOCK_FUNCTION_ATTR(a) /* ignore */
#endif
/*-------------------------------------------------------
@@ -39,7 +39,7 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) CMOCK_FUNCTION_ATTR(pure);
void CMock_Guts_MemFreeAll(void);
+32 -32
View File
@@ -26,61 +26,61 @@ extern const char* CMockStringMismatch;
/* define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc
* when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total */
#ifdef CMOCK_MEM_STATIC
#undef CMOCK_MEM_DYNAMIC
#undef CMOCK_MEM_DYNAMIC
#endif
#ifdef CMOCK_MEM_DYNAMIC
#include <stdlib.h>
#include <stdlib.h>
#endif
/* this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type */
#ifndef CMOCK_MEM_PTR_AS_INT
#ifdef UNITY_POINTER_WIDTH
#ifdef UNITY_INT_WIDTH
#if UNITY_POINTER_WIDTH == UNITY_INT_WIDTH
#define CMOCK_MEM_PTR_AS_INT unsigned int
#endif
#endif
#endif
#ifdef UNITY_POINTER_WIDTH
#ifdef UNITY_INT_WIDTH
#if UNITY_POINTER_WIDTH == UNITY_INT_WIDTH
#define CMOCK_MEM_PTR_AS_INT unsigned int
#endif
#endif
#endif
#endif
#ifndef CMOCK_MEM_PTR_AS_INT
#ifdef UNITY_POINTER_WIDTH
#ifdef UNITY_LONG_WIDTH
#if UNITY_POINTER_WIDTH == UNITY_LONG_WIDTH
#define CMOCK_MEM_PTR_AS_INT unsigned long
#endif
#if UNITY_POINTER_WIDTH > UNITY_LONG_WIDTH
#define CMOCK_MEM_PTR_AS_INT unsigned long long
#endif
#endif
#endif
#ifdef UNITY_POINTER_WIDTH
#ifdef UNITY_LONG_WIDTH
#if UNITY_POINTER_WIDTH == UNITY_LONG_WIDTH
#define CMOCK_MEM_PTR_AS_INT unsigned long
#endif
#if UNITY_POINTER_WIDTH > UNITY_LONG_WIDTH
#define CMOCK_MEM_PTR_AS_INT unsigned long long
#endif
#endif
#endif
#endif
#ifndef CMOCK_MEM_PTR_AS_INT
#define CMOCK_MEM_PTR_AS_INT unsigned long
#define CMOCK_MEM_PTR_AS_INT unsigned long
#endif
/* 0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit */
#ifndef CMOCK_MEM_ALIGN
#ifdef UNITY_LONG_WIDTH
#if (UNITY_LONG_WIDTH == 16)
#define CMOCK_MEM_ALIGN (1)
#elif (UNITY_LONG_WIDTH == 32)
#define CMOCK_MEM_ALIGN (2)
#elif (UNITY_LONG_WIDTH == 64)
#define CMOCK_MEM_ALIGN (3)
#ifdef UNITY_LONG_WIDTH
#if (UNITY_LONG_WIDTH == 16)
#define CMOCK_MEM_ALIGN (1)
#elif (UNITY_LONG_WIDTH == 32)
#define CMOCK_MEM_ALIGN (2)
#elif (UNITY_LONG_WIDTH == 64)
#define CMOCK_MEM_ALIGN (3)
#else
#define CMOCK_MEM_ALIGN (2)
#endif
#else
#define CMOCK_MEM_ALIGN (2)
#define CMOCK_MEM_ALIGN (2)
#endif
#else
#define CMOCK_MEM_ALIGN (2)
#endif
#endif
/* amount of memory to allow cmock to use in its internal heap */
#ifndef CMOCK_MEM_SIZE
#define CMOCK_MEM_SIZE (32768)
#define CMOCK_MEM_SIZE (32768)
#endif
/* automatically calculated defs for easier reading */
+1 -1
View File
@@ -28,6 +28,6 @@
:executable: '.exe'
:defines:
:common:
:test:
- CMOCK
+48 -42
View File
@@ -27,18 +27,22 @@ SYSTEM_TEST_SUPPORT_DIRS.each do |dir|
CLOBBER.include(dir)
end
$cmock_test_config_file = DEFAULT_CONFIG_FILE
$cmock_test_overlay_file = nil
task :prep_system_tests => SYSTEM_TEST_SUPPORT_DIRS
configure_toolchain(DEFAULT_CONFIG_FILE)
task :default => [:test]
task :ci => [:no_color, :default, 'test:examples', 'style:check', 'test:summary']
task :cruise => :ci
desc "Load configuration"
task :config, [:config_file, :cmock_overlay] do |t, args|
configure_toolchain(args[:config_file], args[:cmock_overlay])
$cmock_test_config_file = args[:config_file]
$cmock_test_overlay_file = args[:cmock_overlay]
end
task :config_toolchains do
configure_toolchain($cmock_test_config_file, $cmock_test_overlay_file)
end
# Still support testing everything with just 'test' but switch default to ceedling-like test:all
@@ -46,63 +50,65 @@ task :test => ['test:all']
namespace :test do
desc "Run all unit, c, and system tests"
task :all => [:clobber, :prep_system_tests, 'test:units', 'test:c', 'test:system']
task :all => [:config_toolchains, :clobber, :prep_system_tests, 'test:unit', 'test:c', 'test:system']
desc "Run Unit Tests"
task :units => [:prep_system_tests] do
task :unit => [:config_toolchains, :prep_system_tests] do
run_ruby_unit_tests
end
#individual unit tests
FileList['unit/*_test.rb'].each do |test|
Rake::TestTask.new(File.basename(test,'.*').sub('_test','')) do |t|
t.pattern = test
t.verbose = true
namespace :unit do
FileList['unit/*_test.rb'].each do |test|
desc "Run unit test #{File.basename(test,'.*')}"
Rake::TestTask.new(File.basename(test,'.*').sub('_test','') => [:config_toolchains]) do |t|
t.pattern = test
t.verbose = true
end
end
end
desc "Run C Unit Tests"
task :c => [:prep_system_tests] do
task :c => [:config_toolchains, :prep_system_tests] do
unless (unsupported_tests.include? "C")
build_and_test_c_files
end
end
desc "Run System Tests"
task :system => [:clobber, :prep_system_tests] do
#get a list of all system tests, removing unsupported tests for this compiler
sys_unsupported = unsupported_tests.map {|a| 'system/test_interactions/'+a+'.yml'}
sys_tests_to_run = FileList['system/test_interactions/*.yml'] - sys_unsupported
compile_unsupported = unsupported_tests.map {|a| SYSTEST_COMPILE_MOCKABLES_PATH+a+'.h'}
compile_tests_to_run = FileList[SYSTEST_COMPILE_MOCKABLES_PATH + '*.h'] - compile_unsupported
unless (sys_unsupported.empty? and compile_unsupported.empty?)
report "\nIgnoring these system tests..."
sys_unsupported.each {|a| report a}
compile_unsupported.each {|a| report a}
end
task :system => [:config_toolchains, :clobber, :prep_system_tests] do
report "\nRunning system tests..."
tests_failed = run_system_test_interactions(sys_tests_to_run)
tests_failed = run_system_test_interactions(FileList['system/test_interactions/*.yml'])
raise "System tests failed." if (tests_failed > 0)
run_system_test_compilations(compile_tests_to_run)
end
desc "Test cmock examples"
task :examples => [:prep_system_tests] do
run_examples(true)
run_system_test_compilations(FileList[SYSTEST_COMPILE_MOCKABLES_PATH + '*.h'])
end
#individual system tests
FileList['system/test_interactions/*.yml'].each do |test|
basename = File.basename(test,'.*')
#desc "Run system test #{basename}"
task basename do
run_system_test_interactions([test])
namespace :system do
FileList['system/test_interactions/*.yml'].each do |test|
basename = File.basename(test,'.*')
desc "Run system test #{basename}"
task basename => [:config_toolchains, :prep_system_tests] do
run_system_test_interactions([test])
end
end
FileList[SYSTEST_COMPILE_MOCKABLES_PATH + '*.h'].each do |test|
basename = File.basename(test,'.*')
desc "Run system test #{basename}"
task basename => [:config_toolchains, :prep_system_tests] do
run_system_test_compilations([test])
end
end
end
desc "Test cmock examples"
task :examples => [:config_toolchains, :prep_system_tests] do
run_examples()
end
desc "Profile Mock Generation"
task :profile => [:clobber, :prep_system_tests] do
task :profile => [:config_toolchains, :clobber, :prep_system_tests] do
run_system_test_profiles(FileList[SYSTEST_COMPILE_MOCKABLES_PATH + '*.h'])
end
@@ -119,7 +125,7 @@ end
################### CODING STYLE VALIDATION
namespace :style do
desc "Check style"
task :check do
task :check => [:config_toolchains] do
report "\n"
report "--------------------\n"
report "VERIFYING RUBY STYLE\n"
@@ -129,25 +135,25 @@ namespace :style do
end
desc "Fix Style of all C Code"
task :c do
run_astyle("../src/*.* ../extras/fixture/src/*.*")
task :c => [:config_toolchains]do
run_astyle("../src/*.*")
end
desc "Attempt to Autocorrect style"
task :auto => ['style:clean'] do
task :auto => [:config_toolchains, 'style:clean'] do
execute("rubocop ../lib ../examples ../config ../scripts --autocorrect --config ../vendor/unity/test/.rubocop.yml", true)
report "Autocorrected What We Could."
end
desc "Update style todo list"
task :todo => ['style:clean'] do
task :todo => [:config_toolchains, 'style:clean'] do
execute("rubocop ../lib ../examples ../config ../scripts --auto-gen-config --config ../vendor/unity/test/.rubocop.yml", true)
report "Updated Style TODO List."
end
task :clean do
task :clean => [:config_toolchains] do
File.delete(".rubocop_todo.yml") if File.exist?(".rubocop_todo.yml")
end
end
task :style => ['style:check']
task :style => [:config_toolchains, 'style:check']
+116 -50
View File
@@ -44,29 +44,40 @@ 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_target = "../vendor/unity/test/targets/#{$cfg_file}"
unity_targets_dir = '../vendor/unity/test/targets'
cmock_targets_dir = './targets'
config_basename = File.basename(config_file)
path_specified = File.dirname(config_file) != '.'
if File.exist?(unity_target)
# Resolve the target file location:
# - path specified → use only that location
# - no path → check current directory first, then vendor unity targets
config_target = if path_specified
config_file
elsif File.exist?("./#{config_file}")
"./#{config_file}"
else
"#{unity_targets_dir}/#{config_file}"
end
if File.exist?(config_target)
# Load Unity base target, then CMock overlay (unsupported list, extra defines)
puts "Loading Unity target: #{unity_target}"
$unity_cfg = load_yaml(unity_target)
puts "Loading Toolchain target: #{config_target}"
$unity_cfg = load_yaml(config_target)
cmock_file = cmock_overlay || find_cmock_target(cmock_targets_dir, $cfg_file)
cmock_file = cmock_overlay || find_cmock_target(cmock_targets_dir, config_basename)
if cmock_file
puts "Loading CMock overlay: #{cmock_targets_dir}/#{cmock_file}"
puts "Loading Toolchain overlay: #{cmock_targets_dir}/#{cmock_file}"
$cmock_cfg = load_yaml("#{cmock_targets_dir}/#{cmock_file}")
else
puts "No CMock overlay found for #{$cfg_file}"
puts "No Toolchain overlay found for #{config_file}"
$cmock_cfg = {}
end
else
# CMock-only target (no Unity equivalent); it uses Unity format directly
puts "Loading CMock-only target: #{cmock_targets_dir}/#{$cfg_file}"
$unity_cfg = load_yaml("#{cmock_targets_dir}/#{$cfg_file}")
$cmock_cfg = {}
raise "Cannot find Config File #{config_target}"
end
$colour_output = $proj[:project][:colour]
@@ -79,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
@@ -122,7 +132,7 @@ module RakefileHelpers
# All defines: project common + Unity target + CMock overlay + any extras
def all_defines(extra = [])
(($proj[:defines][:common] || []) +
(($proj[:defines][:test] || []) +
($unity_cfg[:defines][:test] || []) +
(($cmock_cfg[:defines] || {})[:test] || []) +
extra).uniq
@@ -131,26 +141,46 @@ module RakefileHelpers
# Toolchain-specific include paths: Array items in Unity's :paths: :test:
# (e.g., IAR compiler include directories encoded as path-concatenation arrays)
def toolchain_include_paths
($unity_cfg[:paths][:test] || []).select { |p| p.is_a?(Array) }
(($unity_cfg[:paths] || {})[:test] || []).select { |p| p.is_a?(Array) }
end
# Returns the unsupported test list, regardless of whether it came from
# a CMock overlay or a CMock-only target file.
# Returns the full unsupported test list for the current toolchain, combining:
# - explicit :unsupported lists from the CMock overlay and Unity target files
# - implicit criteria (tests that require defines not present in the toolchain)
UNSUPPORTED_CRITERIA = {
'out_of_memory' => { :defines => ['CMOCK_MEM_STATIC'] },
'unity_64bit_support' => { :defines => ['UNITY_SUPPORT_64'] }
}.freeze
def unsupported_tests
$cmock_cfg[:unsupported] || $unity_cfg[:unsupported] || []
result = ($cmock_cfg[:unsupported] || []) | ($unity_cfg[:unsupported] || [])
conf_defs = all_defines
UNSUPPORTED_CRITERIA.each_pair do |name, crit|
result |= [name] if (crit[:defines] & conf_defs).empty?
end
result
end
# Resolve Unity's argument template tokens and produce a flat argument string.
# COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE → -I per toolchain path (Arrays from :paths: :test:)
# COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR → -I per project include path
# COLLECTION_DEFINES_TEST_AND_VENDOR → -D per define
# Resolve argument template tokens and produce a flat argument string.
# Supports Ceedling-style positional tokens and legacy Unity COLLECTION_* tokens.
# ${5} → expands to one arg per include path (toolchain paths + project paths combined)
# ${6} → expands to one arg per define
# ${1} → input file(s)
# ${2} → output file
# COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE → (legacy) -I per toolchain path
# COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR → (legacy) -I per project include path
# COLLECTION_DEFINES_TEST_AND_VENDOR → (legacy) -D per define
def build_argument_list(raw_args, toolchain_paths, project_paths, defines, input, output)
result = []
raw_args.each do |arg|
if arg.is_a?(Array)
result << arg.join
elsif arg.include?('${5}')
(toolchain_paths + project_paths).each do |p|
result << arg.gsub('${5}', p.is_a?(Array) ? p.join : p.to_s)
end
elsif arg.include?('${6}')
defines.each { |d| result << arg.gsub('${6}', d) }
elsif arg.include?('COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE')
toolchain_paths.each { |p| result << "-I\"#{p.is_a?(Array) ? p.join : p}\"" }
elsif arg.include?('COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR')
@@ -166,8 +196,8 @@ module RakefileHelpers
def compile(file, extra_defines = [])
tool = $unity_cfg[:tools][:test_compiler]
ext = $unity_cfg[:extension][:object]
build_root = $proj[:project][:build_root]
ext = $unity_cfg[:extension][:object] || '.o'
build_root = $proj[:project][:build_root] || 'build/'
obj_file = build_root + File.basename(file, C_EXTENSION) + ext
cmd_str = tackit(tool[:executable]) + ' ' +
@@ -181,8 +211,8 @@ module RakefileHelpers
end
def link_it(exe_name, obj_list)
tool = $unity_cfg[:tools][:test_linker]
ext = $unity_cfg[:extension][:executable]
tool = $unity_cfg[:tools][:test_linker]
ext = $unity_cfg[:extension][:executable] || ''
build_root = $proj[:project][:build_root]
input_files = obj_list.uniq.map { |obj| build_root + obj }.join(' ')
@@ -209,7 +239,8 @@ module RakefileHelpers
{ command: "#{executable} ", pre_support: pre, post_support: post }
end
def execute(command_string, verbose=true, raise_on_failure=true)
def execute(command_string, verbose=false, raise_on_failure=true)
report(command_string) if verbose
output = `#{command_string}`.chomp
report(output) if (verbose && !output.nil? && (output.length > 0))
if ($?.exitstatus != 0) and (raise_on_failure)
@@ -224,7 +255,7 @@ module RakefileHelpers
"--style=allman --indent=spaces=4 --indent-switches --indent-preproc-define --indent-preproc-block " \
"--pad-oper --pad-comma --unpad-paren --pad-header " \
"--align-pointer=type --align-reference=name " \
"--add-brackets --mode=c --suffix=none " \
"--mode=c --suffix=none " \
"#{style_what}"
execute(command, false)
report "Styling C:PASS"
@@ -269,7 +300,7 @@ module RakefileHelpers
total_runs = total_failures = total_errors = total_skips = 0
Dir['unit/*_test.rb'].sort.each do |tst|
report "\nRunning #{tst.to_s}"
output = execute("ruby -I. #{tst}", true, false)
output = execute("ruby -I. #{tst} -v", true, false)
output.each_line do |line|
if line =~ /(\d+) runs, \d+ assertions, (\d+) failures, (\d+) errors, (\d+) skips/
total_runs += Regexp.last_match(1).to_i
@@ -300,20 +331,30 @@ module RakefileHelpers
def run_system_test_interactions(test_case_files)
load '../lib/cmock.rb'
SystemTestGenerator.new.generate_files(test_case_files)
test_files = FileList.new(SYSTEST_GENERATED_FILES_PATH + 'test*.c')
unsupported = unsupported_tests
test_case_files = test_case_files.reject do |f|
name = File.basename(f, YAML_EXTENSION)
if unsupported.include?(name)
report "Ignoring system test: #{name}"
true
end
end
load_configuration($cfg_file)
SystemTestGenerator.new.generate_files(test_case_files)
load_configuration($cfg_file, $cmock_test_overlay_file)
include_dirs = get_local_include_dirs
# Build and execute each unit test
test_files.each do |test|
test_case_files.each do |yaml|
obj_list = []
test_base = File.basename(test, C_EXTENSION)
cmock_config = test_base.gsub(/test_/, '') + '_cmock.yml'
name = File.basename(yaml, YAML_EXTENSION)
test_base = 'test_' + name
test = SYSTEST_GENERATED_FILES_PATH + test_base + C_EXTENSION
cmock_config = name + '_cmock.yml'
report "Executing system tests in #{File.basename(test)}..."
@@ -345,7 +386,7 @@ module RakefileHelpers
# Execute unit test and generate results file
simulator = build_simulator_fields
ext = $unity_cfg[:extension][:executable]
ext = $unity_cfg[:extension][:executable] || ''
build_root = $proj[:project][:build_root]
executable = build_root + test_base + ext
cmd_str = if simulator.nil?
@@ -363,6 +404,7 @@ module RakefileHelpers
total_failures = 0
failure_messages = []
report "\n\nSystem Testing Results: "
test_case_files.each do |test_case|
tests = (load_yaml(test_case))[:systest][:tests][:units]
total_tests += tests.size
@@ -382,11 +424,16 @@ module RakefileHelpers
if (this_failed)
total_failures += 1
test_results[index] =~ /test#{index+1}:(.+)/
failure_messages << "#{test_file}:test#{index+1}:should #{test[:should]}:#{$1}"
end
if (test[:verify_error]) and not (test_results[index] =~ /test#{index+1}:.*#{test[:verify_error]}/)
new_msg = "#{test_file}:test#{index+1}:should #{test[:should]}:#{$1}"
failure_messages << new_msg
report new_msg
elsif (test[:verify_error]) and not (test_results[index] =~ /test#{index+1}:.*#{test[:verify_error]}/)
total_failures += 1
failure_messages << "#{test_file}:test#{index+1}:should #{test[:should]}:should have output matching '#{test[:verify_error]}' but was '#{test_results[index]}'"
new_msg = "#{test_file}:test#{index+1}:should #{test[:should]}:should have output matching '#{test[:verify_error]}' but was '#{test_results[index]}'"
failure_messages << new_msg
report new_msg
else
report "#{test_file}:test#{index+1}:should #{test[:should]}:PASS"
end
end
end
@@ -433,7 +480,16 @@ 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|
name = File.basename(f, '.h')
if unsupported.include?(name)
report "Ignoring system test compilation: #{name}"
true
end
end
report "\n"
report "------------------------------------\n"
@@ -453,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"
@@ -476,7 +532,7 @@ module RakefileHelpers
report "----------------\n"
report "UNIT TEST C CODE\n"
report "----------------\n"
ext = $unity_cfg[:extension][:executable]
ext = $unity_cfg[:extension][:executable] || ''
build_root = $proj[:project][:build_root]
combined_output = ''
FileList.new("c/*.yml").each do |yaml_file|
@@ -484,7 +540,7 @@ module RakefileHelpers
report "\nTesting #{yaml_file.sub('.yml','')}"
report "(#{test[:options].join(', ')})"
test[:files].each { |f| compile(f, test[:options]) }
obj_files = test[:files].map { |f| f.gsub!(/.*\//,'').gsub!(C_EXTENSION, $unity_cfg[:extension][:object]) }
obj_files = test[:files].map { |f| f.gsub!(/.*\//,'').gsub!(C_EXTENSION, $unity_cfg[:extension][:object] || '.o') }
link_it('TestCMockC', obj_files)
simulator = build_simulator_fields
executable = build_root + 'TestCMockC' + ext
@@ -496,7 +552,7 @@ module RakefileHelpers
raise "C unit tests failed." if result =~ /FAILED/
end
def run_examples(verbose=false, raise_on_failure=true)
def run_examples()
report "\n"
report "-----------------\n"
report "VALIDATE EXAMPLES\n"
@@ -504,11 +560,19 @@ module RakefileHelpers
total_tests = 0
total_failures = 0
total_ignored = 0
[ "cd #{File.join("..", "examples", "make_example")} && make clean && make setup && make test",
"cd #{File.join("..", "examples", "temp_sensor")} && rake ci"
].each do |cmd|
report "Testing '#{cmd}'"
execute(cmd, verbose, false).each_line do |line|
cfg_file = "#{($cmock_test_config_file =~ /[\\\/]/) ? '../' : ''}#{$cmock_test_config_file}"
# Determine which examples are valid for this platform
examples = {
:make_example => "cd #{File.join("..", "examples", "make_example")} && make clean && make setup && make test",
:rake_example => "cd #{File.join("..", "examples", "temp_sensor")} && rake config[\"#{cfg_file}\"] ci"
}
examples.delete(:make_example) unless ($cmock_test_config_file =~ /gcc/)
# Run the examples
examples.each_pair do |key, cmd|
report "Testing Example: '#{key}'"
execute(cmd, true, false).each_line do |line|
if line =~ /(\d+) TOTAL TESTS (\d+) TOTAL FAILURES (\d+) IGNORED/
total_tests += Regexp.last_match(1).to_i
total_failures += Regexp.last_match(2).to_i
@@ -516,10 +580,12 @@ module RakefileHelpers
end
end
end
# Report the results from the examples
result = "#{total_tests} Tests #{total_failures} Failures #{total_ignored} Ignored\n"
result += total_failures > 0 ? "FAILED\n" : "OK\n"
save_test_results('examples', result)
raise "Examples failed." if total_failures > 0 && raise_on_failure
raise "Examples failed." if total_failures > 0
end
def fail_out(msg)
+3
View File
@@ -15,3 +15,6 @@
:treat_as_void:
- OSEK_TASK
- VOID_TYPE_CRAZINESS
:strippables:
- SAMPLE_EXTERN
- SAMPLE_MODE
+6 -6
View File
@@ -24,15 +24,15 @@ void const_variants2(
const int * const_retval1(void); /* nicety version for pointer to constant int */
int const * const_retval2(void); /* formal version for pointer to constant int */
//int * const const_retval3(void); /* formal version for constant pointer to int */
//int const * const const_retval4(void); /* formal version for constant pointer to constant int */
int * const const_retval3(void); /* formal version for constant pointer to int */
int const * const const_retval4(void); /* formal version for constant pointer to constant int */
const int* const_retval5(void); /* sticky-left nicety version for pointer to constant int */
int const* const_retval6(void); /* sticky-left formal version for pointer to constant int */
//int* const const_retval7(void); /* sticky-left formal version for constant pointer to int */
//int const* const const_retval8(void); /* sticky-left formal version for constant pointer to constant int */
int* const const_retval7(void); /* sticky-left formal version for constant pointer to int */
int const* const const_retval8(void); /* sticky-left formal version for constant pointer to constant int */
const int *const_retval9(void); /* sticky-right nicety version for pointer to constant int */
int const *const_retvalA(void); /* sticky-right formal version for pointer to constant int */
//int *const const_retvalB(void); /* sticky-right formal version for constant pointer to int */
//int const *const const_retvalC(void); /* sticky-right formal version for constant pointer to constant int */
int *const const_retvalB(void); /* sticky-right formal version for constant pointer to int */
int const *const const_retvalC(void); /* sticky-right formal version for constant pointer to constant int */
+26
View File
@@ -18,6 +18,16 @@ typedef struct _POINT_T
int y;
} POINT_T;
/* The comments in the following enum are important, as are the newlines and commas */
/* This combination caused a curious bug when used together. Make sure it doesn't come back. */
typedef enum
{
MY_ERROR_ID = -18,/**< Driver not ready */
MY_OTHER_ID = -19 /**< Node-id is in LSS unconfigured
state. If objects are handled properly,
his may not be an error. */
} MY_STATE_ID_T;
/* typedef edge case;
not ANSI C but it has been done and will break cmock if not handled */
typedef void VOID_TYPE_CRAZINESS;
@@ -101,3 +111,19 @@ inline int stuff(int num)
}
return reg;
}
/* it seems like CMock didn't love a func-looking struct before a func */
#define FOO_TYPE(a) foo_##a
struct FOO_TYPE(bar) { int baz; };
char b(void);
/* Here are more macros that sorta look like functions. Only sample_func is real */
#define SAMPLE_EXTERN
#define SAMPLE_MODE
#define SAMPLE_DEPRECATED(a,b)
struct struct_a;
struct struct_b;
SAMPLE_EXTERN SAMPLE_MODE SAMPLE_DEPRECATED(1.1.2, "It was bad. real bad()")
void sample_func(struct struct_a **a,
struct struct_b **b,
...);
@@ -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());
}
@@ -110,7 +110,7 @@
}
- :pass: TRUE
:should: 'handle floating point numbers with Unity support: pass'
:should: 'handle floating point numbers with Unity support to pass'
:code: |
test()
{
@@ -119,7 +119,7 @@
}
- :pass: FALSE
:should: 'handle floating point numbers with Unity support: fail'
:should: 'handle floating point numbers with Unity support to fail'
:code: |
test()
{
@@ -27,7 +27,7 @@
const char const * bars(void);
:source:
:header: |
:header: |
#include "CException.h"
void function_a(void);
void function_b(void);
@@ -7,19 +7,22 @@
---
:cmock:
:plugins: []
:plugins: [ignore, expect_any_args, array]
:treat_as:
custom_type: INT
:systest:
:types: |
#define BIG_FAT_STRUCT_SIZE (512)
typedef struct _BIG_FAT_STRUCT_T
{
char bytes[512];
char bytes[BIG_FAT_STRUCT_SIZE];
} BIG_FAT_STRUCT_T;
:mockable: |
void foo(BIG_FAT_STRUCT_T a);
int get_result(void);
void process_data(int* data, int count);
:source:
:header: |
@@ -52,21 +55,75 @@
:code: |
test()
{
int i=0;
BIG_FAT_STRUCT_T expected = { { 8, 0 } };
foo_Expect(expected);
function_a();
// Fill expectations until there is not enough room for more.
// We know we can ask one more when there is only enough room for 2 blocks, ignoring overhead.
while (CMock_Guts_MemBytesFree() > (CMOCK_MEM_SIZE*2)) {
i++;
foo_Expect(expected);
}
for (; i>0; i--) {
function_a();
}
}
- :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()
{
int i=0;
BIG_FAT_STRUCT_T expected1 = { { 9, 1, 0 } };
BIG_FAT_STRUCT_T expected2 = { { 9, 2, 0 } };
foo_Expect(expected1);
foo_Expect(expected2);
function_b();
// Ask for more room than we have
while (CMock_Guts_MemBytesFree() > 0) {
foo_Expect(expected1);
foo_Expect(expected2);
}
// It should not actually get here
for (i=0; i < (CMOCK_MEM_SIZE/BIG_FAT_STRUCT_SIZE - 1); i++) {
function_b();
}
}
- :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);
}
...
-12
View File
@@ -1,12 +0,0 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
# CMock overlay for vendor/unity/test/targets/clang_strict.yml
# Only contains additions not present in the Unity base target.
:unsupported:
- out_of_memory
- callingconv
-14
View File
@@ -1,14 +0,0 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
# CMock overlay for vendor/unity/test/targets/gcc_32.yml
# Only contains additions not present in the Unity base target.
---
:unsupported:
- out_of_memory
- unity_64bit_support
- callingconv
-12
View File
@@ -1,12 +0,0 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
# CMock overlay for vendor/unity/test/targets/gcc_64.yml
# Only contains additions not present in the Unity base target.
:unsupported:
- out_of_memory
- callingconv
-2
View File
@@ -9,8 +9,6 @@
# Only contains additions not present in the Unity base target.
:unsupported:
- out_of_memory
- nonstandard_parsed_stuff_1
- const
- callingconv
- unity_64bit_support
-1
View File
@@ -31,7 +31,6 @@
- struct_union_enum_expect_and_return
- struct_union_enum_expect_and_return_with_plugins
- stubs_with_callbacks
- unity_64bit_support
- unity_ignores
- callingconv
- C
@@ -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
+228 -108
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"
@@ -1038,7 +1038,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:ptr? => true,
:const? => false,
:const_ptr? => true,
:str => "int* cmock_to_return",
:str => "int* const cmock_to_return",
:void? => false
},
:modifier=>"const",
@@ -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
+1 -1