1
0
mirror of https://github.com/ThrowTheSwitch/CMock synced 2025-05-16 01:39:33 -04:00

* split :args_only feature from :ignore plugin to be its own :expect_any_args plugin

* made :expect_any_args work with intermixed expects the way you would think it should work.
This commit is contained in:
Mark VanderVoord 2014-03-03 19:28:50 -05:00
parent 6bfe7ce784
commit 86594eea25
9 changed files with 409 additions and 285 deletions

@ -1,82 +1,82 @@
[All code is copyright © 2007-2010 Cmock Project
by Mike Karlesky, Mark VanderVoord, and Greg Williams.
This Documentation Is Released Under a Creative Commons 3.0
Attribution Share-Alike License]
This Documentation Is Released Under a Creative Commons 3.0
Attribution Share-Alike License]
What the What?
==============
CMock is a nice little tool which takes your header files and creates
a Mock interface for it so that you can more easily Unit test modules
that touch other modules. For each function prototype in your
header, like this one:
CMock is a nice little tool which takes your header files and creates
a Mock interface for it so that you can more easily Unit test modules
that touch other modules. For each function prototype in your
header, like this one:
int DoesSomething(int a, int b);
...you get an automatically generated DoesSomething function
that you can link to instead of your real DoesSomething function.
By using this Mocked version, you can then verify that it receives
the data you want, and make it return whatever data you desire,
make it throw errors when you want, and more... Create these for
everything your latest real module touches, and you're suddenly
in a position of power: You can control and verify every detail
of your latest creation.
To make that easier, CMock also gives you a bunch of functions
like the ones below, so you can tell that generated DoesSomething
function how to behave for each test:
...you get an automatically generated DoesSomething function
that you can link to instead of your real DoesSomething function.
By using this Mocked version, you can then verify that it receives
the data you want, and make it return whatever data you desire,
make it throw errors when you want, and more... Create these for
everything your latest real module touches, and you're suddenly
in a position of power: You can control and verify every detail
of your latest creation.
To make that easier, CMock also gives you a bunch of functions
like the ones below, so you can tell that generated DoesSomething
function how to behave for each test:
void DoesSomething_ExpectAndReturn(int a, int b, int toReturn);
void DoesSomething_ExpectAndThrow(int a, int b, EXCEPTION_T error);
void DoesSomething_StubWithCallback(CMOCK_DoesSomething_CALLBACK YourCallback);
void DoesSomething_IgnoreAndReturn(int toReturn);
You can pile a bunch of these back to back, and it remembers what
you wanted to pass when, like so:
You can pile a bunch of these back to back, and it remembers what
you wanted to pass when, like so:
test_CallsDoesSomething_ShouldDoJustThat(void)
{
DoesSomething_ExpectAndReturn(1,2,3);
DoesSomething_ExpectAndReturn(4,5,6);
DoesSomething_ExpectAndThrow(7,8, STATUS_ERROR_OOPS);
CallsDoesSomething( );
}
This test will call CallsDoesSomething, which is the function
we are testing. We are expecting that function to call DoesSomething
three times. The first time, we check to make sure it's called
as DoesSomething(1, 2) and we'll magically return a 3. The second
time we check for DoesSomething(4, 5) and we'll return a 6. The
third time we verify DoesSomething(7, 8) and we'll throw an error
instead of returning anything. If CallsDoesSomething gets
any of this wrong, it fails the test. It will fail if you didn't
call DoesSomething enough, or too much, or with the wrong arguments,
or in the wrong order.
CMock is based on Unity, which it uses for all internal testing.
It uses Ruby to do all the main work (versions 1.8.6 through 1.9.2).
This test will call CallsDoesSomething, which is the function
we are testing. We are expecting that function to call DoesSomething
three times. The first time, we check to make sure it's called
as DoesSomething(1, 2) and we'll magically return a 3. The second
time we check for DoesSomething(4, 5) and we'll return a 6. The
third time we verify DoesSomething(7, 8) and we'll throw an error
instead of returning anything. If CallsDoesSomething gets
any of this wrong, it fails the test. It will fail if you didn't
call DoesSomething enough, or too much, or with the wrong arguments,
or in the wrong order.
CMock is based on Unity, which it uses for all internal testing.
It uses Ruby to do all the main work (versions 1.8.6 through 1.9.2).
Generated Mock Module Summary
=============================
In addition to the mocks themselves, CMock will generate the
following functions for use in your tests. The expect functions
are always generated. The other functions are only generated
if those plugins are enabled:
In addition to the mocks themselves, CMock will generate the
following functions for use in your tests. The expect functions
are always generated. The other functions are only generated
if those plugins are enabled:
Expect:
-------
Your basic staple Expects which will be used for most of your day
to day CMock work.
Your basic staple Expects which will be used for most of your day
to day CMock work.
* `void func(void)` => `void func_Expect(void)`
* `void func(params)` => `void func_Expect(expected_params)`
@ -87,9 +87,9 @@ to day CMock work.
Array:
------
An ExpectWithArray will check as many elements as you specify.
If you specify zero elements, it will check just the pointer if
`:smart` mode is configured or fail if `:compare_data` is set.
An ExpectWithArray will check as many elements as you specify.
If you specify zero elements, it will check just the pointer if
`:smart` mode is configured or fail if `:compare_data` is set.
* `void func(void)` => (nothing. In fact, an additional function is only generated if the params list contains pointers)
* `void func(ptr * param, other)` => `void func_ExpectWithArray(ptr* param, int param_depth, other)`
@ -100,11 +100,11 @@ If you specify zero elements, it will check just the pointer if
Callback:
---------
As soon as you stub a callback in a test, it will call the callback
whenever the mock is encountered and return the retval returned
from the callback (if any) instead of performing the usual expect
checks. It can be configured to check the arguments first (like
expects) or just jump directly to the callback.
As soon as you stub a callback in a test, it will call the callback
whenever the mock is encountered and return the retval returned
from the callback (if any) instead of performing the usual expect
checks. It can be configured to check the arguments first (like
expects) or just jump directly to the callback.
* `void func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
where `CMOCK_func_CALLBACK` looks like: `void func(int NumCalls)`
@ -119,10 +119,10 @@ where `CMOCK_func_CALLBACK` looks like: `retval func(params, int NumCalls)`
Cexception:
-----------
If you are using Cexception for error handling, you can use this
to throw errors from inside mocks. Like Expects, it remembers
which call was supposed to throw the error, and it still checks
parameters.
If you are using Cexception for error handling, you can use this
to throw errors from inside mocks. Like Expects, it remembers
which call was supposed to throw the error, and it still checks
parameters.
* `void func(void)` => `void func_ExpectAndThrow(value_to_throw)`
* `void func(params)` => `void func_ExpectAndThrow(expected_params, value_to_throw)`
@ -133,10 +133,10 @@ parameters.
Ignore:
-------
This plugin supports two modes. You can use it to force CMock to
ignore calls to specific functions or to just ignore the arguments
passed to those functions. Either way you can specify multiple
returns or a single value to always return, whichever you prefer.
This plugin supports two modes. You can use it to force CMock to
ignore calls to specific functions or to just ignore the arguments
passed to those functions. Either way you can specify multiple
returns or a single value to always return, whichever you prefer.
* `void func(void)` => `void func_Ignore(void)`
* `void func(params)` => `void func_Ignore(void)`
@ -147,59 +147,59 @@ returns or a single value to always return, whichever you prefer.
Running CMock
=============
CMock is a Ruby script and class. You can therefore use it directly
from the command line, or include it in your own scripts or rakefiles.
CMock is a Ruby script and class. You can therefore use it directly
from the command line, or include it in your own scripts or rakefiles.
Mocking from the Command Line
-----------------------------
After unpacking CMock, you will find CMock.rb in the 'lib' directory.
This is the file that you want to run. It takes a list of header files
to be mocked, as well as an optional yaml file for a more detailed
configuration (see config options below).
After unpacking CMock, you will find CMock.rb in the 'lib' directory.
This is the file that you want to run. It takes a list of header files
to be mocked, as well as an optional yaml file for a more detailed
configuration (see config options below).
For example, this will create three mocks using the configuration
specified in MyConfig.yml:
For example, this will create three mocks using the configuration
specified in MyConfig.yml:
ruby cmock.rb -oMyConfig.yml super.h duper.h awesome.h
And this will create two mocks using the default configuration:
And this will create two mocks using the default configuration:
ruby cmock.rb ../mocking/stuff/is/fun.h ../try/it/yourself.h
Mocking From Scripts or Rake
----------------------------
CMock can be used directly from your own scripts or from a rakefile.
Start by including cmock.rb, then create an instance of CMock.
When you create your instance, you may initialize it in one of
three ways.
CMock can be used directly from your own scripts or from a rakefile.
Start by including cmock.rb, then create an instance of CMock.
When you create your instance, you may initialize it in one of
three ways.
You may specify nothing, allowing it to run with default settings:
You may specify nothing, allowing it to run with default settings:
cmock = CMock.new
You may specify a YAML file containing the configuration options
you desire:
You may specify a YAML file containing the configuration options
you desire:
cmock = CMock.new('../MyConfig.yml')
You may specify the options explicitly:
You may specify the options explicitly:
cmock = Cmock.new(:plugins => [:cexception, :ignore], :mock_path => 'my/mocks/')
Config Options:
Config Options:
The following configuration options can be specified in the
yaml file or directly when instantiating.
The following configuration options can be specified in the
yaml file or directly when instantiating.
Passed as Ruby, they look like this:
Passed as Ruby, they look like this:
{ :attributes => [“__funky”, “__intrinsic”], :when_ptr => :compare }
Defined in the yaml file, they look more like this:
Defined in the yaml file, they look more like this:
:cmock:
:cmock:
:attributes:
- __funky
- __intrinsic
@ -238,11 +238,6 @@ Defined in the yaml file, they look more like this:
unity test frameworks (or if you write one for us), they'll get added
here.
* `:ignore`:
Tell `:ignore` plugin to ignore `:args_only` or `:args_and_calls`
(default) where it doesn't even care how many times the mock was
called
* `:includes`:
An array of additional include files which should be added to the
mocks. Useful for global types and definitions used in your project.
@ -320,37 +315,37 @@ Defined in the yaml file, they look more like this:
Compiled Options:
-----------------
A number of #defines also exist for customizing the cmock experience.
A number of #defines also exist for customizing the cmock experience.
CMOCK_MEM_STATIC or CMOCK_MEM_DYNAMIC
CMOCK_MEM_STATIC or CMOCK_MEM_DYNAMIC
Define one of these to determine if you want to dynamically add
memory during tests as required from the heap. If static, you
can control the total footprint of Cmock. If dynamic, you will
need to make sure you make some heap space available for Cmock.
Define one of these to determine if you want to dynamically add
memory during tests as required from the heap. If static, you
can control the total footprint of Cmock. If dynamic, you will
need to make sure you make some heap space available for Cmock.
CMOCK_MEM_SIZE
CMOCK_MEM_SIZE
In static mode this is the total amount of memory you are allocating
to Cmock. In Dynamic mode this is the size of each chunk allocated
at once (larger numbers grab more memory but require less mallocs).
In static mode this is the total amount of memory you are allocating
to Cmock. In Dynamic mode this is the size of each chunk allocated
at once (larger numbers grab more memory but require less mallocs).
CMOCK_MEM_ALIGN
CMOCK_MEM_ALIGN
The way to align your data to. Not everything is as flexible as
a PC, as most embedded designers know. This defaults to 2, meaning
align to the closest 2^2 -> 4 bytes (32 bits). You can turn off alignment
by setting 0, force alignment to the closest uint16 with 1 or even
to the closest uint64 with 3.
The way to align your data to. Not everything is as flexible as
a PC, as most embedded designers know. This defaults to 2, meaning
align to the closest 2^2 -> 4 bytes (32 bits). You can turn off alignment
by setting 0, force alignment to the closest uint16 with 1 or even
to the closest uint64 with 3.
CMOCK_MEM_PTR_AS_INT
CMOCK_MEM_PTR_AS_INT
This is used internally to hold pointers... it needs to be big
enough. On most processors a pointer is the same as an unsigned
long... but maybe that's not true for yours?
This is used internally to hold pointers... it needs to be big
enough. On most processors a pointer is the same as an unsigned
long... but maybe that's not true for yours?
CMOCK_MEM_INDEX_TYPE
CMOCK_MEM_INDEX_TYPE
This needs to be something big enough to point anywhere in Cmock's
memory space... usually it's an unsigned int.
This needs to be something big enough to point anywhere in Cmock's
memory space... usually it's an unsigned int.

@ -2,11 +2,11 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
class CMockConfig
CMockDefaultOptions =
CMockDefaultOptions =
{
:framework => :unity,
:mock_path => 'mocks',
@ -24,24 +24,23 @@ class CMockConfig
:when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart
:verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
:treat_externs => :exclude, #the options being :include or :exclude
:ignore => :args_and_calls, #the options being :args_and_calls or :args_only
:callback_include_count => true,
:callback_after_arg_check => false,
:includes => nil,
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
:includes_c_pre_header => nil,
:includes => nil,
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
:includes_c_pre_header => nil,
:includes_c_post_header => nil
}
def initialize(options=nil)
case(options)
when NilClass then options = CMockDefaultOptions.clone
when NilClass then options = CMockDefaultOptions.clone
when String then options = CMockDefaultOptions.clone.merge(load_config_file_from_yaml(options))
when Hash then options = CMockDefaultOptions.clone.merge(options)
else raise "If you specify arguments, it should be a filename or a hash of options"
end
#do some quick type verification
[:plugins, :attributes, :treat_as_void].each do |opt|
unless (options[opt].class == Array)
@ -59,30 +58,30 @@ class CMockConfig
options[:plugins].compact!
options[:plugins].map! {|p| p.to_sym}
@options = options
treat_as_map = standard_treat_as_map()#.clone
treat_as_map.merge!(@options[:treat_as])
@options[:treat_as] = treat_as_map
@options.each_key { |key| eval("def #{key.to_s}() return @options[:#{key.to_s}] end") }
end
def load_config_file_from_yaml yaml_filename
require 'yaml'
require 'fileutils'
YAML.load_file(yaml_filename)[:cmock]
end
def set_path(path)
@src_path = path
end
def load_unity_helper
return File.new(@options[:unity_helper_path]).read if (@options[:unity_helper_path])
return nil
end
def standard_treat_as_map
def standard_treat_as_map
{
'int' => 'INT',
'char' => 'INT8',

@ -0,0 +1,67 @@
# ==========================================
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
class CMockGeneratorPluginExpectAnyArgs
attr_reader :priority
attr_reader :config, :utils
def initialize(config, utils)
@config = config
@utils = utils
@priority = 3
end
def instance_structure(function)
if (function[:return][:void?]) || (@config.plugins.include? :ignore)
""
else
" #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
end
end
def instance_typedefs(function)
" CMOCK_ARG_MODE IgnoreMode;\n"
end
def mock_function_declarations(function)
if (function[:return][:void?])
return "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" +
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
else
return "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" +
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
end
def mock_implementation(function)
lines = " if (cmock_call_instance->IgnoreMode == CMOCK_ARG_NONE)\n {\n"
if (function[:return][:void?])
lines << " return;\n }\n"
else
retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} )
lines << " " + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless (retval[:void?])
lines << " return cmock_call_instance->ReturnVal;\n }\n"
end
lines
end
def mock_interfaces(function)
lines = ""
if (function[:return][:void?])
lines << "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n"
else
lines << "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
end
lines << @utils.code_add_base_expectation(function[:name], true)
unless (function[:return][:void?])
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
end
lines << " cmock_call_instance->IgnoreMode = CMOCK_ARG_NONE;\n"
lines << "}\n\n"
end
end

@ -2,28 +2,19 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
class CMockGeneratorPluginIgnore
attr_reader :priority
attr_reader :config, :utils
def initialize(config, utils)
@config = config
if (@config.ignore == :args_and_calls)
alias :mock_implementation_precheck :mock_implementation_for_ignores
alias :mock_implementation :nothing
alias :mock_verify :mock_conditionally_verify_counts
else
alias :mock_implementation :mock_implementation_for_ignores
alias :mock_implementation_precheck :nothing
alias :mock_verify :nothing
end
@utils = utils
@priority = 2
end
def instance_structure(function)
if (function[:return][:void?])
" int #{function[:name]}_IgnoreBool;\n"
@ -31,24 +22,19 @@ class CMockGeneratorPluginIgnore
" int #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
end
end
def mock_function_declarations(function)
if (function[:return][:void?])
if (@config.ignore == :args_only)
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore(__LINE__)\n" +
"void #{function[:name]}_CMockIgnore(UNITY_LINE_TYPE cmock_line);\n"
else
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" +
"void #{function[:name]}_CMockIgnore(void);\n"
end
else
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" +
"void #{function[:name]}_CMockIgnore(void);\n"
else
return "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" +
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
end
end
def mock_implementation_for_ignores(function)
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
def mock_implementation_precheck(function)
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
if (function[:return][:void?])
lines << " return;\n }\n"
else
@ -59,22 +45,15 @@ class CMockGeneratorPluginIgnore
end
lines
end
def mock_interfaces(function)
lines = ""
args_only = (@config.ignore == :args_only)
if (function[:return][:void?])
if (args_only)
lines << "void #{function[:name]}_CMockIgnore(UNITY_LINE_TYPE cmock_line)\n{\n"
else
lines << "void #{function[:name]}_CMockIgnore(void)\n{\n"
end
lines << "void #{function[:name]}_CMockIgnore(void)\n{\n"
else
lines << "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
end
if (args_only)
lines << @utils.code_add_base_expectation(function[:name], true)
elsif (!function[:return][:void?])
if (!function[:return][:void?])
lines << @utils.code_add_base_expectation(function[:name], false)
end
unless (function[:return][:void?])
@ -84,12 +63,8 @@ class CMockGeneratorPluginIgnore
lines << "}\n\n"
end
def mock_conditionally_verify_counts(function)
def mock_conditionally_verify(function)
func_name = function[:name]
" if (Mock.#{func_name}_IgnoreBool)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n"
end
def nothing(function)
return ""
end
end

@ -2,7 +2,7 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
class CMockGeneratorUtils
@ -14,22 +14,23 @@ class CMockGeneratorUtils
@ordered = @config.enforce_strict_ordering
@arrays = @config.plugins.include? :array
@cexception = @config.plugins.include? :cexception
@expect_any = @config.plugins.include? :expect_any_args
@return_thru_ptr = @config.plugins.include? :return_thru_ptr
@ignore_arg = @config.plugins.include? :ignore_arg
@treat_as = @config.treat_as
@helpers = helpers
if (@arrays)
case(@ptr_handling)
when :smart then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_smart_arrays
when :compare_data then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_normal_arrays
when :smart then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_smart_arrays
when :compare_data then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_normal_arrays
when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option."
end
else
alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_no_arrays
end
end
def code_add_base_expectation(func_name, global_ordering_supported=true)
lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n"
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n"
@ -38,37 +39,38 @@ class CMockGeneratorUtils
lines << " cmock_call_instance->LineNumber = cmock_line;\n"
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if (@ordered and global_ordering_supported)
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if (@cexception)
lines << " cmock_call_instance->IgnoreMode = CMOCK_ARG_ALL;\n" if (@expect_any)
lines
end
def code_add_an_arg_expectation(arg, depth=1)
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 and (depth.class == 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 and ptr_or_str?(arg[:type]) and not arg[:const?])
lines
end
def code_assign_argument_quickly(dest, arg)
def code_assign_argument_quickly(dest, arg)
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
" #{dest} = #{arg[:const?] ? "(#{arg[:type]})" : ''}#{arg[:name]};\n"
else
" memcpy(&#{dest}, &#{arg[:name]}, sizeof(#{arg[:type]}));\n"
end
end
def code_add_argument_loader(function)
if (function[:args_string] != "void")
if (@arrays)
args_string = function[:args].map do |m|
args_string = function[:args].map do |m|
const_str = m[ :const? ] ? 'const ' : ''
m[:ptr?] ? "#{const_str}#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{const_str}#{m[:type]} #{m[:name]}"
end.join(', ')
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\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) ) } +
"}\n\n"
else
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg) } +
"}\n\n"
end
@ -76,25 +78,25 @@ class CMockGeneratorUtils
""
end
end
def code_call_argument_loader(function)
if (function[:args_string] != "void")
args = function[:args].map do |m|
(@arrays and m[:ptr?]) ? "#{m[:name]}, 1" : m[:name]
end
" CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n"
" CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n"
else
""
end
end
def ptr_or_str?(arg_type)
return (arg_type.include? '*' or
@treat_as.fetch(arg_type, "").include? '*')
end
#private ######################
def lookup_expect_type(function, arg)
c_type = arg[:type]
arg_name = arg[:name]
@ -108,7 +110,7 @@ class CMockGeneratorUtils
unity_msg = "Function '#{function[:name]}' called with unexpected value for argument '#{arg_name}'."
return c_type, arg_name, expected, ignore, unity_func[0], unity_func[1], unity_msg
end
def code_verify_an_arg_expectation_with_no_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
lines = ""
@ -129,12 +131,12 @@ class CMockGeneratorUtils
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, \"#{unity_msg}\"); }\n"
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
end
lines << " }\n"
lines
end
def code_verify_an_arg_expectation_with_normal_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
@ -160,12 +162,12 @@ class CMockGeneratorUtils
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
end
lines << " }\n"
lines
end
def code_verify_an_arg_expectation_with_smart_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
@ -193,10 +195,10 @@ class CMockGeneratorUtils
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
end
lines << " }\n"
lines
end
end

@ -14,6 +14,10 @@
#define CMOCK_GUTS_NONE (0)
#define CMOCK_ARG_MODE CMOCK_MEM_INDEX_TYPE
#define CMOCK_ARG_ALL 0
#define CMOCK_ARG_NONE ((CMOCK_MEM_INDEX_TYPE)(~0))
//-------------------------------------------------------
// Memory API
//-------------------------------------------------------

54
targets/gcc_64.yml Normal file

@ -0,0 +1,54 @@
---
compiler:
path: gcc
source_path: &systest_generated_path 'test/system/generated/'
unit_tests_path: &unit_tests_path 'examples/test/'
mocks_path: &systest_mocks_path 'test/system/generated/'
build_path: &systest_build_path 'test/system/build/'
options:
- '-c'
- '-m64'
- '-Wall'
- '-Wunused-parameter'
- '-Wno-address'
- '-std=c99'
- '-pedantic'
includes:
prefix: '-I'
items:
- *systest_generated_path
- *unit_tests_path
- *systest_mocks_path
- 'src/'
- 'vendor/unity/src/'
- 'vendor/c_exception/lib/'
- 'test/system/test_compilation/'
- 'test/'
defines:
prefix: '-D'
items:
- 'UNITY_SUPPORT_64'
object_files:
prefix: '-o'
extension: '.o'
destination: *systest_build_path
linker:
path: gcc
options:
- -lm
- '-m64'
includes:
prefix: '-I'
object_files:
path: *systest_build_path
extension: '.o'
bin_files:
prefix: '-o'
extension: '.exe'
destination: *systest_build_path
unsupported:
- callingconv
colour: true

@ -3,12 +3,12 @@
:cmock:
:enforce_strict_ordering: 1
:treat_externs: :include
:ignore: :args_only
:plugins:
- :array
- :cexception
- :ignore
- :callback
- :expect_any_args
:systest:
:types: |
@ -28,9 +28,9 @@
int mixed(int a, int* b, int c);
void no_args(void);
:source:
:header: |
#include "CException.h"
:source:
:header: |
#include "CException.h"
void function_a(void);
void function_b(void);
void function_c(void);
@ -38,40 +38,40 @@
void function_e(void);
:code: |
void function_a(void)
void function_a(void)
{
foo(bar());
}
}
void function_b(void) {
fooa(bar());
}
void function_c(void) {
CEXCEPTION_T e;
Try {
foos(bars());
} Catch(e) { foos("err"); }
}
int function_d(void) {
int test_list[] = { 1, 2, 3, 4, 5 };
no_pointers(1, "silly");
return mixed(6, test_list, 7);
}
void function_e(void) {
foos("Hello");
foos("Tuna");
foos("Oranges");
}
:tests:
:common: |
#include "CException.h"
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'handle the situation where we pass nulls to pointers'
@ -80,10 +80,10 @@
{
bar_ExpectAndReturn(NULL);
foo_Expect(NULL);
function_a();
}
- :pass: FALSE
:should: 'handle the situation where we expected nulls to pointers but did not get that'
:code: |
@ -92,10 +92,10 @@
POINT_T pt = {1, 2};
bar_ExpectAndReturn(&pt);
foo_Expect(NULL);
function_a();
}
- :pass: FALSE
:should: 'handle the situation where we did not expect nulls to pointers but got null'
:code: |
@ -104,10 +104,10 @@
POINT_T ex = {1, 2};
bar_ExpectAndReturn(NULL);
foo_Expect(&ex);
function_a();
}
- :pass: FALSE
:should: 'handle the situation where we pass single object with expect and it is wrong'
:code: |
@ -117,10 +117,10 @@
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: |
@ -130,10 +130,10 @@
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: |
@ -143,10 +143,10 @@
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'
:code: |
@ -156,10 +156,10 @@
POINT_T ex[] = {{1, 2}, {3, 4}, {5, 6}};
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 at end'
:code: |
@ -169,7 +169,7 @@
POINT_T ex[] = {{1, 2}, {3, 4}, {5, 9}};
bar_ExpectAndReturn(pt);
foo_ExpectWithArray(ex, 3);
function_a();
}
@ -182,7 +182,7 @@
POINT_T ex = {1, 2};
bar_ExpectAndReturn(&pt);
fooa_Expect(&ex);
function_b();
}
@ -193,10 +193,10 @@
{
bars_ExpectAndReturn("This is a\0 silly string");
foos_Expect("This is a\0 wacky string");
function_c();
}
- :pass: FALSE
:should: 'handle standard c string as null terminated and not do crappy memory compares of a byte, finding failures'
:code: |
@ -204,7 +204,7 @@
{
bars_ExpectAndReturn("This is a silly string");
foos_Expect("This is a wacky string");
function_c();
}
@ -216,7 +216,7 @@
int expect_list[] = { 1, 9 };
no_pointers_Expect(1, "silly");
mixed_ExpectAndReturn(6, expect_list, 7, 13);
TEST_ASSERT_EQUAL(13, function_d());
}
@ -228,7 +228,7 @@
int expect_list[] = { 9, 1 };
no_pointers_Expect(1, "silly");
mixed_ExpectAndReturn(6, expect_list, 7, 13);
TEST_ASSERT_EQUAL(13, function_d());
}
@ -240,7 +240,7 @@
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_d());
}
@ -252,7 +252,7 @@
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_d());
}
@ -264,7 +264,7 @@
bars_ExpectAndReturn("This is a\0 silly string");
foos_ExpectAndThrow("This is a\0 wacky string", 55);
foos_Expect("err");
function_c();
}
@ -276,7 +276,7 @@
bars_ExpectAndReturn("This is a\0 silly string");
foos_ExpectAndThrow("This is a\0 wacky string", 55);
foos_Expect("wrong error");
function_c();
}
@ -288,53 +288,53 @@
int expect_list[] = { 1, 2, 3, 4, 6 };
mixed_ExpectWithArrayAndReturn(6, expect_list, 4, 7, 13);
no_pointers_Expect(1, "silly");
TEST_ASSERT_EQUAL(13, function_d());
}
- :pass: TRUE
:should: 'properly ignore first function but the other will work properly'
:should: 'properly ExpectAnyArgs first function but the other will work properly'
:code: |
test()
{
int expect_list[] = { 1, 2, 3, 4, 6 };
no_pointers_Ignore();
no_pointers_ExpectAnyArgs();
mixed_ExpectWithArrayAndReturn(6, expect_list, 4, 7, 13);
TEST_ASSERT_EQUAL(13, function_d());
}
- :pass: TRUE
:should: 'properly ignore last function but the other will work properly'
:should: 'properly ExpectAnyArgs last function but the other will work properly'
:code: |
test()
{
no_pointers_Expect(1, "silly");
mixed_IgnoreAndReturn(13);
mixed_ExpectAnyArgsAndReturn(13);
TEST_ASSERT_EQUAL(13, function_d());
}
- :pass: TRUE
:should: 'be ok if we ignore a call each because we are counting calls'
:should: 'be ok if we ExpectAnyArgs a call each because we are counting calls'
:code: |
test()
{
foos_Ignore();
foos_Ignore();
foos_Ignore();
foos_ExpectAnyArgs();
foos_ExpectAnyArgs();
foos_ExpectAnyArgs();
function_e();
}
- :pass: FALSE
:should: 'fail if we do not ignore a call once because we are counting calls'
:should: 'fail if we do not ExpectAnyArgs a call once because we are counting calls'
:code: |
test()
{
foos_Ignore();
foos_Ignore();
foos_ExpectAnyArgs();
foos_ExpectAnyArgs();
function_e();
}

@ -1,8 +1,7 @@
---
:cmock:
:plugins:
- 'ignore'
:ignore: :args_only
- 'expect_any_args'
:systest:
:types: |
@ -14,12 +13,17 @@
:source:
:header: |
int function(int a, int b, int c);
void func_b(int a);
:code: |
int function(int a, int b, int c)
{
bar(b);
return foo(a) + foo(b) + foo(c);
}
void func_b(int a)
{
bar(a);
}
:tests:
:common: |
@ -39,50 +43,50 @@
}
- :pass: TRUE
:should: 'ignore foo() calls'
:should: 'ignore foo() call details'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(10);
foo_IgnoreAndReturn(40);
foo_IgnoreAndReturn(80);
foo_ExpectAnyArgsAndReturn(10);
foo_ExpectAnyArgsAndReturn(40);
foo_ExpectAnyArgsAndReturn(80);
TEST_ASSERT_EQUAL(130, function(3, 4, 3));
}
- :pass: FALSE
:should: 'ignore foo() calls and notice if we called foo() more times than expected'
:should: 'ignore foo() call details and notice if we called foo() more times than expected'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(20);
foo_IgnoreAndReturn(30);
foo_ExpectAnyArgsAndReturn(20);
foo_ExpectAnyArgsAndReturn(30);
TEST_ASSERT_EQUAL(50, function(3, 4, 9));
}
- :pass: FALSE
:should: 'ignore foo() calls and notice if we called foo() less times than expected'
:should: 'ignore foo() call details and notice if we called foo() less times than expected'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(20);
foo_IgnoreAndReturn(10);
foo_IgnoreAndReturn(50);
foo_IgnoreAndReturn(60);
foo_ExpectAnyArgsAndReturn(20);
foo_ExpectAnyArgsAndReturn(10);
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAnyArgsAndReturn(60);
TEST_ASSERT_EQUAL(70, function(3, 4, 9));
}
- :pass: TRUE
:should: 'ignore bar() and foo() calls'
:should: 'ignore bar() and foo() call details'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(50);
foo_IgnoreAndReturn(50);
foo_IgnoreAndReturn(50);
bar_ExpectAnyArgs();
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
TEST_ASSERT_EQUAL(150, function(0, 0, 0));
}
@ -91,9 +95,9 @@
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(50);
foo_IgnoreAndReturn(50);
bar_ExpectAnyArgs();
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAndReturn(3, 50);
TEST_ASSERT_EQUAL(150, function(1, 2, 3));
}
@ -103,10 +107,10 @@
:code: |
test()
{
bar_Ignore();
bar_ExpectAnyArgs();
foo_ExpectAndReturn(1, 50);
foo_IgnoreAndReturn(50);
foo_IgnoreAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
TEST_ASSERT_EQUAL(150, function(1, 2, 3));
}
@ -115,52 +119,76 @@
:code: |
test()
{
bar_Ignore();
bar_ExpectAnyArgs();
foo_ExpectAndReturn(1, 50);
foo_IgnoreAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAndReturn(3, 50);
TEST_ASSERT_EQUAL(150, function(1, 2, 3));
}
# TODO: THIS IS WHAT PEOPLE EXPECT, BUT IS NOT BEING MET YET.
- :pass: FALSE
:should: 'be able to detect problems with an expect even when using ignores'
:code: |
test()
{
bar_Ignore();
bar_ExpectAnyArgs();
foo_ExpectAndReturn(1, 50);
foo_IgnoreAndReturn(50);
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAndReturn(4, 50);
TEST_ASSERT_EQUAL(150, function(1, 2, 3));
}
- :pass: TRUE
:should: 'be able to handle a lone ExpectAnyArg call'
:code: |
test()
{
bar_ExpectAnyArgs();
func_b(1);
}
- :pass: FALSE
:should: 'be able to handle a lone ExpectAnyArg call that does not get called'
:code: |
test()
{
bar_ExpectAnyArgs();
}
- :pass: FALSE
:should: 'be able to handle a missing ExpectAnyArg call'
:code: |
test()
{
func_b(1);
}
- :pass: TRUE
:should: 'ignore foo() calls over multiple mock calls'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(50);
foo_IgnoreAndReturn(60);
foo_IgnoreAndReturn(70);
bar_ExpectAnyArgs();
foo_ExpectAnyArgsAndReturn(50);
foo_ExpectAnyArgsAndReturn(60);
foo_ExpectAnyArgsAndReturn(70);
TEST_ASSERT_EQUAL(180, function(0, 0, 0));
bar_Ignore();
foo_IgnoreAndReturn(30);
foo_IgnoreAndReturn(80);
foo_IgnoreAndReturn(10);
bar_ExpectAnyArgs();
foo_ExpectAnyArgsAndReturn(30);
foo_ExpectAnyArgsAndReturn(80);
foo_ExpectAnyArgsAndReturn(10);
TEST_ASSERT_EQUAL(120, function(0, 0, 0));
bar_Ignore();
foo_IgnoreAndReturn(70);
foo_IgnoreAndReturn(20);
foo_IgnoreAndReturn(20);
bar_ExpectAnyArgs();
foo_ExpectAnyArgsAndReturn(70);
foo_ExpectAnyArgsAndReturn(20);
foo_ExpectAnyArgsAndReturn(20);
TEST_ASSERT_EQUAL(110, function(0, 0, 0));
}
- :pass: TRUE
:should: 'multiple cycles of expects still pass when ignores enabled'
:should: 'have multiple cycles of expects still pass when this plugin enabled'
:code: |
test()
{
@ -184,7 +212,7 @@
}
- :pass: FALSE
:should: 'multiple cycles of expects still fail when ignores enabled'
:should: 'have multiple cycles of expects still fail when this plugin enabled'
:code: |
test()
{