Comments (6)
You've done a great job of documenting the issue. I really appreciate that. I don't have the time at the moment to run your example directly, but I have a guess as to your error, and I have a philosophy of how best to handle these situations.
Philosophy:
The root problem you're running into is a common one: one where headers aren't really "standalone" without depending on other headers for information... this is particularly common in complex API's.
If the API is complex enough, the easiest thing to do is to create your own header files that has just the types and functions that you care about. You can then use that instead of directly calling the original headers. Let's say we made such a header timer_api.h
:
#ifndef TEST
// When we're not testing, just include the original headers
#include "dl_timerg.h"
#include "dl_timer.h"
#else
// we can still include headers to grab types.
// we put function prototypes here to be mocked.
// we can even put function prototypes here for things that are macros in the real API!
#endif
Now, in both your release code and your test code, include timer_api.h
instead of using the individual timer files. It's easily mockable (a win for tests) and it serves as documentation for what parts of the complex API you are actually using (good for maintenance). It also protects you against API changes if those header files are upgraded or settings are changed. If the API changes below, you now potentially have the option to update the abstraction in one place (this wrapper file) instead of everywhere it is called.
The Error Ceedling is Giving You:
It is possible that the error you're seeing is exactly what you've said... a mismatch in what is getting used in two different places. Most often, though, these mismatches will fail to compile or link completely. It's rarely a runtime error.
Is DL_TimerG_isPowerEnabled
a macro that directly passes through to DL_Timer_isPowerEnabled
? If so, I'm not seeing how this could cause a crash. You're pulling in the mock of both headers, so it's going to create a fake version of DL_Timer_isPowerEnabled
... The macro DL_TimerG_isPowerEnabled
remains unchanged, so it will still want to call DL_Timer_isPowerEnabled
. When linked, the DL_Timer_isPowerEnabled
it is connected to is the one that has been mocked, because otherwise there would be a conflict of multiple definitions. Your expectation would be the correct one and everything should pass.
My suspicion would be that DL_Timer_isPowerEnabled
does more than just pass the call along to the next step, and perhaps that's what's failing. I'd be doubly suspicious of anything that uses a pointer (these API's often like to pass around handles, etc). There's a good chance that a handle is being dereferenced or something when it has never been initialized.
In any case, best of luck. I hope this helps.
from ceedling.
Thank you very much for the suggestion!
To answer your question, yes, DL_TimerG_isPowerEnabled
is a macro to DL_Timer_isPowerEnabled
, which is static inline. Is there a way in project.yaml to tell the linker which file to get?
from ceedling.
Ceedling automatically knows which file to use based on your test. You included the mocked header, so it knows to use the mocked C file for the test, not the normal C file. If you included both the mock and unmocked header, it would attempt to pull in both and it would fail.
I think we found the problem, though! DL_Timer_isPowerEnabled
is static inline! So even though you're properly mocking this interface, the func
call has already flattened the static inline to the things it actually does and doesn't believe there is anything to call there (Oh C... you're painful sometimes!).
Are you able to modify either of these files? If not, your only option is the long API explanation I wrote above. If you CAN tweak these files slightly, maybe you want to change inline
to INLINE. Then use this:
#ifdef TEST
#define INLINE
#else
#define INLINE inline
#endif
This will make it so that the function isn't inlined during tests and you can mock it properly.
from ceedling.
Ceedling automatically knows which file to use based on your test. You included the mocked header, so it knows to use the mocked C file for the test, not the normal C file. If you included both the mock and unmocked header, it would attempt to pull in both and it would fail.
I think we found the problem, though!
DL_Timer_isPowerEnabled
is static inline! So even though you're properly mocking this interface, thefunc
call has already flattened the static inline to the things it actually does and doesn't believe there is anything to call there (Oh C... you're painful sometimes!).Are you able to modify either of these files? If not, your only option is the long API explanation I wrote above. If you CAN tweak these files slightly, maybe you want to change
inline
to INLINE. Then use this:#ifdef TEST #define INLINE #else #define INLINE inline #endif
This will make it so that the function isn't inlined during tests and you can mock it properly.
This solution works, but now a new issue has entered: I get some assembler errors, die to the fact that the CMSIS included in the SDK adds some __ASM which is not recognized by the native GCC, so now I have ti find a way to workaround the cmsis_gcc.h. I guess the proper way is to compile with ARM GCC and run unit test directky on chip or a simulated environment (QEMU?). Do you have any suggestion?
from ceedling.
Yes. You can run on QEMU and it'll solve this particular issue. It'll also have the benefit of testing using the same compiler your release uses, etc.
The alternative is still to build an API file as I described above, which avoids the entire CMSIS layer altogether.
Either will work. They have pros and cons and it's really a matter of preference.
from ceedling.
Yes. You can run on QEMU and it'll solve this particular issue. It'll also have the benefit of testing using the same compiler your release uses, etc.
The alternative is still to build an API file as I described above, which avoids the entire CMSIS layer altogether.
Either will work. They have pros and cons and it's really a matter of preference.
Thank you very much!
from ceedling.
Related Issues (20)
- How to add list of source files to every test HOT 3
- unit test an output message written in the console with printf HOT 3
- Can not set environment variables from imported files. HOT 6
- How to read/catch stdout (shell) HOT 1
- Environment variables at flags and define fields HOT 5
- Has anyone tried unity with .elf build output? HOT 1
- gcc flags don't work when using ceedling test:* HOT 12
- How do we get test case line/function coverage in ceedling?
- different test results when running gcov HOT 3
- How do I enable test specific #defines? HOT 1
- issue
- Non-US-ASCII characters stop ceedling's rake in an unhelpful way
- Test report file not created HOT 2
- Stop printing rake abort messages on compilation/linking failure HOT 2
- How does "default_tasks" section work? HOT 2
- Mocking Variable Length Array (VLA) not working
- GcovCoverageResults are generated empty when build_root is outside of the project folder HOT 1
- Allow creation of mocks from the terminal HOT 2
- Unexpected return data of mock function after initialization in setUp function HOT 3
- Ceedling 0.32.0 doesn't support verbosity task HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ceedling.