Correct way to use compare strings in CMock Expect calls

347 views
Skip to first unread message

David Good

unread,
Mar 13, 2022, 3:35:30 PM3/13/22
to throwth...@googlegroups.com
Hi All!

I would like CMock to compare the entire string in _Expect calls, but am not having much luck. For instance:

module_put_str_Expect ("+123");

I know from experience (and the documentation) that only the first byte is being checked here, so if the expectation is called with "-123" it fails, but if it's called with "+124" the expectation passes.

I also know about the Array plugin and that is how I'm currently dealing with these situations.

module_put_str_ExpectWithArray ("+123", 5);

Now, I've read in the documentation why this happens (:when_ptr: :smart as the default), and would like to try changing this behavior, however I'm not having much luck. Setting :when_ptr: :compare_data seems to do nothing.

:cmock:
  :mock_prefix: "mock_"
  :callback_include_count: TRUE
  :when_no_prototypes: :warn
  :enforce_strict_ordering: TRUE
  :when_ptr: :compare_data
  :plugins:
    - :ignore
    - :callback
    - :array
    - :expect_any_args
  :includes:
    - compiler_defs.h

After making this change, I'm running ceedling clobber just in case, but there doesn't seem to be any change in behavior (still single byte comparison).

~/$ ceedling version
   Ceedling:: 0.31.0
      Unity:: 2.5.2
      CMock:: 2.5.3
 CException:: 1.3.3

What am I missing?

Thanks!

--David

Mark Vander Voord

unread,
Mar 14, 2022, 7:35:49 AM3/14/22
to throwth...@googlegroups.com
Hi David:

What type are the "strings" you're referring to? If they're actually a standard C string type, like "char*" or "const char*", they're already treated like strings, not arrays. Strings are a special case in Unity and they ignore the array handling plugin unless you instruct them otherwise.

Can you post the prototype of a function that has this problem?

Very likely, you just need to tell CMock that this type should also be treated as a string. For example, if my prototype looked like this:

void module_put_str(MY_STRING val);

I would add the following to the cmock configuration:

:cmock:
  :treat_as:
    'MY_STRING': 'STRING'



--
You received this message because you are subscribed to the Google Groups "ThrowTheSwitch Forums" group.
To unsubscribe from this group and stop receiving emails from it, send an email to throwtheswitc...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/throwtheswitch/CALMFhSxv7cikAT6BMrwKPhVCfCbUC3v7sUgVSiwNHf%3DPu94AwA%40mail.gmail.com.

David Good

unread,
Mar 14, 2022, 6:01:46 PM3/14/22
to throwth...@googlegroups.com
Hi Mark!

Sorry, just getting back to this.

I'm working with 8051 8-bit microcontrollers, so all of my code uses unsigned chars everywhere. The prototype is:

void fmnetint_put_str (U8 *str);

and U8 is defined differently for various compilers in compiler_defs.h. When using _GNUC_ for ceedling, U8 is defined as:

typedef unsigned char bit;
typedef unsigned char U8;
typedef unsigned short int U16;
typedef unsigned int U32;
typedef signed char S8;
typedef signed short int S16;
typedef signed int S32;

So, I just tried to apply your idea and after some trial and error, got it working by adding the following lines to my :cmock: section:
:cmock:
  :treat_as:
    U8:       UINT8
    U8*:      STRING

Interestingly, I had to add both the U8 line as well as the U8* line. Originally, I tried adding 'unsigned char*': STRING, but that broke several other tests in obviously incorrect ways (turned regular number args into strings somehow). I think I understand how this is working. It's doing literal string substitutions in ruby before letting the c preprocessor run with the result. That explains why the typedefs alone (c preprocessor) didn't have the full effect (ruby didn't know how to properly pre-generate the macros). Right?

Thanks for the help!

--David




Mark Vander Voord

unread,
Mar 15, 2022, 7:10:12 AM3/15/22
to throwth...@googlegroups.com
David:

You are correct. CMock itself doesn't understand anything about preprocessors or compilers. It does its best to parse header files, and the generates corresponding code where it thinks it understood correctly.

CMock doesn't actually do literal string replacements. Instead, the :treat_as gives CMock a clue as to how to work with types it doesn't recognize. If it doesn't recognize a type otherwise, it makes assumptions about it. Most often, the assumption is that it should fall back to a memory comparison of that type, which will usually work.

The end effect is the same, though. It encounters a prototype with a non-standard type like U8*, notices it's not one of the usual suspects, and so first checks to see if you've written a custom handler for it (in a unity_helper file). Not finding one there, it then checks its list of custom types listed in treat_as. If you just included "unsigned char*" in the treat_as list, it'll never find U8*, so it continues to the internal list of treat_as values. It doesn't find it there either, so it uses memory comparisons.

Mark

David Good

unread,
Mar 15, 2022, 11:54:42 AM3/15/22
to throwth...@googlegroups.com
Makes sense! Thanks for the explanation!

The last part to understand is why setting :when_ptr: :compare_data didn't have any effect. Regardless of the type discussion above, shouldn't setting :compare_data have made CMock do more than a single byte comparison? Or is it that CMock still doesn't know how much data to compare, so it falls back to just one byte? But, if that's the case, what use is compare_data at all?

--David

--
You received this message because you are subscribed to the Google Groups "ThrowTheSwitch Forums" group.
To unsubscribe from this group and stop receiving emails from it, send an email to throwtheswitc...@googlegroups.com.

Mark Vander Voord

unread,
Mar 15, 2022, 12:50:15 PM3/15/22
to throwth...@googlegroups.com
The :compare_data option dereferences the pointer and compares a single instance of the thing being pointed at, unless you inform it that it's an array and how far it can test. This is incredibly useful if you have a pointer to a struct or even a pointer to an integer that you want to have CMock automatically check the results for... In your case, you were pointing to an unsigned char, so that's what it checked... a single dereferenced unsigned character. ;)

Mark

David Good

unread,
Mar 15, 2022, 4:04:03 PM3/15/22
to throwth...@googlegroups.com
Now THAT makes sense :) 

Thanks Mark! 

--David

On Tue, Mar 15, 2022, 11:50 Mark Vander Voord <mvande...@gmail.com> wrote:
The :compare_data option dereferences the pointer and compares a single instance of the thing being pointed at, unless you inform it that it's an array and how far it can test. This is incredibly useful if you have a pointer to a struct or even a pointer to an integer that you want to have CMock automatically check the results for... In your case, you were pointing to an unsigned char, so that's what it checked... a single dereferenced unsigned character. ;)

Mark

--
You received this message because you are subscribed to the Google Groups "ThrowTheSwitch Forums" group.
To unsubscribe from this group and stop receiving emails from it, send an email to throwtheswitc...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages