320 Commits

Author SHA1 Message Date
Mark VanderVoord 3eccb8e3d4 Revert "CMock can now compile without setjmp.h present on the platform" 2021-01-28 08:15:10 -05:00
Mark VanderVoord 1f939c9005 Merge pull request #329 from jmrubillon/master
CMock can now compile without setjmp.h present on the platform
2021-01-28 08:04:40 -05:00
Jean Rubillon 9e1c6c068d Fix missed has_setjmp_h convert to exclude_setjmp_h 2021-01-28 12:57:02 +00:00
Jean Rubillon 4ae268dbbe Changed has_setjmp_h option to exclude_setjmp_h 2021-01-27 18:56:02 +00:00
Mark VanderVoord d847e6777c Merge pull request #344 from ThrowTheSwitch/test/switch_to_actions
Switch to github actions
2021-01-16 22:22:34 -05:00
Mark VanderVoord dcde998087 cleanup style 2021-01-16 22:20:16 -05:00
Mark VanderVoord 38d6dccc8e Show the correct badge for this project.
Fix a bug in a test.
2021-01-16 22:15:36 -05:00
Mark VanderVoord 03acc531bf when we checkout the project, do it recursively so we get unity for our tests. :) 2021-01-16 21:33:19 -05:00
Mark VanderVoord 45920ed724 Need project present before running bundler. 2021-01-16 21:21:51 -05:00
Mark VanderVoord c4842fad0c Don't run bundler as root. 2021-01-16 21:17:55 -05:00
Mark VanderVoord 9f3cee70cd Switch to github actions 2021-01-16 21:13:55 -05:00
Mark VanderVoord 4dd557f2df Merge pull request #311 from andred/master
allow compilation with stricter warnings
2021-01-07 18:02:24 -05:00
Mark VanderVoord af1818a652 Merge pull request #327 from Hannes103/feature/sub-folder-supprt
add optional folder argument to create_mock()
2021-01-07 17:59:10 -05:00
Mark VanderVoord e352bb8c3b Merge pull request #340 from CezaryGapinski/fix-static-variables-for-enabled-inline-funcs-mocks
Fix static variables detection in headers for enabled inline function mocks
2021-01-07 17:57:36 -05:00
Mark VanderVoord 63f5e2f962 Merge pull request #341 from laurensmiers/master
Remove comments before start of inline-function-parsing
2021-01-07 17:57:17 -05:00
Cezary Gapinski 5eec2510b1 Change inline function detection to leave code not related to functions
static keyword can be used for variable in headers, like in issue #313 or ThrowTheSwitch/Ceedling#541
2020-12-15 21:10:45 +01:00
Cezary Gapinski f5984f44e8 Add test to leaves static variables for enabled inline functions mocks 2020-12-14 21:12:11 +01:00
Mark VanderVoord 9c1c6a05dc Merge pull request #337 from ollehu/master
Improve the regexps for parsing parameters to cmock.rb
2020-11-12 11:54:15 -05:00
ollehu 70d5750659 Merge branch 'master' into master 2020-11-12 16:01:43 +01:00
Mark VanderVoord 72f1c9e2b8 Merge pull request #339 from naggety/master
Allow parsing empty values for options in CLI arguments
2020-11-04 07:06:33 -05:00
Iñigo Huguet 334f46781a Allow parsing empty values for options in CLI arguments
If an option is passed via CLI, it cannot be passed with an
empty value because the Regex makes it to match 1 or more
characters.

For example, arguments `--mock_prefix=""` and `--mock_prefix=`
are invalid, because they don't match the regex and are not
recognized as options, so they're treated as files to mock.

Changing the regex to match 0 or more characters for the option
value, instead of 1 or more, solves the problem.
2020-11-04 09:42:36 +01:00
Olle Hynén Ulfsjöö ea061bbb50 Improve the regexps for parsing parameters to cmock.rb
Also, conform to the standard 80 character limit

Change-Id: I7830ddd5d65ccc06c96884c1c3d4575241f99e6d
2020-10-23 16:26:36 +02:00
Jean Rubillon 21d181380f Signal that cexception needs setjmp to be supported. 2020-09-08 21:11:54 +01:00
Jean Rubillon 72b356b97d Added option to remove setjmp.h from generated mock files as not supported on all embedded systems 2020-09-08 20:50:48 +01:00
Hannes Bachl 22a7228bbc add optional folder argument to create_mock() 2020-09-01 10:17:54 +02:00
Mark VanderVoord afa294982e Merge pull request #326 from cloudsftp/ignore_stateless
Resolve Ruby Offenses found by CI
2020-08-19 07:51:00 -04:00
cloudsftp 44f126878b remove trailing whitespace 2020-08-19 13:15:21 +02:00
cloudsftp 1987138e81 resolve ruby offenses found by CI 2020-08-19 12:40:35 +02:00
Mark VanderVoord baa946a05f Merge pull request #325 from cloudsftp/ignore_stateless
Plugin: IgnoreStateless
2020-08-19 06:38:03 -04:00
cloudsftp d304ff273a add StopIgnore to new plugin 2020-08-19 11:25:27 +02:00
cloudsftp 56faeb935f add documentation 2020-08-19 10:38:26 +02:00
cloudsftp 61ed5cc7f8 add more tests for the new plugin 2020-08-19 10:17:05 +02:00
cloudsftp 496cabff10 add more test cases for the new plugin 2020-08-18 16:56:36 +02:00
cloudsftp 94ca645061 add first simple test and remove warning "unused parameter" 2020-08-18 16:31:45 +02:00
cloudsftp d36662da2a repair failing unit tests for plugins 2020-08-18 15:33:51 +02:00
cloudsftp b735d09603 add plugin :ignore_stateless that solves ThrowTheSwitch/CMock#307 2020-08-18 15:25:55 +02:00
Mark VanderVoord 5f8ec6da7f Merge pull request #321 from michaelbrockus/let_meson_handle_flags
Letting Meson handle flags
2020-08-06 16:29:30 -04:00
Michael Brockus 3e28a5412d use files method 2020-08-06 13:26:00 -07:00
Michael Brockus 5f8e90b82a Update meson.build 2020-08-06 12:39:56 -07:00
laurens 541e7034ad Remove comments before start of inline-function-parsing 2020-06-13 12:49:33 +02:00
Mark VanderVoord eeecc49ce8 Merge pull request #312 from Skinner927/patch-1
Stop strippables default value from being parsed (Thanks @Skinner927 )
2020-06-04 13:15:31 -04:00
Dennis Skinner 175a834574 Stop strippables default value from being parsed
Default value for `:strippables` was rendering incorrectly because of markdown parsing.
2020-06-04 13:02:30 -04:00
André Draszik ec6fa2c516 Revert "drop unnecessary prototype (immediately before definition)"
This reverts commit 7fbeb40965.

This causes compilation warnings / errors when a project uses
-Wmissing-prototypes compilation flags for safety reasons:

.../test/mocks/mock_logMessages.c:685:6: warning: no previous prototype for ‘CMockExpectParameters_log_message’ [-Wmissing-prototypes]
  685 | void CMockExpectParameters_log_message(CMOCK_log_message_CALL_INSTANCE* cmock_call_instance, const char* logMessage, int messageID, severity_t severityIn)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

etc.

Signed-off-by: André Draszik <git@andred.net>
2020-05-25 16:35:54 +01:00
André Draszik 7ee27d6891 cmock: annotate pure & const APIs (fix Wsuggest-attribute= warnings)
GCC (& Clang) have the notion of pure and const functions [1],
where those attributes are intended to help the optimiser.

Annotate a few APIs here with the appropriate key words, which
also fixes Wsuggest-attribute=pure and Wsuggest-attribute=const
warnings, which a source base might have enabled:

.../src/cmock.c: In function ‘CMock_Guts_MemNext’:
.../src/cmock.c:118:22: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  118 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
      |                      ^~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemEndOfChain’:
.../src/cmock.c:140:22: warning: function might be candidate for attribute ‘pure’ if it is known to return normally [-Wsuggest-attribute=pure]
  140 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_GetAddressFor’:
.../src/cmock.c:158:7: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  158 | void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
      |       ^~~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemBytesCapacity’:
.../src/cmock.c:173:22: warning: function might be candidate for attribute ‘const’ [-Wsuggest-attribute=const]
  173 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemBytesFree’:
.../src/cmock.c:181:22: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  181 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemBytesUsed’:
.../src/cmock.c:189:22: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  189 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~

[1] https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

Signed-off-by: André Draszik <git@andred.net>
2020-05-25 15:39:21 +01:00
André Draszik 2568a3657f return_thru_ptr: fix Wsign-conversion warning
Compiling a source base / test with Wsign-conversion enabled, gives
the following warning:

build/test/mocks/mock_logMessages.c: In function ‘countLogMessages’:
build/test/mocks/mock_logMessages.c:749:26: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
  749 |       cmock_call_instance->ReturnThruPtr_fileIn_Size);
      |       ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~

The ReturnThruPtr_XXX_Size is used as argument to a call to memcpy(),
which expects size_t (unsigned) for a good reason. The size leading
to this call is being determined using sizeof(), so there appears
no reason to ever convert this to (signed) int.

Stop converting size_t to int, and thereby fix the compiler
warning.

Signed-off-by: André Draszik <git@andred.net>
2020-05-25 07:45:34 +01:00
Mark VanderVoord 150573c742 Latest Unity 2020-05-03 16:13:52 -04:00
Mark VanderVoord 7ec556d209 Bump Version 2020-05-03 16:10:55 -04:00
Mark VanderVoord 6259630f00 Merge pull request #301 from booz-allen-hamilton/cpp-static-min
add support for mocking C++ static class member methods
2020-05-03 13:57:14 -04:00
Mark VanderVoord a262194af8 Submit some style cleanup.
Bump Unity Version.
2020-05-03 09:05:39 -04:00
Mark VanderVoord fb8f48a10d Fix tests that were left behind. 2020-05-03 08:53:51 -04:00
Mark VanderVoord b30c22780e Fixed previous error with extra junk and bumped subproject versions 2020-05-03 08:31:23 -04:00
Mark VanderVoord 0d593c60d3 Merge pull request #305 from pwatt01/master
add <function>_StopIgnore()  function
2020-05-02 14:45:23 -04:00
pwatt01 555b608116 Remove Trailing whitespace 2020-04-27 12:23:29 +09:30
pwatt01 3c3dad1eb2 Remove trailing whitespace 2020-04-27 12:21:41 +09:30
pwatt01 7bfa02cd23 Fix whitespace errors, minimize unnecessary branching 2020-04-24 21:49:16 +09:30
pwatt01 1f16f4b5a3 Fix Ignore declaration missing, fix StopIgnore to handle returns 2020-04-24 14:09:02 +09:30
pwatt01 553dc94b76 Fix typo 2020-04-24 12:08:50 +09:30
pwatt01 b6a6bd0a11 Updated documentation 2020-04-24 09:24:54 +09:30
pwatt01 d0214e4e9d add <function>_StopIgnore() function 2020-04-22 15:34:01 +09:30
Mark VanderVoord ee412d296a Merge pull request #299 from Tuc-an/unnecessary-prototype
drop unnecessary prototype (immediately before definition)
2020-04-09 16:11:51 -04:00
Tuc-An e06540f3d7 add support for mocking C++ static class member methods 2020-04-06 11:20:15 -04:00
Tuc-An 7fbeb40965 drop unnecessary prototype (immediately before definition) 2020-03-27 11:17:14 -04:00
Mark VanderVoord b32e3cd601 Merge pull request #298 from Tuc-an/compact
convert Boolean values from int to char to reduce memory
2020-03-25 10:11:14 -04:00
Tuc-An cfcca2e43e convert Boolean values from int to char to reduce memory 2020-03-25 10:00:05 -04:00
Mark VanderVoord 80d2c3a4e9 Merge pull request #297 from Tuc-an/size_t
change CMOCK_MEM_INDEX_TYPE default type to size_t
2020-03-25 08:01:45 -04:00
Tuc-An aaeae0e217 update doc to match 2020-03-25 07:25:47 -04:00
Tuc-An d78b5e4ab6 change CMOCK_MEM_INDEX_TYPE default type to size_t 2020-03-25 07:19:54 -04:00
Mark VanderVoord 2bbf3ab5e5 Merge pull request #296 from Tuc-an/old-c-style-comments
switch comments to C-style to improve compatibility with pre-C99 and …
2020-03-25 06:39:49 -04:00
Tuc-An 2bd9128689 Trigger notification 2020-03-25 05:53:46 -04:00
Tuc-An 24daea45ab switch comments to C-style to improve compatibility with pre-C99 and match unity 2020-03-25 05:41:14 -04:00
mvandervoord 382c196379 Latest Unity 2020-03-19 11:46:58 -04:00
Mark VanderVoord 586ec41c26 Merge pull request #294 from ThrowTheSwitch/style
Update Testing and Style to match our coding standard
2020-03-19 11:43:26 -04:00
mvandervoord 11a278eebf astyle not on travis, therefore don't test with CI 2020-03-19 11:40:30 -04:00
mvandervoord 69ad84b06b No need to freeze immutable objects 2020-03-19 11:35:22 -04:00
mvandervoord 13ee7c9eec Further cleanup based on server results 2020-03-19 11:29:17 -04:00
mvandervoord 1bdb299566 update gem file to drop old requirements 2020-03-19 10:27:51 -04:00
mvandervoord 4706da4453 another try 2020-03-19 10:17:30 -04:00
mvandervoord 44c8d4718a Further tweaks to testing 2020-03-19 10:09:22 -04:00
mvandervoord 9b393ad4fb Further style changes to match standard.
Pull in latest Unity.
Update testing parameters to include Ruby 2.7
2020-03-19 10:00:12 -04:00
mvandervoord 67858837d1 Update coding style to match our own official coding guidelines 2020-03-18 19:16:58 -04:00
Mark VanderVoord 9f8624a722 Merge pull request #283 from michaelbadcrumble/master
Cleaner implementation of Meson build support
2020-03-18 15:20:07 -04:00
mvandervoord 0f196a52cf Deal with more complex array length expressions. (thanks @jlindgren90 !) 2020-03-18 15:19:23 -04:00
mvandervoord 8885be7e55 Support alternative header file extension support (thanks @Tuc-an) 2020-03-18 15:08:21 -04:00
mvandervoord ae677d6481 Tweak to support test runner generator returning includes with extensions now. 2020-03-18 12:29:52 -04:00
mvandervoord 6aafb8184f Update to latest Unity 2020-03-18 11:55:43 -04:00
Mark VanderVoord bd0a8bfd38 Merge pull request #272 from jlindgren90/master
Some minor optimizations
2020-03-16 13:45:10 -04:00
Mark VanderVoord 300ebb86fd Merge branch 'master' into master 2020-03-16 13:44:41 -04:00
mvandervoord 3cfa437460 Make skeleton path configurable 2020-03-12 17:08:51 -04:00
mvandervoord f5abf20f4b Add ability to generate skeleton from header. woo! 2020-03-12 12:20:33 -04:00
Mark VanderVoord 2eb209b2a8 Merge pull request #286 from andred/for-merge
cmock_generator_plugin_callback: allow usage with Clang scan-build
2020-02-13 22:01:07 -05:00
André Draszik ccfe2690f4 cmock_generator_plugin_callback: allow usage with Clang scan-build
Running a project through Clang's scan-build produces countless
warnings like

build/test/mocks/mock_handleTroubleEvents.c:321:5: warning: Value stored to 'call_instance' is never read
    call_instance = CMOCK_GUTS_NONE;
    ^               ~~~~~~~~~~~~~~~

scan-build correctly determines that in the following snippet

    UNITY_CLR_DETAILS();
    if (Mock.checkForActiveTroubleAfterDebounce_CallbackFunctionPointer != NULL)
      call_instance = CMOCK_GUTS_NONE;
    call_instance = Mock.startStopTimer_CallInstance;

as generated by Ceedling / CMock, the first assignment to
call_instance is completely unused.

The sheer amount of warnings makes it very hard to impossible to
spot real problems in one's code, and creates huge code analysis
reports that just distract from actual problems in one's code.

Without being too invasive, we can instruct scan-build to ignore
this dead store using
    https://clang-analyzer.llvm.org/faq.html#dead_store

Signed-off-by: André Draszik <git@andred.net>
2020-02-14 02:56:21 +00:00
Mark VanderVoord 46db68699c Merge pull request #279 from laurensmiers/fix_bug_pull_request
Fix parsing of inline function declarations/macro's
2020-02-12 13:14:11 -05:00
Michael Brockus 4d0ea1afda Update meson.build 2020-01-27 23:18:39 -08:00
Michael Brockus a1b6da1773 Update meson.build 2020-01-27 23:17:18 -08:00
John Lindgren 3093a440dd expect: Optimize mock_verify() for the successful case.
Remove unconditional UNITY_SET_DETAIL/UNITY_CLEAR_DETAILS pair and
only call UNITY_SET_DETAIL if we are failing.
2020-01-27 15:24:06 -05:00
John Lindgren 574d532df7 callback: mock_verify() has no effect.
callback has a later priority than expect, so setting call_instance
to CMOCK_GUTS_NONE at this point has no effect.  This mock_verify()
has probably been obsolete for a long time.
2020-01-27 15:24:06 -05:00
laurensmiers 87cae74434 Re-use global function declaration regex in inline-function parsing 2020-01-15 00:04:28 +01:00
laurensmiers fda0b13fe5 Remove debug prints 2020-01-14 22:23:31 +01:00
laurensmiers 1c67efc485 Update inline function parsing documentation 2020-01-14 22:18:17 +01:00
laurensmiers 9571c52d70 Replace search for first bracket/semicolon with regex matching first function declaration
The regex matches the function declaration at the start of the
string (post-match).
2020-01-14 22:18:17 +01:00
laurens faceb864b8 Fix deleting of next line in user supplied inline function pattern
If we have a 'empty' macro, f.e.:
\#if <something>
\#define MY_LIBRARY_INLINE
\#endif
and using the user pattern 'MY_LIBRARY_INLINE', we would get the
following effect:
match = 'MY_LIBRARY_INLINE\n' <--- NOTE THAT THE NEWLINE IS PART OF THE MATCH
post-match = '#endif\n' <--- NO BEGINNING NEWLINE SINCE IT IS PART OF
THE MATCH ABOVE

And lead to the new header:
\#if <something>
Which gives a compilation error since the preprocessor-if is not
terminated properly.

The root cause is that we add a any-whitespace-character regex to the
user regex.
This any-whitespace-character regex was added only to cleanup the
 whitespaces after a user regex.

So the next line will be deleted if we check for any whitespace
character (THIS INCLUDES A NEWLINE!) after the user regex.
But this had the side effect that when matching a user regex, the newline was
also seen as part of the match. Which in the case of an empty macro
 would mean that in the cleanup of the post-match, we would delete the
 line immediately after the empty macro (\#endif in the example above).
So instead of matching with every whitespace character (which includes
newlines!), we explicitly only check for whitespaces.

Taking the example above, this has the desired effect:
match = 'MY_LIBRARY_INLINE' <--- NOTE THAT THE NEWLINE IS NO LONGER PART OF THE MATCH
post-match = '\n#endif\n' <--- BEGINNING NEWLINE NOW

Now the cleanup after a define will see the beginning newline in the
post-match and only remove that newline and now the preprocessor-if is
terminated properly
2020-01-14 22:18:17 +01:00
laurensmiers cf0e55b6e4 Fix system test compile error
if there is no semicolon in the file, first_semicolon is nil, so check
it before using it.
2020-01-14 22:18:17 +01:00
laurensmiers cfe1b4ef3d Handle user defined inline macro's
First squash all multiline macro's, it makes parsing easier. Otherwise
the regex to remove the macro would become more comples if we have to
deal with newlines etc.

When we have a match, we check if the last line in the pre_match is
the beginning of a macro declaration.
If it is, we remove the beginning of this macro
declaration (#define<space>) and remove the body of the macro from the
post_match, which is basically everything until the next newline.
There is a possible edge case (pretty unlikely but still):
if there is no newline in the post_match, meaning it is a macro at the
end of the line, we should delete it as well, hence the '[\n]?' in the
post match regex.
2020-01-14 22:18:17 +01:00
laurens 3254aef5e5 Handle headers which only have inline-function-declarations
This means there is NO opening bracket, since there are no struct
declarations or inline function definitions.
2020-01-14 22:18:17 +01:00
laurens 7a5d712d79 Expand inline function declaration test
Add a random struct in between to make sure we are not touching it
+
multiple newlines are allowed in the function declaration before the
semicolon, add a test to make sure we handle this.
2020-01-14 22:18:17 +01:00
laurens 550e141c59 Handle inline function declarations when mocking inline functions
When a inline function was declared in a file, we would find the
declaration and remove the function body. However, since it is a
declaration, there is NO function body, so we were deleting a random
piece of code that was between square brackets in the file.

To properly handle this, we have to detect if we are dealing with a
function declaration or a function definition.
If we are dealing with a function declaration, a semicolon
will come BEFORE the first square bracket.
If we are dealing with a function definition, a square bracket will
come BEFORE the first semicolon (the first semicolon will be in the
inline function body, so between the square brackets).
So we determine the location of the first semicolon and the first
square bracket after the function name and apply the logic described
above to handle function declarations.

If we are dealing with a function declaration, we don't do anything,
we just move to the next match.
This will result in redeclarations of the inline function, but this is
allowed in C and I'd rather not touch the file anymore than necessary.
2020-01-14 22:16:32 +01:00
laurens 972814622f Some more debug info 2020-01-14 22:15:14 +01:00
laurens c7f24da4f7 Some debug info during inline function parsing 2020-01-14 22:15:14 +01:00
laurens f291ed217c Trying to reproduce bug pull request 2020-01-14 22:15:14 +01:00
Mark VanderVoord bd5fbc30eb Merge pull request #271 from jvcdk/maintenance/update-submodules
Update submodule unity to current master.
2019-12-06 06:10:36 -05:00
Jørn Villesen Christensen 81345af180 Update submodule unity to current master. 2019-12-06 10:15:09 +01:00
mvandervoord 649005a917 Verify multiline functions are being parsed properly. 2019-12-05 09:15:47 -05:00
Mark VanderVoord 1e6634ca93 Merge pull request #270 from michaelbadcrumble/meson_support
Keep Meson support back to 0.50.0:
2019-12-04 06:03:07 -05:00
Michael Brockus ddf9030b9a Keep Meson support back to version 0.50.0 2019-12-03 22:49:15 -08:00
Michael Brockus 532ddd2c3d Update root meson.build 2019-12-03 22:45:39 -08:00
mvandervoord 7035578605 Grab the latest vendor tools 2019-12-03 18:48:28 -05:00
mvandervoord 91d5e578d8 Add support for function pointers using the shorthand notation 2019-11-18 09:09:42 -05:00
Mark VanderVoord 2afdebd228 Merge pull request #268 from jlindgren90/master
Allow arbitrary parentheses within length of array arguments.
2019-11-17 13:18:03 -05:00
John Lindgren 615b3874b8 Allow arbitrary parentheses within length of array arguments.
Previously, CMock would fail to parse a function like this one:

    void broken(uint8_t arg[((uint8_t)8)]);
2019-11-15 16:55:05 -05:00
Mark VanderVoord a6ec9f968a Merge pull request #267 from jlindgren90/master
Revert "Add quick pointer check before memory comparisons (#224)"
2019-11-15 13:11:19 -05:00
John Lindgren 03ddcb9bad Revert "Add quick pointer check before memory comparisons (#224)"
It didn't add direct comparisons only for pointer arguments, but
also other types of arguments like structs, which can't be compared
with '==' and cause a compiler error instead.

To reproduce, just enable the :array plugin in
system/test_interactions/expect_and_return_custom_types.yml:

In function ‘foo’:
error: invalid operands to binary != (have ‘EXAMPLE_STRUCT_T’ {aka
‘struct _EXAMPLE_STRUCT_T’} and ‘EXAMPLE_STRUCT_T’ {aka ‘struct
 _EXAMPLE_STRUCT_T’})
   59 |     if (cmock_call_instance->Expected_a != a) {
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~

This reverts commit 4df532afcc.
2019-11-15 12:46:28 -05:00
Mark VanderVoord 7dcb78c629 Merge pull request #265 from laurensmiers/master
User provided patterns for inline function mocking
2019-11-15 11:56:32 -05:00
laurens c0162e1ea6 Remove double unit test for inline_function_patterns 2019-11-15 16:25:23 +01:00
laurens 02cf882d36 Update documentation of :inline_function_patterns 2019-11-15 09:34:50 +01:00
laurens cb55b73522 Simplify inline function removal during source/function parsing
- If inlines are included, we don't do anything since they are
  disguised already as normal functions
- If inlines are NOT included, we remove anything that has inline in
  it
2019-11-14 13:38:10 +01:00
laurens 0f6e4604ff Remove inline specific keywords before starting function parsing 2019-11-14 13:37:57 +01:00
laurens 31244992db Add test for including mocks for user defined inline functions
- Failing now
2019-11-14 13:15:39 +01:00
laurens 56bad95cf7 Make test default inline_function_patterns the default value
- Tests that test the user provided patterns should define them in the
  test itself and not rely on the global one being set
2019-11-14 13:06:33 +01:00
laurens d5a8fcb6a2 Add documentation on configuring build system for :treat_includes 2019-11-13 16:21:49 +01:00
laurens 27002370dd Add documentation for :inline_function_patterns 2019-11-13 13:33:19 +01:00
laurens 9bc3f25281 Remove internal regex for inline functions and make them fully user-defined
- We set the defaults but the user is free to add his own.
  This will overwrite our defaults but they will be added to the
  documentation as reference for the user
2019-11-13 13:33:16 +01:00
laurens 8a7c45c20b Take into account user-provided inline function patterns 2019-11-13 12:44:40 +01:00
laurens 73fa7a6bb2 Add unit test for inline_function_patterns (failing now) 2019-11-13 12:28:28 +01:00
laurens 21e37780fa Add :inline_function_patterns configuration option 2019-11-13 12:08:52 +01:00
mvandervoord 543c230f33 bump version 2019-11-12 18:27:33 -05:00
Mark VanderVoord 968d3f6ec4 Merge pull request #263 from laurensmiers/master
Inline function mocking refactor
2019-11-12 18:26:32 -05:00
laurens 0c45d26a28 Rename total_levels to total_pairs
- We are counting pairs of braces, not levels of indentation
2019-11-13 00:03:52 +01:00
laurens 811b85e1b1 Use <counter>.times iso until <condition> 2019-11-13 00:03:30 +01:00
laurens 759d1826c8 Add test with no braces in source
- Should return 0 since no braces in source
2019-11-12 20:28:08 +01:00
laurens 60a1829acf Fix comments 2019-11-12 20:04:30 +01:00
laurens 8ba3ed99a1 Extract count_number_of_pairs_of_braces_in_function method 2019-11-12 20:01:09 +01:00
laurens 0af0e20d15 Refactor transform_inline_functions
- Just looking for static|inline in the gsub is a bit too aggressive.
  Instead, look for the "static inline" and parse it:
  - Everything before the match should just be copied, we don't want
    to touch anything but the inline functions.
  - Remove the implementation of the inline function (this is enclosed
    in square brackets) and replace it with ";" to complete the
    transformation to normal/non-inline function.
  - Copy everything after the inline function implementation

Repeat the above step until we can't find "static inline" anymore

- To remove the inline implementation,
  we count the number of square-bracket 'levels' in the inline function
  and remove every pair. This ensures that constructs like:
  inline void func(void) {
      if (...) {
        //NOP
      }
      else
      {
        //NOP
      }
  }
  will not end up leaving the 'else' keyword unremoved:
  inline void func(void);
      else
  If we count the number of levels, we don't end up in this scenario
  since we remove 3 'pairs', the if-one, the else-one and finally the
  main body.
2019-11-12 20:01:04 +01:00
laurens 2def6c4f21 Fix compile warnings on inline.h test header 2019-11-12 12:10:27 +01:00
Mark VanderVoord d403eb88c8 Merge pull request #258 from jlindgren90/master
Fix compile error when :unity_helper_path is relative.
2019-11-11 08:38:14 -05:00
Mark VanderVoord 18b2deca85 Merge pull request #261 from laurensmiers/master
Inline function mocking
2019-11-11 08:36:21 -05:00
laurens bd91eb4cca Refactor calling of transform_inline_functions
- This way, @normalized_source will always be defined, which it should
  because we are referencing it a few lines down, thanks to
  @mvandervoord for the suggestion
2019-11-11 14:26:29 +01:00
laurens fe829f2d8a Expand transform_inline_functions unit test with more usecases 2019-11-11 13:26:40 +01:00
laurens 5650b79dcd Replace NOP with actual operations to test inline.h compilation 2019-11-11 13:22:00 +01:00
laurens 9908930bc5 Fix multi-line each + use gsub! iso gsub 2019-11-11 13:14:18 +01:00
laurens b256013c5e Only normalize source if treat_inlines is enabled 2019-11-11 13:12:15 +01:00
laurens 927ca1bec0 Extract method to remove_nested_pair_of_braces in cmock_header_parser 2019-11-10 20:55:02 +01:00
laurens e1c6851492 Rename normalize_source to transform_inline_functions 2019-11-10 20:13:35 +01:00
laurens e0a61d484e Add unit tests for normalize_source
- Refactor normalize_source to do the minimum amount that is
  necessary.
  For now, this is just removing inline functions.
2019-11-10 20:11:27 +01:00
laurens 431c5c678a Refactor cleanup actions when normalizing source 2019-11-10 19:35:27 +01:00
laurens 3a07201a3f Add treat_inlines to all_plugins_coexist test 2019-11-10 18:44:20 +01:00
laurens 11dfb9c668 osek.h does not need to be executable 2019-11-10 18:39:35 +01:00
laurens 27e89dd05e Rename treat_inline to treat_inlines 2019-11-10 18:39:35 +01:00
laurens 237c02dade Write converted header file (without inline) to separate file
- This prevents changing the original mock file that is generated,
  it thinks it includes the 'original' header file that is being
  mocked,
  but if we place our newly generated header file in the same
  directory as the mock_<header_file>.h, it will include our newly
  generated header file.
2019-11-10 18:39:20 +01:00
laurens 5ee470d7e4 Convert inline functions in header-mock to 'normal' functions
- normalize_source() will convert the header-to-mock.
  It will look for the inline function definitions and transform them
  into function declarations for non-inline functions.
2019-11-10 18:39:20 +01:00
laurensmiers 79ee5b8419 Add documentation 2019-11-10 18:39:20 +01:00
laurensmiers fba3bc22a2 Some more tests for :treat_include: with extern + some comments 2019-11-10 18:39:20 +01:00
laurensmiers 01536c4a67 Better handling of inline functions with declaration in header 2019-11-10 18:39:20 +01:00
laurensmiers 7a32429bd2 Add handling of treat_inline
- treat_externs only has effect on "extern", not "inline" anymore
- when treat_inline = :include, we remove the "inline" so that the inline functions become 'normal' functions
  - they are handled as as usual and will be mocked
- Add tests to check inline functions are not deleted when treat_inline=:include (and thus mocked)
2019-11-10 18:39:20 +01:00
laurensmiers dbb2f4964c Add treat_inline configuration option 2019-11-10 18:39:20 +01:00
John Lindgren 2817da62db Fix compile error when :unity_helper_path is relative.
Including :unity_helper_path directly doesn't work if the path is
relative and :mock_path is not the same as the working directory.
2019-11-05 15:39:32 -05:00
Mark VanderVoord ee3ae84e64 Merge pull request #257 from art-of-dom/ret-var-name-change
make ret variable more unique to prevent collision with with code under test
2019-11-04 23:21:09 -05:00
Dom Postorivo 0cdc742538 make ret variable more unique to prevent collision with with code under test 2019-11-04 11:23:57 -05:00
Mark VanderVoord c1b1ff6350 Merge pull request #255 from jlindgren90/master
Add documentation for :array_size_type and :array_size_name.
2019-10-30 17:02:27 -04:00
John Lindgren 73afa2973b Add documentation for :array_size_type and :array_size_name.
Closes #253.
2019-10-30 16:20:47 -04:00
mvandervoord db98427231 Verify old parsing issue is gone (see issue #195) 2019-10-30 14:30:18 -04:00
mvandervoord 7615806e34 Address issue #196 to better deal with passing pointer types 2019-10-30 14:10:59 -04:00
Mark VanderVoord 9a0bf38c76 Merge pull request #254 from jlindgren90/master
Fix typo (unity_gelper -> unity_helper)
2019-10-30 12:47:40 -04:00
John Lindgren 277dc34fa1 Fix typo (unity_gelper -> unity_helper). 2019-10-30 12:45:19 -04:00
Mark VanderVoord 9327cd7af1 Merge pull request #252 from jlindgren90/master
Documentation fixes
2019-10-30 11:59:41 -04:00
Mark VanderVoord 71b4ec2088 Merge pull request #249 from michaelbadcrumble/meson_support
Upgrade Meson version too 0.52.0
2019-10-30 11:57:32 -04:00
John Lindgren 639d4120d1 Documentation fixes. 2019-10-30 11:56:43 -04:00
Mark VanderVoord 16900b4b7f Merge pull request #251 from jlindgren90/master
Fix minor memory-management bugs
2019-10-30 11:54:45 -04:00
mvandervoord 14d57c2e93 Update to latest Unity 2019-10-30 10:34:37 -04:00
John Lindgren c787042e6d Fix off-by-one error in out-of-memory check.
We should be able to allocate up to CMock_Guts_MemBytesFree() minus
CMOCK_MEM_INDEX_SIZE.  An incorrect less-than-or-equal prevented
allocating the very last byte.
2019-10-30 10:30:25 -04:00
John Lindgren ea71fb0e0e CMock_Guts_MemBytesUsed() should return 0 initially.
Set CMock_Guts_FreePtr to CMOCK_MEM_ALIGN_SIZE initially (the same
value it is reset to by CMock_Guts_MemFreeAll().  This makes sure
that the value returned by CMock_Guts_MemBytesUsed() is 0 initially
and not a negative value.
2019-10-30 10:22:05 -04:00
John Lindgren 74fa13f6a0 CMOCK_MEM_ALIGN should not change depending on #include order.
The value of CMOCK_MEM_ALIGN changed depending on whether unity.h
or cmock.h was included first.  Since cmock_internals.h uses
features from unity.h, it should include unity.h.
2019-10-30 10:14:30 -04:00
mvandervoord bb3e821eb2 Verify that void* is treated as a bytewise array comparison. 2019-10-28 07:30:51 -04:00
mvandervoord 4946aaac37 Update to latest Unity 2019-10-24 15:45:45 -04:00
mvandervoord cda809765e Protect again memory overruns.
Get rid of warnings.
2019-10-23 17:12:18 -04:00
Mark VanderVoord 8f1156dddc latest 2019-10-23 16:38:59 -04:00
Mark VanderVoord a210abdd12 Merge branch 'master' of https://github.com/ThrowTheSwitch/CMock
* 'master' of https://github.com/ThrowTheSwitch/CMock:
  Fixed an error.
2019-10-23 16:37:36 -04:00
Mark VanderVoord 10e8cc27eb Add resetTest to documentation 2019-10-23 16:36:59 -04:00
mvandervoord b2e312e434 Fixed an error. 2019-10-23 16:03:42 -04:00
Mark VanderVoord 741b1067a3 ExpectAnyArgs should not be generated for functions with no arguments (#201) 2019-10-23 15:51:22 -04:00
mvandervoord b37b3cd86b Removing mac testing from Travis because Travis is always breaking it. *sigh* 2019-10-23 08:15:40 -04:00
Mark VanderVoord abec576fdb bump version of ruby run by travis 2019-10-21 11:23:39 -04:00
Mark VanderVoord b90706424a Switching to universal version being in the header file itself. 2019-10-21 10:13:19 -04:00
Michael Brockus 2ff29226e8 Upgrade Meson version too 0.52.0
Simply bumping Meson build support version 0.52.0
2019-10-12 09:22:31 -07:00
Mark VanderVoord bc8e20e88d Merge pull request #246 from michaelbadcrumble/meson_support
Add Meson support in CMock.
2019-09-26 08:50:27 -04:00
Mark VanderVoord c5becef9fd Merge pull request #243 from jlindgren90/expect-any-args-cleanup
Replace IgnoreMode with ExpectAnyArgsBool (no functional change).
2019-09-26 08:31:05 -04:00
Michael Brockus d2c5df2f5e Adding meson.build script at root directory. 2019-09-20 16:51:15 -07:00
Michael Brockus 0e9f8c54bc Created sub meson.build in source directory. 2019-09-20 16:25:04 -07:00
John Lindgren b76d570d4a Replace IgnoreMode with ExpectAnyArgsBool (no functional change).
IgnoreMode was used only for the ExpectAnyArgs plugin, and the
semantics of it were backwards:

  - IgnoreMode = CMOCK_ARG_NONE means to ignore all arguments
  - IgnoreMode = CMOCK_ARG_ALL means to verify all arguments

ExpectAnyArgsBool should make the purpose and semantics of this
field clearer.

Additionally, ExpectAnyArgs doesn't use FinalReturn for anything.
2019-09-16 13:28:14 -04:00
Mark VanderVoord c23c01266a We need function prototypes to comply with strict compiler settings 2019-09-09 16:32:39 -04:00
Mark VanderVoord e17728fe4d Minor tweaks to overcome Ruby style warnings. 2019-09-09 14:46:14 -04:00
Mark VanderVoord 37be90bd96 Add another test for function pointers which should be ignored. 2019-09-09 11:12:27 -04:00
Mark VanderVoord 533ae7a7b1 Merge pull request #236 from jlindgren90/redundant-destroy
callback's mock_destroy() is redundant.
2019-09-09 11:02:06 -04:00
Mark VanderVoord 582e0f87cf Reworked naming of the new divided callback functionality to better reflect what is happening and avoid another use of the word Ignore. 2019-09-09 11:00:09 -04:00
Mark VanderVoord 5e9264f993 Merge pull request #237 from jlindgren90/ignore-with-callback-2
Add CheckWithCallback and IgnoreWithCallback.
2019-09-09 10:44:54 -04:00
Mark VanderVoord 6ae662f2e8 Update documentation for clarity.
Grab latest Unity
2019-09-09 10:32:42 -04:00
Mark VanderVoord e1f7c35f2e Merge pull request #241 from jlindgren90/expect-details
Expect plugin should call UNITY_SET/CLR_DETAILS in pairs.
2019-09-03 11:07:03 -04:00
John Lindgren b895a4575a Expect plugin should call UNITY_SET/CLR_DETAILS in pairs.
The generated _Expect() functions called UNITY_CLR_DETAILS, which was
unnecessary because they did not call UNITY_SET_DETAIL.

The generated _Verify() functions called UNITY_SET_DETAIL but never
called UNITY_CLR_DETAILS to clean up after themselves.
2019-08-30 12:14:11 -04:00
Mark VanderVoord e17180b2ef Merge pull request #240 from edgarholleis/master
Improve comment suppression to cope with '/*xxx*//*yyy*/'.
2019-08-22 06:21:22 -04:00
Edgar J Holleis 23d2341c4c Improve comment suppression to cope with '/*xxx*//*yyy*/'. 2019-08-22 10:58:13 +02:00
John Lindgren 5f2ae0ee0f Update documentation 2019-07-24 13:55:04 -04:00
John Lindgren c70cec0b19 Add CheckWithCallback and IgnoreWithCallback.
StubWithCallback can currently be configured to run the callback
function either before or after argument+ordering checks, based on
:callback_after_arg_check.  Currently, however, you can't use both
behaviors in the same test suite; you have to pick one.

This change makes both behaviors available under two new names:
 - IgnoreWithCallback, as if :callback_after_arg_check = false
 - CheckWithCallback, as if :callback_after_arg_check = true

StubWithCallback simply becomes an alias (#define) for either
IgnoreWithCallback or CheckWithCallback, depending on config.
2019-07-24 13:36:41 -04:00
John Lindgren fbb0828ee0 callback's mock_destroy() is redundant.
create_mock_destroy_function() in cmock_generator.rb already clears
the entire mock to 0 (using memset) before call the plugin's
mock_destroy() function.  So mock_destroy() in the callback plugin
is doing work that was already done.
2019-07-24 12:05:50 -04:00
John Lindgren f8281e456d callback's mock_destroy() is redundant.
create_mock_destroy_function() in cmock_generator.rb already clears
the entire mock to 0 (using memset) before call the plugin's
mock_destroy() function.  So mock_destroy() in the callback plugin
is doing work that was already done.
2019-07-24 11:43:44 -04:00
John Lindgren 8b4deef12b Call UNITY_CLR_DETAILS() before returning from mock 2019-07-23 17:41:28 -04:00
John Lindgren 9e5afe4255 Refactor callback generator a bit (no functional change) 2019-07-23 17:14:33 -04:00
Mark VanderVoord 4df532afcc Add quick pointer check before memory comparisons (#224) 2019-07-09 23:16:02 -04:00
Mark VanderVoord 12c74c0349 Keep function pointers from choking CMock (fixes issues #102, #222, #226) 2019-07-09 22:23:40 -04:00
Mark VanderVoord 4c6fe35bbf Clean up full header list. (Why didn't this get caught in my local tests?) 2019-07-09 11:14:10 -04:00
Mark VanderVoord 4ab728b6d3 Whoops 2019-07-09 10:57:31 -04:00
Mark VanderVoord 7761b3fb3f automatically pull in unity helper into tests when specified in both example and cmock's includes. 2019-07-09 10:50:29 -04:00
Mark VanderVoord 0b6118e410 Merge pull request #186 from jlindgren90/master
mock_Verify functions should ideally not modify the state of the mock.
2019-07-07 15:12:07 -04:00
Mark VanderVoord d5dffde17d Merge pull request #187 from jlindgren90/array-typedefs
Add treat_as_array configuration option.
2019-07-07 15:10:18 -04:00
Mark VanderVoord 347dfc181a Merge branch 'master' into array-typedefs 2019-07-07 15:06:49 -04:00
Mark VanderVoord 4a6ee8680c Merge pull request #190 from achsfy/master
Detect array_data,array_size pattern when generating mock
2019-07-07 14:51:21 -04:00
Mark VanderVoord f909378a1d Clean up example makefile to properly support externally supported paths. (This is a tiny fix to PR 193) 2019-07-07 14:43:20 -04:00
Mark VanderVoord 035141e2ab - Added capacity accessor for easier testing
- Made test size-agnostic for easier boundary checking.
2019-07-07 14:15:35 -04:00
Mark VanderVoord 5eab75a078 Reimplement PR 227 with fixed tests. 2019-07-06 12:11:56 -04:00
Mark VanderVoord 99c2223a1d Back out broken changes. (See issue #210. Thanks @HamboLagos) 2019-07-03 11:09:06 -04:00
Mark VanderVoord 4b35cb2e43 Merge pull request #198 from Xenoamor/master
Fix bug where if folder "mocks" doesn't exist it fails
2019-03-22 05:47:44 -04:00
Mark VanderVoord e417f323fc Merge pull request #211 from merazmus/fix_missing_header
Fix missing framework header in mock header files
2019-03-22 05:41:23 -04:00
merazmus af59c531f7 Update unit tests 2019-03-22 09:11:58 +01:00
merazmus a5616dc2df Fix missing framework header in mock header files 2019-03-22 09:10:16 +01:00
Joshua Booth 5716454e11 Merge branch 'master' of https://github.com/Xenoamor/CMock 2019-03-21 19:08:45 +00:00
Xenoamor 80454dc1f3 Fix bug where if folder mocks doesn't exist it fails 2019-03-21 19:08:26 +00:00
Mark VanderVoord 2b93dfdd1d Merge pull request #208 from art-of-dom/travis-fix
Adjusted travis to use ruby 2.3 to make OSX build pass
2019-03-20 05:56:56 -04:00
Dom Postorivo 727a5cc8a8 adjusted travis to use ruby 2.3 to make OSX build pass 2019-03-20 00:00:41 -04:00
Mark VanderVoord c243b9a7a7 Merge pull request #203 from bmcdonnell/grammar
Grammar fix--"fewer times", not "less times"
2019-03-01 22:27:53 -05:00
Brendan McDonnell b409ba6a1d Grammar fix--"fewer times", not "less times" 2019-03-01 21:52:12 -05:00
Xenoamor b2adf60b2f Fix bug where if folder mocks doesn't exist it fails 2019-01-28 15:53:33 +00:00
John Lindgren cfa46d6440 Prevent undefined behavior due to typedef array usage. 2018-12-04 18:22:53 -05:00
John Lindgren 789c5852b5 Add treat_as_array configuration option. 2018-12-04 18:18:43 -05:00
Mark VanderVoord 99fa519136 Merge pull request #194 from danyeaw/license-detection
Move license for GitHub detection (Thanks @danyeaw !)
2018-11-13 21:13:58 -05:00
Dan Yeaw 0706e8b355 Move license for GitHub detection 2018-11-13 21:11:15 -05:00
Aurelien CHAPPUIS 8d16dca722 Update cmock_header_parser_test.rb tests to include new configuration items array_size_type and array_size_name 2018-09-18 15:06:10 +02:00
Aurelien CHAPPUIS e8c7ad9706 Try to find 'array pair' in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name>
When such a pattern is used, the second parameter is used as the array size in _Expect method.
2018-09-18 12:06:40 +02:00
John Lindgren 63527a3217 mock_Verify functions should ideally not modify the state of the mock.
In typical unit tests, this doesn't matter since the Verify functions
are called only from the end of the test.  However, in longer integration
tests, where a sequence of function calls is to be tested, it's handy
to be able to verify the Expects halfway through the test.  This change
is a first step in making that possible.
2018-08-28 14:51:41 -04:00
Mark VanderVoord 7cc41ddfdd Merge pull request #172 from Vicentra/Issue66
Fix alignment error of CMock_Guts_Buffer (Thanks @jmzeeman !)
2018-08-08 13:37:03 -04:00
Mark VanderVoord 407c2ef3b9 Grab latest unity to test as next release candidate 2018-08-08 13:21:00 -04:00
Mark VanderVoord 5edf07e87c Update travis to use a proper gem version for rubocop 2018-07-18 10:40:48 -04:00
Mark VanderVoord 7c6552bb2f Merge pull request #179 from Xenoamor/master
Add "cd test" to README.md for running rake (Thanks!)
2018-07-18 09:15:17 -04:00
Xenoamor ab339721ae Add "cd test" to README.md for running rake
Running rake from the project root directory generates the error: "No Rakefile found"
2018-07-18 14:05:55 +01:00
Matthijs Zeeman 732556700d Fix alignment error of CMock_Guts_Buffer
Changed allocation to use CMOCK_MEM_INDEX_TYPE instead of unsigned char. This may allocate extra memory if CMOCK_MEM_SIZE  is not a multiple of CMOCK_MEM_INDEX_SIZE. Had to substitute CMock_Guts_Buffer with a define in this case because  pointers are not constants.
2018-06-21 11:33:13 +02:00
Mark VanderVoord c3a95e93be Merge pull request #155 from paulsc/master
Fix for issue #154 (rusty or not, it works! Thanks @paulsc )
2017-12-07 06:41:23 -05:00
Paul 49bc3ebcce fix for mock prefix & suffix filter 2017-12-07 09:08:29 +01:00
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
80 changed files with 4831 additions and 1324 deletions
+41
View File
@@ -0,0 +1,41 @@
---
# Continuous Integration Workflow: Test case suite run + validation build check
name: CI
# Controls when the action will run.
# Triggers the workflow on push or pull request events but only for the master branch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
# Job: Unit test suite
unit-tests:
name: "Unit Tests"
runs-on: ubuntu-latest
steps:
# Install Multilib
- name: Install Multilib
run: |
sudo apt-get install --assume-yes --quiet gcc-multilib
# Checks out repository under $GITHUB_WORKSPACE
- name: Checkout Latest Repo
uses: actions/checkout@v2
with:
submodules: recursive
# Install Ruby Testing Tools
- name: Setup Ruby Testing Tools
run: |
sudo gem install bundler
sudo gem install rspec
sudo gem install rubocop -v 0.57.2
bundle install
# Run Tests
- name: Run All Unit Tests
run: |
cd test && rake ci
+2
View File
@@ -1,8 +1,10 @@
test/system/build
test/system/generated
*.sublime-project
*.sublime-workspace
Gemfile.lock
.rake_t_cache
.DS_Store
*.swp
examples/make_example/build
examples/temp_sensor/build
-29
View File
@@ -1,29 +0,0 @@
language: ruby
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 test
- cd ..
- cd temp_sensor
- rake ci
+2 -3
View File
@@ -1,8 +1,7 @@
source "http://rubygems.org/"
gem "bundler", "~> 1.1.rc.7"
gem "rake", ">= 0.9.2.2"
gem "bundler"
gem "rake"
gem "minitest"
gem "require_all"
gem "constructor"
View File
+12 -6
View File
@@ -1,23 +1,29 @@
CMock - Mock/stub generator for C
=================================
CMock ![CI](https://github.com/ThrowTheSwitch/CMock/workflows/CI/badge.svg)
=====
CMock is a mock and stub generator and runtime for unit testing C. It's been designed
to work smoothly with Unity Test, another of the embedded-software testing tools
developed by ThrowTheSwitch.org. CMock automagically parses your C headers and creates
useful and usable mock interfaces for unit testing. Give it a try!
[![CMock Build Status](https://api.travis-ci.org/ThrowTheSwitch/CMock.png?branch=master)](https://travis-ci.org/ThrowTheSwitch/CMock)
If you don't care to manage unit testing builds yourself, consider checking out Ceedling,
a test-centered build manager for unit testing C code.
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:
> cd test
> rake # Run all CMock self tests
API Documentation
+5 -7
View File
@@ -2,13 +2,11 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
# Setup our load path:
[
'lib',
[
'lib'
].each do |dir|
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__)) + '/../', dir) )
$:.unshift(File.join(__dir__ + '/../', dir))
end
+1 -1
View File
@@ -12,5 +12,5 @@
'./vendor/unity/auto/',
'./test/system/'
].each do |dir|
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) )
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__) + '/../'), dir))
end
+315 -79
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:
@@ -117,23 +117,23 @@ ExpectAnyArgs:
This behaves just like the Expects calls, except that it doesn't really
care what the arguments are that the mock gets called with. It still counts
the number of times the mock is called and it still handles return values
if there are some.
if there are some. Note that an ExpectAnyArgs call is not generated for
functions that have no arguments, because it would act exactly like the existing
Expect and ExpectAndReturn calls.
* `void func(void)` => `void func_ExpectAnyArgs(void)`
* `void func(params)` => `void func_ExpectAnyArgs(void)`
* `retval func(void)` => `void func_ExpectAnyArgsAndReturn(retval_to_return)`
* `retval func(params)` => `void func_ExpectAnyArgsAndReturn(retval_to_return)`
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 fewer 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)`
@@ -161,6 +161,35 @@ care how many times it was called, right?
* `retval func(void)` => `void func_IgnoreAndReturn(retval_to_return)`
* `retval func(params)` => `void func_IgnoreAndReturn(retval_to_return)`
StopIgnore:
-------
Maybe you want to ignore a particular function for part of a test but dont want to
ignore it later on. In that case, you want to use StopIgnore which will cancel the
previously called Ignore or IgnoreAndReturn requiring you to Expect or otherwise
handle the call to a function.
* `void func(void)` => `void func_StopIgnore(void)`
* `void func(params)` => `void func_StopIgnore(void)`
* `retval func(void)` => `void func_StopIgnore(void)`
* `retval func(params)` => `void func_StopIgnore(void)`
IgnoreStateless:
----------------
This plugin is similar to the Ignore plugin, but the IgnoreAndReturn functions are
stateless. So the Ignored function will always return the last specified return value
and does not queue the return values as the IgnoreAndReturn of the default plugin will.
To stop ignoring a function you can call StopIgnore or simply overwrite the Ignore
(resp. IgnoreAndReturn) with an Expect (resp. ExpectAndReturn). Note that calling
Ignore (resp IgnoreAndReturn) will clear your previous called Expect
(resp. ExpectAndReturn), so they are not restored after StopIgnore is called.
You can use this plugin by using `:ignore_stateless` instead of `:ignore` in your
CMock configuration file.
The generated functions are the same as **Ignore** and **StopIgnore** above.
Ignore Arg:
------------
@@ -168,9 +197,11 @@ Ignore Arg:
Maybe you overall want to use Expect and its similar variations, but you don't care
what is passed to a particular argument. This is particularly useful when that argument
is a pointer to a value that is supposed to be filled in by the function. You don't want
to use ExpectAnyArgs, because you still care about the other arguments. Instead, before
any of your Expect calls are made, you can call this function. It tells CMock to ignore
a particular argument for the rest of this test, for this mock function.
to use ExpectAnyArgs, because you still care about the other arguments. Instead, after
an Expect call is made, you can call this function. It tells CMock to ignore
a particular argument for the rest of this test, for this mock function. You may call
multiple instances of this to ignore multiple arguments after each expectation if
desired.
* `void func(params)` => `void func_IgnoreArg_paramName(void)`
@@ -179,7 +210,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.
@@ -194,25 +225,36 @@ 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
first (like expects) or just jump directly to the callback.
whenever the mock is encountered and return the retval returned from the callback (if any).
* `void func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
* `void func(void)` => `void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback)`
where `CMOCK_func_CALLBACK` looks like: `void func(int NumCalls)`
* `void func(params)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
* `void func(params)` => `void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback)`
where `CMOCK_func_CALLBACK` looks like: `void func(params, int NumCalls)`
* `retval func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
* `retval func(void)` => `void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback)`
where `CMOCK_func_CALLBACK` looks like: `retval func(int NumCalls)`
* `retval func(params)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
* `retval func(params)` => `void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback)`
where `CMOCK_func_CALLBACK` looks like: `retval func(params, int NumCalls)`
You can choose from two options:
* `func_AddCallback` tells the mock to check its arguments and calling
order (based on any Expects you've set up) before calling the callback.
* `func_Stub` tells the mock to skip all the normal checks and jump directly
to the callback instead. In this case, you are replacing the normal mock calls
with your own custom stub function.
There is also an older name, `func_StubWithCallback`, which is just an alias
for either `func_AddCallback` or `func_Stub` depending on setting of the
`:callback_after_arg_check` toggle. This is deprecated and we recommend using
the two options above.
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)`
@@ -269,6 +311,22 @@ You may specify the options explicitly:
cmock = Cmock.new(:plugins => [:cexception, :ignore], :mock_path => 'my/mocks/')
Creating Skeletons:
-------------------
Not only is CMock able to generate mock files from a header file, but it is also able
to generate (and update) skeleton C files from headers. It does this by creating a
(mostly) empty implementation for every function that is declared in the header. If you later
add to that header list, just run this feature again and it will add prototypes for the missing
functions!
Like the normal usecase for CMock, this feature can be used from the command line
or from within its ruby API. For example, from the command line, add `--skeleton` to
generate a skeleton instead:
```
ruby cmock.rb --skeleton ../create/c/for/this.h
```
Config Options:
---------------
@@ -295,8 +353,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 +364,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 +381,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 +397,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 +412,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 +426,61 @@ 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
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
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_stateless`
* `: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*\(+.*?\)+)']
* 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 +491,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'
@@ -479,20 +538,71 @@ from the defaults. We've tried to specify what the defaults are below.
* 'float': 'FLOAT'
* 'double': 'FLOAT'
* `:treat_as_array`:
A specialized sort of `:treat_as` to be used when you've created a
typedef of an array type, such as `typedef int TenIntegers[10];`. This
is a hash of typedef name to element type. For example:
{ "TenIntegers" => "int",
"ArrayOfFloat" => "float" }
Telling CMock about these typedefs allows it to be more intelligent
about parameters of such types, so that you can use features like
ExpectWithArray and ReturnArrayThruPtr with them.
* `:treat_as_void`:
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).
* `:treat_inlines`:
This specifies how you want CMock to handle functions that have been
marked as inline in the header file. Should it mock them?
* `:include` will mock inlined functions
* `:exclude` will ignore inlined functions (default).
CMock will look for the following default patterns (simplified from the actual regex):
- "static inline"
- "inline static"
- "inline"
- "static"
You can override these patterns, check out :inline_function_patterns.
Enabling this feature does require a change in the build system that
is using CMock. To understand why, we need to give some more info
on how we are handling inline functions internally.
Let's say we want to mock a header called example.h. example.h
contains inline functions, we cannot include this header in the
mocks or test code if we want to mock the inline functions simply
because the inline functions contain an implementation that we want
to override in our mocks!
So, to circumvent this, we generate a new header, also named
example.h, in the same directory as mock_example.h/c . This newly
generated header should/is exactly the same as the original header,
only difference is the inline functions are transformed to 'normal'
functions declarations. Placing the new header in the same
directory as mock_example.h/c ensures that they will include the new
header and not the old one.
However, CMock has no control in how the build system is configured
and which include paths the test code is compiled with. In order
for the test code to also see the newly generated header ,and not
the old header with inline functions, the build system has to add
the mock folder to the include paths.
Furthermore, we need to keep the order of include paths in mind. We
have to set the mock folder before the other includes to avoid the
test code including the original header instead of the newly
generated header (without inline functions).
* `:unity_helper_path`:
If you have created a header with your own extensions to unity to
handle your own types, you can set this argument to that path. CMock
@@ -500,23 +610,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 +635,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 +648,92 @@ 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
* `:array_size_type`:
* `:array_size_name`:
When the `:array` plugin is disabled, these options do nothing.
When the `:array` plugin is enabled, these options allow CMock to recognize
functions with parameters that might refer to an array, like the following,
and treat them more intelligently:
* `void GoBananas(Banana * bananas, int num_bananas)`
* `int write_data(int fd, const uint8_t * data, uint32_t size)`
To recognize functions like these, CMock looks for a parameter list
containing a pointer (which could be an array) followed by something that
could be an array size. "Something", by default, means an `int` or `size_t`
parameter with a name containing "size" or "len".
`:array_size_type` is a list of additional types (besides `int` and `size_t`)
that could be used for an array size parameter. For example, to get CMock to
recognize that `uint32_t size` is an array size, you'd need to say:
cfg[:array_size_type] = ['uint32_t']
`:array_size_name` is a regular expression used to match an array size
parameter by name. By default, it's 'size|len'. To get CMock to recognize a
name like `num_bananas`, you could tell it to also accept names containing
'num_' like this:
cfg[:array_size_name] = 'size|len|num_'
Parameters must match *both* `:array_size_type` and `:array_size_name` (and
must come right after a pointer parameter) to be treated as an array size.
Once you've told it how to recognize your arrays, CMock will give you `_Expect`
calls that work more like `_ExpectWithArray`, and compare an array of objects
rather than just a single object.
For example, if you write the following, CMock will check that GoBananas is
called and passed an array containing a green banana followed by a yellow
banana:
Banana b[2] = {GreenBanana, YellowBanana};
GoBananas_Expect(b, 2);
In other words, `GoBananas_Expect(b, 2)` now works just the same as:
GoBananas_ExpectWithArray(b, 2, 2);
* `: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).
* `:inline_function_patterns`:
An array containing a list of strings to detect inline functions.
This option is only taken into account if you enable :treat_inlines.
These strings are interpreted as regex patterns so be sure to escape
certain characters. For example, use `:inline_function_patterns: ['static inline __attribute__ \(\(always_inline\)\)']`
to recognize `static inline __attribute__ ((always_inline)) int my_func(void)`
as an inline function.
The default patterns are are:
* default: ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*']
* **note:**
The order of patterns is important here!
We go from specific patterns ('static inline') to general patterns ('inline'),
otherwise we would miss functions that use 'static inline' iso 'inline'.
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.
@@ -559,7 +746,7 @@ based on other settings, particularly Unity's settings.
* `CMOCK_MEM_SIZE`
In static mode this is the total amount of memory you are allocating
to Cmock. In Dynamic mode this is the size of each chunk allocated
at once (larger numbers grab more memory but require less mallocs).
at once (larger numbers grab more memory but require fewer mallocs).
* `CMOCK_MEM_ALIGN`
The way to align your data to. Not everything is as flexible as
@@ -575,14 +762,63 @@ based on other settings, particularly Unity's settings.
* `CMOCK_MEM_INDEX_TYPE`
This needs to be something big enough to point anywhere in Cmock's
memory space... usually it's an unsigned int.
memory space... usually it's a size_t.
Other Tips
==========
resetTest
---------
While this isn't strictly a CMock feature, often users of CMock are using
either the test runner generator scripts in Unity or using Ceedling. In
either case, there is a handy function called `resetTest` which gets
generated with your runner. You can then use this handy function in your tests
themselves. Call it during a test to have CMock validate everything to this point
and start over clean. This is really useful when wanting to test a function in
an iterative manner with different arguments.
C++ Support
---------
C++ unit test/mocking frameworks often use a completely different approach (vs.
CMock) that relies on overloading virtual class members and does not support
directly mocking static class member methods or free functions (i.e., functions
in plain C). One workaround is to wrap the non-virtual functions in an object
that exposes them as virtual methods and modify your code to inject mocks at
run-time... but there is another way!
Simply use CMock to mock the static member methods and a C++ mocking framework
to handle the virtual methods. (Yes, you can mix mocks from CMock and a C++
mocking framework together in the same test!)
Keep in mind that since C++ mocking frameworks often link the real object to the
unit test too, we need to resolve multiple definition errors with something like
the following in the source of the real implementation for any functions that
CMock mocks:
#if defined(TEST)
__attribute__((weak))
#endif
To address potential issues with re-using the same function name in different
namespaces/classes, the generated function names include the namespace(s) and
class. For example:
namespace MyNamespace {
class MyClass {
static int DoesSomething(int a, int b);
};
}
Will generate functions like
void MyNamespace_MyClass_DoesSomething_ExpectAndReturn(int a, int b, int toReturn);
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. ;)
+4 -4
View File
@@ -1,8 +1,8 @@
CC ?= gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
TEST_DIR ?= ./test
TEST_BUILD_DIR ?= ${BUILD_DIR}/test
export BUILD_DIR ?= ./build
export SRC_DIR ?= ./src
export TEST_DIR ?= ./test
export TEST_BUILD_DIR ?= ${BUILD_DIR}/test
TEST_MAKEFILE = ${TEST_BUILD_DIR}/MakefileTestSupport
OBJ ?= ${BUILD_DIR}/obj
OBJ_DIR = ${OBJ}
+11 -11
View File
@@ -1,4 +1,4 @@
HERE = File.expand_path(File.dirname(__FILE__)) + '/'
HERE = __dir__ + '/'
require 'rake'
require 'rake/clean'
@@ -7,36 +7,36 @@ require './rakefile_helper'
include RakefileHelpers
REQUIRED_DIRS = [ './build', './build/mocks' ]
REQUIRED_DIRS = ['./build', './build/mocks'].freeze
REQUIRED_DIRS.each do |v|
directory v
end
# Load default configuration, for now
DEFAULT_CONFIG_FILE = 'gcc.yml'
DEFAULT_CONFIG_FILE = 'gcc.yml'.freeze
configure_toolchain(DEFAULT_CONFIG_FILE)
task :unit do
run_tests(get_unit_test_files)
run_tests(unit_test_files)
end
desc "Generate test summary"
desc 'Generate test summary'
task :summary do
report_summary
end
desc "Build and test Unity"
task :all => [:clean, :unit, :summary]
task :default => REQUIRED_DIRS + [:clobber, :all]
desc 'Build and test Unity'
task :all => %i[clean unit summary]
task :default => REQUIRED_DIRS + %i[clobber all]
task :ci => [:default]
task :cruise => [:default]
desc "Load configuration"
task :config, :config_file do |t, args|
desc 'Load configuration'
task :config, :config_file do |_t, args|
configure_toolchain(args[:config_file])
end
desc "Return error on Failures"
desc 'Return error on Failures'
task :strict do
$return_error_on_failures = true
end
+95 -99
View File
@@ -5,10 +5,9 @@ require '../../vendor/unity/auto/generate_test_runner'
require '../../vendor/unity/auto/colour_reporter'
module RakefileHelpers
$return_error_on_failures = false
C_EXTENSION = '.c'
C_EXTENSION = '.c'.freeze
def load_configuration(config_file)
$cfg_file = config_file
@@ -20,22 +19,22 @@ module RakefileHelpers
CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil?
end
def configure_toolchain(config_file=DEFAULT_CONFIG_FILE)
def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
config_file += '.yml' unless config_file =~ /\.yml$/
load_configuration(config_file)
configure_clean
end
def get_unit_test_files
def unit_test_files
path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION
path.gsub!(/\\/, '/')
path.tr!('\\', '/')
FileList.new(path)
end
def get_local_include_dirs
def local_include_dirs
include_dirs = $cfg['compiler']['includes']['items'].dup
include_dirs.delete_if {|dir| dir.is_a?(Array)}
return include_dirs
include_dirs.delete_if { |dir| dir.is_a?(Array) }
include_dirs
end
def extract_headers(filename)
@@ -43,133 +42,134 @@ module RakefileHelpers
lines = File.readlines(filename)
lines.each do |line|
m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/)
if not m.nil?
unless m.nil?
includes << m[1]
end
end
return includes
includes
end
def find_source_file(header, paths)
paths.each do |dir|
src_file = dir + header.ext(C_EXTENSION)
if (File.exists?(src_file))
if File.exist?(src_file)
return src_file
end
end
return nil
nil
end
def tackit(strings)
case(strings)
when Array
"\"#{strings.join}\""
when /^-/
strings
when /\s/
"\"#{strings}\""
else
strings
case strings
when Array
"\"#{strings.join}\""
when /^-/
strings
when /\s/
"\"#{strings}\""
else
strings
end
end
def squash(prefix, items)
result = ''
items.each { |item| result += " #{prefix}#{tackit(item)}" }
return result
result
end
def build_compiler_fields
command = tackit($cfg['compiler']['path'])
if $cfg['compiler']['defines']['items'].nil?
defines = ''
else
defines = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'])
end
options = squash('', $cfg['compiler']['options'])
command = tackit($cfg['compiler']['path'])
defines = if $cfg['compiler']['defines']['items'].nil?
''
else
squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'])
end
options = squash('', $cfg['compiler']['options'])
includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
return {:command => command, :defines => defines, :options => options, :includes => includes}
{ :command => command, :defines => defines, :options => options, :includes => includes }
end
def compile(file, defines=[])
def compile(file, _defines = [])
compiler = build_compiler_fields
cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " +
cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " \
"#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}"
obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
execute(cmd_str + obj_file)
return obj_file
obj_file
end
def build_linker_fields
command = tackit($cfg['linker']['path'])
if $cfg['linker']['options'].nil?
options = ''
else
options = squash('', $cfg['linker']['options'])
end
if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?)
includes = ''
else
includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
end
command = tackit($cfg['linker']['path'])
options = if $cfg['linker']['options'].nil?
''
else
squash('', $cfg['linker']['options'])
end
includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?
''
else
squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
end
includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
return {:command => command, :options => options, :includes => includes}
{ :command => command, :options => options, :includes => includes }
end
def link_it(exe_name, obj_list)
linker = build_linker_fields
cmd_str = "#{linker[:command]}#{linker[:includes]} " +
(obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join +
$cfg['linker']['bin_files']['prefix'] + ' ' +
$cfg['linker']['bin_files']['destination'] +
exe_name + $cfg['linker']['bin_files']['extension'] + " #{linker[:options]}"
(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join +
$cfg['linker']['bin_files']['prefix'] + ' ' +
$cfg['linker']['bin_files']['destination'] +
exe_name + $cfg['linker']['bin_files']['extension'] + " #{linker[:options]}"
execute(cmd_str)
end
def build_simulator_fields
return nil if $cfg['simulator'].nil?
if $cfg['simulator']['path'].nil?
command = ''
else
command = (tackit($cfg['simulator']['path']) + ' ')
end
if $cfg['simulator']['pre_support'].nil?
pre_support = ''
else
pre_support = squash('', $cfg['simulator']['pre_support'])
end
if $cfg['simulator']['post_support'].nil?
post_support = ''
else
post_support = squash('', $cfg['simulator']['post_support'])
end
return {:command => command, :pre_support => pre_support, :post_support => post_support}
command = if $cfg['simulator']['path'].nil?
''
else
(tackit($cfg['simulator']['path']) + ' ')
end
pre_support = if $cfg['simulator']['pre_support'].nil?
''
else
squash('', $cfg['simulator']['pre_support'])
end
post_support = if $cfg['simulator']['post_support'].nil?
''
else
squash('', $cfg['simulator']['post_support'])
end
{ :command => command, :pre_support => pre_support, :post_support => post_support }
end
def execute(command_string, verbose=true, ok_to_fail=false)
def execute(command_string, verbose = true, ok_to_fail = false)
report command_string
output = `#{command_string}`.chomp
report(output) if (verbose && !output.nil? && (output.length > 0))
unless $?.exitstatus.zero? || ok_to_fail
report(output) if verbose && !output.nil? && !output.empty?
unless (!$?.nil? && $?.exitstatus.zero?) || ok_to_fail
raise "Command failed. (Returned #{$?.exitstatus})"
end
return output
output
end
def report_summary
summary = UnityTestSummary.new
summary.root = HERE
results_glob = "#{$cfg['compiler']['build_path']}*.test*"
results_glob.gsub!(/\\/, '/')
results_glob.tr!('\\', '/')
results = Dir[results_glob]
summary.targets = results
report summary.run
raise "There were failures" if (summary.failures > 0) && $return_error_on_failures
raise 'There were failures' if (summary.failures > 0) && $return_error_on_failures
end
def run_tests(test_files)
report 'Running system tests...'
# Tack on TEST define for compiling unit tests
@@ -178,30 +178,28 @@ module RakefileHelpers
$cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil?
$cfg['compiler']['defines']['items'] << 'TEST'
include_dirs = get_local_include_dirs
include_dirs = local_include_dirs
# Build and execute each unit test
test_files.each do |test|
obj_list = []
# Detect dependencies and build required required modules
header_list = extract_headers(test) + ['cmock.h']
header_list = (extract_headers(test) + ['cmock.h'] + [$cfg[:cmock][:unity_helper_path]]).compact.uniq
header_list.each do |header|
# create mocks if needed
next unless header =~ /Mock/
#create mocks if needed
if (header =~ /Mock/)
require "../../lib/cmock.rb"
@cmock ||= CMock.new($cfg_file)
@cmock.setup_mocks([$cfg['compiler']['source_path']+header.gsub('Mock','')])
end
require '../../lib/cmock.rb'
@cmock ||= CMock.new($cfg_file)
@cmock.setup_mocks([$cfg['compiler']['source_path'] + header.gsub('Mock', '')])
end
#compile all mocks
# compile all mocks
header_list.each do |header|
#compile source file header if it exists
# compile source file header if it exists
src_file = find_source_file(header, include_dirs)
if !src_file.nil?
unless src_file.nil?
obj_list << compile(src_file, test_defines)
end
end
@@ -228,35 +226,34 @@ module RakefileHelpers
# Execute unit test and generate results file
simulator = build_simulator_fields
executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension']
if simulator.nil?
cmd_str = executable
else
cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
end
cmd_str = if simulator.nil?
executable
else
"#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
end
output = execute(cmd_str, true, true)
test_results = $cfg['compiler']['build_path'] + test_base
if output.match(/OK$/m).nil?
test_results += '.testfail'
else
test_results += '.testpass'
end
test_results += if output.match(/OK$/m).nil?
'.testfail'
else
'.testpass'
end
File.open(test_results, 'w') { |f| f.print output }
end
end
def build_application(main)
report "Building application..."
report 'Building application...'
obj_list = []
load_configuration($cfg_file)
main_path = $cfg['compiler']['source_path'] + main + C_EXTENSION
# Detect dependencies and build required required modules
include_dirs = get_local_include_dirs
include_dirs = local_include_dirs
extract_headers(main_path).each do |header|
src_file = find_source_file(header, include_dirs)
if !src_file.nil?
unless src_file.nil?
obj_list << compile(src_file)
end
end
@@ -268,5 +265,4 @@ module RakefileHelpers
# Create the executable
link_it(main_base, obj_list)
end
end
+53 -28
View File
@@ -4,49 +4,63 @@
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
[ "../config/production_environment",
"cmock_header_parser",
"cmock_generator",
"cmock_file_writer",
"cmock_config",
"cmock_plugin_manager",
"cmock_generator_utils",
"cmock_unityhelper_parser"].each {|req| require "#{File.expand_path(File.dirname(__FILE__))}/#{req}"}
['../config/production_environment',
'cmock_header_parser',
'cmock_generator',
'cmock_file_writer',
'cmock_config',
'cmock_plugin_manager',
'cmock_generator_utils',
'cmock_unityhelper_parser'].each { |req| require "#{__dir__}/#{req}" }
class CMock
def initialize(options=nil)
def initialize(options = nil)
cm_config = CMockConfig.new(options)
cm_unityhelper = CMockUnityHelperParser.new(cm_config)
cm_writer = CMockFileWriter.new(cm_config)
cm_gen_utils = CMockGeneratorUtils.new(cm_config, {:unity_helper => cm_unityhelper})
cm_gen_utils = CMockGeneratorUtils.new(cm_config,
:unity_helper => cm_unityhelper)
cm_gen_plugins = CMockPluginManager.new(cm_config, cm_gen_utils)
@cm_parser = CMockHeaderParser.new(cm_config)
@cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils, cm_gen_plugins)
@cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils,
cm_gen_plugins)
@silent = (cm_config.verbosity < 2)
end
def setup_mocks(files)
def setup_mocks(files, folder = nil)
[files].flatten.each do |src|
generate_mock src
generate_mock(src, folder)
end
end
def setup_skeletons(files)
[files].flatten.each do |src|
generate_skeleton src
end
end
private ###############################
def generate_mock(src)
name = File.basename(src, '.h')
def generate_mock(src, folder)
name = File.basename(src, '.*')
ext = File.extname(src)
puts "Creating mock for #{name}..." unless @silent
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)))
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext, folder)
end
def generate_skeleton(src)
name = File.basename(src, '.*')
puts "Creating skeleton for #{name}..." unless @silent
@cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src)))
end
end
def option_maker(options, key, val)
options = options || {}
options ||= {}
options[key.to_sym] =
if val.chr == ":"
if val.chr == ':'
val[1..-1].to_sym
elsif val.include? ";"
elsif val.include? ';'
val.split(';')
elsif val == 'true'
true
@@ -60,12 +74,12 @@ def option_maker(options, key, val)
options
end
# Command Line Support ###############################
# Command Line Support ###############################
if ($0 == __FILE__)
if $0 == __FILE__
usage = "usage: ruby #{__FILE__} (-oOptionsFile) File(s)ToMock"
if (!ARGV[0])
unless ARGV[0]
puts usage
exit 1
end
@@ -73,14 +87,25 @@ if ($0 == __FILE__)
options = {}
filelist = []
ARGV.each do |arg|
if (arg =~ /^-o\"?([a-zA-Z0-9._\\\/:\s]+)\"?/)
options.merge! CMockConfig.load_config_file_from_yaml( arg.gsub(/^-o/,'') )
elsif (arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]+)\"?/)
options = option_maker(options, $1, $2)
if arg =~ /^-o\"?([a-zA-Z0-9@._\\\/:\s]+)\"?/
options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, ''))
elsif arg == '--skeleton'
options[:skeleton] = true
elsif arg =~ /^--strippables=\"?(.*)\"?/
# --strippables are dealt with separately since the user is allowed to
# enter any valid regular expression as argument
options = option_maker(options, 'strippables', Regexp.last_match(1))
elsif arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]*)\"?/x
options = option_maker(options, Regexp.last_match(1),
Regexp.last_match(2))
else
filelist << arg
end
end
CMock.new(options).setup_mocks(filelist)
if options[:skeleton]
CMock.new(options).setup_skeletons(filelist)
else
CMock.new(options).setup_mocks(filelist)
end
end
+85 -52
View File
@@ -5,90 +5,119 @@
# ==========================================
class CMockConfig
CMOCK_DEFAULT_OPTIONS =
{
:framework => :unity,
:mock_path => 'mocks',
:mock_prefix => 'Mock',
:mock_suffix => '',
:skeleton_path => '',
:weak => '',
:subdir => nil,
:plugins => [],
:strippables => ['(?:__attribute__\s*\(+.*?\)+)'],
:attributes => %w[__ramfunc __irq __fiq register extern],
:c_calling_conventions => %w[__stdcall __cdecl __fastcall],
:enforce_strict_ordering => false,
:fail_on_unexpected_calls => true,
:unity_helper_path => false,
:treat_as => {},
:treat_as_array => {},
:treat_as_void => [],
:memcmp_if_unknown => true,
:when_no_prototypes => :warn, # the options being :ignore, :warn, or :error
:when_ptr => :compare_data, # the options being :compare_ptr, :compare_data, or :smart
:verbosity => 2, # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
:treat_externs => :exclude, # the options being :include or :exclude
:treat_inlines => :exclude, # the options being :include or :exclude
:callback_include_count => true,
:callback_after_arg_check => false,
:includes => nil,
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
:includes_c_pre_header => nil,
:includes_c_post_header => nil,
:orig_header_include_fmt => '#include "%s"',
:array_size_type => [],
:array_size_name => 'size|len',
:skeleton => false,
CMockDefaultOptions =
{
:framework => :unity,
:mock_path => 'mocks',
:mock_prefix => 'Mock',
:mock_suffix => '',
:weak => '',
:subdir => nil,
:plugins => [],
:strippables => ['(?:__attribute__\s*\(+.*?\)+)'],
:attributes => ['__ramfunc', '__irq', '__fiq', 'register', 'extern'],
:c_calling_conventions => ['__stdcall', '__cdecl', '__fastcall'],
:enforce_strict_ordering => false,
:unity_helper_path => false,
:treat_as => {},
:treat_as_void => [],
:memcmp_if_unknown => true,
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
:when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart
:verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
:treat_externs => :exclude, #the options being :include or :exclude
:callback_include_count => true,
:callback_after_arg_check => false,
:includes => nil,
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
:includes_c_pre_header => nil,
:includes_c_post_header => nil,
:orig_header_include_fmt => "#include \"%s\"",
}
# Format to look for inline functions.
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
# There are several possibilities:
# - sometimes they appear together, sometimes individually,
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
# so we check for word boundaries when searching for them
# - We first remove "static inline" combinations and boil down to single inline or static statements
:inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*'] # Last part (\s*) is just to remove whitespaces (only to prettify the output)
}.freeze
def initialize(options=nil)
case(options)
when NilClass then options = CMockDefaultOptions.clone
when String then options = CMockDefaultOptions.clone.merge(load_config_file_from_yaml(options))
when Hash then options = CMockDefaultOptions.clone.merge(options)
else raise "If you specify arguments, it should be a filename or a hash of options"
def initialize(options = nil)
case options
when NilClass then options = CMOCK_DEFAULT_OPTIONS.dup
when String then options = CMOCK_DEFAULT_OPTIONS.dup.merge(load_config_file_from_yaml(options))
when Hash then options = CMOCK_DEFAULT_OPTIONS.dup.merge(options)
else raise 'If you specify arguments, it should be a filename or a hash of options'
end
#do some quick type verification
[:plugins, :attributes, :treat_as_void].each do |opt|
unless (options[opt].class == Array)
# do some quick type verification
%i[plugins attributes treat_as_void].each do |opt|
unless options[opt].class == Array
options[opt] = []
puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1)
puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1
end
end
[:includes, :includes_h_pre_orig_header, :includes_h_post_orig_header, :includes_c_pre_header, :includes_c_post_header].each do |opt|
unless (options[opt].nil? or (options[opt].class == Array))
%i[includes includes_h_pre_orig_header includes_h_post_orig_header includes_c_pre_header includes_c_post_header].each do |opt|
unless options[opt].nil? || (options[opt].class == Array)
options[opt] = []
puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1)
puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1
end
end
options[:unity_helper_path] ||= options[:unity_helper]
options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String
if options[:unity_helper_path]
require 'pathname'
includes1 = options[:includes_c_post_header] || []
includes2 = options[:unity_helper_path].map do |path|
Pathname(path).relative_path_from(Pathname(options[:mock_path])).to_s
end
options[:includes_c_post_header] = (includes1 + includes2).uniq
end
options[:plugins].compact!
options[:plugins].map! {|p| p.to_sym}
options[:plugins].map!(&:to_sym)
@options = options
treat_as_map = standard_treat_as_map()#.clone
treat_as_map = standard_treat_as_map # .clone
treat_as_map.merge!(@options[:treat_as])
@options[:treat_as] = treat_as_map
@options.each_key { |key| eval("def #{key.to_s}() return @options[:#{key.to_s}] end") }
@options.each_key do |key|
unless methods.include?(key)
eval("def #{key}() return @options[:#{key}] end")
end
end
end
def load_config_file_from_yaml yaml_filename
def load_config_file_from_yaml(yaml_filename)
self.class.load_config_file_from_yaml yaml_filename
end
def self.load_config_file_from_yaml yaml_filename
def self.load_config_file_from_yaml(yaml_filename)
require 'yaml'
require 'fileutils'
YAML.load_file(yaml_filename)[:cmock]
end
def set_path(path)
@src_path = path
def path(new_path)
@src_path = new_path
end
def load_unity_helper
return nil unless (@options[:unity_helper_path])
return nil unless @options[:unity_helper_path]
return @options[:unity_helper_path].inject("") do |unity_helper, filename|
@options[:unity_helper_path].inject('') do |unity_helper, filename|
unity_helper + "\n" + File.new(filename).read
end
end
@@ -119,6 +148,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 +161,8 @@ class CMockConfig
'UINT8' => 'HEX8',
'UINT8_T' => 'HEX8',
'char*' => 'STRING',
'char const*' => 'STRING',
'const char*' => 'STRING',
'pCHAR' => 'STRING',
'cstring' => 'STRING',
'CSTRING' => 'STRING',
+16 -12
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockFileWriter
attr_reader :config
def initialize(config)
@@ -13,31 +12,36 @@ class CMockFileWriter
end
def create_subdir(subdir)
if !Dir.exists?("#{@config.mock_path}/")
require 'fileutils'
FileUtils.mkdir_p "#{@config.mock_path}/"
end
if subdir && !Dir.exists?("#{@config.mock_path}/#{subdir+'/' if subdir}")
require 'fileutils'
FileUtils.mkdir_p "#{@config.mock_path}/#{subdir+'/' if subdir}"
end
require 'fileutils'
FileUtils.mkdir_p "#{@config.mock_path}/" unless Dir.exist?("#{@config.mock_path}/")
FileUtils.mkdir_p "#{@config.mock_path}/#{subdir + '/' if subdir}" if subdir && !Dir.exist?("#{@config.mock_path}/#{subdir + '/' if subdir}")
end
def create_file(filename, subdir)
raise "Where's the block of data to create?" unless block_given?
full_file_name_temp = "#{@config.mock_path}/#{subdir+'/' if subdir}#{filename}.new"
full_file_name_done = "#{@config.mock_path}/#{subdir+'/' if subdir}#{filename}"
full_file_name_temp = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}.new"
full_file_name_done = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}"
File.open(full_file_name_temp, 'w') do |file|
yield(file, filename)
end
update_file(full_file_name_done, full_file_name_temp)
end
def append_file(filename, subdir)
raise "Where's the block of data to create?" unless block_given?
full_file_name = "#{@config.skeleton_path}/#{subdir + '/' if subdir}#{filename}"
File.open(full_file_name, 'a') do |file|
yield(file, filename)
end
end
private ###################################
def update_file(dest, src)
require 'fileutils'
FileUtils.rm(dest) if (File.exist?(dest))
FileUtils.rm(dest) if File.exist?(dest)
FileUtils.cp(src, dest)
FileUtils.rm(src)
end
+151 -54
View File
@@ -5,8 +5,7 @@
# ==========================================
class CMockGenerator
attr_accessor :config, :file_writer, :module_name, :clean_mock_name, :mock_name, :utils, :plugins, :weak, :ordered
attr_accessor :config, :file_writer, :module_name, :module_ext, :clean_mock_name, :mock_name, :utils, :plugins, :weak, :ordered
def initialize(config, file_writer, utils, plugins)
@file_writer = file_writer
@@ -16,57 +15,86 @@ class CMockGenerator
@prefix = @config.mock_prefix
@suffix = @config.mock_suffix
@weak = @config.weak
@ordered = @config.enforce_strict_ordering
@framework = @config.framework.to_s
@include_inline = @config.treat_inlines
@ordered = @config.enforce_strict_ordering
@framework = @config.framework.to_s
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
@subdir = @config.subdir
@subdir = @config.subdir
@folder = nil
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
@includes_c_pre_header = (@config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
@includes_c_post_header = (@config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
@includes_c_pre_header = (@config.includes_c_pre_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
@includes_c_post_header = (@config.includes_c_post_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
here = File.dirname __FILE__
unity_path_in_ceedling = "#{here}/../../unity" # path to Unity from within Ceedling
unity_path_in_cmock = "#{here}/../vendor/unity" # path to Unity from within CMock
# path to Unity as specified by env var
unity_path_in_env = ENV.has_key?("UNITY_DIR") ? File.expand_path(ENV.fetch("UNITY_DIR")) : nil
unity_path_in_env = ENV.key?('UNITY_DIR') ? File.expand_path(ENV.fetch('UNITY_DIR')) : nil
if unity_path_in_env and File.exist? unity_path_in_env
if unity_path_in_env && File.exist?(unity_path_in_env)
require "#{unity_path_in_env}/auto/type_sanitizer"
elsif File.exist? unity_path_in_ceedling
require "#{unity_path_in_ceedling}/auto/type_sanitizer"
elsif File.exist? unity_path_in_cmock
require "#{unity_path_in_cmock}/auto/type_sanitizer"
else
raise "Failed to find an instance of Unity to pull in type_sanitizer module!"
raise 'Failed to find an instance of Unity to pull in type_sanitizer module!'
end
end
def create_mock(module_name, parsed_stuff)
def create_mock(module_name, parsed_stuff, module_ext = nil, folder = nil)
@module_name = module_name
@module_ext = module_ext || '.h'
@mock_name = @prefix + @module_name + @suffix
@clean_mock_name = TypeSanitizer.sanitize_c_identifier(@mock_name)
create_mock_subdir()
@folder = if folder && @subdir
File.join(@subdir, folder)
elsif @subdir
@subdir
else
folder
end
# adds a trailing slash to the folder output
@folder = File.join(@folder, '') if @folder
create_mock_subdir
create_mock_header_file(parsed_stuff)
create_mock_source_file(parsed_stuff)
end
def create_skeleton(module_name, parsed_stuff)
@module_name = module_name
create_skeleton_source_file(parsed_stuff)
end
private if $ThisIsOnlyATest.nil? ##############################
def create_mock_subdir()
if @subdir
@file_writer.create_subdir(@subdir)
end
def create_mock_subdir
@file_writer.create_subdir(@folder)
end
def create_using_statement(file, function)
file << "using namespace #{function[:namespace].join('::')};\n" unless function[:namespace].empty?
end
def create_mock_header_file(parsed_stuff)
@file_writer.create_file(@mock_name + ".h", @subdir) do |file, filename|
if @include_inline == :include
@file_writer.create_file(@module_name + (@module_ext || '.h'), @folder) do |file, _filename|
file << parsed_stuff[:normalized_source]
end
end
@file_writer.create_file(@mock_name + (@module_ext || '.h'), @folder) do |file, filename|
create_mock_header_header(file, filename)
create_mock_header_service_call_declarations(file)
create_typedefs(file, parsed_stuff[:typedefs])
parsed_stuff[:functions].each do |function|
create_using_statement(file, function)
file << @plugins.run(:mock_function_declarations, function)
end
create_mock_header_footer(file)
@@ -74,7 +102,7 @@ class CMockGenerator
end
def create_mock_source_file(parsed_stuff)
@file_writer.create_file(@mock_name + ".c", @subdir) do |file, filename|
@file_writer.create_file(@mock_name + '.c', @folder) do |file, filename|
create_source_header_section(file, filename, parsed_stuff[:functions])
create_instance_structure(file, parsed_stuff[:functions])
create_extern_declarations(file)
@@ -88,20 +116,35 @@ class CMockGenerator
end
end
def create_mock_header_header(file, filename)
def create_skeleton_source_file(parsed_stuff)
filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{module_name}.c"
existing = File.exist?(filename) ? File.read(filename) : ''
@file_writer.append_file(@module_name + '.c', @subdir) do |file, fullname|
create_source_header_section(file, fullname, []) if existing.empty?
parsed_stuff[:functions].each do |function|
create_function_skeleton(file, function, existing)
end
end
end
def create_mock_header_header(file, _filename)
define_name = @clean_mock_name.upcase
orig_filename = (@subdir ? @subdir + "/" : "") + @module_name + ".h"
orig_filename = (@folder || '') + @module_name + (@module_ext || '.h')
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
file << "#ifndef _#{define_name}_H\n"
file << "#define _#{define_name}_H\n\n"
@includes_h_pre_orig_header.each {|inc| file << "#include #{inc}\n"}
file << @config.orig_header_include_fmt.gsub(/%s/, "#{orig_filename}") + "\n"
@includes_h_post_orig_header.each {|inc| file << "#include #{inc}\n"}
file << "#include \"#{@framework}.h\"\n"
@includes_h_pre_orig_header.each { |inc| file << "#include #{inc}\n" }
file << @config.orig_header_include_fmt.gsub(/%s/, orig_filename.to_s) + "\n"
@includes_h_post_orig_header.each { |inc| file << "#include #{inc}\n" }
plugin_includes = @plugins.run(:include_files)
file << plugin_includes if (!plugin_includes.empty?)
file << plugin_includes unless plugin_includes.empty?
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"
@@ -113,7 +156,7 @@ class CMockGenerator
def create_typedefs(file, typedefs)
file << "\n"
typedefs.each {|typedef| file << "#{typedef}\n" }
typedefs.each { |typedef| file << "#{typedef}\n" }
file << "\n\n"
end
@@ -124,25 +167,31 @@ 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)
header_file = (@subdir ? @subdir + '/' : '') + filename.gsub(".c",".h")
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
header_file = (@folder || '') + filename.gsub('.c', (@module_ext || '.h'))
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless functions.empty?
file << "#include <string.h>\n"
file << "#include <stdlib.h>\n"
file << "#include <setjmp.h>\n"
file << "#include \"#{@framework}.h\"\n"
file << "#include \"cmock.h\"\n"
@includes_c_pre_header.each {|inc| file << "#include #{inc}\n"}
@includes_c_pre_header.each { |inc| file << "#include #{inc}\n" }
file << "#include \"#{header_file}\"\n"
@includes_c_post_header.each {|inc| file << "#include #{inc}\n"}
@includes_c_post_header.each { |inc| file << "#include #{inc}\n" }
file << "\n"
strs = []
functions.each do |func|
strs << func[:name]
func[:args].each {|arg| strs << arg[:name] }
func[:args].each { |arg| strs << arg[:name] }
end
strs.uniq.sort.each do |str|
file << "static const char* CMockString_#{str} = \"#{str}\";\n"
@@ -158,7 +207,7 @@ class CMockGenerator
file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n"
end
file << "static struct #{@clean_mock_name}Instance\n{\n"
if (functions.size == 0)
if functions.empty?
file << " unsigned char placeHolder;\n"
end
functions.each do |function|
@@ -170,7 +219,7 @@ class CMockGenerator
def create_extern_declarations(file)
file << "extern jmp_buf AbortFrame;\n"
if (@ordered)
if @ordered
file << "extern int GlobalExpectCount;\n"
file << "extern int GlobalVerifyOrder;\n"
end
@@ -179,9 +228,15 @@ class CMockGenerator
def create_mock_verify_function(file, functions)
file << "void #{@clean_mock_name}_Verify(void)\n{\n"
verifications = functions.collect {|function| @plugins.run(:mock_verify, function)}.join
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" unless verifications.empty?
file << verifications
verifications = functions.collect do |function|
v = @plugins.run(:mock_verify, function)
v.empty? ? v : [" call_instance = Mock.#{function[:name]}_CallInstance;\n", v]
end.join
unless verifications.empty?
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
file << " CMOCK_MEM_INDEX_TYPE call_instance;\n"
file << verifications
end
file << "}\n\n"
end
@@ -195,8 +250,13 @@ class CMockGenerator
file << "void #{@clean_mock_name}_Destroy(void)\n{\n"
file << " CMock_Guts_MemFreeAll();\n"
file << " memset(&Mock, 0, sizeof(Mock));\n"
file << functions.collect {|function| @plugins.run(:mock_destroy, function)}.join
if (@ordered)
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"
end
@@ -209,17 +269,28 @@ class CMockGenerator
(function[:return][:type]) +
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
args_string = function[:args_string]
args_string += (", " + function[:var_arg]) unless (function[:var_arg].nil?)
args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil?
# Encapsulate in namespace(s) if applicable
function[:namespace].each do |ns|
file << "namespace #{ns} {\n"
end
# Determine class prefix (if any)
cls_pre = ''
unless function[:class].nil?
cls_pre = "#{function[:class]}::"
end
# Create mock function
if (not @weak.empty?)
file << "#if defined (__IAR_SYSTEMS_ICC__)\n"
file << "#pragma weak #{function[:name]}\n"
file << "#else\n"
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string}) #{weak};\n"
file << "#endif\n\n"
unless @weak.empty?
file << "#if defined (__IAR_SYSTEMS_ICC__)\n"
file << "#pragma weak #{function[:unscoped_name]}\n"
file << "#else\n"
file << "#{function_mod_and_rettype} #{function[:unscoped_name]}(#{args_string}) #{weak};\n"
file << "#endif\n\n"
end
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string})\n"
file << "#{function_mod_and_rettype} #{cls_pre}#{function[:unscoped_name]}(#{args_string})\n"
file << "{\n"
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n"
@@ -229,21 +300,47 @@ class CMockGenerator
file << @plugins.run(:mock_implementation_precheck, function)
file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n"
file << " cmock_line = cmock_call_instance->LineNumber;\n"
if (@ordered)
if @ordered
file << " if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)\n"
file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);\n"
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 << "}\n\n"
file << " return cmock_call_instance->ReturnVal;\n" unless function[:return][:void?]
file << "}\n"
# Close any namespace(s) opened above
function[:namespace].each do
file << "}\n"
end
file << "\n"
end
def create_mock_interfaces(file, function)
file << @utils.code_add_argument_loader(function)
file << @plugins.run(:mock_interfaces, function)
end
def create_function_skeleton(file, function, existing)
# prepare return value and arguments
function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") +
(function[:return][:type]) +
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
args_string = function[:args_string]
args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil?
decl = "#{function_mod_and_rettype} #{function[:name]}(#{args_string})"
return if existing.include?(decl)
file << "#{decl}\n"
file << "{\n"
file << " /*TODO: Implement Me!*/\n"
function[:args].each { |arg| file << " (void)#{arg[:name]};\n" }
file << " return (#{(function[:return][:type])})0;\n" unless function[:return][:void?]
file << "}\n\n"
end
end
+19 -19
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockGeneratorPluginArray
attr_reader :priority
attr_accessor :config, :utils, :unity_helper, :ordered
def initialize(config, utils)
@@ -18,46 +17,47 @@ class CMockGeneratorPluginArray
end
def instance_typedefs(function)
function[:args].inject("") do |all, arg|
(arg[:ptr?]) ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
function[:args].inject('') do |all, arg|
arg[:ptr?] ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
end
end
def mock_function_declarations(function)
return nil unless function[:contains_ptr?]
args_call = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : "#{m[:name]}"}.join(', ')
args_call = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : (m[:name]).to_s }.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" +
if function[:return][:void?]
return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" \
"void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
else
return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" +
return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
end
end
def mock_interfaces(function)
return nil unless function[:contains_ptr?]
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?])
lines << "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n"
else
lines << "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n"
end
call_string = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name] }.join(', ')
lines << if function[:return][:void?]
"void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n"
else
"void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n"
end
lines << "{\n"
lines << @utils.code_add_base_expectation(func_name)
lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n"
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless (function[:return][:void?])
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless function[:return][:void?]
lines << "}\n\n"
end
end
+44 -56
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockGeneratorPluginCallback
attr_accessor :include_count
attr_reader :priority
attr_reader :config, :utils
@@ -16,85 +15,74 @@ class CMockGeneratorPluginCallback
@priority = 6
@include_count = @config.callback_include_count
if (@config.callback_after_arg_check)
alias :mock_implementation :mock_implementation_for_callbacks_after_arg_check
alias :mock_implementation_precheck :nothing
else
alias :mock_implementation_precheck :mock_implementation_for_callbacks_without_arg_check
alias :mock_implementation :nothing
end
end
def instance_structure(function)
func_name = function[:name]
" CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" +
" char #{func_name}_CallbackBool;\n" \
" CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" \
" int #{func_name}_CallbackCalls;\n"
end
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]
action = @config.callback_after_arg_check ? 'AddCallback' : 'Stub'
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"
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]});\n" \
"void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \
"void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \
"#define #{func_name}_StubWithCallback #{func_name}_#{action}\n"
end
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)
when 0 then " Mock.#{func_name}_CallbackFunctionPointer();\n }\n"
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"
end
def generate_call(function)
args = function[:args].map { |m| m[:name] }
args << "Mock.#{function[:name]}_CallbackCalls++" if @include_count
"Mock.#{function[:name]}_CallbackFunctionPointer(#{args.join(', ')})"
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)
when 0 then " Mock.#{func_name}_CallbackFunctionPointer();\n return;\n }\n"
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"
end
def mock_implementation(function)
" if (Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" +
if function[:return][:void?]
" #{generate_call(function)};\n }\n"
else
" cmock_call_instance->ReturnVal = #{generate_call(function)};\n }\n"
end
end
def nothing(function)
return ""
def mock_implementation_precheck(function)
" if (!Mock.#{function[:name]}_CallbackBool &&\n" \
" Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" +
if function[:return][:void?]
" #{generate_call(function)};\n" \
" UNITY_CLR_DETAILS();\n" \
" return;\n }\n"
else
" #{function[:return][:type]} cmock_cb_ret = #{generate_call(function)};\n" \
" UNITY_CLR_DETAILS();\n" \
" return cmock_cb_ret;\n }\n"
end
end
def mock_interfaces(function)
func_name = function[:name]
lines = ""
lines << "void #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
if @config.plugins.include? :ignore
lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n"
end
has_ignore = @config.plugins.include? :ignore
lines = ''
lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
lines << " Mock.#{func_name}_CallbackBool = (char)1;\n"
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
lines << " Mock.#{func_name}_CallbackBool = (char)0;\n"
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
end
def mock_destroy(function)
" Mock.#{function[:name]}_CallbackFunctionPointer = NULL;\n" +
" Mock.#{function[:name]}_CallbackCalls = 0;\n"
end
def mock_verify(function)
func_name = function[:name]
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n"
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" \
" call_instance = CMOCK_GUTS_NONE;\n" \
" (void)call_instance;\n }\n"
end
end
+15 -18
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockGeneratorPluginCexception
attr_reader :priority
attr_reader :config, :utils
@@ -16,37 +15,35 @@ class CMockGeneratorPluginCexception
end
def include_files
return "#include \"CException.h\"\n"
"#include \"CException.h\"\n"
end
def instance_typedefs(function)
def instance_typedefs(_function)
" CEXCEPTION_T ExceptionToThrow;\n"
end
def mock_function_declarations(function)
if (function[:args_string] == "void")
return "#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" +
if function[:args_string] == 'void'
"#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" \
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, CEXCEPTION_T cmock_to_throw);\n"
else
return "#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" +
"#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" \
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, CEXCEPTION_T cmock_to_throw);\n"
end
end
def mock_implementation(function)
" if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" +
" UNITY_CLR_DETAILS();\n" +
" Throw(cmock_call_instance->ExceptionToThrow);\n }\n"
def mock_implementation(_function)
" if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" \
" UNITY_CLR_DETAILS();\n" \
" Throw(cmock_call_instance->ExceptionToThrow);\n }\n"
end
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),
" cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n",
"}\n\n" ].join
arg_insert = function[:args_string] == 'void' ? '' : "#{function[:args_string]}, "
["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),
" cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n",
"}\n\n"].join
end
end
+36 -40
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockGeneratorPluginExpect
attr_reader :priority
attr_accessor :config, :utils, :unity_helper, :ordered
@@ -17,7 +16,7 @@ class CMockGeneratorPluginExpect
@unity_helper = @utils.helpers[:unity_helper]
@priority = 5
if (@config.plugins.include? :expect_any_args)
if @config.plugins.include? :expect_any_args
alias :mock_implementation :mock_implementation_might_check_args
else
alias :mock_implementation :mock_implementation_always_check_args
@@ -25,9 +24,9 @@ class CMockGeneratorPluginExpect
end
def instance_typedefs(function)
lines = ""
lines << " #{function[:return][:type]} ReturnVal;\n" unless (function[:return][:void?])
lines << " int CallOrder;\n" if (@ordered)
lines = ''
lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?]
lines << " int CallOrder;\n" if @ordered
function[:args].each do |arg|
lines << " #{arg[:type]} Expected_#{arg[:name]};\n"
end
@@ -35,27 +34,25 @@ class CMockGeneratorPluginExpect
end
def mock_function_declarations(function)
if (function[:args].empty?)
if (function[:return][:void?])
return "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" +
if function[:args].empty?
if function[:return][:void?]
"#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n"
else
return "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" +
"#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
elsif function[:return][:void?]
"#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" \
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
else
if (function[:return][:void?])
return "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" +
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
else
return "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" +
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
end
"#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
end
end
def mock_implementation_always_check_args(function)
lines = ""
lines = ''
function[:args].each do |arg|
lines << @utils.code_verify_an_arg_expectation(function, arg)
end
@@ -63,42 +60,41 @@ class CMockGeneratorPluginExpect
end
def mock_implementation_might_check_args(function)
return "" if (function[:args].empty?)
lines = " if (cmock_call_instance->IgnoreMode != CMOCK_ARG_NONE)\n {\n"
return '' if function[:args].empty?
lines = " if (!cmock_call_instance->ExpectAnyArgsBool)\n {\n"
function[:args].each do |arg|
lines << @utils.code_verify_an_arg_expectation(function, arg)
end
lines << "\n }\n"
lines << " }\n"
lines
end
def mock_interfaces(function)
lines = ""
lines = ''
func_name = function[:name]
if (function[:return][:void?])
if (function[:args_string] == "void")
lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n"
else
lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n"
end
else
if (function[:args_string] == "void")
lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
else
lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
end
end
lines << if function[:return][:void?]
if function[:args_string] == 'void'
"void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n"
else
"void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n"
end
elsif function[:args_string] == 'void'
"void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
else
"void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
end
lines << @utils.code_add_base_expectation(func_name)
lines << @utils.code_call_argument_loader(function)
lines << @utils.code_assign_argument_quickly("cmock_call_instance->ReturnVal", function[:return]) unless (function[:return][:void?])
lines << " UNITY_CLR_DETAILS();\n"
lines << @utils.code_assign_argument_quickly('cmock_call_instance->ReturnVal', function[:return]) unless function[:return][:void?]
lines << "}\n\n"
end
def mock_verify(function)
func_name = function[:name]
" UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" +
" UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.#{func_name}_CallInstance, cmock_line, CMockStringCalledLess);\n"
" if (CMOCK_GUTS_NONE != call_instance)\n" \
" {\n" \
" UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" \
" UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess);\n" \
" }\n"
end
end
+21 -39
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockGeneratorPluginExpectAnyArgs
attr_reader :priority
attr_reader :config, :utils
@@ -15,54 +14,37 @@ class CMockGeneratorPluginExpectAnyArgs
@priority = 3
end
def instance_structure(function)
if (function[:return][:void?]) || (@config.plugins.include? :ignore)
""
else
" #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
end
end
def instance_typedefs(function)
" CMOCK_ARG_MODE IgnoreMode;\n"
def instance_typedefs(_function)
" char ExpectAnyArgsBool;\n"
end
def mock_function_declarations(function)
if (function[:return][:void?])
return "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" +
if function[:args].empty?
''
elsif function[:return][:void?]
"#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" \
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
else
return "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" +
"#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" \
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
end
# def mock_implementation(function)
# lines = " if (cmock_call_instance->IgnoreMode == CMOCK_ARG_NONE)\n {\n"
# if (function[:return][:void?])
# lines << " return;\n }\n"
# else
# retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} )
# lines << " " + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless (retval[:void?])
# 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?])
lines << "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n"
else
lines << "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
lines = ''
unless function[:args].empty?
lines << if function[:return][:void?]
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n"
else
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
end
lines << @utils.code_add_base_expectation(function[:name], true)
unless function[:return][:void?]
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
end
lines << " cmock_call_instance->ExpectAnyArgsBool = (char)1;\n"
lines << "}\n\n"
end
lines << @utils.code_add_base_expectation(function[:name], true)
unless (function[:return][:void?])
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
end
lines << " cmock_call_instance->IgnoreMode = CMOCK_ARG_NONE;\n"
lines << "}\n\n"
lines
end
end
+43 -27
View File
@@ -5,7 +5,6 @@
# ==========================================
class CMockGeneratorPluginIgnore
attr_reader :priority
attr_reader :config, :utils
@@ -16,57 +15,74 @@ class CMockGeneratorPluginIgnore
end
def instance_structure(function)
if (function[:return][:void?])
" int #{function[:name]}_IgnoreBool;\n"
if function[:return][:void?]
" char #{function[:name]}_IgnoreBool;\n"
else
" int #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
" char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
end
end
def mock_function_declarations(function)
if (function[:return][:void?])
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" +
"void #{function[:name]}_CMockIgnore(void);\n"
else
return "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" +
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
lines = if function[:return][:void?]
"#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \
"void #{function[:name]}_CMockIgnore(void);\n"
else
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" \
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
end
# Add stop ignore function. it does not matter if there are any args
lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \
"void #{function[:name]}_CMockStopIgnore(void);\n"
lines
end
def mock_implementation_precheck(function)
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
lines << " UNITY_CLR_DETAILS();\n"
if (function[:return][:void?])
if function[:return][:void?]
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 << " " + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless (retval[:void?])
lines << " return #{return_type}cmock_call_instance->ReturnVal;\n }\n"
retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal')
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 cmock_call_instance->ReturnVal;\n }\n"
end
lines
end
def mock_interfaces(function)
lines = ""
if (function[:return][:void?])
lines << "void #{function[:name]}_CMockIgnore(void)\n{\n"
else
lines << "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
end
if (!function[:return][:void?])
lines = ''
lines << if function[:return][:void?]
"void #{function[:name]}_CMockIgnore(void)\n{\n"
else
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
end
unless function[:return][:void?]
lines << @utils.code_add_base_expectation(function[:name], false)
end
unless (function[:return][:void?])
unless function[:return][:void?]
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
end
lines << " Mock.#{function[:name]}_IgnoreBool = (int)1;\n"
lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n"
lines << "}\n\n"
# Add stop ignore function. it does not matter if there are any args
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
unless function[:return][:void?]
lines << " if(Mock.#{function[:name]}_IgnoreBool)\n"
lines << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
end
lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n"
lines << "}\n\n"
end
def mock_ignore(function)
" Mock.#{function[:name]}_IgnoreBool = (char) 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"
" if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n"
end
end
+8 -10
View File
@@ -2,21 +2,21 @@ class CMockGeneratorPluginIgnoreArg
attr_reader :priority
attr_accessor :utils
def initialize(config, utils)
def initialize(_config, utils)
@utils = utils
@priority = 10
end
def instance_typedefs(function)
lines = ""
lines = ''
function[:args].each do |arg|
lines << " int IgnoreArg_#{arg[:name]};\n"
lines << " char IgnoreArg_#{arg[:name]};\n"
end
lines
end
def mock_function_declarations(function)
lines = ""
lines = ''
function[:args].each do |arg|
lines << "#define #{function[:name]}_IgnoreArg_#{arg[:name]}()"
lines << " #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(__LINE__)\n"
@@ -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 << " 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
@@ -0,0 +1,85 @@
# ==========================================
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
class CMockGeneratorPluginIgnoreStateless
attr_reader :priority
attr_reader :config, :utils
def initialize(config, utils)
@config = config
@utils = utils
@priority = 2
end
def instance_structure(function)
if function[:return][:void?]
" char #{function[:name]}_IgnoreBool;\n"
else
" char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
end
end
def mock_function_declarations(function)
lines = if function[:return][:void?]
"#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \
"void #{function[:name]}_CMockIgnore(void);\n"
else
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" \
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"
end
# Add stop ignore function. it does not matter if there are any args
lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \
"void #{function[:name]}_CMockStopIgnore(void);\n"
lines
end
def mock_implementation_precheck(function)
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
lines << " UNITY_CLR_DETAILS();\n"
if function[:return][:void?]
lines << " return;\n }\n"
else
retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal')
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 cmock_call_instance->ReturnVal;\n }\n"
end
lines
end
# this function is adjusted
def mock_interfaces(function)
lines = ''
lines << if function[:return][:void?]
"void #{function[:name]}_CMockIgnore(void)\n{\n"
else
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n"
end
unless function[:return][:void?]
lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n"
lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n"
end
lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n"
lines << "}\n\n"
# Add stop ignore function. it does not matter if there are any args
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n"
lines << "}\n\n"
lines
end
def mock_ignore(function)
" Mock.#{function[:name]}_IgnoreBool = (char)1;\n"
end
def mock_verify(function)
func_name = function[:name]
" if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n"
end
end
+42 -38
View File
@@ -2,35 +2,41 @@ class CMockGeneratorPluginReturnThruPtr
attr_reader :priority
attr_accessor :utils
def initialize(config, utils)
def initialize(_config, utils)
@utils = utils
@priority = 9
end
def instance_typedefs(function)
lines = ""
lines = ''
function[:args].each do |arg|
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
lines << " int ReturnThruPtr_#{arg[:name]}_Used;\n"
lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n"
lines << " int ReturnThruPtr_#{arg[:name]}_Size;\n"
end
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
lines << " char ReturnThruPtr_#{arg[:name]}_Used;\n"
lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n"
lines << " size_t ReturnThruPtr_#{arg[:name]}_Size;\n"
end
lines
end
def mock_function_declarations(function)
lines = ""
lines = ''
function[:args].each do |arg|
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n"
lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (int)(cmock_len * (int)sizeof(*#{arg[:name]})))\n"
lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n"
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, int cmock_size);\n"
end
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})"
# If the pointer type actually contains an asterisk, we can do sizeof the type (super safe), otherwise
# we need to do a sizeof the dereferenced pointer (which could be a problem if give the wrong size
lines << if arg[:type][-1] == '*'
" #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(#{arg[:type][0..-2]}))\n"
else
" #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n"
end
lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_len * sizeof(*#{arg[:name]}))\n"
lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n"
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, size_t cmock_size);\n"
end
lines
end
@@ -40,18 +46,17 @@ 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"
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, CMockStringPtrPreExp);\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n"
lines << "}\n\n"
end
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, size_t cmock_size)\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, CMockStringPtrPreExp);\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n"
lines << "}\n\n"
end
lines
end
@@ -60,15 +65,14 @@ 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"
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
lines << " memcpy((void*)#{arg_name}, (void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
lines << " }\n"
end
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
lines << " {\n"
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
lines << " memcpy((void*)#{arg_name}, (void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
lines << " }\n"
end
lines
end
+147 -125
View File
@@ -5,10 +5,9 @@
# ==========================================
class CMockGeneratorUtils
attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays, :cexception
def initialize(config, helpers={})
def initialize(config, helpers = {})
@config = config
@ptr_handling = @config.when_ptr
@ordered = @config.enforce_strict_ordering
@@ -16,213 +15,236 @@ class CMockGeneratorUtils
@cexception = @config.plugins.include? :cexception
@expect_any = @config.plugins.include? :expect_any_args
@return_thru_ptr = @config.plugins.include? :return_thru_ptr
@ignore_arg = @config.plugins.include? :ignore_arg
@ignore = @config.plugins.include? :ignore
@treat_as = @config.treat_as
@helpers = helpers
@ignore_arg = @config.plugins.include? :ignore_arg
@ignore = @config.plugins.include? :ignore
@ignore_stateless = @config.plugins.include? :ignore_stateless
@treat_as = @config.treat_as
@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)
when :smart then code_verify_an_arg_expectation_with_smart_arrays(function, arg)
when :compare_data then code_verify_an_arg_expectation_with_normal_arrays(function, arg)
when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option."
if @arrays
case @ptr_handling
when :smart then code_verify_an_arg_expectation_with_smart_arrays(function, arg)
when :compare_data then code_verify_an_arg_expectation_with_normal_arrays(function, arg)
when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option."
end
else
code_verify_an_arg_expectation_with_no_arrays(function, arg)
end
end
def code_add_base_expectation(func_name, global_ordering_supported=true)
def code_add_base_expectation(func_name, global_ordering_supported = true)
lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n"
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n"
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n"
lines << " memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n"
lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n"
lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n" if (@ignore)
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless
lines << " cmock_call_instance->LineNumber = cmock_line;\n"
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if (@ordered and global_ordering_supported)
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if (@cexception)
lines << " cmock_call_instance->IgnoreMode = CMOCK_ARG_ALL;\n" if (@expect_any)
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception
lines << " cmock_call_instance->ExpectAnyArgsBool = (char)0;\n" if @expect_any
lines
end
def code_add_an_arg_expectation(arg, depth=1)
def code_add_an_arg_expectation(arg, depth = 1)
lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg)
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if (@arrays and (depth.class == String))
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if (@ignore_arg)
lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if (@return_thru_ptr and ptr_or_str?(arg[:type]) and not arg[:const?])
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if @arrays && (depth.class == String)
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if @ignore_arg
lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if @return_thru_ptr && ptr_or_str?(arg[:type]) && !(arg[:const?])
lines
end
def code_assign_argument_quickly(dest, arg)
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
" #{dest} = #{arg[:const?] ? "(#{arg[:type]})" : ''}#{arg[:name]};\n"
if arg[:ptr?] || @treat_as.include?(arg[:type])
" #{dest} = #{arg[:name]};\n"
else
" memcpy(&#{dest}, &#{arg[:name]}, sizeof(#{arg[:type]}));\n"
assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1"
comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */"
" memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}),\n" \
" sizeof(#{arg[:type]}[#{assert_expr}])); #{comment}\n"
end
end
def code_add_argument_loader(function)
if (function[:args_string] != "void")
if (@arrays)
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) ) } +
"}\n\n"
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string});\n" \
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" +
function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1)) } +
"}\n\n"
else
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg) } +
"}\n\n"
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]});\n" \
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg) } +
"}\n\n"
end
else
""
''
end
end
def code_call_argument_loader(function)
if (function[:args_string] != "void")
if function[:args_string] != 'void'
args = function[:args].map do |m|
(@arrays and m[:ptr?]) ? "#{m[:name]}, 1" : m[:name]
if @arrays && m[:ptr?] && !(m[:array_data?])
"#{m[:name]}, 1"
elsif @arrays && m[:array_size?]
"#{m[:name]}, #{m[:name]}"
else
m[:name]
end
end
" CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n"
else
""
''
end
end
def ptr_or_str?(arg_type)
return (arg_type.include? '*' or
@treat_as.fetch(arg_type, "").include? '*')
(arg_type.include?('*') ||
@treat_as.fetch(arg_type, '').include?('*'))
end
#private ######################
# private ######################
def lookup_expect_type(function, arg)
def lookup_expect_type(_function, arg)
c_type = arg[:type]
arg_name = arg[:name]
expected = "cmock_call_instance->Expected_#{arg_name}"
ignore = "cmock_call_instance->IgnoreArg_#{arg_name}"
unity_func = if ((arg[:ptr?]) and ((c_type =~ /\*\*/) or (@ptr_handling == :compare_ptr)))
unity_func = if (arg[:ptr?]) && ((c_type =~ /\*\*/) || (@ptr_handling == :compare_ptr))
['UNITY_TEST_ASSERT_EQUAL_PTR', '']
else
(@helpers.nil? or @helpers[:unity_helper].nil?) ? ["UNITY_TEST_ASSERT_EQUAL",''] : @helpers[:unity_helper].get_helper(c_type)
@helpers.nil? || @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
[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)
lines = ""
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
lines = ''
lines << " if (!#{ignore})\n" if @ignore_arg
lines << " {\n"
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
case(unity_func)
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
c_type_local = c_type.gsub(/\*$/,'')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
if (pre == '&')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if (pre == '&')
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch); }\n"
end
case unity_func
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
c_type_local = c_type.gsub(/\*$/, '')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
if pre == '&'
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n"
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if pre == '&'
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
end
lines << " }\n"
lines
end
def code_verify_an_arg_expectation_with_normal_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
lines = ""
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
lines << " {\n"
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
case(unity_func)
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
c_type_local = c_type.gsub(/\*$/,'')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
if (pre == '&')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if (pre == '&')
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
case unity_func
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
c_type_local = c_type.gsub(/\*$/, '')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
if pre == '&'
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n"
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if pre == '&'
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
end
lines << " }\n"
lines
end
def code_verify_an_arg_expectation_with_smart_arrays(function, arg)
c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
lines = ""
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
lines << " {\n"
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
case(unity_func)
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
c_type_local = c_type.gsub(/\*$/,'')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
if (pre == '&')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : "")
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if (pre == '&')
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : "")
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
case unity_func
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
c_type_local = c_type.gsub(/\*$/, '')
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
if pre == '&'
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '')
lines << " else\n"
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
when /_ARRAY/
if pre == '&'
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
else
lines << " if (#{pre}#{expected} == NULL)\n"
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '')
lines << " else\n"
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
end
else
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
end
lines << " }\n"
lines
end
end
+457 -150
View File
@@ -5,66 +5,236 @@
# ==========================================
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, :treat_inlines, :inline_function_patterns
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_array = cfg.treat_as_array
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
@declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m
@standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq
@function_declaration_parse_base_match = '([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+\-\/]*)\)'
@declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m
@standards = (%w[int short char long unsigned signed] + cfg.treat_as.keys).uniq
@array_size_name = cfg.array_size_name
@array_size_type = (%w[int size_t] + cfg.array_size_type).uniq
@when_no_prototypes = cfg.when_no_prototypes
@local_as_void = @treat_as_void
@verbosity = cfg.verbosity
@treat_externs = cfg.treat_externs
@c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs
@treat_inlines = cfg.treat_inlines
@inline_function_patterns = cfg.inline_function_patterns
@c_strippables += ['extern'] if @treat_externs == :include # we'll need to remove the attribute if we're allowing externs
@c_strippables += ['inline'] if @treat_inlines == :include # we'll need to remove the attribute if we're allowing inlines
end
def parse(name, source)
@module_name = name.gsub(/\W/,'')
@module_name = name.gsub(/\W/, '')
@typedefs = []
@funcs = []
@normalized_source = nil
function_names = []
parse_functions( import_source(source) ).map do |decl|
func = parse_declaration(decl)
unless (function_names.include? func[:name])
all_funcs = parse_functions(import_source(source)).map { |item| [item] }
all_funcs += parse_cpp_functions(import_source(source, true))
all_funcs.map do |decl|
func = parse_declaration(*decl)
unless function_names.include? func[:name]
@funcs << func
function_names << func[:name]
end
end
@normalized_source = if @treat_inlines == :include
transform_inline_functions(source)
else
''
end
{ :includes => nil,
:functions => @funcs,
:typedefs => @typedefs
}
:typedefs => @typedefs,
:normalized_source => @normalized_source }
end
private if $ThisIsOnlyATest.nil? ################
def import_source(source)
# Remove C/C++ comments from a string
# +source+:: String which will have the comments removed
def remove_comments_from_source(source)
# remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/(?<!\*)\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
end
def remove_nested_pairs_of_braces(source)
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
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
source
end
# Return the number of pairs of braces/square brackets in the function provided by the user
# +source+:: String containing the function to be processed
def count_number_of_pairs_of_braces_in_function(source)
is_function_start_found = false
curr_level = 0
total_pairs = 0
source.each_char do |c|
if c == '{'
curr_level += 1
total_pairs += 1
is_function_start_found = true
elsif c == '}'
curr_level -= 1
end
break if is_function_start_found && curr_level == 0 # We reached the end of the inline function body
end
if curr_level != 0
total_pairs = 0 # Something is fishy about this source, not enough closing braces?
end
total_pairs
end
# Transform inline functions to regular functions in the source by the user
# +source+:: String containing the source to be processed
def transform_inline_functions(source)
inline_function_regex_formats = []
square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets
# Convert user provided string patterns to regex
# Use word bounderies before and after the user regex to limit matching to actual word iso part of a word
@inline_function_patterns.each do |user_format_string|
user_regex = Regexp.new(user_format_string)
word_boundary_before_user_regex = /\b/
cleanup_spaces_after_user_regex = /[ ]*\b/
inline_function_regex_formats << Regexp.new(word_boundary_before_user_regex.source + user_regex.source + cleanup_spaces_after_user_regex.source)
end
# let's clean up the encoding in case they've done anything weird with the characters we might find
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil)
source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil)
# Comments can contain words that will trigger the parser (static|inline|<user_defined_static_keyword>)
remove_comments_from_source(source)
# smush multiline macros into single line (checking for continuation character at end of line '\')
# If the user uses a macro to declare an inline function,
# smushing the macros makes it easier to recognize them as a macro and if required,
# remove them later on in this function
source.gsub!(/\s*\\\s*/m, ' ')
# Just looking for static|inline in the gsub is a bit too aggressive (functions that are named like this, ...), so we try to be a bit smarter
# Instead, look for an inline pattern (f.e. "static inline") and parse it.
# Below is a small explanation on how the general mechanism works:
# - Everything before the match should just be copied, we don't want
# to touch anything but the inline functions.
# - Remove the implementation of the inline function (this is enclosed
# in square brackets) and replace it with ";" to complete the
# transformation to normal/non-inline function.
# To ensure proper removal of the function body, we count the number of square-bracket pairs
# and remove the pairs one-by-one.
# - Copy everything after the inline function implementation and start the parsing of the next inline function
# There are ofcourse some special cases (inline macro declarations, inline function declarations, ...) which are handled and explained below
inline_function_regex_formats.each do |format|
inspected_source = ''
regex_matched = false
loop do
inline_function_match = source.match(/#{format}/) # Search for inline function declaration
if inline_function_match.nil? # No inline functions so nothing to do
# Join pre and post match stripped parts for the next inline function detection regex
source = inspected_source + source if regex_matched == true
break
end
regex_matched = true
# 1. Determine if we are dealing with a user defined macro to declare inline functions
# If the end of the pre-match string is a macro-declaration-like string,
# we are dealing with a user defined macro to declare inline functions
if /(#define\s*)\z/ =~ inline_function_match.pre_match
# Remove the macro from the source
stripped_pre_match = inline_function_match.pre_match.sub(/(#define\s*)\z/, '')
stripped_post_match = inline_function_match.post_match.sub(/\A(.*[\n]?)/, '')
inspected_source += stripped_pre_match
source = stripped_post_match
next
end
# 2. Determine if we are dealing with an inline function declaration iso function definition
# If the start of the post-match string is a function-declaration-like string (something ending with semicolon after the function arguments),
# we are dealing with a inline function declaration
if /\A#{@function_declaration_parse_base_match}\s*;/m =~ inline_function_match.post_match
# Only remove the inline part from the function declaration, leaving the function declaration won't do any harm
inspected_source += inline_function_match.pre_match
source = inline_function_match.post_match
next
end
# 3. If we get here, we found an inline function declaration AND inline function body.
# Remove the function body to transform it into a 'normal' function declaration.
if /\A#{@function_declaration_parse_base_match}\s*\{/m =~ inline_function_match.post_match
total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match)
break if total_pairs_to_remove == 0 # Bad source?
inline_function_stripped = inline_function_match.post_match
total_pairs_to_remove.times do
inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ';') # Remove inline implementation (+ some whitespace because it's prettier)
end
inspected_source += inline_function_match.pre_match
source = inline_function_stripped
next
end
# 4. If we get here, it means the regex match, but it is not related to the function (ex. static variable in header)
# Leave this code as it is.
inspected_source += inline_function_match.pre_match + inline_function_match[0]
source = inline_function_match.post_match
end
end
source
end
def import_source(source, cpp = false)
# let's clean up the encoding in case they've done anything weird with the characters we might find
source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil)
# void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void
# to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void
@local_as_void = @treat_as_void
void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w\d]+)\s*;/)
void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w]+)\s*;/)
if void_types
@local_as_void += void_types.flatten.uniq.compact
end
# If user wants to mock inline functions,
# remove the (user specific) inline keywords before removing anything else to avoid missing an inline function
if @treat_inlines == :include
@inline_function_patterns.each do |user_format_string|
source.gsub!(/#{user_format_string}/, '') # remove user defined inline function patterns
end
end
# smush multiline macros into single line (checking for continuation character at end of line '\')
source.gsub!(/\s*\\\s*/m, ' ')
#remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
remove_comments_from_source(source)
# remove assembler pragma sections
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
@@ -79,236 +249,373 @@ 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)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords
source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
# remove problem keywords
source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2')
source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/,'\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
#scan for functions which return function pointers, because they are a pain
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |m|
# scan standalone function pointers and remove them, because they can just be ignored
source.gsub!(/\w+\s*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/, ';')
# scan for functions which return function pointers, because they are a pain
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |_m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
@typedefs << "typedef #{$1.strip}(*#{functype})(#{$4});"
"#{functype} #{$2.strip}(#{$3});"
unless cpp # only collect once
@typedefs << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});"
"#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});"
end
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, '{ }')
source = remove_nested_pairs_of_braces(source) unless cpp
if @treat_inlines == :include
# Functions having "{ }" at this point are/were inline functions,
# User wants them in so 'disguise' them as normal functions with the ";"
source.gsub!('{ }', ';')
end
# remove function definitions by stripping off the arguments right now
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ";")
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ';')
#drop extra white space to make the rest go faster
# drop extra white space to make the rest go faster
source.gsub!(/^\s+/, '') # remove extra white space from beginning of line
source.gsub!(/\s+$/, '') # remove extra white space from end of line
source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens
source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens
source.gsub!(/\s+/, ' ') # remove remaining extra white space
#split lines on semicolons and remove things that are obviously not what we are looking for
src_lines = source.split(/\s*;\s*/).uniq
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays
if (@treat_externs == :include)
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
else
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern|inline)\s+/).nil?} # remove inline and extern functions
# split lines on semicolons and remove things that are obviously not what we are looking for
src_lines = source.split(/\s*;\s*/)
src_lines = src_lines.uniq unless cpp # must retain closing braces for class/namespace
src_lines.delete_if { |line| line.strip.empty? } # remove blank lines
src_lines.delete_if { |line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil? } # remove function pointer arrays
unless @treat_externs == :include
src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:extern)\s+/).nil? } # remove extern functions
end
src_lines.delete_if {|line| line.empty? } #drop empty lines
unless @treat_inlines == :include
src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil? } # remove inline functions
end
src_lines.delete_if(&:empty?) # drop empty lines
end
# Rudimentary C++ parser - does not handle all situations - e.g.:
# * A namespace function appears after a class with private members (should be parsed)
# * Anonymous namespace (shouldn't parse anything - no matter how nested - within it)
# * A class nested within another class
def parse_cpp_functions(source)
funcs = []
ns = []
pub = false
source.each do |line|
# Search for namespace, class, opening and closing braces
line.scan(/(?:(?:\b(?:namespace|class)\s+(?:\S+)\s*)?{)|}/).each do |item|
if item == '}'
ns.pop
else
token = item.strip.sub(/\s+/, ' ')
ns << token
pub = false if token.start_with? 'class'
pub = true if token.start_with? 'namespace'
end
end
pub = true if line =~ /public:/
pub = false if line =~ /private:/ || line =~ /protected:/
# ignore non-public and non-static
next unless pub
next unless line =~ /\bstatic\b/
line.sub!(/^.*static/, '')
next unless line =~ @declaration_parse_matcher
tmp = ns.reject { |item| item == '{' }
# Identify class name, if any
cls = nil
if tmp[-1].start_with? 'class '
cls = tmp.pop.sub(/class (\S+) {/, '\1')
end
# Assemble list of namespaces
tmp.each { |item| item.sub!(/(?:namespace|class) (\S+) {/, '\1') }
funcs << [line.strip.gsub(/\s+/, ' '), tmp, cls]
end
funcs
end
def parse_functions(source)
funcs = []
source.each {|line| funcs << line.strip.gsub(/\s+/, ' ') if (line =~ @declaration_parse_matcher)}
source.each { |line| funcs << line.strip.gsub(/\s+/, ' ') if line =~ @declaration_parse_matcher }
if funcs.empty?
case @when_no_prototypes
when :error
raise "ERROR: No function prototypes found!"
when :warn
puts "WARNING: No function prototypes found!" unless (@verbosity < 1)
when :error
raise 'ERROR: No function prototypes found!'
when :warn
puts 'WARNING: No function prototypes found!' unless @verbosity < 1
end
end
return funcs
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
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))
return args if arg =~ /^\s*((\.\.\.)|(void))\s*$/ # we're done if we reach void by itself or ...
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
# in C, array arguments implicitly degrade to pointers
# make the translation explicit here to simplify later logic
if @treat_as_array[arg_info[:type]] && !(arg_info[:ptr?])
arg_info[:type] = "#{@treat_as_array[arg_info[:type]]}*"
arg_info[:type] = "const #{arg_info[:type]}" if arg_info[:const?]
arg_info[:ptr?] = true
end
args << arg_info
end
return args
# Try to find array pair in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name>
args.each_with_index do |val, index|
next_index = index + 1
next unless args.length > next_index
if (val[:ptr?] == true) && args[next_index][:name].match(@array_size_name) && @array_size_type.include?(args[next_index][:type])
val[:array_data?] = true
args[next_index][:array_size?] = true
end
end
args
end
def divine_ptr(arg_type)
return false unless arg_type.include? '*'
return false if arg_type.gsub(/(const|char|\*|\s)+/,'').empty?
return true
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
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
if arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg) : (/(^|\s)const(\s|$)/ =~ arg)
true
else
false
end
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
# an arg containing "const" after the last * is a constant pointer
divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false
# 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
return divination
divination
end
def clean_args(arg_list)
if ((@local_as_void.include?(arg_list.strip)) or (arg_list.empty?))
return 'void'
if @local_as_void.include?(arg_list.strip) || arg_list.empty?
'void'
else
c=0
arg_list.gsub!(/(\w+)(?:\s*\[\s*\(*[\s\d\w+-]*\)*\s*\])+/,'*\1') # magically turn brackets into asterisks, also match for parentheses that come from macros
arg_list.gsub!(/\s+\*/,'*') # remove space to place asterisks with type (where they belong)
arg_list.gsub!(/\*(\w)/,'* \1') # pull asterisks away from arg to place asterisks with type (where they belong)
#scan argument list for function pointers and replace them with custom types
arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |m|
c = 0
# magically turn brackets into asterisks, also match for parentheses that come from macros
arg_list.gsub!(/(\w+)(?:\s*\[[^\[\]]*\])+/, '*\1')
# remove space to place asterisks with type (where they belong)
arg_list.gsub!(/\s+\*/, '*')
# pull asterisks away from arg to place asterisks with type (where they belong)
arg_list.gsub!(/\*(\w)/, '* \1')
# scan argument list for function pointers and replace them with custom types
arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
funcret = $1.strip
funcname = $2.strip
funcargs = $3.strip
funcret = Regexp.last_match(1).strip
funcname = Regexp.last_match(2).strip
funcargs = Regexp.last_match(3).strip
funconst = ''
if (funcname.include? 'const')
funcname.gsub!('const','').strip!
if funcname.include? 'const'
funcname.gsub!('const', '').strip!
funconst = 'const '
end
@typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});"
funcname = "cmock_arg#{c+=1}" if (funcname.empty?)
funcname = "cmock_arg#{c += 1}" if funcname.empty?
"#{functype} #{funconst}#{funcname}"
end
#automatically name unnamed arguments (those that only had a type)
arg_list.split(/\s*,\s*/).map { |arg|
# scan argument list for function pointers with shorthand notation and replace them with custom types
arg_list.gsub!(/([\w\s\*]+)+\s+(\w+)\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
funcret = Regexp.last_match(1).strip
funcname = Regexp.last_match(2).strip
funcargs = Regexp.last_match(3).strip
funconst = ''
if funcname.include? 'const'
funcname.gsub!('const', '').strip!
funconst = 'const '
end
@typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});"
funcname = "cmock_arg#{c += 1}" if funcname.empty?
"#{functype} #{funconst}#{funcname}"
end
# automatically name unnamed arguments (those that only had a type)
arg_list.split(/\s*,\s*/).map do |arg|
parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*'])
if ((parts.size < 2) or (parts[-1][-1].chr == '*') or (@standards.include?(parts[-1])))
"#{arg} cmock_arg#{c+=1}"
if (parts.size < 2) || (parts[-1][-1].chr == '*') || @standards.include?(parts[-1])
"#{arg} cmock_arg#{c += 1}"
else
arg
end
}.join(', ')
end.join(', ')
end
end
def parse_declaration(declaration)
def parse_declaration(declaration, namespace = [], classname = nil)
decl = {}
decl[:namespace] = namespace
decl[:class] = classname
regex_match = @declaration_parse_matcher.match(declaration)
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
#grab argument list
# grab argument list
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
# process function attributes, return type, and name
parsed = parse_type_and_name(regex_match[1])
#grab name
decl[:name] = descriptors[-1] #snag name as last array item
# Record original name without scope prefix
decl[:unscoped_name] = parsed[:name]
#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
# Prefix name with namespace scope (if any) and then class
decl[:name] = namespace.join('_')
unless classname.nil?
decl[:name] << '_' unless decl[:name].empty?
decl[:name] << classname
end
decl[:modifier] = decl[:modifier].join(' ')
rettype = rettype.join(' ')
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))
# Add original name to complete fully scoped name
decl[:name] << '_' unless decl[:name].empty?
decl[:name] << decl[:unscoped_name]
#remove default argument statements from mock definitions
decl[:modifier] = parsed[:modifier]
unless parsed[:c_calling_convention].nil?
decl[:c_calling_convention] = parsed[:c_calling_convention]
end
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'),
:ptr? => parsed[:ptr?] || false,
:const? => parsed[:const?] || false,
:const_ptr? => parsed[:const_ptr?] || false }
# remove default argument statements from mock definitions
args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ')
#check for var args
if (args =~ /\.\.\./)
decl[:var_arg] = args.match( /[\w\s]*\.\.\./ ).to_s.strip
if (args =~ /\,[\w\s]*\.\.\./)
args = args.gsub!(/\,[\w\s]*\.\.\./,'')
else
args = 'void'
end
# check for var args
if args =~ /\.\.\./
decl[:var_arg] = args.match(/[\w\s]*\.\.\./).to_s.strip
args = if args =~ /\,[\w\s]*\.\.\./
args.gsub!(/\,[\w\s]*\.\.\./, '')
else
'void'
end
else
decl[:var_arg] = nil
end
args = clean_args(args)
decl[:args_string] = args
decl[:args] = parse_args(args)
decl[:args_call] = decl[:args].map{|a| a[:name]}.join(', ')
decl[:contains_ptr?] = decl[:args].inject(false) {|ptr, arg| arg[:ptr?] ? true : ptr }
decl[:args_call] = decl[:args].map { |a| a[:name] }.join(', ')
decl[:contains_ptr?] = decl[:args].inject(false) { |ptr, arg| arg[:ptr?] ? true : ptr }
if (decl[:return][:type].nil? or decl[:name].nil? or decl[:args].nil? or
decl[:return][:type].empty? or decl[:name].empty?)
raise "Failed Parsing Declaration Prototype!\n" +
" declaration: '#{declaration}'\n" +
" modifier: '#{decl[:modifier]}'\n" +
" return: #{prototype_inspect_hash(decl[:return])}\n" +
" function: '#{decl[:name]}'\n" +
" args: #{prototype_inspect_array_of_hashes(decl[:args])}\n"
if decl[:return][:type].nil? || decl[:name].nil? || decl[:args].nil? ||
decl[:return][:type].empty? || decl[:name].empty?
raise "Failed Parsing Declaration Prototype!\n" \
" declaration: '#{declaration}'\n" \
" modifier: '#{decl[:modifier]}'\n" \
" return: #{prototype_inspect_hash(decl[:return])}\n" \
" function: '#{decl[:name]}'\n" \
" args: #{prototype_inspect_array_of_hashes(decl[:args])}\n"
end
return decl
decl
end
def prototype_inspect_hash(hash)
pairs = []
hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if (value.class == String)}#{value}#{"'" if (value.class == String)}" }
return "{#{pairs.join(', ')}}"
hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if value.class == String}#{value}#{"'" if value.class == String}" }
"{#{pairs.join(', ')}}"
end
def prototype_inspect_array_of_hashes(array)
hashes = []
array.each { |hash| hashes << prototype_inspect_hash(hash) }
case (array.size)
case array.size
when 0
return "[]"
return '[]'
when 1
return "[#{hashes[0]}]"
else
return "[\n #{hashes.join("\n ")}\n ]\n"
end
end
end
+29 -19
View File
@@ -2,39 +2,49 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
class 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
object_name = 'CMockGeneratorPlugin' + camelize(plugin_name)
self.class.mutex.synchronize { load_plugin(plugin_name, object_name, config, utils) }
end
@plugins.sort! {|a,b| a.priority <=> b.priority }
@plugins.sort! { |a, b| a.priority <=> b.priority }
end
def run(method, args=nil)
def run(method, args = nil)
if args.nil?
return @plugins.collect{ |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join
@plugins.collect { |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join
else
return @plugins.collect{ |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join
@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 }
lower_case_and_underscored_word.gsub(/\/(.?)/) { '::' + Regexp.last_match(1).upcase }.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase }
end
def self.mutex
@mutex ||= Mutex.new
end
private
def load_plugin(plugin_name, object_name, config, utils)
unless Object.const_defined? object_name
file_name = "#{__dir__}/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 StandardError
file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
raise "ERROR: CMock unable to load plugin '#{plugin_name}' '#{object_name}' #{file_name}"
end
end
+40 -38
View File
@@ -2,74 +2,76 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
class CMockUnityHelperParser
attr_accessor :c_types
def initialize(config)
@config = config
@fallback = @config.plugins.include?(:array) ? 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' : 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
@c_types = map_C_types.merge(import_source)
@c_types = map_c_types.merge(import_source)
end
def get_helper(ctype)
lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/,'\1\3\5\6').strip.gsub(/\s+/,'_')
return [@c_types[lookup], ''] if (@c_types[lookup])
if (lookup =~ /\*$/)
lookup = lookup.gsub(/\*$/,'')
return [@c_types[lookup], '*'] if (@c_types[lookup])
lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/, '\1\3\5\6').strip.gsub(/\s+/, '_')
return [@c_types[lookup], ''] if @c_types[lookup]
if lookup =~ /\*$/
lookup = lookup.gsub(/\*$/, '')
return [@c_types[lookup], '*'] if @c_types[lookup]
else
lookup = lookup + '*'
return [@c_types[lookup], '&'] if (@c_types[lookup])
lookup += '*'
return [@c_types[lookup], '&'] if @c_types[lookup]
end
return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if (ctype =~ /cmock_\w+_ptr\d+/)
return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if ctype =~ /cmock_\w+_ptr\d+/
raise("Don't know how to test #{ctype} and memory tests are disabled!") unless @config.memcmp_if_unknown
return (lookup =~ /\*$/) ? [@fallback, '&'] : [@fallback, '']
lookup =~ /\*$/ ? [@fallback, '&'] : [@fallback, '']
end
private ###########################
def map_C_types
def map_c_types
c_types = {}
@config.treat_as.each_pair do |ctype, expecttype|
c_type = ctype.gsub(/\s+/,'_')
if (expecttype =~ /\*/)
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.gsub(/\*/,'')}_ARRAY"
c_type = ctype.gsub(/\s+/, '_')
if expecttype =~ /\*/
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.delete('*')}_ARRAY"
else
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype}"
c_types[c_type+'*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY"
c_types[c_type + '*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY"
end
end
c_types
end
def import_source
source = @config.load_unity_helper
return {} if source.nil?
c_types = {}
source = source.gsub(/\/\/.*$/, '') #remove line comments
source = source.gsub(/\/\*.*?\*\//m, '') #remove block comments
#scan for comparison helpers
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4,'\s*\w+\s*').join(',') + '\)')
source = source.gsub(/\/\/.*$/, '') # remove line comments
source = source.gsub(/\/\*.*?\*\//m, '') # remove block comments
# scan for comparison helpers
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4, '\s*\w+\s*').join(',') + '\)')
pairs = source.scan(match_regex).flatten.compact
(pairs.size/2).times do |i|
expect = pairs[i*2]
ctype = pairs[(i*2)+1]
c_types[ctype] = expect unless expect.include?("_ARRAY")
(pairs.size / 2).times do |i|
expect = pairs[i * 2]
ctype = pairs[(i * 2) + 1]
c_types[ctype] = expect unless expect.include?('_ARRAY')
end
#scan for array variants of those helpers
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5,'\s*\w+\s*').join(',') + '\)')
# scan for array variants of those helpers
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5, '\s*\w+\s*').join(',') + '\)')
pairs = source.scan(match_regex).flatten.compact
(pairs.size/2).times do |i|
expect = pairs[i*2]
ctype = pairs[(i*2)+1]
c_types[ctype.gsub('_ARRAY','*')] = expect
(pairs.size / 2).times do |i|
expect = pairs[i * 2]
ctype = pairs[(i * 2) + 1]
c_types[ctype.gsub('_ARRAY', '*')] = expect
end
c_types
end
end
Executable
+17
View File
@@ -0,0 +1,17 @@
#
# build script written by : Michael Brockus.
# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams.
#
# license: MIT
#
project('cmock', 'c',
license: 'MIT',
meson_version: '>=0.53.0',
subproject_dir : 'vendor',
default_options: ['werror=true', 'c_std=c11']
)
unity_dep = dependency('unity', fallback: ['unity', 'unity_dep'])
subdir('src')
cmock_dep = declare_dependency(link_with: cmock_lib, include_directories: cmock_dir)
-2
View File
@@ -1,2 +0,0 @@
215
-2
View File
@@ -1,2 +0,0 @@
2.4.4
+101 -61
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
@@ -27,38 +28,53 @@ end
all_headers_to_mock = []
suppress_error = !ARGV.nil? && !ARGV.empty? && (ARGV[0].upcase == "--SILENT")
File.open(TEST_MAKEFILE, "w") do |mkfile|
suppress_error = !ARGV.nil? && !ARGV.empty? && (ARGV[0].casecmp('--SILENT') == 0)
File.open(TEST_MAKEFILE, 'w') do |mkfile|
# Define make variables
mkfile.puts "CC ?= gcc"
mkfile.puts "BUILD_DIR ?= ./build"
mkfile.puts "SRC_DIR ?= ./src"
mkfile.puts "TEST_DIR ?= ./test"
mkfile.puts "TEST_CFLAGS ?= -DTEST"
mkfile.puts 'CC ?= gcc'
mkfile.puts "BUILD_DIR = #{BUILD_DIR}"
mkfile.puts "SRC_DIR = #{SRC_DIR}"
mkfile.puts "TEST_DIR = #{TEST_DIR}"
mkfile.puts 'TEST_CFLAGS ?= -DTEST'
mkfile.puts "CMOCK_DIR ?= #{CMOCK_DIR}"
mkfile.puts "UNITY_DIR ?= #{UNITY_DIR}"
mkfile.puts "TEST_BUILD_DIR ?= ${BUILD_DIR}/test"
mkfile.puts "TEST_MAKEFILE = ${TEST_BUILD_DIR}/MakefileTestSupport"
mkfile.puts "OBJ ?= ${BUILD_DIR}/obj"
mkfile.puts "OBJ_DIR = ${OBJ}"
mkfile.puts ""
mkfile.puts 'TEST_BUILD_DIR ?= ${BUILD_DIR}/test'
mkfile.puts 'TEST_MAKEFILE = ${TEST_BUILD_DIR}/MakefileTestSupport'
mkfile.puts 'OBJ ?= ${BUILD_DIR}/obj'
mkfile.puts 'OBJ_DIR = ${OBJ}'
mkfile.puts ''
# Build Unity
mkfile.puts "#{UNITY_OBJ}: #{UNITY_SRC}/unity.c"
mkfile.puts "\t${CC} -o $@ -c $< -I #{UNITY_SRC}"
mkfile.puts ""
mkfile.puts ''
# Build CMock
mkfile.puts "#{CMOCK_OBJ}: #{CMOCK_SRC}/cmock.c"
mkfile.puts "\t${CC} -o $@ -c $< -I #{UNITY_SRC} -I #{CMOCK_SRC}"
mkfile.puts ""
mkfile.puts ''
test_sources = Dir["#{TEST_DIR}/**/test_*.c"]
test_targets = []
generator = UnityTestRunnerGenerator.new
all_headers = Dir["#{SRC_DIR}/**/*.h"]
# headers that begin with prefix or end with suffix are not included
all_headers = Dir["#{SRC_DIR}/**/*.h*"]
def reject_mock_files(file)
extn = File.extname file
filename = File.basename file, extn
if MOCK_SUFFIX.empty?
return filename.start_with? MOCK_PREFIX
end
(filename.start_with?(MOCK_PREFIX) || filename.end_with?(MOCK_SUFFIX))
end
all_headers = all_headers.reject { |f| reject_mock_files(f) }
makefile_targets = []
test_sources.each do |test|
module_name = File.basename(test, '.c')
@@ -67,97 +83,121 @@ 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')
# 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 ""
# Create runners
mkfile.puts "#{runner_source}: #{test}"
mkfile.puts "\t@UNITY_DIR=${UNITY_DIR} ruby ${CMOCK_DIR}/scripts/create_runner.rb #{test} #{runner_source}"
mkfile.puts ""
# 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 ""
# 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"}
# 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")
unless 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.to_s)
linkonlymodule_obj = File.join(OBJ_DIR, "#{linkonlybase}.o")
linkonly_objs.push(linkonlymodule_obj)
# only create the target if we didn't already
next if 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
# Create runners
mkfile.puts "#{runner_source}: #{test}"
mkfile.puts "\t@UNITY_DIR=${UNITY_DIR} ruby ${CMOCK_DIR}/scripts/create_runner.rb #{test} #{runner_source}"
mkfile.puts ''
# 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} ${INCLUDE_PATH}"
mkfile.puts ''
# Collect mocks to generate
system_mocks = cfg[:includes][:system].select { |name| name =~ MOCK_MATCHER }
raise 'Mocking of system headers is not yet supported!' unless 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}/, '').to_s }
headers_to_mock = []
module_names_to_mock.each do |name|
header_to_mock = nil
all_headers.each do |header|
if (header =~ /[\/\\]?#{name}$/)
if header =~ /[\/\\]?#{name}$/
header_to_mock = header
break
end
end
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')
mock_name = MOCK_PREFIX + File.basename(hdr, '.*')
File.join(MOCKS_DIR, mock_name + '.o')
end
all_headers_to_mock.uniq!
# 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 ""
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 ""
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 ""
mkfile.puts "\t-#{test_bin} > #{test_results} 2>&1"
mkfile.puts ''
test_targets << test_bin
end
# Generate and build mocks
all_headers_to_mock.each do |hdr|
mock_name = MOCK_PREFIX + File.basename(hdr, '.h')
mock_header = File.join(MOCKS_DIR, mock_name + '.h')
mock_name = MOCK_PREFIX + File.basename(hdr, '.*')
mock_header = File.join(MOCKS_DIR, mock_name + File.extname(hdr))
mock_src = File.join(MOCKS_DIR, mock_name + '.c')
mock_obj = File.join(MOCKS_DIR, mock_name + '.o')
mkfile.puts "#{mock_src}: #{hdr}"
mkfile.puts "\t@CMOCK_DIR=${CMOCK_DIR} ruby ${CMOCK_DIR}/scripts/create_mock.rb #{hdr}"
mkfile.puts ""
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 ""
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
# Create test summary task
mkfile.puts "test_summary:"
mkfile.puts 'test_summary:'
mkfile.puts "\t@UNITY_DIR=${UNITY_DIR} ruby ${CMOCK_DIR}/scripts/test_summary.rb #{suppress_error ? '--silent' : ''}"
mkfile.puts ""
mkfile.puts ".PHONY: test_summary"
mkfile.puts ""
mkfile.puts ''
mkfile.puts '.PHONY: test_summary'
mkfile.puts ''
# Create target to run all tests
mkfile.puts "test: #{test_targets.map{|t| t + '.result'}.join(' ')} test_summary"
mkfile.puts ""
mkfile.puts "test: #{test_targets.map { |t| t + '.testresult' }.join(' ')} test_summary"
mkfile.puts ''
end
+2 -2
View File
@@ -1,8 +1,8 @@
require "#{ENV['CMOCK_DIR']}/lib/cmock"
raise "Header file to mock must be specified!" unless ARGV.length >= 1
raise 'Header file to mock must be specified!' unless ARGV.length >= 1
mock_out = ENV.fetch('MOCK_OUT', './build/test/mocks')
mock_prefix = ENV.fetch('MOCK_PREFIX', 'mock_')
cmock = CMock.new({:plugins => [:ignore, :return_thru_ptr], :mock_prefix => mock_prefix, :mock_path => mock_out})
cmock = CMock.new(:plugins => %i[ignore return_thru_ptr], :mock_prefix => mock_prefix, :mock_path => mock_out)
cmock.setup_mocks(ARGV[0])
+7 -9
View File
@@ -1,13 +1,12 @@
if ($0 == __FILE__)
if $0 == __FILE__
#make sure there is at least one parameter left (the input file)
# make sure there is at least one parameter left (the input file)
if ARGV.length < 2
puts ["\nusage: ruby #{__FILE__} input_test_file (output)",
"",
" input_test_file - this is the C file you want to create a runner for",
" output - this is the name of the runner file to generate",
" defaults to (input_test_file)_Runner",
].join("\n")
'',
' input_test_file - this is the C file you want to create a runner for',
' output - this is the name of the runner file to generate',
' defaults to (input_test_file)_Runner'].join("\n")
exit 1
end
@@ -15,6 +14,5 @@ if ($0 == __FILE__)
test = ARGV[0]
runner = ARGV[1]
generator = UnityTestRunnerGenerator.new.run(test, runner)
UnityTestRunnerGenerator.new.run(test, runner)
end
+2 -3
View File
@@ -1,5 +1,4 @@
suppress_error = !ARGV.nil? && !ARGV.empty? && (ARGV[0].upcase == "--SILENT")
suppress_error = !ARGV.nil? && !ARGV.empty? && (ARGV[0].casecmp('--SILENT') == 0)
begin
require "#{ENV['UNITY_DIR']}/auto/unity_test_summary.rb"
@@ -7,7 +6,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
+61 -49
View File
@@ -4,13 +4,12 @@
[Released under MIT License. Please refer to license.txt for details]
========================================== */
#include "unity.h"
#include "cmock.h"
//public constants to be used by mocks
/* public constants to be used by mocks */
const char* CMockStringOutOfMemory = "CMock has run out of memory. Please allocate more.";
const char* CMockStringCalledMore = "Called more times than expected.";
const char* CMockStringCalledLess = "Called less times than expected.";
const char* CMockStringCalledLess = "Called fewer times than expected.";
const char* CMockStringCalledEarly = "Called earlier than expected.";
const char* CMockStringCalledLate = "Called later than expected.";
const char* CMockStringCallOrder = "Called out of order.";
@@ -20,43 +19,48 @@ const char* CMockStringPtrIsNULL = "Pointer is NULL.";
const char* CMockStringExpNULL = "Expected NULL.";
const char* CMockStringMismatch = "Function called with unexpected argument value.";
//private variables
/* private variables */
#ifdef CMOCK_MEM_DYNAMIC
static unsigned char* CMock_Guts_Buffer = NULL;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
#else
static unsigned char CMock_Guts_Buffer[CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE];
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr;
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
#endif
//-------------------------------------------------------
// CMock_Guts_MemNew
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemNew
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
{
CMOCK_MEM_INDEX_TYPE index;
//verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere)
/* verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) */
if (size < 1)
return CMOCK_GUTS_NONE;
//verify we have enough room
/* verify we have enough room */
size = size + CMOCK_MEM_INDEX_SIZE;
if (size & CMOCK_MEM_ALIGN_MASK)
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
{
#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
/* determine where we're putting this new block, and init its pointer to be the end of the line */
index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE;
*(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE;
CMock_Guts_FreePtr += size;
@@ -64,9 +68,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
return index;
}
//-------------------------------------------------------
// CMock_Guts_MemChain
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemChain
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index)
{
CMOCK_MEM_INDEX_TYPE index;
@@ -76,12 +80,12 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
if (root_index == CMOCK_GUTS_NONE)
{
//if there is no root currently, we return this object as the root of the chain
/* if there is no root currently, we return this object as the root of the chain */
return obj_index;
}
else
{
//reject illegal nodes
/* reject illegal nodes */
if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr))
{
return CMOCK_GUTS_NONE;
@@ -94,7 +98,7 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
root = (void*)(&CMock_Guts_Buffer[root_index]);
obj = (void*)(&CMock_Guts_Buffer[obj_index]);
//find the end of the existing chain and add us
/* find the end of the existing chain and add us */
next = root;
do {
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
@@ -108,21 +112,21 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
}
}
//-------------------------------------------------------
// CMock_Guts_MemNext
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemNext
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
{
CMOCK_MEM_INDEX_TYPE index;
void* previous_item;
//There is nothing "next" if the pointer isn't from our buffer
/* There is nothing "next" if the pointer isn't from our buffer */
if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr))
return CMOCK_GUTS_NONE;
previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]);
//if the pointer is good, then use it to look up the next index
//(we know the first element always goes in zero, so NEXT must always be > 1)
/* if the pointer is good, then use it to look up the next index
* (we know the first element always goes in zero, so NEXT must always be > 1) */
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE);
if ((index > 1) && (index < CMock_Guts_FreePtr))
return index;
@@ -130,9 +134,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index
return CMOCK_GUTS_NONE;
}
//-------------------------------------------------------
// CMock_Guts_MemEndOfChain
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemEndOfChain
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
{
CMOCK_MEM_INDEX_TYPE index = root_index;
@@ -148,9 +152,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
return index;
}
//-------------------------------------------------------
// CMock_GetAddressFor
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_GetAddressFor
*-------------------------------------------------------*/
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
{
if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr))
@@ -163,33 +167,41 @@ void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
}
}
//-------------------------------------------------------
// CMock_Guts_MemBytesFree
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemBytesCapacity
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
{
return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE);
}
/*-------------------------------------------------------
* CMock_Guts_MemBytesFree
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
{
return CMock_Guts_BufferSize - CMock_Guts_FreePtr;
}
//-------------------------------------------------------
// CMock_Guts_MemBytesUsed
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemBytesUsed
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
{
return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE;
}
//-------------------------------------------------------
// CMock_Guts_MemFreeAll
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemFreeAll
*-------------------------------------------------------*/
void CMock_Guts_MemFreeAll(void)
{
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; //skip the very beginning
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; /* skip the very beginning */
}
//-------------------------------------------------------
// CMock_Guts_MemFreeFinal
//-------------------------------------------------------
/*-------------------------------------------------------
* CMock_Guts_MemFreeFinal
*-------------------------------------------------------*/
void CMock_Guts_MemFreeFinal(void)
{
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
+23 -14
View File
@@ -9,30 +9,39 @@
#include "cmock_internals.h"
//should be big enough to index full range of CMOCK_MEM_MAX
#define CMOCK_VERSION_MAJOR 2
#define CMOCK_VERSION_MINOR 5
#define CMOCK_VERSION_BUILD 2
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
/* should be big enough to index full range of CMOCK_MEM_MAX */
#ifndef CMOCK_MEM_INDEX_TYPE
#define CMOCK_MEM_INDEX_TYPE unsigned int
#include <stddef.h>
#define CMOCK_MEM_INDEX_TYPE size_t
#endif
#define CMOCK_GUTS_NONE (0)
#define CMOCK_ARG_MODE CMOCK_MEM_INDEX_TYPE
#define CMOCK_ARG_ALL 0
#define CMOCK_ARG_NONE ((CMOCK_MEM_INDEX_TYPE)(~0U))
#if defined __GNUC__
# define CMOCK_FUNCTION_ATTR(a) __attribute__((a))
#else
# define CMOCK_FUNCTION_ATTR(a) /* ignore */
#endif
//-------------------------------------------------------
// Memory API
//-------------------------------------------------------
/*-------------------------------------------------------
* Memory API
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) CMOCK_FUNCTION_ATTR(pure);
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index);
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) CMOCK_FUNCTION_ATTR(pure);
void CMock_Guts_MemFreeAll(void);
void CMock_Guts_MemFreeFinal(void);
#endif //CMOCK_FRAMEWORK
#endif /* end of CMOCK_FRAMEWORK_H */
+10 -8
View File
@@ -7,7 +7,9 @@
#ifndef CMOCK_FRAMEWORK_INTERNALS_H
#define CMOCK_FRAMEWORK_INTERNALS_H
//These are constants that the generated mocks have access to
#include "unity.h"
/* These are constants that the generated mocks have access to */
extern const char* CMockStringOutOfMemory;
extern const char* CMockStringCalledMore;
extern const char* CMockStringCalledLess;
@@ -20,8 +22,8 @@ extern const char* CMockStringPtrIsNULL;
extern const char* CMockStringExpNULL;
extern const char* CMockStringMismatch;
//define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc
//when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total
/* define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc
* when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total */
#ifdef CMOCK_MEM_STATIC
#undef CMOCK_MEM_DYNAMIC
#endif
@@ -30,7 +32,7 @@ extern const char* CMockStringMismatch;
#include <stdlib.h>
#endif
//this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type
/* this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type */
#ifndef CMOCK_MEM_PTR_AS_INT
#ifdef UNITY_POINTER_WIDTH
#ifdef UNITY_INT_WIDTH
@@ -58,7 +60,7 @@ extern const char* CMockStringMismatch;
#define CMOCK_MEM_PTR_AS_INT unsigned long
#endif
//0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit
/* 0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit */
#ifndef CMOCK_MEM_ALIGN
#ifdef UNITY_LONG_WIDTH
#if (UNITY_LONG_WIDTH == 16)
@@ -75,15 +77,15 @@ extern const char* CMockStringMismatch;
#endif
#endif
//amount of memory to allow cmock to use in its internal heap
/* amount of memory to allow cmock to use in its internal heap */
#ifndef CMOCK_MEM_SIZE
#define CMOCK_MEM_SIZE (32768)
#endif
//automatically calculated defs for easier reading
/* automatically calculated defs for easier reading */
#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN)
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1)
#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE)
#endif //CMOCK_FRAMEWORK_INTERNALS
#endif /* end of CMOCK_FRAMEWORK_INTERNALS_H */
+12
View File
@@ -0,0 +1,12 @@
#
# build script written by : Michael Brockus.
# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams.
#
# license: MIT
#
cmock_dir = include_directories('.')
cmock_lib = static_library(meson.project_name(),
files('cmock.c'),
dependencies: [unity_dep],
include_directories: cmock_dir)
+15 -5
View File
@@ -25,8 +25,18 @@ void test_MemNewWillReturnNullIfGivenIllegalSizes(void)
TEST_ASSERT_NULL( CMock_Guts_GetAddressFor(CMOCK_GUTS_NONE) );
//verify we're cleared still
TEST_ASSERT_EQUAL(0, CMock_Guts_MemBytesUsed());
TEST_ASSERT_EQUAL(CMOCK_MEM_SIZE, CMock_Guts_MemBytesFree());
TEST_ASSERT_LESS_OR_EQUAL_UINT32(CMOCK_MEM_SIZE, CMock_Guts_MemBytesCapacity());
TEST_ASSERT_EQUAL_UINT32(0, CMock_Guts_MemBytesUsed());
TEST_ASSERT_LESS_OR_EQUAL_UINT32(CMOCK_MEM_SIZE, CMock_Guts_MemBytesFree());
}
void test_MemShouldProtectAgainstMemoryOverflow(void)
{
(void)CMock_Guts_MemNew(CMOCK_MEM_SIZE - TEST_MEM_INDEX_SIZE);
//verify we've used all the memory
TEST_ASSERT_LESS_OR_EQUAL_UINT32(TEST_MEM_INDEX_SIZE, CMock_Guts_MemBytesFree());
TEST_ASSERT_GREATER_OR_EQUAL_UINT32(CMOCK_MEM_SIZE, CMock_Guts_MemBytesUsed());
}
void test_MemChainWillReturnNullAndDoNothingIfGivenIllegalInformation(void)
@@ -258,11 +268,11 @@ void test_ThatWeCanAskForAllSortsOfSizes(void)
}
//show that we can't ask for too much memory
TEST_ASSERT_EQUAL_HEX(CMOCK_GUTS_NONE, CMock_Guts_MemNew(12));
TEST_ASSERT_EQUAL_HEX(CMOCK_GUTS_NONE, CMock_Guts_MemNew(5));
TEST_ASSERT_EQUAL_HEX(CMOCK_GUTS_NONE, CMock_Guts_MemNew(CMOCK_MEM_SIZE - sum + 8));
TEST_ASSERT_EQUAL_HEX(CMOCK_GUTS_NONE, CMock_Guts_MemNew(CMOCK_MEM_SIZE - sum + 1));
//but we CAN ask for something that will still fit
next = CMock_Guts_MemNew(4);
next = CMock_Guts_MemNew(CMOCK_MEM_SIZE - sum - 4);
TEST_ASSERT_MESSAGE(next != CMOCK_GUTS_NONE, "Should Not Have Returned CMOCK_GUTS_NONE");
first = CMock_Guts_MemChain(first, next);
+1
View File
@@ -8,6 +8,7 @@
- 'TEST'
- 'CMOCK_MEM_STATIC'
- 'CMOCK_MEM_SIZE=128'
#- 'CMOCK_MEM_SIZE=40000'
- 'CMOCK_MEM_ALIGN=2'
- 'CMOCK_MEM_INDEX_TYPE=int'
+9 -7
View File
@@ -12,6 +12,7 @@ extern void setUp(void);
extern void tearDown(void);
extern void test_MemNewWillReturnNullIfGivenIllegalSizes(void);
extern void test_MemShouldProtectAgainstMemoryOverflow(void);
extern void test_MemChainWillReturnNullAndDoNothingIfGivenIllegalInformation(void);
extern void test_MemNextWillReturnNullIfGivenABadRoot(void);
extern void test_ThatWeCanClaimAndChainAFewElementsTogether(void);
@@ -26,13 +27,14 @@ int main(void)
UnityBegin(Unity.TestFile);
RUN_TEST(test_MemNewWillReturnNullIfGivenIllegalSizes, 21);
RUN_TEST(test_MemChainWillReturnNullAndDoNothingIfGivenIllegalInformation, 32);
RUN_TEST(test_MemNextWillReturnNullIfGivenABadRoot, 46);
RUN_TEST(test_ThatWeCanClaimAndChainAFewElementsTogether, 57);
RUN_TEST(test_MemEndOfChain, 282);
RUN_TEST(test_ThatCMockStopsReturningMoreDataWhenItRunsOutOfMemory, 139);
RUN_TEST(test_ThatCMockStopsReturningMoreDataWhenAskForMoreThanItHasLeftEvenIfNotAtExactEnd, 185);
RUN_TEST(test_ThatWeCanAskForAllSortsOfSizes, 233);
RUN_TEST(test_MemShouldProtectAgainstMemoryOverflow, 33);
RUN_TEST(test_MemChainWillReturnNullAndDoNothingIfGivenIllegalInformation, 42);
RUN_TEST(test_MemNextWillReturnNullIfGivenABadRoot, 56);
RUN_TEST(test_ThatWeCanClaimAndChainAFewElementsTogether, 67);
RUN_TEST(test_MemEndOfChain, 149);
RUN_TEST(test_ThatCMockStopsReturningMoreDataWhenItRunsOutOfMemory, 195);
RUN_TEST(test_ThatCMockStopsReturningMoreDataWhenAskForMoreThanItHasLeftEvenIfNotAtExactEnd, 244);
RUN_TEST(test_ThatWeCanAskForAllSortsOfSizes, 298);
UnityEnd();
return 0;
+45 -4
View File
@@ -32,7 +32,7 @@ configure_clean
configure_toolchain(DEFAULT_CONFIG_FILE)
task :default => [:test]
task :ci => [:no_color, :default]
task :ci => [:no_color, :default, 'test:examples', 'style:check']
task :cruise => :ci
desc "Load configuration"
@@ -42,10 +42,13 @@ task :config, :config_file do |t, args|
configure_toolchain(args[:config_file])
end
desc "Run all unit, c, and system tests"
task :test => [:clobber, :prep_system_tests, 'test:units', 'test:c', 'test:system']
# Still support testing everything with just 'test' but switch default to ceedling-like test:all
task :test => ['test:all']
namespace :test do
desc "Run all unit, c, and system tests"
task :all => [:clobber, :prep_system_tests, 'test:units', 'test:c', 'test:system']
desc "Run Unit Tests"
Rake::TestTask.new('units') do |t|
t.pattern = 'unit/*_test.rb'
@@ -86,10 +89,15 @@ namespace :test do
run_system_test_compilations(compile_tests_to_run)
end
desc "Test cmock examples"
task :examples => [:prep_system_tests] do
run_examples()
end
#individual system tests
FileList['system/test_interactions/*.yml'].each do |test|
basename = File.basename(test,'.*')
desc "Run system test #{basename}"
#desc "Run system test #{basename}"
task basename do
run_system_test_interactions([test])
end
@@ -104,3 +112,36 @@ end
task :no_color do
$colour_output = false
end
################### CODING STYLE VALIDATION
namespace :style do
desc "Check style"
task :check do
report "\nVERIFYING RUBY STYLE"
report execute("rubocop ../lib ../examples ../config ../scripts --config ../vendor/unity/test/.rubocop.yml", true)
report "Styling Ruby:PASS"
end
desc "Fix Style of all C Code"
task :c do
run_astyle("../src/*.* ../extras/fixture/src/*.*")
end
desc "Attempt to Autocorrect style"
task :auto => ['style:clean'] do
report execute("rubocop ../lib ../examples ../config ../scripts --auto-correct --config ../vendor/unity/test/.rubocop.yml", true)
report "Autocorrected What We Could."
end
desc "Update style todo list"
task :todo => ['style:clean'] do
report execute("rubocop ../lib ../examples ../config ../scripts --auto-gen-config --config ../vendor/unity/test/.rubocop.yml", true)
report "Updated Style TODO List."
end
task :clean do
File.delete(".rubocop_todo.yml") if File.exists?(".rubocop_todo.yml")
end
end
task :style => ['style:check']
+22
View File
@@ -50,6 +50,7 @@ module RakefileHelpers
includes << m[1]
end
end
includes << File.basename(filename,".c").slice(5,256) + "_unity_helper.h"
return includes
end
@@ -160,6 +161,18 @@ module RakefileHelpers
end
end
def run_astyle(style_what)
report "Styling C Code..."
command = "AStyle " \
"--style=allman --indent=spaces=4 --indent-switches --indent-preproc-define --indent-preproc-block " \
"--pad-oper --pad-comma --unpad-paren --pad-header " \
"--align-pointer=type --align-reference=name " \
"--add-brackets --mode=c --suffix=none " \
"#{style_what}"
execute(command, false)
report "Styling C:PASS"
end
def report_summary
summary = UnityTestSummary.new
summary.root = File.expand_path(File.dirname(__FILE__)) + '/'
@@ -373,6 +386,15 @@ module RakefileHelpers
end
end
def run_examples()
[ "cd #{File.join("..","examples","make_example")} && make clean && make setup && make test",
"cd #{File.join("..","examples","temp_sensor")} && rake ci"
].each do |cmd|
report "Testing '#{cmd}'"
execute(cmd, false)
end
end
def fail_out(msg)
puts msg
exit(-1)
+14 -3
View File
@@ -66,6 +66,7 @@ class SystemTestGenerator
generate_test_file(yaml_hash, namix, name)
generate_source_file(yaml_hash, namix, name)
generate_skeleton_file(yaml_hash, namix, name)
end
def generate_types_file(yaml_hash, namix)
@@ -104,7 +105,6 @@ class SystemTestGenerator
return if tests.nil?
includes = [UNITY_H, CMOCK_H]
includes << (namix + UNITY_HELPER_H) if not yaml_hash[:systest][:unity_helper].nil?
includes << [MOCK_PREFIX + namix + MOCKABLE_H]
includes << [name + H_EXTENSION]
@@ -137,11 +137,22 @@ class SystemTestGenerator
includes << (namix + MOCKABLE_H) if not yaml_hash[:systest][:mockable].nil?
includes << header_file
write_source_file(GENERATED_PATH + name + C_EXTENSION, includes.flatten) do |out|
out.puts(source[:code])
unless (source[:code].nil?)
write_source_file(GENERATED_PATH + name + C_EXTENSION, includes.flatten) do |out|
out.puts(source[:code])
end
end
end
def generate_skeleton_file(yaml_hash, namix, name)
source = yaml_hash[:systest][:skeleton]
return if source.nil?
require 'cmock.rb'
cmock = CMock.new(GENERATED_PATH + namix + 'cmock' + YAML_EXTENSION)
cmock.setup_skeletons("#{$cfg['compiler']['source_path']}#{name}.h")
end
def write_header_file(filename, upcase_name, include_list=[])
File.open(filename, 'w') do |out|
out.puts("#ifndef _#{upcase_name}")
+1
View File
@@ -4,6 +4,7 @@
:includes: []
:mock_path: ./system/generated/
:mock_prefix: mock_
:treat_inlines: :include
:treat_as_void:
- OSEK_TASK
- VOID_TYPE_CRAZINESS
+23
View File
@@ -0,0 +1,23 @@
static inline int dummy_func_0(void) {
return 5;
}
inline static int dummy_func_1(int a) {
int a = dummy_func_0();
int b = 10;
return a + b;
}
int inline static dummy_func_2(int a, char b, float c) {
c += 3.14;
b -= 32;
return a + (int)(b) + (int)c;
}
void dummy_normal_func(int a);
inline void dummy_func_3(void) {
//NOP
}
View File
+37
View File
@@ -50,3 +50,40 @@ extern unsigned long int incredible_descriptors(register const unsigned short a)
int32_t example_c99_type(int32_t param1);
void I2CIntRegister(uint32_t ui32Base, void (*pfnHandler)(void));
/* these are function pointers, not function declarations USING a function pointer, and so should NOT get mocked */
int (* func_pointer)(void);
extern int (*another_func_pointer)(unsigned int argument);
struct struct_to_be_ignored {
union {
int i32;
void *p;
} variant;
void (*a_function_pointer_in_a_struct)(void *);
};
typedef struct
{
uint32_t a;
struct
{
uint32_t bb;
float bc;
float bd;
} b;
int (*another_function_pointer_in_a_struct) (void);
} another_thing_that_should_get_ignored;
inline int stuff(int num)
{
int reg = 0x12;
if (num > 0)
{
reg |= (0x0Eu);
}
else
{
reg |= (0x07u);
}
return reg;
}
@@ -12,6 +12,7 @@
:callback_after_arg_check: true
:callback_include_count: false
:treat_externs: :include
:treat_inlines: :include
:systest:
:types: |
@@ -100,7 +100,7 @@
- :pass: FALSE
:should: 'fail because bar() is called twice but is expected once'
:verify_error: 'Called less times than expected'
:verify_error: 'Called fewer times than expected'
:code: |
test()
{
@@ -3,6 +3,7 @@
:plugins:
- # none
:memcmp_if_unknown: false
:unity_helper_path: expect_and_return_custom_types_unity_helper.h
:systest:
:types: |
@@ -35,7 +36,6 @@
:tests:
:common: |
#include "expect_and_return_custom_types_unity_helper.h"
void setUp(void) {}
void tearDown(void) {}
@@ -66,7 +66,7 @@
}
- :pass: FALSE
:should: 'ignore foo() call details and notice if we called foo() less times than expected'
:should: 'ignore foo() call details and notice if we called foo() fewer times than expected'
:code: |
test()
{
@@ -12,14 +12,15 @@
:mockable: |
void takes_function_type( FUNCTION_T myfunc );
void takes_function_ptr( unsigned int (*func_ptr)(int, char) );
void takes_function_ptr_shorthand( unsigned int func_ptr(int, char*) );
void takes_const_function_ptr( unsigned int (* const)(int, char) );
unsigned short (*returns_function_ptr( const char op_code ))( int, long int );
:source:
:source:
:header: |
void exercise_function_pointer_param(void);
unsigned short (*exercise_function_pointer_return( const char op_code ))( int, long int );
// functions for function pointer tests
unsigned int dummy_function1(int a, char b);
unsigned short dummy_function2(int a, long int b);
@@ -28,7 +29,7 @@
/*
* functions used in tests
*/
unsigned int dummy_function1(int a, char b)
{
// prevent compiler warnings by using everything
@@ -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,325 @@
---
:cmock:
:plugins:
- 'ignore_stateless'
: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: 'successfully exercise simple ExpectAndReturn mock calls'
:code: |
test()
{
bar_Expect(2);
foo_ExpectAndReturn(1, 10);
foo_ExpectAndReturn(2, 20);
foo_ExpectAndReturn(3, 30);
TEST_ASSERT_EQUAL(60, function(1, 2, 3));
}
- :pass: TRUE
:should: 'ignore foo() calls'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(40);
TEST_ASSERT_EQUAL(120, function(3, 4, 3));
}
- :pass: TRUE
:should: 'ignore the situation where foo() is not called even though we explicitly ignored it'
:code: |
test()
{
foo_IgnoreAndReturn(20);
//notice we do not call foo
}
- :pass: TRUE
:should: 'ignore foo() calls and always return last item'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(20);
foo_IgnoreAndReturn(30);
TEST_ASSERT_EQUAL(90, function(3, 4, 9));
}
- :pass: TRUE
:should: 'ignore bar() and foo() calls'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(50);
TEST_ASSERT_EQUAL(150, function(0, 0, 0));
}
- :pass: TRUE
:should: 'multiple cycles of expects still pass when ignores enabled'
:code: |
test()
{
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: 'multiple cycles of expects still fail when ignores enabled'
:code: |
test()
{
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(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 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: 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 only the ignore and return is acknowledged'
: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(60, function(4, 5, 6));
}
# StopIgnore
- :pass: FALSE
:should: 'fail when function is called after ignore is stopped'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(10);
function(0, 0, 0);
bar_StopIgnore();
function(0, 0, 0);
}
- :pass: FALSE
:should: 'delete expect after ignore is stopped'
:code: |
test()
{
bar_Ignore();
foo_ExpectAndReturn(0, 40);
foo_ExpectAndReturn(0, 30);
foo_ExpectAndReturn(0, 40);
foo_IgnoreAndReturn(20);
foo_StopIgnore();
TEST_ASSERT_EQUAL(110, function(0, 0, 0)); // THIS SHOULD FAIL
}
- :pass: TRUE
:should: 'delete expected return values after ignore is stopped'
:code: |
test()
{
bar_Ignore();
foo_ExpectAndReturn(0, 40);
foo_ExpectAndReturn(0, 30);
foo_ExpectAndReturn(0, 40);
foo_IgnoreAndReturn(20);
foo_StopIgnore();
foo_ExpectAndReturn(0, 50);
foo_ExpectAndReturn(0, 30);
foo_ExpectAndReturn(0, 40);
TEST_ASSERT_EQUAL(120, function(0, 0, 0));
}
...
@@ -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);
}
...
@@ -0,0 +1,55 @@
---
:cmock:
:plugins:
- # none
:skeleton_path: system/generated
:systest:
:types: |
#define UINT32 unsigned int
:mockable: |
UINT32 something(int a);
:skeleton: skeleton.h
:source:
:header: |
void function_a(void);
int function_b(int a, int b);
const char* function_c(void);
# we are purposefully not including a :code section because it will be generated with skeleton
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'generate an empty shell for functions with no return values'
:code: |
test()
{
function_a();
}
- :pass: TRUE
:should: 'return numerical zero for numerical return values'
:code: |
test()
{
TEST_ASSERT_EQUAL_INT(0, function_b(1, 2));
}
- :pass: TRUE
:should: 'return null for pointer return values'
:code: |
test()
{
TEST_ASSERT_NULL(function_c());
}
...
@@ -0,0 +1,76 @@
---
:cmock:
:plugins:
- # none
:skeleton_path: system/generated
:systest:
:types: |
#define UINT32 unsigned int
:mockable: |
UINT32 something(int a);
:skeleton: skeleton_update.h
:source:
:header: |
void function_a(void);
int function_b(int a, int b);
const char* function_c(void);
# note that this code section exists and will be updated by the skeleton generator
:code: |
const char* donuts = "donuts";
const char* function_c(void)
{
return donuts;
}
int function_d(void)
{
return 77;
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
extern int function_d();
:units:
- :pass: TRUE
:should: 'generate an empty shell for functions with no return values'
:code: |
test()
{
function_a();
}
- :pass: TRUE
:should: 'return numerical zero for numerical return values'
:code: |
test()
{
TEST_ASSERT_EQUAL_INT(0, function_b(1, 2));
}
- :pass: TRUE
:should: 'not overwrite functions that already exist'
:code: |
test()
{
TEST_ASSERT_EQUAL_STRING("donuts", function_c());
}
- :pass: TRUE
:should: 'leave functions it has never heard of'
:code: |
test()
{
TEST_ASSERT_EQUAL_INT(77, function_d());
}
...
@@ -12,7 +12,7 @@
void bar(void);
:source:
:header: |
:header: |
UINT32 function_a(int a);
void function_b(void);
@@ -0,0 +1,91 @@
---
#The purpose of this test is to verify we handle void pointers as memory compares
:cmock:
:plugins:
- :array
:treat_as_array:
VOID_PTR: unsigned char
:systest:
:types: |
#include "unity_internals.h"
typedef void* VOID_PTR;
:mockable: |
void* ret_v_ptr(void);
void get_v_ptr(void* ptr);
void get_v_ptr_typedefed(VOID_PTR ptr);
:source:
:header: |
void function_a(void);
:code: |
void function_a(void) {
void* stuff = ret_v_ptr();
get_v_ptr(stuff);
get_v_ptr_typedefed((VOID_PTR)stuff);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'handle passing working expects'
:code: |
test()
{
char* a = "Hello";
char* b = "Hello";
ret_v_ptr_ExpectAndReturn(a);
get_v_ptr_Expect(b);
get_v_ptr_typedefed_Expect((VOID_PTR)b);
function_a();
}
- :pass: TRUE
:should: 'handle passing array expects'
:code: |
test()
{
char* a = "Hello";
char* b = "Hello";
ret_v_ptr_ExpectAndReturn(a);
get_v_ptr_ExpectWithArray(b,5);
get_v_ptr_typedefed_ExpectWithArray((VOID_PTR)b,5);
function_a();
}
- :pass: FALSE
:should: 'handle failing expects'
:code: |
test()
{
char* a = "Hello";
char* b = "Jello";
ret_v_ptr_ExpectAndReturn(a);
get_v_ptr_Expect(b);
get_v_ptr_typedefed_Expect((VOID_PTR)b);
function_a();
}
- :pass: FALSE
:should: 'handle failing array expects'
:code: |
test()
{
char* a = "Hello";
char* b = "Hella";
ret_v_ptr_ExpectAndReturn(a);
get_v_ptr_ExpectWithArray(b,5);
get_v_ptr_typedefed_ExpectWithArray((VOID_PTR)b,5);
function_a();
}
...
+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
+18 -10
View File
@@ -13,31 +13,39 @@ 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_equal(CMockConfig::CMockDefaultOptions[:attributes], config.attributes)
assert_equal(CMockConfig::CMockDefaultOptions[:plugins], config.plugins)
assert_equal(CMockConfig::CMockDefaultOptions[:treat_externs], config.treat_externs)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:mock_path], config.mock_path)
assert_nil(CMockConfig::CMOCK_DEFAULT_OPTIONS[:includes])
assert_nil(config.includes)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:attributes], config.attributes)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:plugins], config.plugins)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:treat_externs], config.treat_externs)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:treat_inlines], config.treat_inlines)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:inline_function_patterns], config.inline_function_patterns)
end
it "replace only options specified in a hash" do
test_includes = ['hello']
test_attributes = ['blah', 'bleh']
config = CMockConfig.new(:includes => test_includes, :attributes => test_attributes)
assert_equal(CMockConfig::CMockDefaultOptions[:mock_path], config.mock_path)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:mock_path], config.mock_path)
assert_equal(test_includes, config.includes)
assert_equal(test_attributes, config.attributes)
assert_equal(CMockConfig::CMockDefaultOptions[:plugins], config.plugins)
assert_equal(CMockConfig::CMockDefaultOptions[:treat_externs], config.treat_externs)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:plugins], config.plugins)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:treat_externs], config.treat_externs)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:treat_inlines], config.treat_inlines)
assert_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:inline_function_patterns], config.inline_function_patterns)
end
it "replace only options specified in a yaml file" 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_equal(CMockConfig::CMOCK_DEFAULT_OPTIONS[:mock_path], config.mock_path)
assert_nil(CMockConfig::CMOCK_DEFAULT_OPTIONS[:includes])
assert_nil(config.includes)
assert_equal(test_plugins, config.plugins)
assert_equal(:include, config.treat_externs)
assert_equal(:include, config.treat_inlines)
assert_equal(['MY_INLINE_FUNCTION_DECLARATION_PATTERN'], config.inline_function_patterns)
end
it "populate treat_as map with internal standard_treat_as_map defaults, redefine defaults, and add custom values" do
+3 -1
View File
@@ -2,4 +2,6 @@
:plugins:
- 'soda'
- 'pizza'
:treat_externs: :include
:treat_externs: :include
:treat_inlines: :include
:inline_function_patterns: ['MY_INLINE_FUNCTION_DECLARATION_PATTERN']
+172 -9
View File
@@ -53,8 +53,11 @@ 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
@config.expect :treat_inlines, :exclude
@cmock_generator = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator.module_name = @module_name
@cmock_generator.module_ext = '.h'
@cmock_generator.mock_name = "Mock#{@module_name}"
@cmock_generator.clean_mock_name = "Mock#{@module_name}"
@@ -70,8 +73,11 @@ 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
@config.expect :treat_inlines, :exclude
@cmock_generator_strict = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator_strict.module_name = @module_name
@cmock_generator_strict.module_ext = '.h'
@cmock_generator_strict.mock_name = "Mock#{@module_name}"
@cmock_generator_strict.clean_mock_name = "Mock#{@module_name}"
end
@@ -79,18 +85,19 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
after do
end
it "create the top of a header file with optional include files from config and include file from plugin" do
def helper_create_header_top_with_opt_incldues_form_config_and_plugin(ext)
@config.expect :mock_prefix, "Mock"
@config.expect :mock_suffix, ""
@config.expect :weak, ""
orig_filename = "PoutPoutFish.h"
@cmock_generator.module_ext = ext
orig_filename = "PoutPoutFish#{ext}"
define_name = "MOCKPOUTPOUTFISH_H"
mock_name = "MockPoutPoutFish"
output = []
expected = [
"/* AUTOGENERATED FILE. DO NOT EDIT. */\n",
"#ifndef _#{define_name}\n",
"#define _#{define_name}\n\n",
"#include \"unity.h\"\n",
"#include \"ConfigRequiredHeader1.h\"\n",
"#include \"ConfigRequiredHeader2.h\"\n",
"#include \"#{orig_filename}\"\n",
@@ -98,6 +105,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",
@@ -110,11 +120,17 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :orig_header_include_fmt, "#include \"%s\""
@plugins.expect :run, "#include \"PluginRequiredHeader.h\"\n", [:include_files]
@cmock_generator.create_mock_header_header(output, "MockPoutPoutFish.h")
@cmock_generator.create_mock_header_header(output, "Mock#{orig_filename}")
assert_equal(expected, output)
end
it "create the top of a header file with optional include files from config and include file from plugin" do
['.h','.hh','.hpp'].each do |ext|
helper_create_header_top_with_opt_incldues_form_config_and_plugin(ext)
end
end
it "handle dashes and spaces in the module name" do
#no strict handling
@config.expect :mock_prefix, "Mock"
@@ -127,8 +143,11 @@ 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
@config.expect :treat_inlines, :exclude
@cmock_generator2 = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator2.module_name = "Pout-Pout Fish"
@cmock_generator2.module_ext = '.h'
@cmock_generator2.mock_name = "MockPout-Pout Fish"
@cmock_generator2.clean_mock_name = "MockPout_Pout_Fish"
@@ -137,12 +156,12 @@ 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",
"#ifndef _#{define_name}\n",
"#define _#{define_name}\n\n",
"#include \"unity.h\"\n",
"#include \"ConfigRequiredHeader1.h\"\n",
"#include \"ConfigRequiredHeader2.h\"\n",
"#include \"#{orig_filename}\"\n",
@@ -150,6 +169,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,18 +195,21 @@ 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",
"#ifndef _#{define_name}\n",
"#define _#{define_name}\n\n",
"#include \"unity.h\"\n",
"#include \"ConfigRequiredHeader1.h\"\n",
"#include \"ConfigRequiredHeader2.h\"\n",
"#include \"#{orig_filename}\"\n",
"\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,12 +233,12 @@ 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",
"#ifndef _#{define_name}\n",
"#define _#{define_name}\n\n",
"#include \"unity.h\"\n",
"#include \"ConfigRequiredHeader1.h\"\n",
"#include \"ConfigRequiredHeader2.h\"\n",
"#include \"#{orig_filename}\"\n",
@@ -221,6 +246,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 +300,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)
@@ -289,7 +325,6 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"#include <string.h>\n",
"#include <stdlib.h>\n",
"#include <setjmp.h>\n",
"#include \"unity.h\"\n",
"#include \"cmock.h\"\n",
"#include \"MockPoutPoutFish.h\"\n",
"\n",
@@ -390,8 +425,11 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
output = []
expected = [ "void MockPoutPoutFish_Verify(void)\n{\n",
" UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n",
" CMOCK_MEM_INDEX_TYPE call_instance;\n",
" call_instance = Mock.First_CallInstance;\n" +
" Uno_First" +
" Dos_First" +
" call_instance = Mock.Second_CallInstance;\n" +
" Uno_Second" +
" Dos_Second",
"}\n\n"
@@ -459,6 +497,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
:args => ["uint32 sandwiches", "const char* named"],
:var_arg => nil,
:name => "SupaFunction",
:unscoped_name => "SupaFunction",
:namespace => [],
:class => nil,
:attributes => "__inline"
}
output = []
@@ -494,6 +535,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
:args => ["uint32 sandwiches"],
:var_arg => "corn ...",
:name => "SupaFunction",
:unscoped_name => "SupaFunction",
:namespace => [],
:class => nil,
:attributes => nil
}
output = []
@@ -520,4 +564,123 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
assert_equal(expected.join, output.join)
end
it "create mock implementation function in source file for C++ static member" do
function = { :modifier => "static",
:return => test_return[:int],
:args_string => "uint32 sandwiches, const char* named",
:args => ["uint32 sandwiches", "const char* named"],
:var_arg => nil,
:unscoped_name => "SupaFunction",
:namespace => ["ns1", "ns2"],
:class => "SupaClass",
:name => "ns1_ns2_SupaClass_SupaFunction",
:attributes => nil
}
output = []
expected = [ "namespace ns1 {\n",
"namespace ns2 {\n",
"static int SupaClass::SupaFunction(uint32 sandwiches, const char* named)\n",
"{\n",
" UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n",
" CMOCK_ns1_ns2_SupaClass_SupaFunction_CALL_INSTANCE* cmock_call_instance;\n",
" UNITY_SET_DETAIL(CMockString_ns1_ns2_SupaClass_SupaFunction);\n",
" cmock_call_instance = (CMOCK_ns1_ns2_SupaClass_SupaFunction_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.ns1_ns2_SupaClass_SupaFunction_CallInstance);\n",
" Mock.ns1_ns2_SupaClass_SupaFunction_CallInstance = CMock_Guts_MemNext(Mock.ns1_ns2_SupaClass_SupaFunction_CallInstance);\n",
" uno",
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n",
" cmock_line = cmock_call_instance->LineNumber;\n",
" dos",
" tres",
" UNITY_CLR_DETAILS();\n",
" return cmock_call_instance->ReturnVal;\n",
"}\n",
"}\n",
"}\n\n",
]
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
@cmock_generator.create_mock_implementation(output, function)
assert_equal(expected.join, output.join)
end
it "create mock implementation functions in source file with different options for C++ static member" do
function = { :modifier => "static",
:c_calling_convention => "__stdcall",
:return => test_return[:int],
:args_string => "uint32 sandwiches",
:args => ["uint32 sandwiches"],
:var_arg => "corn ...",
:name => "SupaClass_SupaFunction",
:unscoped_name => "SupaFunction",
:namespace => [],
:class => "SupaClass",
:attributes => nil
}
output = []
expected = [ "static int __stdcall SupaClass::SupaFunction(uint32 sandwiches, corn ...)\n",
"{\n",
" UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n",
" CMOCK_SupaClass_SupaFunction_CALL_INSTANCE* cmock_call_instance;\n",
" UNITY_SET_DETAIL(CMockString_SupaClass_SupaFunction);\n",
" cmock_call_instance = (CMOCK_SupaClass_SupaFunction_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.SupaClass_SupaFunction_CallInstance);\n",
" Mock.SupaClass_SupaFunction_CallInstance = CMock_Guts_MemNext(Mock.SupaClass_SupaFunction_CallInstance);\n",
" uno",
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n",
" cmock_line = cmock_call_instance->LineNumber;\n",
" dos",
" tres",
" UNITY_CLR_DETAILS();\n",
" return cmock_call_instance->ReturnVal;\n",
"}\n\n"
]
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
@cmock_generator.create_mock_implementation(output, function)
assert_equal(expected.join, output.join)
end
it "creates using statements for C++ static member in namespace" do
function = { :modifier => "static",
:return => test_return[:int],
:args_string => "uint32 sandwiches",
:args => ["uint32 sandwiches"],
:var_arg => nil,
:unscoped_name => "SupaFunction",
:namespace => ["ns1"],
:class => "SupaClass",
:name => "ns1_SupaClass_SupaFunction",
:attributes => nil
}
output = []
expected = "using namespace ns1;\n"
@cmock_generator.create_using_statement(output, function)
assert_equal(expected, output.join)
end
it "creates using statements for C++ static member in nested namespace" do
function = { :modifier => "static",
:return => test_return[:int],
:args_string => "uint32 sandwiches",
:args => ["uint32 sandwiches"],
:var_arg => nil,
:unscoped_name => "SupaFunction",
:namespace => ["ns1", "ns2"],
:class => "SupaClass",
:name => "ns1_ns2_SupaClass_SupaFunction",
:attributes => nil
}
output = []
expected = "using namespace ns1::ns2;\n"
@cmock_generator.create_using_statement(output, function)
assert_equal(expected, output.join)
end
end
+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 }
@@ -32,7 +32,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
it "add to instance structure" do
function = {:name => "Oak", :args => [:type => "int*", :name => "blah", :ptr? => true], :return => test_return[:int_ptr]}
expected = " CMOCK_Oak_CALLBACK Oak_CallbackFunctionPointer;\n" +
expected = " char Oak_CallbackBool;\n" +
" CMOCK_Oak_CALLBACK Oak_CallbackFunctionPointer;\n" +
" int Oak_CallbackCalls;\n"
returned = @cmock_generator_plugin_callback.instance_structure(function)
assert_equal(expected, returned)
@@ -41,7 +42,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
it "add mock function declaration for function without arguments" do
function = {:name => "Maple", :args_string => "void", :args => [], :return => test_return[:void]}
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int cmock_num_calls);\n",
"void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
"#define Maple_StubWithCallback Maple_Stub\n" ].join
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
assert_equal(expected, returned)
end
@@ -49,7 +52,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
it "add mock function declaration for function without arguments when count is also turned off" do
function = {:name => "Maple", :args_string => "void", :args => [], :return => test_return[:void]}
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(void);\n",
"void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
"#define Maple_StubWithCallback Maple_Stub\n" ].join
@cmock_generator_plugin_callback.include_count = false
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
assert_equal(expected, returned)
@@ -58,7 +63,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
it "add mock function declaration for function with arguments" do
function = {:name => "Maple", :args_string => "int* tofu", :args => [1], :return => test_return[:void]}
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n",
"void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
"#define Maple_StubWithCallback Maple_Stub\n" ].join
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
assert_equal(expected, returned)
end
@@ -66,7 +73,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
it "add mock function declaration for function with return values" do
function = {:name => "Maple", :args_string => "int* tofu", :args => [1], :return => test_return[:string]}
expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n",
"void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
"#define Maple_StubWithCallback Maple_Stub\n" ].join
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
assert_equal(expected, returned)
end
@@ -74,7 +83,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
it "add mock function declaration for function with return values and count is turned off" do
function = {:name => "Maple", :args_string => "int* tofu", :args => [1], :return => test_return[:string]}
expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu);\n",
"void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
"#define Maple_StubWithCallback Maple_Stub\n" ].join
@cmock_generator_plugin_callback.include_count = false
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
assert_equal(expected, returned)
@@ -87,7 +98,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
" Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation(function)
assert_equal(expected, returned)
end
@@ -99,7 +110,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
" }\n"
].join
@cmock_generator_plugin_callback.include_count = false
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation(function)
assert_equal(expected, returned)
end
@@ -110,7 +121,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
" cmock_call_instance->ReturnVal = Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation(function)
assert_equal(expected, returned)
end
@@ -125,7 +136,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
" Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation(function)
assert_equal(expected, returned)
end
@@ -141,7 +152,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
" }\n"
].join
@cmock_generator_plugin_callback.include_count = false
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation(function)
assert_equal(expected, returned)
end
@@ -156,31 +167,36 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
" cmock_call_instance->ReturnVal = Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation(function)
assert_equal(expected, returned)
end
it "add mock function implementation for functions without arg check and of style 'void func(void)' when count turned off" do
function = {:name => "Apple", :args => [], :args_string => "void", :return => test_return[:void]}
expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n",
expected = [" if (!Mock.Apple_CallbackBool &&\n",
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
" {\n",
" Mock.Apple_CallbackFunctionPointer();\n",
" UNITY_CLR_DETAILS();\n",
" return;\n",
" }\n"
].join
@cmock_generator_plugin_callback.include_count = false
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
it "add mock function implementation for functions without arg check and of style 'int func(void)'" do
function = {:name => "Apple", :args => [], :args_string => "void", :return => test_return[:int]}
expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n",
expected = [" if (!Mock.Apple_CallbackBool &&\n",
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
" {\n",
" return Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n",
" int cmock_cb_ret = Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n",
" UNITY_CLR_DETAILS();\n",
" return cmock_cb_ret;\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
@@ -190,13 +206,15 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
{ :type => 'uint8_t', :name => 'flag', :ptr? => false} ],
:args_string => "int* steak, uint8_t flag",
:return=> test_return[:void]}
expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n",
expected = [" if (!Mock.Apple_CallbackBool &&\n",
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
" {\n",
" Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
" UNITY_CLR_DETAILS();\n",
" return;\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
@@ -206,14 +224,16 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
{ :type => 'uint8_t', :name => 'flag', :ptr? => false} ],
:args_string => "int* steak, uint8_t flag",
:return=> test_return[:void]}
expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n",
expected = [" if (!Mock.Apple_CallbackBool &&\n",
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
" {\n",
" Mock.Apple_CallbackFunctionPointer(steak, flag);\n",
" UNITY_CLR_DETAILS();\n",
" return;\n",
" }\n"
].join
@cmock_generator_plugin_callback.include_count = false
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
@@ -223,12 +243,15 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
{ :type => 'uint8_t', :name => 'flag', :ptr? => false} ],
:args_string => "int* steak, uint8_t flag",
:return => test_return[:int]}
expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n",
expected = [" if (!Mock.Apple_CallbackBool &&\n",
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
" {\n",
" return Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
" int cmock_cb_ret = Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
" UNITY_CLR_DETAILS();\n",
" return cmock_cb_ret;\n",
" }\n"
].join
returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function)
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
@@ -239,21 +262,20 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
:return => test_return[:int]
}
expected = ["void Lemon_StubWithCallback(CMOCK_Lemon_CALLBACK Callback)\n",
expected = ["void Lemon_AddCallback(CMOCK_Lemon_CALLBACK Callback)\n",
"{\n",
" Mock.Lemon_IgnoreBool = (int)0;\n",
" Mock.Lemon_IgnoreBool = (char)0;\n",
" Mock.Lemon_CallbackBool = (char)1;\n",
" Mock.Lemon_CallbackFunctionPointer = Callback;\n",
"}\n\n",
"void Lemon_Stub(CMOCK_Lemon_CALLBACK Callback)\n",
"{\n",
" Mock.Lemon_IgnoreBool = (char)0;\n",
" Mock.Lemon_CallbackBool = (char)0;\n",
" Mock.Lemon_CallbackFunctionPointer = Callback;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_callback.mock_interfaces(function)
assert_equal(expected, returned)
end
it "add mock destroy for functions" do
function = {:name => "Peach", :args => [], :return => test_return[:void] }
expected = " Mock.Peach_CallbackFunctionPointer = NULL;\n" +
" Mock.Peach_CallbackCalls = 0;\n"
returned = @cmock_generator_plugin_callback.mock_destroy(function)
assert_equal(expected, returned)
end
end
@@ -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
@@ -119,7 +119,6 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
"{\n",
"mock_retval_0 ",
"mock_retval_1 ",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_expect.mock_interfaces(function)
@@ -136,7 +135,6 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
"mock_retval_0 ",
"mock_retval_1 ",
"mock_retval_2",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_expect.mock_interfaces(function)
@@ -153,7 +151,6 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
"mock_retval_0 ",
"mock_retval_1 ",
"mock_retval_2",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_expect.mock_interfaces(function)
@@ -168,7 +165,6 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
"{\n",
"mock_retval_0 ",
"mock_retval_1 ",
" UNITY_CLR_DETAILS();\n",
"}\n\n"
].join
@cmock_generator_plugin_expect.ordered = true
@@ -178,8 +174,11 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
it "add mock verify lines" do
function = {:name => "Banana" }
expected = " UNITY_SET_DETAIL(CMockString_Banana);\n" +
" UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.Banana_CallInstance, cmock_line, CMockStringCalledLess);\n"
expected = " if (CMOCK_GUTS_NONE != call_instance)\n" \
" {\n" \
" UNITY_SET_DETAIL(CMockString_Banana);\n" \
" UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess);\n" \
" }\n"
returned = @cmock_generator_plugin_expect.mock_verify(function)
assert_equal(expected, returned)
end
@@ -26,15 +26,22 @@ describe CMockGeneratorPluginExpectAnyArgs, "Verify CMockGeneratorPluginExpectAn
assert(!@cmock_generator_plugin_expect_any_args.respond_to?(:include_files))
end
it "ignore functions without arguments" do
function = {:name => "Mold", :args_string => "void", :args => [], :return => test_return[:void]}
expected = ""
returned = @cmock_generator_plugin_expect_any_args.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions without return values" do
function = {:name => "Mold", :args_string => "void", :return => test_return[:void]}
function = {:name => "Mold", :args_string => "int meh", :args => [ :stuff ], :return => test_return[:void]}
expected = "#define Mold_ExpectAnyArgs() Mold_CMockExpectAnyArgs(__LINE__)\nvoid Mold_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
returned = @cmock_generator_plugin_expect_any_args.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions that returns something" do
function = {:name => "Fungus", :args_string => "void", :return => test_return[:string]}
function = {:name => "Fungus", :args_string => "int meh", :args => [ :stuff ], :return => test_return[:string]}
expected = "#define Fungus_ExpectAnyArgsAndReturn(cmock_retval) Fungus_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n"+
"void Fungus_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, const char* cmock_to_return);\n"
returned = @cmock_generator_plugin_expect_any_args.mock_function_declarations(function)
@@ -46,11 +53,11 @@ describe CMockGeneratorPluginExpectAnyArgs, "Verify CMockGeneratorPluginExpectAn
end
it "add a new mock interface for ignoring when function had no return value" do
function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:void]}
function = {:name => "Slime", :args_string => "int meh", :args => [ :stuff ], :return => test_return[:void]}
expected = ["void Slime_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n",
"{\n",
"mock_return_1",
" cmock_call_instance->IgnoreMode = CMOCK_ARG_NONE;\n",
" cmock_call_instance->ExpectAnyArgsBool = (char)1;\n",
"}\n\n"
].join
@utils.expect :code_add_base_expectation, "mock_return_1", ["Slime", 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
@@ -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]]
expected = " if (cmock_call_instance->IgnoreMode != CMOCK_ARG_NONE)\n" +
@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->ExpectAnyArgsBool)\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,8 +117,8 @@ 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]]
expected = " if (cmock_call_instance->IgnoreMode != CMOCK_ARG_NONE)\n" +
@utils.expect :code_verify_an_arg_expectation, "mocked_retval_0\n", [function, function[:args][0]]
expected = " if (!cmock_call_instance->ExpectAnyArgsBool)\n" +
" {\n" +
"mocked_retval_0\n" +
" }\n"
@@ -128,13 +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 ",
" UNITY_CLR_DETAILS();\n",
"mock_retval_0\n",
"mock_retval_1\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_expect.mock_interfaces(function)
@@ -143,15 +143,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",
" UNITY_CLR_DETAILS();\n",
"mock_retval_0\n",
"mock_retval_1\n",
"mock_retval_2\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_expect.mock_interfaces(function)
@@ -160,15 +159,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",
" UNITY_CLR_DETAILS();\n",
"mock_retval_0\n",
"mock_retval_1\n",
"mock_retval_2\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_expect.mock_interfaces(function)
@@ -177,13 +175,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 ",
" UNITY_CLR_DETAILS();\n",
"mock_retval_0\n",
"mock_retval_1\n",
"}\n\n"
].join
@cmock_generator_plugin_expect.ordered = true
@@ -193,10 +190,12 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
it "add mock verify lines" do
function = {:name => "Banana" }
expected = " UNITY_SET_DETAIL(CMockString_Banana);\n" +
" UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.Banana_CallInstance, cmock_line, CMockStringCalledLess);\n"
expected = " if (CMOCK_GUTS_NONE != call_instance)\n" \
" {\n" \
" UNITY_SET_DETAIL(CMockString_Banana);\n" \
" UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess);\n" \
" }\n"
returned = @cmock_generator_plugin_expect.mock_verify(function)
assert_equal(expected, returned)
end
end
@@ -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*",
@@ -54,9 +54,9 @@ describe CMockGeneratorPluginIgnoreArg, "Verify CMockGeneratorPluginIgnoreArg Mo
end
it "add to tyepdef structure mock needs of functions of style 'void func(int chicken, int* pork)'" do
expected = " int IgnoreArg_chicken;\n" +
" int IgnoreArg_beef;\n" +
" int IgnoreArg_tofu;\n"
expected = " char IgnoreArg_chicken;\n" +
" char IgnoreArg_beef;\n" +
" char IgnoreArg_tofu;\n"
returned = @cmock_generator_plugin_ignore_arg.instance_typedefs(@complex_func)
assert_equal(expected, returned)
end
@@ -0,0 +1,116 @@
# ==========================================
# 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 File.expand_path(File.dirname(__FILE__)) + "/../test_helper"
require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_plugin_ignore_stateless'
describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnoreStateless Module" do
before do
create_mocks :config, :utils
@config = create_stub(:respond_to? => true)
@cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils)
end
after do
end
it "have set up internal priority" do
assert_equal(2, @cmock_generator_plugin_ignore_stateless.priority)
end
it "not have any additional include file requirements" do
assert(!@cmock_generator_plugin_ignore_stateless.respond_to?(:include_files))
end
it "add a required variable to the instance structure" do
function = {:name => "Grass", :args => [], :return => test_return[:void]}
expected = " char Grass_IgnoreBool;\n"
returned = @cmock_generator_plugin_ignore_stateless.instance_structure(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions without return values" do
function = {:name => "Mold", :args_string => "void", :return => test_return[:void]}
expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n" +
"#define Mold_StopIgnore() Mold_CMockStopIgnore()\nvoid Mold_CMockStopIgnore(void);\n"
returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions that returns something" do
function = {:name => "Fungus", :args_string => "void", :return => test_return[:string]}
expected = "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(cmock_retval)\n"+
"void Fungus_CMockIgnoreAndReturn(const char* cmock_to_return);\n" +
"#define Fungus_StopIgnore() Fungus_CMockStopIgnore()\n"+
"void Fungus_CMockStopIgnore(void);\n"
returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "add required code to implementation precheck with void function" do
function = {:name => "Mold", :args_string => "void", :return => test_return[:void]}
expected = [" if (Mock.Mold_IgnoreBool)\n",
" {\n",
" UNITY_CLR_DETAILS();\n",
" return;\n",
" }\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
it "add required code to implementation precheck with return functions" do
function = {:name => "Fungus", :args_string => "void", :return => test_return[:int]}
retval = test_return[:int].merge({ :name => "cmock_call_instance->ReturnVal"})
@utils.expect :code_assign_argument_quickly, ' mock_retval_0', ["Mock.Fungus_FinalReturn", retval]
expected = [" if (Mock.Fungus_IgnoreBool)\n",
" {\n",
" UNITY_CLR_DETAILS();\n",
" if (cmock_call_instance == NULL)\n",
" return Mock.Fungus_FinalReturn;\n",
" mock_retval_0",
" return cmock_call_instance->ReturnVal;\n",
" }\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
it "add a new mock interface for ignoring when function had no return value" do
function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:void]}
expected = ["void Slime_CMockIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)1;\n",
"}\n\n",
"void Slime_CMockStopIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)0;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function)
assert_equal(expected, returned)
end
it "add a new mock interface for ignoring when function has return value" do
function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:int]}
@utils.expect :code_add_base_expectation, "mock_return_1", ["Slime", false]
expected = ["void Slime_CMockIgnoreAndReturn(int cmock_to_return)\n",
"{\n",
" Mock.Slime_CallInstance = CMOCK_GUTS_NONE;\n",
" Mock.Slime_FinalReturn = cmock_to_return;\n",
" Mock.Slime_IgnoreBool = (char)1;\n",
"}\n\n",
"void Slime_CMockStopIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)0;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function)
assert_equal(expected, returned)
end
end
@@ -28,14 +28,15 @@ describe CMockGeneratorPluginIgnore, "Verify CMockGeneratorPluginIgnore Module"
it "add a required variable to the instance structure" do
function = {:name => "Grass", :args => [], :return => test_return[:void]}
expected = " int Grass_IgnoreBool;\n"
expected = " char Grass_IgnoreBool;\n"
returned = @cmock_generator_plugin_ignore.instance_structure(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions without return values" do
function = {:name => "Mold", :args_string => "void", :return => test_return[:void]}
expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n"
expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n" +
"#define Mold_StopIgnore() Mold_CMockStopIgnore()\nvoid Mold_CMockStopIgnore(void);\n"
returned = @cmock_generator_plugin_ignore.mock_function_declarations(function)
assert_equal(expected, returned)
end
@@ -43,7 +44,9 @@ describe CMockGeneratorPluginIgnore, "Verify CMockGeneratorPluginIgnore Module"
it "handle function declarations for functions that returns something" do
function = {:name => "Fungus", :args_string => "void", :return => test_return[:string]}
expected = "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n"+
"void Fungus_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, const char* cmock_to_return);\n"
"void Fungus_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, const char* cmock_to_return);\n" +
"#define Fungus_StopIgnore() Fungus_CMockStopIgnore()\n"+
"void Fungus_CMockStopIgnore(void);\n"
returned = @cmock_generator_plugin_ignore.mock_function_declarations(function)
assert_equal(expected, returned)
end
@@ -81,7 +84,12 @@ describe CMockGeneratorPluginIgnore, "Verify CMockGeneratorPluginIgnore Module"
function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:void]}
expected = ["void Slime_CMockIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (int)1;\n",
" Mock.Slime_IgnoreBool = (char)1;\n",
"}\n\n",
"void Slime_CMockStopIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)0;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_ignore.mock_interfaces(function)
@@ -95,7 +103,13 @@ describe CMockGeneratorPluginIgnore, "Verify CMockGeneratorPluginIgnore Module"
"{\n",
"mock_return_1",
" cmock_call_instance->ReturnVal = cmock_to_return;\n",
" Mock.Slime_IgnoreBool = (int)1;\n",
" Mock.Slime_IgnoreBool = (char)1;\n",
"}\n\n",
"void Slime_CMockStopIgnore(void)\n{\n",
" if(Mock.Slime_IgnoreBool)\n",
" Mock.Slime_CallInstance = CMock_Guts_MemNext(Mock.Slime_CallInstance);\n",
" Mock.Slime_IgnoreBool = (char)0;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_ignore.mock_interfaces(function)
@@ -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
@@ -71,9 +71,9 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
it "add to tyepdef structure mock needs of functions of style 'void func(int chicken, int* pork)'" do
complex_func_expect()
expected = " int ReturnThruPtr_tofu_Used;\n" +
expected = " char ReturnThruPtr_tofu_Used;\n" +
" int* ReturnThruPtr_tofu_Val;\n" +
" int ReturnThruPtr_tofu_Size;\n"
" size_t ReturnThruPtr_tofu_Size;\n"
returned = @cmock_generator_plugin_return_thru_ptr.instance_typedefs(@complex_func)
assert_equal(expected, returned)
end
@@ -89,12 +89,12 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
expected =
"#define Pine_ReturnThruPtr_tofu(tofu)" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, sizeof(*tofu))\n" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, sizeof(int))\n" +
"#define Pine_ReturnArrayThruPtr_tofu(tofu, cmock_len)" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, (int)(cmock_len * (int)sizeof(*tofu)))\n" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, cmock_len * sizeof(*tofu))\n" +
"#define Pine_ReturnMemThruPtr_tofu(tofu, cmock_size)" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, cmock_size)\n" +
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, int cmock_size);\n"
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, size_t cmock_size);\n"
returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@complex_func)
assert_equal(expected, returned)
@@ -104,7 +104,7 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
complex_func_expect();
expected =
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, int cmock_size)\n" +
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, size_t cmock_size)\n" +
"{\n" +
" CMOCK_Pine_CALL_INSTANCE* cmock_call_instance = " +
"(CMOCK_Pine_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.Pine_CallInstance));\n" +
@@ -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
+50 -24
View File
@@ -20,18 +20,20 @@ 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 :plugins, []
@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
@config.expect :enforce_strict_ordering, true
@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 :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 :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@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
@@ -73,7 +75,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" +
" memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" +
" Mock.Apple_CallInstance = CMock_Guts_MemChain(Mock.Apple_CallInstance, cmock_guts_index);\n" +
" Mock.Apple_IgnoreBool = (int)0;\n" +
" Mock.Apple_IgnoreBool = (char)0;\n" +
" cmock_call_instance->LineNumber = cmock_line;\n" +
" cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" +
" cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n"
@@ -88,7 +90,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" +
" memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" +
" Mock.Apple_CallInstance = CMock_Guts_MemChain(Mock.Apple_CallInstance, cmock_guts_index);\n" +
" Mock.Apple_IgnoreBool = (int)0;\n" +
" Mock.Apple_IgnoreBool = (char)0;\n" +
" cmock_call_instance->LineNumber = cmock_line;\n" +
" cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n"
output = @cmock_generator_utils_complex.code_add_base_expectation("Apple", false)
@@ -99,14 +101,15 @@ 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"
arg4 = { :name => "Lime", :const? => false, :type => 'LIME_T', :ptr? => false }
expected4 = " memcpy(&cmock_call_instance->Expected_Lime, &Lime, sizeof(LIME_T));\n"
expected4 = " memcpy((void*)(&cmock_call_instance->Expected_Lime), (void*)(&Lime),\n" +
" sizeof(LIME_T[sizeof(Lime) == sizeof(LIME_T) ? 1 : -1])); /* add LIME_T to :treat_as_array if this causes an error */\n"
assert_equal(expected1, @cmock_generator_utils_simple.code_add_an_arg_expectation(arg1))
assert_equal(expected2, @cmock_generator_utils_simple.code_add_an_arg_expectation(arg2))
@@ -119,8 +122,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"
@@ -131,7 +134,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
" cmock_call_instance->ReturnThruPtr_Kiwi_Used = 0;\n"
arg4 = { :name => "Lime", :const? => false, :type => 'LIME_T', :ptr? => false }
expected4 = " memcpy(&cmock_call_instance->Expected_Lime, &Lime, sizeof(LIME_T));\n" +
expected4 = " memcpy((void*)(&cmock_call_instance->Expected_Lime), (void*)(&Lime),\n" +
" sizeof(LIME_T[sizeof(Lime) == sizeof(LIME_T) ? 1 : -1])); /* add LIME_T to :treat_as_array if this causes an error */\n" +
" cmock_call_instance->IgnoreArg_Lime = 0;\n"
assert_equal(expected1, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg1))
@@ -151,10 +155,12 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
:args_string => "stuff",
:args => [test_arg[:int_ptr], test_arg[:mytype], test_arg[:string]]
}
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" +
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff);\n" +
"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" +
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType),\n" +
" sizeof(MY_TYPE[sizeof(MyMyType) == sizeof(MY_TYPE) ? 1 : -1])); /* add MY_TYPE to :treat_as_array if this causes an error */\n" +
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
"}\n\n"
assert_equal(expected, @cmock_generator_utils_simple.code_add_argument_loader(function))
end
@@ -164,19 +170,39 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
:args_string => "stuff",
:args => [test_arg[:int_ptr], test_arg[:mytype], test_arg[:string]]
}
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* MyIntPtr, int MyIntPtr_Depth, const MY_TYPE MyMyType, const char* MyStr)\n{\n" +
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* MyIntPtr, int MyIntPtr_Depth, const MY_TYPE MyMyType, const char* MyStr);\n" +
"void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* MyIntPtr, int MyIntPtr_Depth, const MY_TYPE MyMyType, const char* MyStr)\n{\n" +
" cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" +
" cmock_call_instance->Expected_MyIntPtr_Depth = MyIntPtr_Depth;\n" +
" cmock_call_instance->IgnoreArg_MyIntPtr = 0;\n" +
" cmock_call_instance->ReturnThruPtr_MyIntPtr_Used = 0;\n" +
" memcpy(&cmock_call_instance->Expected_MyMyType, &MyMyType, sizeof(MY_TYPE));\n" +
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType),\n" +
" sizeof(MY_TYPE[sizeof(MyMyType) == sizeof(MY_TYPE) ? 1 : -1])); /* add MY_TYPE to :treat_as_array if this causes an error */\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" +
"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 +257,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 +337,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
File diff suppressed because it is too large Load Diff
+10 -1
View File
@@ -21,8 +21,17 @@ describe CMockPluginManager, "Verify CMockPluginManager Module" do
:ignore => :args_and_calls
)
eval "class << @config\ndef plugins\n@plugins||[]\nend\ndef plugins=(val)\n@plugins=val\nend\nend\n"
def @config.plugins
if instance_variable_defined?(:@plugins)
@plugins || []
else
[]
end
end
def @config.plugins=(val)
@plugins = val
end
end
after do
+1 -1