Ceedling Trouble With Ignoring Inline Functions

116 views
Skip to first unread message

Soup Son

unread,
Mar 20, 2024, 1:30:18 PM3/20/24
to ThrowTheSwitch Forums
Hey There,

Ceedling is a really cool test framework, and we're trying to get started with it. Unfortunately, our particular use-case is causing headaches here and I was hoping someone might be able to advise. It seems like this should be a simple issue to work around, but due to the given constraints I wonder if this falls outside of Ceedling's scope. We're new to Ceedling so were wondering what some experienced devs made of the situation. So here goes:

Due to the nature of our use-case we are working with the following constraints:
- Functions we make should avoid using parameters and return values is possible
- Global variables we use are directly addressed in memory and start life as a uint representing the physical address

What this looks like architecturally is that we have a bunch of <void function()> type functions that use directly addressed global variables to pass data around. A header file containing our addresses and defines is included by everything that needs them, which happens to be almost all of our other files. We were able to get tests working well enough by creating a test header file that replaces the addresses with properly typed pointers. This worked fine up until our most recent refactor. Because our variables are directly addressed in this way, an obnoxious amount of casting has to be done before we can do meaningful work with them, making the readability and maintainability of the code suffer.

To fix this, we decided to make a set of inline functions that are effectively getters and setters for each datatype. These just do the casting for us and clean up the code in the process. They are also naturally included by just about everything else in the codebase. Unfortunately, this wreaked havoc on our Ceedling tests.

The initial problem without any changes is that the those inline function included by the functions under test throw undefined reference errors when linking under Ceedling. The ideal solution, if it exists, is to totally ignore these inline functions in a way which just allows them to run as normal without failing tests. Preferably, this would be done in a way that limits the amount of extra code we'd need to maintain.

Things I've Tried So Far:

- Including the file in different places. The test itself, the test globals file, the project.yaml includes tag. 
    -> No change in the undefined references issue

- Explicitly defining the "exclude" tag for inline functions
    -> No change in the undefined references issue

- Splitting the function declarations and definitions by creating a .c file to go with the header. 
    -> This allowed Ceedling to see the functions, but it would oddly still not find their definitions when declared as inline. If we take inline out of the declaration, it treats them as regular included functions. Tests run, but are failed due to expects.

- Do the above, create a set of stubs that duplicate the functionality of the functions, set these up as callbacks for the function mocks, and then ignore them all
    -> This probably crosses the line in terms of the amount of extra code we'd want to maintain for this relatively small application, but was worth a shot anyways. Again, tests ran but failed due to a lack of expects. Tried putting these calls in different orders so that it might pick up the ignores, but had the same issue.

One of these functions looks like this:
inline void set_extern_uint(unsigned int extern_ptr, unsigned int extern_val)
{
    *(unsigned int*)extern_ptr = extern_val;
}

Any ideas? Am I misunderstanding something fundamental here? Is this something we can't work around with Ceedling?

Micah Bunting

unread,
Mar 21, 2024, 9:36:50 PM3/21/24
to ThrowTheSwitch Forums
In Ceedling, tests are compiled with only the .c file and any .h files it needs, as such the test is not linking to the globals.c, only the globals.h.
there are 3 options.
A) Add #include "mock_globals.h" to the test file, which will generate mocks based on globals.h. This is the preferred method, as you can mock the functions in a way that is most useful for your test.
B) Use a #define instead of a function #define set_extern_uint(extern_ptr, extern_val) {*(unsigned int*)extern_ptr = extern_val; }. This completely bypasses the global.c issue.
C) Add TEST_FILE("global.c") to the test file. This will tell ceedling to compile and link global.c

David Good

unread,
Mar 26, 2024, 9:08:21 AM3/26/24
to throwth...@googlegroups.com
Hi Soup ,

There was some take on another thread about inlines being handled better in the latest version of Ceedling which is not fully released yet .

See this message and the one after it :

Also , forgive me if I haven't followed exactly what you've tried , but another idea is something like this :

#ifdef TEST
#define INLINE
#else
#define INLINE inline
#endif

(TEST is automatically defined in Ceedling) .

Then you define your inline functions as INLINE . That way , when the tests run , they are regular functions which work with the tests , and reguler inline when your code compiles regularly .

Using the above method , you could also just define the functions differently for the test version , etc .

Lastly , you mentioned :

"- Do the above, create a set of stubs that duplicate the functionality of the functions, set these up as callbacks for the function mocks, and then ignore them all
    -> This probably crosses the line in terms of the amount of extra code we'd want to maintain for this relatively small application, but was worth a shot anyways. Again, tests ran but failed due to a lack of expects. Tried putting these calls in different orders so that it might pick up the ignores, but had the same issue."

This is also a very good way around tricky situations , but you wouldn't have expectations of these called functions anymore since they are stubbed (no _Expect or _Ignore at all for these functions). You would instead implement some scheme of using the variables (like with an array or something) and then use regular TEST_ASSERT_EQUAL macros to test actual values .

--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.
To view this discussion on the web visit https://groups.google.com/d/msgid/throwtheswitch/6aa20590-e7d8-4cf1-babd-d80a5c072349n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages