66 Commits

Author SHA1 Message Date
Mark VanderVoord cb1ad78b97 Update to latest Unity and Post as release 2017-11-14 16:31:44 -05:00
Mark VanderVoord 2b4f9b43c7 Merge pull request #148 from jlindgren90/master
Fix warnings when running "rake test" -- Thanks @jlindgren90 !
2017-11-01 08:26:00 -04:00
Mark VanderVoord 2a2f19dfae Merge pull request #153 from phonetagger/master
Do not change CMock_Guts_Buffer or CMock_Guts_BufferSize unless
2017-11-01 06:43:43 -04:00
Mark VanderVoord e42996ea67 Let's simplify this testing situation a bit. 2017-10-31 21:49:04 -04:00
Minich b9da6d6def Do not change CMock_Guts_Buffer or CMock_Guts_BufferSize unless
realloc() was successful. Prior to this change, if realloc() failed, the
current test would fail for out-of-memory, but subsequent tests would
continue trying to run with CMock_Guts_Buffer at address 0x00000000 and
thinking that the buffer size was sufficient. Therefore depending on the
system and how it handles (or doesn't handle) null pointer
dereferencing, subsequent tests might pass, fail in strange ways, or
crash the test app.
2017-10-31 12:03:31 -04:00
Mark VanderVoord 0fc09121d7 Merge pull request #152 from metc/bugfix/doc
Bugfix/doc Thanks @metc !
2017-10-06 12:53:34 -04:00
Christopher Métrailler 4df347bf17 Fixed 404 link in documentation. 2017-10-06 18:35:24 +02:00
Christopher Métrailler e765181c8d Remove trailing slashes. 2017-10-06 18:30:49 +02:00
John Lindgren 6d1c0f97f5 Fix Minitest deprecation warnings.
assert_equal() doesn't like to be passed nil any more.
2017-09-14 09:40:48 -04:00
John Lindgren 488c469cdf Fix Ruby warnings (mostly unused variables). 2017-09-14 09:40:48 -04:00
Mark VanderVoord 3df5c035e6 Merge pull request #149 from SteinHeselmans/master
fix #147: Push and Pop pragmas not supported by older GCC
2017-09-14 06:50:11 -04:00
Stein Heselmans 1f87c158da Adapt test cases to new header/footer 2017-09-14 10:43:43 +02:00
Stein Heselmans 76b6231f77 Merge remote-tracking branch 'origin/master' into issue-147 2017-09-14 08:14:58 +02:00
Stein Heselmans ca05fe4285 Fix #147: Push and Pop pragmas not supported by older GCC
Solution: check GCC compiler version to be at least 4.6 before enabling
pragma diagnostic push/pop
2017-09-14 08:13:17 +02:00
Mark VanderVoord 37fcb8535a Merge pull request #146 from jlindgren90/master
Fix handling of pointer-to-constant return values (Thanks @jlindgren90 !)
2017-09-13 06:53:02 -04:00
John Lindgren 526668961a Add an additional test for handling of pointer arguments. 2017-09-12 17:24:35 -04:00
John Lindgren 3b123fb533 Don't assume that pointer-to-constant types have "const" removed.
1. Update treat_as table to include pointer-to-constant types.
2. Remove unnecessary casts in assignments and return statements.
3. Improve logic for adding "const" to types of function arguments.
4. It's no longer necessary to prepend "const" to function return type.
2017-09-12 15:54:47 -04:00
John Lindgren c725e4ddc6 Handle pointer-to-constant types more consistently.
725bfd93a0 fixed handling of pointer-to-constant types in function
arguments but did not apply the same fix to function return types.
Unify the logic in a parse_type_and_name() function that is used
for both arguments and return types.  Update tests.
2017-09-12 13:02:08 -04:00
Mark VanderVoord 6e03886f25 Prepare to publish latest version 2017-09-11 15:51:44 -04:00
Mark VanderVoord 50adf82ed4 Merge pull request #144 from jlindgren90/master
Merge pull request #136 and fix merge conflicts (Thanks @jlindgren90 and @phonetagger !)
2017-09-11 15:05:13 -04:00
Mark VanderVoord f2ea4284a6 Merge pull request #145 from SteinHeselmans/master
Add suffix support to create_makefile (Thanks @SteinHeselmans and @Letme !)
2017-09-11 15:04:00 -04:00
Stein Heselmans fb96bb3033 Try to fix CI 2017-09-11 19:45:42 +02:00
Stein Heselmans 9a44444f8b Revert "Fix path issue in create makefile"
This reverts commit 725641409b.
2017-09-11 14:46:45 +02:00
Stein Heselmans 725641409b Fix path issue in create makefile 2017-09-11 14:25:14 +02:00
Stein Heselmans c4cd7d54a9 create_makefile : add support for suffix 2017-09-11 14:24:40 +02:00
Mark VanderVoord aed11e6d0d Add tests to prove that ignore and expects interoperate quite well. 2017-09-08 17:01:56 -04:00
Mark VanderVoord 51b327042f Merge in latest Unity 2017-09-08 15:49:59 -04:00
John Lindgren ef04f4ab7f Fix recent const changes to account for special (char*) handling. 2017-09-08 15:20:57 -04:00
John Lindgren 27c5a9cff5 Merge remote-tracking branch 'phonetagger/improve-const-ptr-handling' 2017-09-08 15:20:34 -04:00
Mark VanderVoord 43fa31380d - Renamed :strict_mock_calling option to :fail_on_unexpected_calls for clarity. 2017-09-08 14:54:55 -04:00
Mark VanderVoord 413c803543 Merge pull request #120 from shreyasbharath/fix-multi-threading-bug
Fixed race condition that occurs when 'requiring' plugins (Thanks @shreyasbharath !)
2017-09-08 13:12:55 -04:00
Mark VanderVoord ee45a7b1e7 Merge pull request #123 from skelliam/fixoutput
Bugfixes + improvements in makefile-based scripts (Thanks @skelliam !)
2017-09-08 13:08:27 -04:00
Mark VanderVoord 699563e503 Merge pull request #140 from jlindgren90/master
Remove dead code (unity_msg is not used since 647876644b). (Thanks @jlindgren90 )
2017-09-08 13:05:31 -04:00
Mark VanderVoord 454fcfb7a3 Merge pull request #141 from jlindgren90/fix-const-parsing
Fix const determination for pointer-to-pointer types. (Thanks John! (@jlindgren90) )
2017-09-08 13:03:27 -04:00
Mark VanderVoord 4b441eafea Merge pull request #143 from laurensmiers/master
Add 'strict_mock_calling' option (Thanks @laurensmiers for your work, and thanks @snke for your helpful input!)
2017-09-08 09:25:12 -04:00
laurensmiers a04e3f160c Expand docs with 'strict_mock_calling' option 2017-09-07 12:28:18 +02:00
laurensmiers df7c67c445 Fix 'should' text 2017-09-06 14:39:28 +02:00
laurensmiers 9c9f08c48b Add 'strict_mock_calling' option
- By default set to true to maintain the default behaviour of CMock
  - When mocked function is called and no Except/Ignor called,
    test will fail
- When set to false:
  - if test calls mocked function,
    and user did not specify Except/Ignore/...
    test will not fail because of this,
    all calls to mocked functions are ignored
2017-09-06 00:28:37 +02:00
John Lindgren 55462aef40 Fix parsing of declarations like "int const* doStuff(void)".
The "const" in this case was not correctly stripped from the return type,
leading to a double const in generated typedefs, i.e.:

  typedef const int const* (* doStuff_CALLBACK)(int cmock_num_calls);

Add a test for these cases.
2017-09-01 12:30:11 -04:00
John Lindgren 42dab4836d Fix handling of string arguments.
Since 2f0a44d7ce, string arguments were being tested with
UNITY_TEST_ASSERT_EQUAL_PTR, not UNITY_TEST_ASSERT_EQUAL_STRING.
Before that change, we would call divine_ptr(arg_type) where
arg_type had the argument name stripped, i.e. "const char *".
Now we are passing it the name as well, i.e. "const char *str"
and it was not prepared to handle that.
2017-08-31 17:44:08 -04:00
John Lindgren 693c658780 Fix const determination for pointer-to-pointer types.
For example, consider: void function(const int **ret_ptr).
This function stores a (const int *) at the address passed in.
We'd want to test it with function_ReturnThruPtr_ret_ptr, but
CMock was incorrectly considering the (const int **) a constant
argument, and thus did not generate the ReturnThruPtr function.

Add a test to ensure that all permutations of constants and
pointers work as expected.
2017-08-31 16:33:21 -04:00
John Lindgren 7eb7e14fbc Remove trailing whitespace. 2017-08-30 16:03:45 -04:00
John Lindgren 846423768b Fix whitespace checking in tests. 2017-08-30 16:01:11 -04:00
John Lindgren 9e69cfb9b1 Remove an extra newline. 2017-08-30 15:50:20 -04:00
John Lindgren 53d6a7c0e4 Remove a commented-out function (it confuses yard otherwise). 2017-08-30 15:49:14 -04:00
John Lindgren a604fb71a4 Remove dead code (unity_msg is not used since 647876644b). 2017-08-30 10:28:53 -04:00
Mark VanderVoord 46f609efee Merge pull request #139 from snke/master
Minor fixes for the CMock summary (Thanks Simon!)
2017-08-23 06:39:54 -04:00
Simon Kuhnle 5ee669ecc0 Fix minor typos in CMock summary 2017-08-23 09:22:42 +02:00
Simon Kuhnle 02aeab8fef Link to examples directory in CMock summary 2017-08-23 09:21:01 +02:00
Mark VanderVoord 9e33ff32cf Merge pull request #138 from jlindgren90/patch-1
Fix typo (typepdef/typedef) THANKS!
2017-08-22 14:43:31 -04:00
John Lindgren 295fe3be4e Fix typo (typepdef/typedef) 2017-08-22 12:26:45 -04:00
phonetagger 73a6aa003b Oops, removed duplicate line. 2017-08-22 11:28:27 -04:00
phonetagger 725bfd93a0 On some embedded platforms (real or simulated), when RAM and ROM are separate address spaces or RAM pointers are smaller than ROM pointers, the C keyword 'const' may (depending on compiler) be critical for differentiating between assembly code pointer types without having to use compiler-specific attribute flags to pick which address space a pointer refers to. (E.g. the M16C/R8C IAR C/C++ compiler in the Near (default) data model, where 'const char*' is a 3-byte pointer that can point anywhere in ROM or RAM, but 'char*' is a 2-byte pointer that can only point to RAM.)
This change causes CMock to preserve 'const' in argument types so that pointers-to-const continue to point to const data in the mocked code, while still removing the 'const' attribute from the pointers themselves.
2017-08-21 19:12:48 -04:00
Mark VanderVoord 0b303dba29 Support version 1.9.3 again (with slightly less awesome brace matching) 2017-08-18 23:46:15 -04:00
Mark VanderVoord c61a35d2a5 Merge pull request #131 from trond-snekvik/gcc_diags_fix
Push and pop GCC diagnostics to maintain scope for changed warning flags (Awesome! Thanks so much for the fix!)
2017-08-03 06:34:34 -04:00
Trond Einar Snekvik 1ffba4383c Update test header and footer to match updated contents 2017-08-03 10:08:22 +02:00
krsk 08b255868a Push and pop GCC diagnostics to maintain scope for changed warning flags 2017-08-02 13:14:09 +02:00
William Skellenger f0a9b5930e Exclude headers that start with mock_ from analysis 2017-05-04 13:15:54 -04:00
William Skellenger 33dabf8338 Without having 'test' in the results extension we cannot generate junit results,
becuase the unity_to_junit.py script (and others) look for *.result*
2017-05-04 10:07:06 -04:00
William Skellenger 7cd25b07a1 Fix problem of getting .results files with zero length 2017-05-04 09:36:12 -04:00
balaksh b58f15d0be Fixed race condition that occurs when 'requiring' plugins 2017-05-02 10:29:16 +12:00
Mark VanderVoord 58971b15db Merge pull request #117 from skelliam/mods
Leverage TEST_FILE directives when using create_makefile.rb.  Also carry over parent INCLUDE_PATH and LDFLAGS.
2017-05-01 08:57:15 -04:00
William Skellenger 4bda2b21d4 Use TEST_FILE directive in test files if it exists 2017-04-26 14:23:05 -04:00
William Skellenger 14ba424b02 Use LDFLAGS during linking if they exist. I am doing this because I want to link with code coverage options. 2017-04-26 12:54:22 -04:00
William Skellenger 6dff24ecda Use curly braces
Also replace hardcoded -DTEST with TEST_CFLAGS
2017-04-21 14:50:47 -04:00
William Skellenger 4bd12aaaf6 Add INCLUDE_PATH -- for larger projects this is necessary 2017-04-21 14:48:24 -04:00
34 changed files with 836 additions and 300 deletions
+8 -9
View File
@@ -1,29 +1,28 @@
language: ruby
os:
os:
- osx
- linux
rvm:
- "2.0.0"
- "2.2.2"
before_install:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then rvm install 2.1 && rvm use 2.1 && ruby -v; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install --assume-yes --quiet gcc-multilib; fi
install:
- bundle install
- gem install rspec
- gem install rubocop
script:
- cd test && rake ci
- cd ..
- cd examples && cd make_example
- make clean
- make setup
- make clean
- make setup
- make test
- cd ..
- cd temp_sensor
- cd temp_sensor
- rake ci
+3 -3
View File
@@ -7,17 +7,17 @@ Getting Started
================
If you're using Ceedling, there is no need to install CMock. It will handle it for you.
For everyone else, the simplest way is to grab it off github. You can also download it
For everyone else, the simplest way is to grab it off github. You can also download it
as a zip if you prefer. The Github method looks something like this:
> git clone --recursive https://github.com/throwtheswitch/cmock.git
> cd cmock
> bundle install # Ensures you have all RubyGems needed
If you plan to help with the development of CMock (or just want to verify that it can
perform its self tests on your system) then you can enter the test directory and then
ask it to test:
> rake # Run all CMock self tests
API Documentation
+76 -61
View File
@@ -68,15 +68,15 @@ Installing
==========
The first thing you need to do to install CMock is to get yourself
a copy of Ruby. If you're on linux or osx, you probably already
a copy of Ruby. If you're on linux or osx, you probably already
have it. You can prove it by typing the following:
ruby --version
If it replied in a way that implies ignorance, then you're going to
need to install it. You can go to [ruby-lang](https://ruby-lang.org)
to get the latest version. You're also going to need to do that if it
need to install it. You can go to [ruby-lang](https://ruby-lang.org)
to get the latest version. You're also going to need to do that if it
replied with a version that is older than 2.0.0. Go ahead. We'll wait.
Once you have Ruby, you have three options:
@@ -128,12 +128,12 @@ if there are some.
Array:
------
An ExpectWithArray is another variant of Expect. Like expect, it cares about
the number of times a mock is called, the arguments it is called with, and the
values it is to return. This variant has another feature, though. For anything
that resembles a pointer or array, it breaks the argument into TWO arguments.
An ExpectWithArray is another variant of Expect. Like expect, it cares about
the number of times a mock is called, the arguments it is called with, and the
values it is to return. This variant has another feature, though. For anything
that resembles a pointer or array, it breaks the argument into TWO arguments.
The first is the original pointer. The second specify the number of elements
it is to verify of that array. If you specify 1, it'll check one object. If 2,
it is to verify of that array. If you specify 1, it'll check one object. If 2,
it'll assume your pointer is pointing at the first of two elements in an array.
If you specify zero elements, it will check just the pointer if
`:smart` mode is configured or fail if `:compare_data` is set.
@@ -151,9 +151,9 @@ Maybe you don't care about the number of times a particular function is called o
the actual arguments it is called with. In that case, you want to use Ignore. Ignore
only needs to be called once per test. It will then ignore any further calls to that
particular mock. The IgnoreAndReturn works similarly, except that it has the added
benefit of knowing what to return when that call happens. If the mock is called more
benefit of knowing what to return when that call happens. If the mock is called more
times than IgnoreAndReturn was called, it will keep returning the last value without
complaint. If it's called less times, it will also ignore that. You SAID you didn't
complaint. If it's called less times, it will also ignore that. You SAID you didn't
care how many times it was called, right?
* `void func(void)` => `void func_Ignore(void)`
@@ -179,7 +179,7 @@ ReturnThruPtr:
--------------
Another option which operates on a particular argument of a function is the ReturnThruPtr
plugin. For every argument that resembles a pointer or reference, CMock generates an
plugin. For every argument that resembles a pointer or reference, CMock generates an
instance of this function. Just as the AndReturn functions support injecting one or more
return values into a queue, this function lets you specify one or more return values which
are queued up and copied into the space being pointed at each time the mock is called.
@@ -195,7 +195,7 @@ Callback:
If all those other options don't work, and you really need to do something custom, you
still have a choice. 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
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)`
@@ -211,8 +211,8 @@ where `CMOCK_func_CALLBACK` looks like: `retval func(params, int NumCalls)`
Cexception:
-----------
Finally, 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,
Finally, 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 first.
* `void func(void)` => `void func_ExpectAndThrow(value_to_throw)`
@@ -295,8 +295,8 @@ from the defaults. We've tried to specify what the defaults are below.
These are attributes that CMock should ignore for you for testing
purposes. Custom compiler extensions and externs are handy things to
put here. If your compiler is choking on some extended syntax, this
is often a good place to look.
is often a good place to look.
* defaults: ['__ramfunc', '__irq', '__fiq', 'register', 'extern']
* **note:** this option will reinsert these attributes onto the mock's calls.
If that isn't what you are looking for, check out :strippables.
@@ -306,16 +306,16 @@ from the defaults. We've tried to specify what the defaults are below.
might show up in your codebase. If it encounters something it doesn't
recognize, it's not going to mock it. We have the most common covered,
but there are many compilers out there, and therefore many other options.
* defaults: ['__stdcall', '__cdecl', '__fastcall']
* **note:** this option will reinsert these attributes onto the mock's calls.
If that isn't what you are looking for, check out :strippables.
* `:callback_after_arg_check`:
Tell `:callback` plugin to do the normal argument checking **before** it
calls the callback function by setting this to true. WHen false, the
calls the callback function by setting this to true. When false, the
callback function is called **instead** of the argument verification.
* default: false
* `:callback_include_count`:
@@ -323,14 +323,14 @@ from the defaults. We've tried to specify what the defaults are below.
number of times the callback has been called. If set to false, the
callback has the same interface as the mocked function. This can be
handy when you're wanting to use callback as a stub.
* default: true
* `:cexception_include`:
Tell `:cexception` plugin where to find CException.h... You only need to
define this if it's not in your build path already... which it usually
will be for the purpose of your builds.
* default: *nil*
* `:enforce_strict_ordering`:
@@ -339,14 +339,14 @@ from the defaults. We've tried to specify what the defaults are below.
will verify that the sizes are in the order you specified. You might
*also* want to make sure that all different functions are called in a
particular order. If so, set this to true.
* default: false
* `:framework`:
Currently the only option is `:unity.` Eventually if we support other
unity test frameworks (or if you write one for us), they'll get added
here.
: default: :unity
* `:includes`:
@@ -354,11 +354,11 @@ from the defaults. We've tried to specify what the defaults are below.
mocks. Useful for global types and definitions used in your project.
There are more specific versions if you care WHERE in the mock files
the includes get placed. You can define any or all of these options.
* `:includes`
* `:includes_h_pre_orig_header`
* `:includes_h_post_orig_header`
* `:includes_c_pre_header`
* `:includes_c_pre_header`
* `:includes_c_post_header`
* default: nil #for all 5 options
@@ -368,60 +368,60 @@ from the defaults. We've tried to specify what the defaults are below.
the time (though it tries its best). If it comes across a type it doesn't
recognize, you have a choice on how you want it to handle it. It can either
perform a raw memory comparison and report any differences, or it can fail
with a meaningful message. Either way, this feature will only happen after
with a meaningful message. Either way, this feature will only happen after
all other mechanisms have failed (The thing encountered isn't a standard
type. It isn't in the :treat_as list. It isn't in a custom unity_helper).
* default: true
* `:mock_path`:
The directory where you would like the mock files generated to be
placed.
* default: mocks
* `:mock_prefix`:
The prefix to prepend to your mock files. For example, if it's “Mock”, a file
“USART.h” will get a mock called “MockUSART.c”. This CAN be used with a suffix
at the same time.
* default: Mock
* `:mock_suffix`:
The suffix to append to your mock files. For example, it it's "_Mock", a file
"USART.h" will get a mock called "USART_Mock.h". This CAN be used with a prefix
at the same time.
* default: ""
* `:plugins`:
An array of which plugins to enable. ':expect' is always active. Also
available currently:
* `:ignore`
* `:ignore_arg`
* `:ignore`
* `:ignore_arg`
* `:expect_any_args`
* `:array`
* `:cexception`
* `:callback`
* `:cexception`
* `:callback`
* `:return_thru_ptr`
* `:strippables`:
An array containing a list of items to remove from the header
before deciding what should be mocked. This can be something simple
like a compiler extension CMock wouldn't recognize, or could be a
regex to reject certain function name patterns. This is a great way to
regex to reject certain function name patterns. This is a great way to
get rid of compiler extensions when your test compiler doesn't support
them. For example, use `:strippables: ['(?:functionName\s*\(+.*?\)+)']`
to prevent a function `functionName` from being mocked. By default, it
is ignoring all gcc attribute extensions.
* default: ['(?:__attribute__\s*\(+.*?\)+)']
* `:subdir`:
This is a relative subdirectory for your mocks. Set this to e.g. "sys" in
This is a relative subdirectory for your mocks. Set this to e.g. "sys" in
order to create a mock for `sys/types.h` in `(:mock_path)/sys/`.
* default: ""
* `:treat_as`:
@@ -432,11 +432,11 @@ from the defaults. We've tried to specify what the defaults are below.
did that one for you). Maybe you have a type that is a pointer to an
array of unsigned characters? No problem, just add 'UINT8_T*' =>
'HEX8*'
* NOTE: unlike the other options, your specifications MERGE with the
* NOTE: unlike the other options, your specifications MERGE with the
default list. Therefore, if you want to override something, you must
reassign it to something else (or to *nil* if you don't want it)
* default:
* 'int': 'INT'
* 'char': 'INT8'
@@ -483,14 +483,14 @@ from the defaults. We've tried to specify what the defaults are below.
We've seen "fun" legacy systems typedef 'void' with a custom type,
like MY_VOID. Add any instances of those to this list to help CMock
understand how to deal with your code.
* default: []
* `:treat_externs`:
This specifies how you want CMock to handle functions that have been
marked as extern in the header file. Should it mock them?
* `:include` will mock externed functions
* `:include` will mock externed functions
* `:exclude` will ignore externed functions (default).
* `:unity_helper_path`:
@@ -500,23 +500,23 @@ from the defaults. We've tried to specify what the defaults are below.
trick is that you make sure you follow the naming convention:
`UNITY_TEST_ASSERT_EQUAL_YourType`. If it finds macros of the right
shape that match that pattern, it'll use them.
* default: []
* `:verbosity`:
How loud shoudl CMock be?
How loud should CMock be?
* 0 for errors only
* 1 for errors and warnings
* 2 for normal (default)
* 2 for normal (default)
* 3 for verbose
* `:weak`:
When set this to some value, the generated mocks are defined as weak
When set this to some value, the generated mocks are defined as weak
symbols using the configured format. This allows them to be overridden
in particular tests.
* Set to '__attribute ((weak))' for weak mocks when using GCC.
in particular tests.
* Set to '__attribute ((weak))' for weak mocks when using GCC.
* Set to any non-empty string for weak mocks when using IAR.
* default: ""
@@ -525,7 +525,7 @@ from the defaults. We've tried to specify what the defaults are below.
it, it usually contains function prototypes (otherwise what was the
point?). You can control what happens when this isn't true. You can
set this to `:warn,` `:ignore,` or `:error`
* default: :warn
* `:when_ptr`:
@@ -538,15 +538,30 @@ from the defaults. We've tried to specify what the defaults are below.
single element of what is being pointed to. So if you have a pointer
to a struct called ORGAN_T, it will compare one ORGAN_T (whatever that
is).
* default: :smart
* `:fail_on_unexpected_calls`:
By default, CMock will fail a test if a mock is called without _Expect and _Ignore
called first. While this forces test writers to be more explicit in their expectations,
it can clutter tests with _Expect or _Ignore calls for functions which are not the focus
of the test. While this is a good indicator that this module should be refactored, some
users are not fans of the additional noise.
Therefore, :fail_on_unexpected_calls can be set to false to force all mocks to start with
the assumption that they are operating as _Ignore unless otherwise specified.
* default: true
* **note:**
If this option is disabled, the mocked functions will return
a default value (0) when called (and only if they have to return something of course).
Compiled Options:
-----------------
A number of #defines also exist for customizing the cmock experience.
Feel free to pass these into your compiler or whatever is most
Feel free to pass these into your compiler or whatever is most
convenient. CMock will otherwise do its best to guess what you want
based on other settings, particularly Unity's settings.
@@ -580,9 +595,9 @@ based on other settings, particularly Unity's settings.
Examples
========
You can look in the examples directory for a couple of examples on how
You can look in the [examples directory](/examples/) for a couple of examples on how
you might tool CMock into your build process. You may also want to consider
using [Ceedling](https://throwtheswitch.org/Ceedling). Please note that
these examples are meant to show how the build process works. They have
using [Ceedling](https://throwtheswitch.org/ceedling). Please note that
these examples are meant to show how the build process works. They have
failing tests ON PURPOSE to show what that would look like. Don't be alarmed. ;)
+5
View File
@@ -19,6 +19,7 @@ class CMockConfig
:attributes => ['__ramfunc', '__irq', '__fiq', 'register', 'extern'],
:c_calling_conventions => ['__stdcall', '__cdecl', '__fastcall'],
:enforce_strict_ordering => false,
:fail_on_unexpected_calls => true,
:unity_helper_path => false,
:treat_as => {},
:treat_as_void => [],
@@ -119,6 +120,8 @@ class CMockConfig
'UINT32' => 'HEX32',
'UINT32_T' => 'HEX32',
'void*' => 'HEX8_ARRAY',
'void const*' => 'HEX8_ARRAY',
'const void*' => 'HEX8_ARRAY',
'unsigned short' => 'HEX16',
'uint16' => 'HEX16',
'uint16_t' => 'HEX16',
@@ -130,6 +133,8 @@ class CMockConfig
'UINT8' => 'HEX8',
'UINT8_T' => 'HEX8',
'char*' => 'STRING',
'char const*' => 'STRING',
'const char*' => 'STRING',
'pCHAR' => 'STRING',
'cstring' => 'STRING',
'CSTRING' => 'STRING',
+18 -3
View File
@@ -18,6 +18,7 @@ class CMockGenerator
@weak = @config.weak
@ordered = @config.enforce_strict_ordering
@framework = @config.framework.to_s
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
@subdir = @config.subdir
@@ -102,6 +103,9 @@ class CMockGenerator
file << "\n"
file << "/* Ignore the following warnings, since we are copying code */\n"
file << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n"
file << "#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n"
file << "#pragma GCC diagnostic push\n"
file << "#endif\n"
file << "#if !defined(__clang__)\n"
file << "#pragma GCC diagnostic ignored \"-Wpragmas\"\n"
file << "#endif\n"
@@ -124,7 +128,14 @@ class CMockGenerator
end
def create_mock_header_footer(header)
header << "\n#endif\n"
header << "\n"
header << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n"
header << "#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n"
header << "#pragma GCC diagnostic pop\n"
header << "#endif\n"
header << "#endif\n"
header << "\n"
header << "#endif\n"
end
def create_source_header_section(file, filename, functions)
@@ -196,6 +207,11 @@ class CMockGenerator
file << " CMock_Guts_MemFreeAll();\n"
file << " memset(&Mock, 0, sizeof(Mock));\n"
file << functions.collect {|function| @plugins.run(:mock_destroy, function)}.join
unless (@fail_on_unexpected_calls)
file << functions.collect {|function| @plugins.run(:mock_ignore, function)}.join
end
if (@ordered)
file << " GlobalExpectCount = 0;\n"
file << " GlobalVerifyOrder = 0;\n"
@@ -235,10 +251,9 @@ class CMockGenerator
file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n"
file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledLate);\n"
end
return_type = function[:return][:const?] ? "(const #{function[:return][:type]})" : ((function[:return][:type] =~ /cmock/) ? "(#{function[:return][:type]})" : '')
file << @plugins.run(:mock_implementation, function)
file << " UNITY_CLR_DETAILS();\n"
file << " return #{return_type}cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?])
file << " return cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?])
file << "}\n\n"
end
+4 -4
View File
@@ -27,8 +27,8 @@ class CMockGeneratorPluginArray
return nil unless function[:contains_ptr?]
args_call = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : "#{m[:name]}"}.join(', ')
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]}"
type = @utils.arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
end.join(', ')
if (function[:return][:void?])
return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" +
@@ -44,8 +44,8 @@ class CMockGeneratorPluginArray
lines = []
func_name = function[:name]
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]}"
type = @utils.arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
end.join(', ')
call_string = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name]}.join(', ')
if (function[:return][:void?])
+9 -11
View File
@@ -33,7 +33,7 @@ class CMockGeneratorPluginCallback
def mock_function_declarations(function)
func_name = function[:name]
return_type = function[:return][:const?] ? "const #{function[:return][:type]}" : function[:return][:type]
return_type = function[:return][:type]
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2)
styles = [ "void", "int cmock_num_calls", function[:args_string], "#{function[:args_string]}, int cmock_num_calls" ]
"typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\nvoid #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback);\n"
@@ -41,7 +41,6 @@ class CMockGeneratorPluginCallback
def mock_implementation_for_callbacks_after_arg_check(function)
func_name = function[:name]
return_cast = function[:return][:const?] ? "(#{function[:return][:type]})" : ""
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) | (function[:return][:void?] ? 0 : 4)
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" +
case(style)
@@ -49,16 +48,15 @@ class CMockGeneratorPluginCallback
when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n"
when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n"
when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n"
when 4 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer();\n }\n"
when 5 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n"
when 6 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n"
when 7 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n"
when 4 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer();\n }\n"
when 5 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n"
when 6 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n"
when 7 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n"
end
end
def mock_implementation_for_callbacks_without_arg_check(function)
func_name = function[:name]
return_cast = function[:return][:const?] ? "(#{function[:return][:type]})" : ""
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) | (function[:return][:void?] ? 0 : 4)
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" +
case(style)
@@ -66,10 +64,10 @@ class CMockGeneratorPluginCallback
when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n return;\n }\n"
when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n return;\n }\n"
when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n return;\n }\n"
when 4 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer();\n }\n"
when 5 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n"
when 6 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n"
when 7 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n"
when 4 then " return Mock.#{func_name}_CallbackFunctionPointer();\n }\n"
when 5 then " return Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n"
when 6 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n"
when 7 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n"
end
end
-1
View File
@@ -41,7 +41,6 @@ class CMockGeneratorPluginCexception
def mock_interfaces(function)
arg_insert = (function[:args_string] == "void") ? "" : "#{function[:args_string]}, "
call_string = function[:args].map{|m| m[:name]}.join(', ')
[ "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n",
@utils.code_add_base_expectation(function[:name]),
@utils.code_call_argument_loader(function),
+1 -1
View File
@@ -68,7 +68,7 @@ class CMockGeneratorPluginExpect
function[:args].each do |arg|
lines << @utils.code_verify_an_arg_expectation(function, arg)
end
lines << "\n }\n"
lines << " }\n"
lines
end
@@ -28,7 +28,6 @@ class CMockGeneratorPluginExpectAnyArgs
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"
@@ -38,19 +37,6 @@ class CMockGeneratorPluginExpectAnyArgs
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?])
# return_type = function[:return][:const?] ? "(const #{function[:return][:type]})" : ((function[:return][:type] =~ /cmock/) ? "(#{function[:return][:type]})" : '')
# lines << " return #{return_type}cmock_call_instance->ReturnVal;\n }\n"
# end
# lines
# end
def mock_interfaces(function)
lines = ""
if (function[:return][:void?])
+6 -3
View File
@@ -40,10 +40,9 @@ class CMockGeneratorPluginIgnore
lines << " return;\n }\n"
else
retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} )
return_type = function[:return][:const?] ? "(const #{function[:return][:type]})" : ((function[:return][:type] =~ /cmock/) ? "(#{function[:return][:type]})" : '')
lines << " if (cmock_call_instance == NULL)\n return #{return_type}Mock.#{function[:name]}_FinalReturn;\n"
lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n"
lines << " " + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless (retval[:void?])
lines << " return #{return_type}cmock_call_instance->ReturnVal;\n }\n"
lines << " return cmock_call_instance->ReturnVal;\n }\n"
end
lines
end
@@ -65,6 +64,10 @@ class CMockGeneratorPluginIgnore
lines << "}\n\n"
end
def mock_ignore(function)
" Mock.#{function[:name]}_IgnoreBool = (int) 1;\n"
end
def mock_verify(function)
func_name = function[:name]
" if (Mock.#{func_name}_IgnoreBool)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n"
+2 -4
View File
@@ -29,14 +29,12 @@ class CMockGeneratorPluginIgnoreArg
lines = []
func_name = function[:name]
function[:args].each do |arg|
arg_name = arg[:name]
arg_type = arg[:type]
lines << "void #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n"
lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n"
lines << "{\n"
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " +
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n"
lines << " cmock_call_instance->IgnoreArg_#{arg_name} = 1;\n"
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 1;\n"
lines << "}\n\n"
end
lines
@@ -40,7 +40,6 @@ class CMockGeneratorPluginReturnThruPtr
func_name = function[:name]
function[:args].each do |arg|
arg_name = arg[:name]
arg_type = arg[:type]
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, int cmock_size)\n"
lines << "{\n"
@@ -60,7 +59,6 @@ class CMockGeneratorPluginReturnThruPtr
lines = []
function[:args].each do |arg|
arg_name = arg[:name]
arg_type = arg[:type]
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
lines << " {\n"
+20 -8
View File
@@ -22,6 +22,19 @@ class CMockGeneratorUtils
@helpers = helpers
end
def self.arg_type_with_const(arg)
# Restore any "const" that was removed in header parsing
if arg[:type].include?('*')
arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type]
else
arg[:const?] ? "const #{arg[:type]}" : arg[:type]
end
end
def arg_type_with_const(arg)
self.class.arg_type_with_const(arg)
end
def code_verify_an_arg_expectation(function, arg)
if (@arrays)
case(@ptr_handling)
@@ -58,7 +71,7 @@ class CMockGeneratorUtils
def code_assign_argument_quickly(dest, arg)
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
" #{dest} = #{arg[:const?] ? "(#{arg[:type]})" : ''}#{arg[:name]};\n"
" #{dest} = #{arg[:name]};\n"
else
" memcpy(&#{dest}, &#{arg[:name]}, sizeof(#{arg[:type]}));\n"
end
@@ -68,8 +81,8 @@ class CMockGeneratorUtils
if (function[:args_string] != "void")
if (@arrays)
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]}"
type = arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
end.join(', ')
"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) ) } +
@@ -112,12 +125,11 @@ class CMockGeneratorUtils
else
(@helpers.nil? or @helpers[:unity_helper].nil?) ? ["UNITY_TEST_ASSERT_EQUAL",''] : @helpers[:unity_helper].get_helper(c_type)
end
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
return c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]
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)
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
lines = ""
lines << " if (!#{ignore})\n" if @ignore_arg
lines << " {\n"
@@ -152,7 +164,7 @@ class CMockGeneratorUtils
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)
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
lines = ""
lines << " if (!#{ignore})\n" if @ignore_arg
@@ -188,7 +200,7 @@ class CMockGeneratorUtils
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)
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
lines = ""
lines << " if (!#{ignore})\n" if @ignore_arg
+80 -57
View File
@@ -6,12 +6,13 @@
class CMockHeaderParser
attr_accessor :funcs, :c_attributes, :treat_as_void, :treat_externs
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs
def initialize(cfg)
@funcs = []
@c_strippables = cfg.strippables
@c_attributes = (['const'] + cfg.attributes).uniq
@c_attr_noconst = cfg.attributes.uniq - ['const']
@c_attributes = ['const'] + c_attr_noconst
@c_calling_conventions = cfg.c_calling_conventions.uniq
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
@declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m
@@ -79,7 +80,7 @@ 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|typepdef)[\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
source.gsub!(/(\W)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
@@ -94,7 +95,14 @@ class CMockHeaderParser
end
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
source.gsub!(/\{([^\{\}]*|\g<0>)*\}/m, '{ }')
if (RUBY_VERSION.split('.')[0].to_i > 1)
#we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
r = "\\{([^\\{\\}]*|\\g<0>)*\\}"
source.gsub!(/#{r}/m, '{ }')
else
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
end
end
# remove function definitions by stripping off the arguments right now
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ";")
@@ -132,51 +140,77 @@ class CMockHeaderParser
return funcs
end
def parse_type_and_name(arg)
# Split up words and remove known attributes. For pointer types, make sure
# to remove 'const' only when it applies to the pointer itself, not when it
# applies to the type pointed to. For non-pointer types, remove any
# occurrence of 'const'.
arg.gsub!(/(\w)\*/,'\1 *') # pull asterisks away from preceding word
arg.gsub!(/\*(\w)/,'* \1') # pull asterisks away from following word
arg_array = arg.split
arg_info = divine_ptr_and_const(arg)
arg_info[:name] = arg_array[-1]
attributes = arg.include?('*') ? @c_attr_noconst : @c_attributes
attr_array = []
type_array = []
arg_array[0..-2].each do |word|
if attributes.include?(word)
attr_array << word
elsif @c_calling_conventions.include?(word)
arg_info[:c_calling_convention] = word
else
type_array << word
end
end
if arg_info[:const_ptr?]
attr_array << 'const'
type_array.delete_at(type_array.rindex('const'))
end
arg_info[:modifier] = attr_array.join(' ')
arg_info[:type] = type_array.join(' ').gsub(/\s+\*/,'*') # remove space before asterisks
return arg_info
end
def parse_args(arg_list)
args = []
arg_list.split(',').each do |arg|
arg.strip!
return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ...
arg_array = arg.split
arg_elements = arg_array - @c_attributes # split up words and remove known attributes
args << { :type => (arg_type = arg_elements[0..-2].join(' ')),
:name => arg_elements[-1]
}.merge(divine_ptr_and_const(arg))
arg_info = parse_type_and_name(arg)
arg_info.delete(:modifier) # don't care about this
arg_info.delete(:c_calling_convention) # don't care about this
args << arg_info
end
return args
end
def divine_ptr(arg_type)
return false unless arg_type.include? '*'
return false if arg_type.gsub(/(const|char|\*|\s)+/,'').empty?
def divine_ptr(arg)
return false unless arg.include? '*'
# treat "const char *" and similar as a string, not a pointer
return false if /(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg
return true
end
def divine_const(arg)
return false if !(/(?:^|\s|\*)const(?:\*|\s|$)/ =~ arg) # check for const as part of a larger word
return true if (/const(?:\w|\s)*\*/ =~ arg) # check const comes before * indicating const data
return false if (/\*\s*const/ =~ arg) # check const comes after * indicating const ptr
return true
# a non-pointer arg containing "const" is a constant
# an arg containing "const" before the last * is a pointer to a constant
return ( arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg)
: (/(^|\s)const(\s|$)/ =~ arg) ) ? true : false
end
def divine_ptr_and_const(arg)
divination = { :ptr? => false, :const? => false, :const_ptr? => false }
divination = {}
#first check if there is a pointer present and that it's not part of a C string or function definition
#divination[:ptr?] = (arg.split[0..-2].join.include?('*') && !arg.gsub(/(const|char|\*|\s)+/,'').empty?)
divination[:ptr?] = (arg.include?('*') && !arg.gsub(/(const|char|\*|\s)+/,'').empty?)
divination[:ptr?] = divine_ptr(arg)
divination[:const?] = divine_const(arg)
#if there isn't a const that isn't part of a larger word, we're done
return divination if !(/(?:^|\s|\*)const(?:\*|\s|$)/ =~ arg)
divination[:const?] = true
# check const comes after * indicating const ptr
if (/\*\s*const/ =~ arg)
divination[:const_ptr?] = true
#check const comes before * indicating also const data
divination[:const?] = (/const(?:\w|\s)*\*/ =~ arg) ? true : false
end
# an arg containing "const" after the last * is a constant pointer
divination[:const_ptr?] = (/\*(?!.*\*)\s*const(\s|$)/ =~ arg) ? true : false
return divination
end
@@ -229,35 +263,24 @@ class CMockHeaderParser
args = regex_match[2].strip
#process function attributes, return type, and name
descriptors = regex_match[1]
descriptors.gsub!(/\s+\*/,'*') #remove space to place asterisks with return type (where they belong)
descriptors.gsub!(/\*(\w)/,'* \1') #pull asterisks away from function name to place asterisks with return type (where they belong)
descriptors = descriptors.split #array of all descriptor strings
parsed = parse_type_and_name(regex_match[1])
#grab name
decl[:name] = descriptors[-1] #snag name as last array item
#build attribute and return type strings
decl[:modifier] = []
rettype = []
full_retval = descriptors[0..-2].join(' ')
descriptors[0..-2].each do |word|
if @c_attributes.include?(word)
decl[:modifier] << word
elsif @c_calling_conventions.include?(word)
decl[:c_calling_convention] = word
else
rettype << word
end
decl[:name] = parsed[:name]
decl[:modifier] = parsed[:modifier]
unless parsed[:c_calling_convention].nil?
decl[:c_calling_convention] = parsed[:c_calling_convention]
end
decl[:modifier] = decl[:modifier].join(' ')
rettype = rettype.join(' ')
rettype = parsed[:type]
rettype = 'void' if (@local_as_void.include?(rettype.strip))
decl[:return] = { :type => rettype,
:name => 'cmock_to_return',
:str => "#{rettype} cmock_to_return",
:void? => (rettype == 'void')
}.merge(divine_ptr_and_const(full_retval))
decl[:return] = { :type => rettype,
:name => 'cmock_to_return',
:str => "#{rettype} cmock_to_return",
:void? => (rettype == 'void'),
:ptr? => parsed[:ptr?],
:const? => parsed[:const?],
:const_ptr? => parsed[:const_ptr?]
}
#remove default argument statements from mock definitions
args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ')
+27 -12
View File
@@ -2,30 +2,25 @@
# 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]
# ==========================================
# ==========================================
require 'thread'
class CMockPluginManager
attr_accessor :plugins
def initialize(config, utils)
@plugins = []
plugins_to_load = [:expect, config.plugins].flatten.uniq.compact
plugins_to_load.each do |plugin|
plugin_name = plugin.to_s
object_name = "CMockGeneratorPlugin" + camelize(plugin_name)
begin
unless (Object.const_defined? object_name)
require "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
end
@plugins << eval("#{object_name}.new(config, utils)")
rescue
raise "ERROR: CMock unable to load plugin '#{plugin_name}'"
end
self.class.plugin_require_mutex.synchronize { load_plugin(plugin_name, object_name, config, utils) }
end
@plugins.sort! {|a,b| a.priority <=> b.priority }
end
def run(method, args=nil)
if args.nil?
return @plugins.collect{ |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join
@@ -33,8 +28,28 @@ class CMockPluginManager
return @plugins.collect{ |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join
end
end
def camelize(lower_case_and_underscored_word)
lower_case_and_underscored_word.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
end
private
def self.plugin_require_mutex
@mutex ||= Mutex.new
end
def load_plugin(plugin_name, object_name, config, utils)
begin
unless (Object.const_defined? object_name)
file_name = "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
require file_name
end
class_name = Object.const_get(object_name)
@plugins << class_name.new(config, utils)
rescue
file_name = "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
raise "ERROR: CMock unable to load plugin '#{plugin_name}' '#{object_name}' #{file_name}"
end
end
end
+1 -1
View File
@@ -1,2 +1,2 @@
215
217
+1 -1
View File
@@ -1,2 +1,2 @@
2.4.4
2.4.6
+42 -17
View File
@@ -18,8 +18,9 @@ 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_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_MATCHER = /#{MOCK_PREFIX}[A-Za-z_][A-Za-z0-9_\-\.]+#{MOCK_SUFFIX}/
[TEST_BUILD_DIR, OBJ_DIR, RUNNERS_DIR, MOCKS_DIR, TEST_BIN_DIR].each do |dir|
FileUtils.mkdir_p dir
@@ -58,7 +59,8 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
test_sources = Dir["#{TEST_DIR}/**/test_*.c"]
test_targets = []
generator = UnityTestRunnerGenerator.new
all_headers = Dir["#{SRC_DIR}/**/*.h"]
all_headers = Dir["#{SRC_DIR}/**/{[!#{MOCK_PREFIX}]}*{[!#{MOCK_SUFFIX}]}.h"] #headers that begin with prefix or end with suffix are not included
makefile_targets = []
test_sources.each do |test|
module_name = File.basename(test, '.c')
@@ -67,14 +69,39 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
runner_source = File.join(RUNNERS_DIR, "runner_#{module_name}.c")
runner_obj = File.join(OBJ_DIR, "runner_#{module_name}.o")
test_bin = File.join(TEST_BIN_DIR, module_name)
test_results = File.join(TEST_BIN_DIR, module_name + '.result')
test_results = File.join(TEST_BIN_DIR, module_name + '.testresult')
cfg = {
src: test,
includes: generator.find_includes(File.readlines(test).join(''))
}
# Build main project modules, with TEST defined
module_src = File.join(SRC_DIR, "#{src_module_name}.c")
module_obj = File.join(OBJ_DIR, "#{src_module_name}.o")
mkfile.puts "#{module_obj}: #{module_src}"
mkfile.puts "\t${CC} -o $@ -c $< -DTEST -I #{SRC_DIR}"
mkfile.puts ""
if not makefile_targets.include? module_obj
makefile_targets.push(module_obj)
mkfile.puts "#{module_obj}: #{module_src}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{SRC_DIR} ${INCLUDE_PATH}"
mkfile.puts ""
end
# process link-only files
linkonly = cfg[:includes][:linkonly]
linkonly_objs = []
linkonly.each do |linkonlyfile|
linkonlybase = File.basename(linkonlyfile)
linkonlymodule_src = File.join(SRC_DIR, "#{linkonlyfile}.c")
linkonlymodule_obj = File.join(OBJ_DIR, "#{linkonlybase}.o")
linkonly_objs.push(linkonlymodule_obj)
#only create the target if we didn't already
if not makefile_targets.include? linkonlymodule_obj
makefile_targets.push(linkonlymodule_obj)
mkfile.puts "#{linkonlymodule_obj}: #{linkonlymodule_src}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{SRC_DIR} ${INCLUDE_PATH}"
mkfile.puts ""
end
end
# Create runners
mkfile.puts "#{runner_source}: #{test}"
@@ -83,17 +110,14 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
# Build runner
mkfile.puts "#{runner_obj}: #{runner_source}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{SRC_DIR} -I #{MOCKS_DIR} -I #{UNITY_SRC} -I #{CMOCK_SRC}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{SRC_DIR} -I #{MOCKS_DIR} -I #{UNITY_SRC} -I #{CMOCK_SRC} ${INCLUDE_PATH}"
mkfile.puts ""
# Collect mocks to generate
cfg = {
src: test,
includes: generator.find_includes(File.readlines(test).join(''))
}
system_mocks = cfg[:includes][:system].select{|name| name =~ MOCK_MATCHER}
raise "Mocking of system headers is not yet supported!" if !system_mocks.empty?
local_mocks = cfg[:includes][:local].select{|name| name =~ MOCK_MATCHER}
module_names_to_mock = local_mocks.map{|name| "#{name.sub(/#{MOCK_PREFIX}/,'')}.h"}
headers_to_mock = []
module_names_to_mock.each do |name|
@@ -107,6 +131,7 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
raise "Module header '#{name}' not found to mock!" unless header_to_mock
headers_to_mock << header_to_mock
end
all_headers_to_mock += headers_to_mock
mock_objs = headers_to_mock.map do |hdr|
mock_name = MOCK_PREFIX + File.basename(hdr, '.h')
@@ -116,18 +141,18 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
# Build test suite
mkfile.puts "#{test_obj}: #{test} #{module_obj} #{mock_objs.join(' ')}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{SRC_DIR} -I #{UNITY_SRC} -I #{CMOCK_SRC} -I #{MOCKS_DIR}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{SRC_DIR} -I #{UNITY_SRC} -I #{CMOCK_SRC} -I #{MOCKS_DIR} ${INCLUDE_PATH}"
mkfile.puts ""
# Build test suite executable
test_objs = "#{test_obj} #{runner_obj} #{module_obj} #{mock_objs.join(' ')} #{UNITY_OBJ} #{CMOCK_OBJ}"
test_objs = "#{test_obj} #{runner_obj} #{module_obj} #{mock_objs.join(' ')} #{linkonly_objs.join(' ')} #{UNITY_OBJ} #{CMOCK_OBJ}"
mkfile.puts "#{test_bin}: #{test_objs}"
mkfile.puts "\t${CC} -o $@ #{test_objs}"
mkfile.puts "\t${CC} -o $@ ${LDFLAGS} #{test_objs}"
mkfile.puts ""
# Run test suite and generate report
mkfile.puts "#{test_results}: #{test_bin}"
mkfile.puts "\t-#{test_bin} &> #{test_results}"
mkfile.puts "\t-#{test_bin} > #{test_results} 2>&1"
mkfile.puts ""
test_targets << test_bin
@@ -145,7 +170,7 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
mkfile.puts ""
mkfile.puts "#{mock_obj}: #{mock_src} #{mock_header}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{MOCKS_DIR} -I #{SRC_DIR} -I #{UNITY_SRC} -I #{CMOCK_SRC}"
mkfile.puts "\t${CC} -o $@ -c $< ${TEST_CFLAGS} -I #{MOCKS_DIR} -I #{SRC_DIR} -I #{UNITY_SRC} -I #{CMOCK_SRC} ${INCLUDE_PATH}"
mkfile.puts ""
end
@@ -157,7 +182,7 @@ File.open(TEST_MAKEFILE, "w") do |mkfile|
mkfile.puts ""
# Create target to run all tests
mkfile.puts "test: #{test_targets.map{|t| t + '.result'}.join(' ')} test_summary"
mkfile.puts "test: #{test_targets.map{|t| t + '.testresult'}.join(' ')} test_summary"
mkfile.puts ""
end
+1 -1
View File
@@ -7,7 +7,7 @@ begin
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}/*.result"]
results = Dir["#{test_build_dir}/*.testresult"]
parser = UnityTestSummary.new
parser.targets = results
parser.run
+11 -6
View File
@@ -48,12 +48,17 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
{
#ifdef CMOCK_MEM_DYNAMIC
CMock_Guts_BufferSize += CMOCK_MEM_SIZE + size;
CMock_Guts_Buffer = realloc(CMock_Guts_Buffer, (size_t)CMock_Guts_BufferSize);
if (CMock_Guts_Buffer == NULL)
#endif //yes that if will continue to the return below if TRUE
return CMOCK_GUTS_NONE;
#ifndef CMOCK_MEM_DYNAMIC
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;
#endif
}
//determine where we're putting this new block, and init its pointer to be the end of the line
@@ -159,4 +159,171 @@
TEST_ASSERT_EQUAL(110, function(0, 8, 9));
}
- :pass: FALSE
:should: 'With "fail_on_unexpected_calls" enabled, Expect/Ignore/... of bar is required and test fails.'
:code: |
test()
{
function(1, 2, 3);
}
- :pass: TRUE
:should: 'we can override an ignore with an expect and pass'
:code: |
test()
{
bar_Ignore();
bar_Expect(2);
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(8);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: FALSE
:should: 'we can override an ignore with an expect and fail'
:code: |
test()
{
bar_Ignore();
bar_Expect(2);
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(9);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: TRUE
:should: 'we can override an ignore and return with an expect and pass'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(30);
TEST_ASSERT_EQUAL(90, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(8);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: FALSE
:should: 'we can override an ignore and return with an expect and fail'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(0);
TEST_ASSERT_EQUAL(0, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(9);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: TRUE
:should: 'we can override an an expect with an ignore'
:code: |
test()
{
bar_Expect(5);
bar_Ignore();
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
}
- :pass: TRUE
:should: 'we can override an expect with an ignore and return and pass'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(0);
TEST_ASSERT_EQUAL(0, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_IgnoreAndReturn(10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Ignore();
foo_IgnoreAndReturn(60);
TEST_ASSERT_EQUAL(180, function(7, 8, 9));
}
- :pass: FALSE
:should: 'we can override an expect with an ignore and return and fail after'
:code: |
test()
{
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 50);
foo_IgnoreAndReturn(20);
TEST_ASSERT_EQUAL(100, function(4, 5, 6));
bar_Expect(5);
foo_ExpectAndReturn(9, 30); //THIS ONE WILL FAIL
foo_ExpectAndReturn(2, 80);
foo_ExpectAndReturn(3, 60);
TEST_ASSERT_EQUAL(170, function(1, 2, 3));
}
- :pass: TRUE
:should: 'we can override an expect with an ignore and return and the expected values are ignored'
:code: |
test()
{
bar_Expect(5);
foo_ExpectAndReturn(2, 30); //NOTE THIS WOULD NORMALLY FAIL
foo_ExpectAndReturn(5, 50);
foo_IgnoreAndReturn(20); //BUT WE SAID WE NO LONGER CARE
TEST_ASSERT_EQUAL(100, function(4, 5, 6));
}
...
@@ -0,0 +1,37 @@
---
:cmock:
:plugins:
- 'ignore'
:fail_on_unexpected_calls: FALSE
:systest:
:types: |
:mockable: |
int foo(int a);
void bar(int b);
:source:
:header: |
int function(int a, int b, int c);
:code: |
int function(int a, int b, int c)
{
bar(b);
return foo(a) + foo(b) + foo(c);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'With "fail_on_unexpected_calls" disabled, Expect/Ignore/... of bar is NOT required.'
:code: |
test()
{
function(1, 2, 3);
}
...
+11 -10
View File
@@ -24,20 +24,21 @@ end
def test_return
{
:int => {:type => "int", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => false, :str => 'int cmock_to_return'},
:int_ptr => {:type => "int*", :name => 'cmock_to_return', :ptr? => true, :const? => false, :void? => false, :str => 'int* cmock_to_return'},
:void => {:type => "void", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => true, :str => 'void cmock_to_return'},
:string => {:type => "char*", :name => 'cmock_to_return', :ptr? => false, :const? => true, :void? => false, :str => 'const char* cmock_to_return'},
:int => {:type => "int", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => false, :str => 'int cmock_to_return'},
:int_ptr => {:type => "int*", :name => 'cmock_to_return', :ptr? => true, :const? => false, :void? => false, :str => 'int* cmock_to_return'},
:void => {:type => "void", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => true, :str => 'void cmock_to_return'},
:string => {:type => "const char*", :name => 'cmock_to_return', :ptr? => false, :const? => true, :void? => false, :str => 'const char* cmock_to_return'},
}
end
def test_arg
{
:int => {:type => "int", :name => 'MyInt', :ptr? => false, :const? => false},
:int_ptr => {:type => "int*", :name => 'MyIntPtr', :ptr? => true, :const? => false},
:mytype => {:type => "MY_TYPE", :name => 'MyMyType', :ptr? => false, :const? => true},
:mytype_ptr => {:type => "MY_TYPE*", :name => 'MyMyTypePtr', :ptr? => true, :const? => false},
:string => {:type => "char*", :name => 'MyStr', :ptr? => false, :const? => true},
:int => {:type => "int", :name => 'MyInt', :ptr? => false, :const? => false, :const_ptr? => false},
:int_ptr => {:type => "int*", :name => 'MyIntPtr', :ptr? => true, :const? => false, :const_ptr? => false},
:const_ptr => {:type => "int*", :name => 'MyConstPtr', :ptr? => true, :const? => false, :const_ptr? => true},
:double_ptr => {:type => "int const**", :name => 'MyDoublePtr', :ptr? => true, :const? => true, :const_ptr? => false},
:mytype => {:type => "MY_TYPE", :name => 'MyMyType', :ptr? => false, :const? => true, :const_ptr? => false},
:mytype_ptr => {:type => "MY_TYPE*", :name => 'MyMyTypePtr', :ptr? => true, :const? => false, :const_ptr? => false},
:string => {:type => "const char*", :name => 'MyStr', :ptr? => false, :const? => true, :const_ptr? => false},
}
end
+4 -2
View File
@@ -14,7 +14,8 @@ describe CMockConfig, "Verify CMockConfig Module" do
it "use default settings when no parameters are specified" do
config = CMockConfig.new
assert_equal(CMockConfig::CMockDefaultOptions[:mock_path], config.mock_path)
assert_equal(CMockConfig::CMockDefaultOptions[:includes], config.includes)
assert_nil(CMockConfig::CMockDefaultOptions[:includes])
assert_nil(config.includes)
assert_equal(CMockConfig::CMockDefaultOptions[:attributes], config.attributes)
assert_equal(CMockConfig::CMockDefaultOptions[:plugins], config.plugins)
assert_equal(CMockConfig::CMockDefaultOptions[:treat_externs], config.treat_externs)
@@ -35,7 +36,8 @@ describe CMockConfig, "Verify CMockConfig Module" do
test_plugins = [:soda, :pizza]
config = CMockConfig.new("#{File.expand_path(File.dirname(__FILE__))}/cmock_config_test.yml")
assert_equal(CMockConfig::CMockDefaultOptions[:mock_path], config.mock_path)
assert_equal(CMockConfig::CMockDefaultOptions[:includes], config.includes)
assert_nil(CMockConfig::CMockDefaultOptions[:includes])
assert_nil(config.includes)
assert_equal(test_plugins, config.plugins)
assert_equal(:include, config.treat_externs)
end
+24 -5
View File
@@ -53,6 +53,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :includes_c_pre_header, nil
@config.expect :includes_c_post_header, nil
@config.expect :subdir, nil
@config.expect :fail_on_unexpected_calls, true
@cmock_generator = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator.module_name = @module_name
@cmock_generator.mock_name = "Mock#{@module_name}"
@@ -70,6 +71,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :includes_c_pre_header, nil
@config.expect :includes_c_post_header, nil
@config.expect :subdir, nil
@config.expect :fail_on_unexpected_calls, true
@cmock_generator_strict = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator_strict.module_name = @module_name
@cmock_generator_strict.mock_name = "Mock#{@module_name}"
@@ -85,7 +87,6 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :weak, ""
orig_filename = "PoutPoutFish.h"
define_name = "MOCKPOUTPOUTFISH_H"
mock_name = "MockPoutPoutFish"
output = []
expected = [
"/* AUTOGENERATED FILE. DO NOT EDIT. */\n",
@@ -98,6 +99,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"\n",
"/* Ignore the following warnings, since we are copying code */\n",
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n",
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n",
"#pragma GCC diagnostic push\n",
"#endif\n",
"#if !defined(__clang__)\n",
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n",
"#endif\n",
@@ -127,6 +131,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :includes_c_pre_header, nil
@config.expect :includes_c_post_header, nil
@config.expect :subdir, nil
@config.expect :fail_on_unexpected_calls, true
@cmock_generator2 = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator2.module_name = "Pout-Pout Fish"
@cmock_generator2.mock_name = "MockPout-Pout Fish"
@@ -137,7 +142,6 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :weak, ""
orig_filename = "Pout-Pout Fish.h"
define_name = "MOCKPOUT_POUT_FISH_H"
mock_name = "MockPout_Pout_Fish"
output = []
expected = [
"/* AUTOGENERATED FILE. DO NOT EDIT. */\n",
@@ -150,6 +154,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"\n",
"/* Ignore the following warnings, since we are copying code */\n",
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n",
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n",
"#pragma GCC diagnostic push\n",
"#endif\n",
"#if !defined(__clang__)\n",
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n",
"#endif\n",
@@ -173,7 +180,6 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :weak, ""
orig_filename = "PoutPoutFish.h"
define_name = "MOCKPOUTPOUTFISH_H"
mock_name = "MockPoutPoutFish"
output = []
expected = [
"/* AUTOGENERATED FILE. DO NOT EDIT. */\n",
@@ -185,6 +191,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"\n",
"/* Ignore the following warnings, since we are copying code */\n",
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n",
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n",
"#pragma GCC diagnostic push\n",
"#endif\n",
"#if !defined(__clang__)\n",
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n",
"#endif\n",
@@ -208,7 +217,6 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :weak, ""
orig_filename = "PoutPoutFish.h"
define_name = "MOCKPOUTPOUTFISH_H"
mock_name = "MockPoutPoutFish"
output = []
expected = [
"/* AUTOGENERATED FILE. DO NOT EDIT. */\n",
@@ -221,6 +229,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"\n",
"/* Ignore the following warnings, since we are copying code */\n",
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n",
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n",
"#pragma GCC diagnostic push\n",
"#endif\n",
"#if !defined(__clang__)\n",
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n",
"#endif\n",
@@ -272,7 +283,15 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
it "append the proper footer to the header file" do
output = []
expected = ["\n#endif\n"]
expected = ["\n",
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n",
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n",
"#pragma GCC diagnostic pop\n",
"#endif\n",
"#endif\n",
"\n",
"#endif\n"
]
@cmock_generator.create_mock_header_footer(output)
+20 -12
View File
@@ -6,21 +6,29 @@
require File.expand_path(File.dirname(__FILE__)) + "/../test_helper"
require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_plugin_array'
require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_utils'
class UtilsStub
def helpers
{}
end
def arg_type_with_const(arg)
CMockGeneratorUtils.arg_type_with_const(arg)
end
def code_add_base_expectation(func)
"mock_retval_0"
end
end
describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do
before do
create_mocks :utils
#no strict ordering
@config = create_stub(
:when_ptr => :compare_data,
:enforce_strict_ordering => false,
:respond_to? => true )
@utils = create_stub(
:helpers => {},
:code_add_base_expectation => "mock_retval_0"
)
@utils = UtilsStub.new
@cmock_generator_plugin_array = CMockGeneratorPluginArray.new(@config, @utils)
end
@@ -29,8 +37,8 @@ describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do
end
it "have set up internal priority" do
assert_equal(nil, @cmock_generator_plugin_array.unity_helper)
assert_equal(8, @cmock_generator_plugin_array.priority)
assert_nil(@cmock_generator_plugin_array.unity_helper)
assert_equal(8, @cmock_generator_plugin_array.priority)
end
it "not include any additional include files" do
@@ -88,10 +96,10 @@ describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do
it "add another mock function declaration for functions of style 'const char* func(const int* tofu)'" do
function = {:name => "Pine",
:args => [{ :type => "int*",
:name => "tofu",
:ptr? => true,
:const? => true,
:args => [{ :type => "const int*",
:name => "tofu",
:ptr? => true,
:const? => true,
}],
:return => test_return[:string],
:contains_ptr? => true }
@@ -26,8 +26,8 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
end
it "have set up internal priority on init" do
assert_equal(nil, @cmock_generator_plugin_expect.unity_helper)
assert_equal(5, @cmock_generator_plugin_expect.priority)
assert_nil(@cmock_generator_plugin_expect.unity_helper)
assert_equal(5, @cmock_generator_plugin_expect.priority)
end
it "not include any additional include files" do
@@ -26,8 +26,8 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
end
it "have set up internal priority on init" do
assert_equal(nil, @cmock_generator_plugin_expect.unity_helper)
assert_equal(5, @cmock_generator_plugin_expect.priority)
assert_nil(@cmock_generator_plugin_expect.unity_helper)
assert_equal(5, @cmock_generator_plugin_expect.priority)
end
it "not include any additional include files" do
@@ -96,11 +96,12 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock function implementation for functions of style 'int func(int veal, unsigned int sushi)'" do
function = {:name => "Cherry", :args => [ { :type => "int", :name => "veal" }, { :type => "unsigned int", :name => "sushi" } ], :return => test_return[:int]}
@utils.expect :code_verify_an_arg_expectation, " mocked_retval_1", [function, function[:args][0]]
@utils.expect :code_verify_an_arg_expectation, " mocked_retval_2", [function, function[:args][1]]
@utils.expect :code_verify_an_arg_expectation, "mocked_retval_1\n", [function, function[:args][0]]
@utils.expect :code_verify_an_arg_expectation, "mocked_retval_2\n", [function, function[:args][1]]
expected = " if (cmock_call_instance->IgnoreMode != CMOCK_ARG_NONE)\n" +
" {\n" +
" mocked_retval_1 mocked_retval_2\n" +
"mocked_retval_1\n" +
"mocked_retval_2\n" +
" }\n"
returned = @cmock_generator_plugin_expect.mock_implementation(function)
assert_equal(expected, returned)
@@ -116,7 +117,7 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock function implementation for functions of style 'void func(int worm)' and strict ordering" do
function = {:name => "Apple", :args => [{ :type => "int", :name => "worm" }], :return => test_return[:void]}
@utils.expect :code_verify_an_arg_expectation, "mocked_retval_0", [function, function[:args][0]]
@utils.expect :code_verify_an_arg_expectation, "mocked_retval_0\n", [function, function[:args][0]]
expected = " if (cmock_call_instance->IgnoreMode != CMOCK_ARG_NONE)\n" +
" {\n" +
"mocked_retval_0\n" +
@@ -128,12 +129,12 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock interfaces for functions of style 'void func(void)'" do
function = {:name => "Pear", :args => [], :args_string => "void", :return => test_return[:void]}
@utils.expect :code_add_base_expectation, "mock_retval_0 ", ["Pear"]
@utils.expect :code_call_argument_loader, "mock_retval_1 ", [function]
@utils.expect :code_add_base_expectation, "mock_retval_0\n", ["Pear"]
@utils.expect :code_call_argument_loader, "mock_retval_1\n", [function]
expected = ["void Pear_CMockExpect(UNITY_LINE_TYPE cmock_line)\n",
"{\n",
"mock_retval_0 ",
"mock_retval_1 ",
"mock_retval_0\n",
"mock_retval_1\n",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
@@ -143,14 +144,14 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock interfaces for functions of style 'int func(void)'" do
function = {:name => "Orange", :args => [], :args_string => "void", :return => test_return[:int]}
@utils.expect :code_add_base_expectation, "mock_retval_0 ", ["Orange"]
@utils.expect :code_call_argument_loader, "mock_retval_1 ", [function]
@utils.expect :code_assign_argument_quickly, "mock_retval_2", ["cmock_call_instance->ReturnVal", function[:return]]
@utils.expect :code_add_base_expectation, "mock_retval_0\n", ["Orange"]
@utils.expect :code_call_argument_loader, "mock_retval_1\n", [function]
@utils.expect :code_assign_argument_quickly, "mock_retval_2\n", ["cmock_call_instance->ReturnVal", function[:return]]
expected = ["void Orange_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return)\n",
"{\n",
"mock_retval_0 ",
"mock_retval_1 ",
"mock_retval_2",
"mock_retval_0\n",
"mock_retval_1\n",
"mock_retval_2\n",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
@@ -160,14 +161,14 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock interfaces for functions of style 'int func(char* pescado)'" do
function = {:name => "Lemon", :args => [{ :type => "char*", :name => "pescado"}], :args_string => "char* pescado", :return => test_return[:int]}
@utils.expect :code_add_base_expectation, "mock_retval_0 ", ["Lemon"]
@utils.expect :code_call_argument_loader, "mock_retval_1 ", [function]
@utils.expect :code_assign_argument_quickly, "mock_retval_2", ["cmock_call_instance->ReturnVal", function[:return]]
@utils.expect :code_add_base_expectation, "mock_retval_0\n", ["Lemon"]
@utils.expect :code_call_argument_loader, "mock_retval_1\n", [function]
@utils.expect :code_assign_argument_quickly, "mock_retval_2\n", ["cmock_call_instance->ReturnVal", function[:return]]
expected = ["void Lemon_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, char* pescado, int cmock_to_return)\n",
"{\n",
"mock_retval_0 ",
"mock_retval_1 ",
"mock_retval_2",
"mock_retval_0\n",
"mock_retval_1\n",
"mock_retval_2\n",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
@@ -177,12 +178,12 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock interfaces for functions when using ordering" do
function = {:name => "Pear", :args => [], :args_string => "void", :return => test_return[:void]}
@utils.expect :code_add_base_expectation, "mock_retval_0 ", ["Pear"]
@utils.expect :code_call_argument_loader, "mock_retval_1 ", [function]
@utils.expect :code_add_base_expectation, "mock_retval_0\n", ["Pear"]
@utils.expect :code_call_argument_loader, "mock_retval_1\n", [function]
expected = ["void Pear_CMockExpect(UNITY_LINE_TYPE cmock_line)\n",
"{\n",
"mock_retval_0 ",
"mock_retval_1 ",
"mock_retval_0\n",
"mock_retval_1\n",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
@@ -21,9 +21,9 @@ describe CMockGeneratorPluginIgnoreArg, "Verify CMockGeneratorPluginIgnoreArg Mo
:name => "chicken",
:ptr? => false,
},
{ :type => "int*",
:name => "beef",
:ptr? => true,
{ :type => "const int*",
:name => "beef",
:ptr? => true,
:const? => true,
},
{ :type => "int*",
@@ -27,9 +27,9 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
:name => "chicken",
:ptr? => false,
},
{ :type => "int*",
:name => "beef",
:ptr? => true,
{ :type => "const int*",
:name => "beef",
:ptr? => true,
:const? => true,
},
{ :type => "int*",
@@ -52,7 +52,7 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
def complex_func_expect
@utils.expect :ptr_or_str?, false, ['int']
@utils.expect :ptr_or_str?, true, ['int*']
@utils.expect :ptr_or_str?, true, ['const int*']
@utils.expect :ptr_or_str?, true, ['int*']
end
@@ -124,11 +124,13 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
expected =
" if (cmock_call_instance->ReturnThruPtr_tofu_Used)\n" +
" {\n" +
" memcpy(tofu, cmock_call_instance->ReturnThruPtr_tofu_Val,\n" +
" UNITY_TEST_ASSERT_NOT_NULL(tofu, cmock_line, CMockStringPtrIsNULL);\n" +
" memcpy((void*)tofu, (void*)cmock_call_instance->ReturnThruPtr_tofu_Val,\n" +
" cmock_call_instance->ReturnThruPtr_tofu_Size);\n" +
" }\n" +
" }\n"
returned = @cmock_generator_plugin_return_thru_ptr.mock_implementation(@complex_func).join("")
assert_equal(expected, returned)
end
end
+27 -10
View File
@@ -20,7 +20,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
@config.expect :plugins, []
@config.expect :plugins, []
@config.expect :plugins, []
@config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','char*' => 'STRING'}
@config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','const char*' => 'STRING'}
@cmock_generator_utils_simple = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper})
@config.expect :when_ptr, :smart
@@ -31,7 +31,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','uint32_t' => 'HEX32','char*' => 'STRING'}
@config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','uint32_t' => 'HEX32','const char*' => 'STRING'}
@cmock_generator_utils_complex = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper, :A=>1, :B=>2})
end
@@ -99,8 +99,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
arg1 = { :name => "Orange", :const? => false, :type => 'int', :ptr? => false }
expected1 = " cmock_call_instance->Expected_Orange = Orange;\n"
arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => true }
expected2 = " cmock_call_instance->Expected_Lemon = (const char*)Lemon;\n"
arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => false }
expected2 = " cmock_call_instance->Expected_Lemon = Lemon;\n"
arg3 = { :name => "Kiwi", :const? => false, :type => 'KIWI_T*', :ptr? => true }
expected3 = " cmock_call_instance->Expected_Kiwi = Kiwi;\n"
@@ -119,8 +119,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
expected1 = " cmock_call_instance->Expected_Orange = Orange;\n" +
" cmock_call_instance->IgnoreArg_Orange = 0;\n"
arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => true }
expected2 = " cmock_call_instance->Expected_Lemon = (const char*)Lemon;\n" +
arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => false }
expected2 = " cmock_call_instance->Expected_Lemon = Lemon;\n" +
" cmock_call_instance->Expected_Lemon_Depth = Lemon_Depth;\n" +
" cmock_call_instance->IgnoreArg_Lemon = 0;\n"
@@ -154,7 +154,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" +
" cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" +
" memcpy(&cmock_call_instance->Expected_MyMyType, &MyMyType, sizeof(MY_TYPE));\n" +
" cmock_call_instance->Expected_MyStr = (char*)MyStr;\n" +
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
"}\n\n"
assert_equal(expected, @cmock_generator_utils_simple.code_add_argument_loader(function))
end
@@ -171,12 +171,29 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
" cmock_call_instance->ReturnThruPtr_MyIntPtr_Used = 0;\n" +
" memcpy(&cmock_call_instance->Expected_MyMyType, &MyMyType, sizeof(MY_TYPE));\n" +
" cmock_call_instance->IgnoreArg_MyMyType = 0;\n" +
" cmock_call_instance->Expected_MyStr = (char*)MyStr;\n" +
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
" cmock_call_instance->IgnoreArg_MyStr = 0;\n" +
"}\n\n"
assert_equal(expected, @cmock_generator_utils_complex.code_add_argument_loader(function))
end
it 'create an argument loader when the function has pointer arguments supporting arrays' do
function = { :name => "Melon",
:args_string => "stuff",
:args => [test_arg[:const_ptr], test_arg[:double_ptr]]
}
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* const MyConstPtr, int MyConstPtr_Depth, int const** MyDoublePtr, int MyDoublePtr_Depth)\n{\n" +
" cmock_call_instance->Expected_MyConstPtr = MyConstPtr;\n" +
" cmock_call_instance->Expected_MyConstPtr_Depth = MyConstPtr_Depth;\n" +
" cmock_call_instance->IgnoreArg_MyConstPtr = 0;\n" +
" cmock_call_instance->ReturnThruPtr_MyConstPtr_Used = 0;\n" +
" cmock_call_instance->Expected_MyDoublePtr = MyDoublePtr;\n" +
" cmock_call_instance->Expected_MyDoublePtr_Depth = MyDoublePtr_Depth;\n" +
" cmock_call_instance->IgnoreArg_MyDoublePtr = 0;\n" +
"}\n\n"
assert_equal(expected, @cmock_generator_utils_complex.code_add_argument_loader(function))
end
it "not call argument loader if there are no arguments to actually use for this function" do
function = { :name => "Pineapple", :args_string => "void" }
@@ -231,7 +248,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
" UNITY_TEST_ASSERT_EQUAL_STRING(cmock_call_instance->Expected_MyStr, MyStr, cmock_line, CMockStringMismatch);\n" +
" }\n"
@unity_helper.expect :nil?, false
@unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['char*']
@unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['const char*']
assert_equal(expected, @cmock_generator_utils_simple.code_verify_an_arg_expectation(function, arg))
end
@@ -311,7 +328,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
" UNITY_TEST_ASSERT_EQUAL_STRING(cmock_call_instance->Expected_MyStr, MyStr, cmock_line, CMockStringMismatch);\n" +
" }\n"
@unity_helper.expect :nil?, false
@unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['char*']
@unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['const char*']
assert_equal(expected, @cmock_generator_utils_complex.code_verify_an_arg_expectation(function, arg))
end
+190 -4
View File
@@ -805,6 +805,64 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, @parser.parse("module", source)[:functions])
end
it "should properly handle const before return type" do
sources = [
"const int * PorkRoast(void);\n",
"const int* PorkRoast(void);\n",
"const int *PorkRoast(void);\n"
]
expected = [{ :var_arg => nil,
:name => "PorkRoast",
:return => { :type => "const int*",
:name => 'cmock_to_return',
:ptr? => true,
:const? => true,
:const_ptr? => false,
:str => "const int* cmock_to_return",
:void? => false
},
:modifier => "",
:contains_ptr? => false,
:args => [],
:args_string => "void",
:args_call => ""
}]
sources.each do |source|
assert_equal(expected, @parser.parse("module", source)[:functions])
end
end
it "should properly handle const before return type" do
sources = [
"int const * PorkRoast(void);\n",
"int const* PorkRoast(void);\n",
"int const *PorkRoast(void);\n"
]
expected = [{ :var_arg => nil,
:name => "PorkRoast",
:return => { :type => "int const*",
:name => 'cmock_to_return',
:ptr? => true,
:const? => true,
:const_ptr? => false,
:str => "int const* cmock_to_return",
:void? => false
},
:modifier => "",
:contains_ptr? => false,
:args => [],
:args_string => "void",
:args_call => ""
}]
sources.each do |source|
assert_equal(expected, @parser.parse("module", source)[:functions])
end
end
it "should properly handle const applied after asterisk in return type (not legal C, but sometimes used)" do
source = "int * const PorkRoast(void);\n"
@@ -828,6 +886,69 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, @parser.parse("module", source)[:functions])
end
it "properly parse const and pointer argument types with no arg names" do
source = "void foo(int const*, int*const, const int*, const int*const, int const*const, int*, int, const int);\n"
expected = [{ :name => "foo",
:modifier => "",
:return => { :type => "void",
:name => "cmock_to_return",
:str => "void cmock_to_return",
:void? => true,
:ptr? => false,
:const? => false,
:const_ptr? => false
},
: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_call => "cmock_arg1, cmock_arg2, cmock_arg3, cmock_arg4, cmock_arg5, cmock_arg6, cmock_arg7, cmock_arg8",
:contains_ptr? => true
}]
assert_equal(expected, @parser.parse("module", source)[:functions])
end
it "properly parse const and pointer argument types with arg names" do
source = "void bar(int const* param1, int*const param2, const int* param3, const int*const param4,\n" +
" int const*const param5, int*param6, int param7, const int param8);\n"
expected = [{ :name => "bar",
:modifier => "",
:return => { :type => "void",
:name => "cmock_to_return",
:str => "void cmock_to_return",
:void? => true,
:ptr? => false,
:const? => false,
:const_ptr? => false
},
: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_call => "param1, param2, param3, param4, param5, param6, param7, param8",
:contains_ptr? => true
}]
assert_equal(expected, @parser.parse("module", source)[:functions])
end
it "properly detect typedef'd variants of void and use those" do
source = "typedef (void) FUNKY_VOID_T;\n" +
@@ -904,7 +1025,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:name=>"Penny",
:modifier=>"",
:contains_ptr? => true,
:args=>[ {:type=>"struct _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :const? => true, :const_ptr? => true} ],
:args=>[ {:type=>"struct const _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :const? => true, :const_ptr? => true} ],
:args_string=>"struct const _KeepYourHeadUp_* const BillyBuddy",
:args_call=>"BillyBuddy"
},
@@ -1052,7 +1173,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, result[:functions])
end
it "handle arrays and treat them as pointers" do
it "handle arrays and treat them as pointers or strings" do
source = "void KeyOperated(CUSTOM_TYPE thing1[], int thing2 [ ], char thing3 [][2 ][ 3], int* thing4[4])"
expected = [{:var_arg=>nil,
:return=>{ :type => "void",
@@ -1068,7 +1189,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:contains_ptr? => true,
:args=>[ {:type=>"CUSTOM_TYPE*", :name=>"thing1", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"int*", :name=>"thing2", :ptr? => true, :const? => false, :const_ptr? => false},
{:type=>"char*", :name=>"thing3", :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} #THIS one will likely change in the future when we improve multidimensional array support
],
:args_string=>"CUSTOM_TYPE* thing1, int* thing2, char* thing3, int** thing4",
@@ -1407,7 +1528,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
: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=>"char*", :name=>"cmock_arg4", :ptr? => true, :const? => true, :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}
],
@@ -1510,4 +1631,69 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, @parser.parse("module", source)[:functions])
end
it "divines all permutations of ptr, const, and const_ptr correctly" do
truth_table = [
# argument ptr const const_ptr
[ "constNOTconst constNOTconst", false, false, false ],
[ "const constNOTconst constNOTconst", false, true, false ],
[ "constNOTconst const constNOTconst", false, true, false ],
[ "constNOTconst *constNOTconst", true, false, false ],
[ "const constNOTconst *constNOTconst", true, true, false ],
[ "constNOTconst const *constNOTconst", true, true, false ],
[ "constNOTconst *const constNOTconst", true, false, true ],
[ "const constNOTconst *const constNOTconst", true, true, true ],
[ "constNOTconst const *const constNOTconst", true, true, true ],
[ "constNOTconst **constNOTconst", true, false, false ],
[ "const constNOTconst **constNOTconst", true, false, false ],
[ "constNOTconst const **constNOTconst", true, false, false ],
[ "constNOTconst *const *constNOTconst", true, true, false ],
[ "const constNOTconst *const *constNOTconst", true, true, false ],
[ "constNOTconst const *const *constNOTconst", true, true, false ],
[ "constNOTconst **const constNOTconst", true, false, true ],
[ "const constNOTconst **const constNOTconst", true, false, true ],
[ "constNOTconst const **const constNOTconst", true, false, true ],
[ "constNOTconst *const *const constNOTconst", true, true, true ],
[ "const constNOTconst *const *const constNOTconst", true, true, true ],
[ "constNOTconst const *const *const constNOTconst", true, true, true ]
]
truth_table.each do |entry|
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] })
end
end
it "divines ptr correctly for string types" do
truth_table = [
# argument ptr
[ "char s", false ],
[ "const char s", false ],
[ "char const s", false ],
[ "char *s", false ],
[ "const char *s", false ],
[ "char const *s", false ],
[ "char *const s", false ],
[ "const char *const s", false ],
[ "char const *const s", false ],
[ "char **s", true ],
[ "const char **s", true ],
[ "char const **s", true ],
[ "char *const *s", true ],
[ "const char *const *s", true ],
[ "char const *const *s", true ],
[ "char **const s", true ],
[ "const char **const s", true ],
[ "char const **const s", true ],
[ "char *const *const s", true ],
[ "const char *const *const s", true ],
[ "char const *const *const s", true ]
]
truth_table.each do |entry|
assert_equal(@parser.divine_ptr(entry[0]), entry[1])
end
end
end
+1 -1