We are now introducing unit tests in our company and thinking about best way of mocking system calls.
Consider the following code
int fd = open(path, O_RDONLY);
if (fd < 0) {
LOG.error() << "cannot load plugin " << path << std::endl;
return ERROR(ERROR_OPENING_PLUGING);
}
// do other stuff
Obviously, we need to mock system call to open
I have found following ways to do so:
Correct - in the terms of design but ugly way. Create interface and impl
class ISystem { public: typedef std::auto_ptr<ISystem> Ptr; ISystem() {}; virtual ~ISystem() {}; virtual int open(const char* file, int path) = 0; }; class System : public ISystem { public: System() {}; virtual ~System() {}; virtual int open(const char* file, int path); static ISystem::Ptr Get(); };
and use it
Common::Error dlopen_signed(ISystem::Ptr& system, const char* path, int flags, void*& ret)
{
int fd = system->open(path, O_RDONLY);
if (fd < 0) {
LOG.error() << "cannot load plugin " << path << std::endl;
return ERROR(ERROR_OPENING_PLUGING);
}
char fd_path[32];
I dont like it because every function will need to have one more argument - ISystem::Ptr& system, that will be the same for all production code.
Also, not sure about speed (this involves extra layers for basic system calls that must be really fast)
2) Use a link seam Linker is designed so that it prefer your versions of functions than system ones.
But this does not work for some system calls, for example open (not sure about the reason), and this solution is a little bit hackish.
3) use --wrap compiler functionality
--wrap symbol Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol. This can be used to provide a wrapper for a system function. The wrapper function should be called __wrap_symbol. If it wishes to call the system function, it should call __real_symbol. Here is a trivial example:
void *
__wrap_malloc (int c)
{
printf ("malloc called with %ld\n", c);
return __real_malloc (c);
}
This solution is nice but does not work for all compilers I guess.
The question is - which one are you using on your projects?