A minimal mocking utility for C projects.
Project description
🎣 narmock
A minimal mocking utility for C projects.
Narmock finds the functions mocked in your tests and generates mocks with a slick API.
#include <time.h>
#include "__mocks__.h"
#include "narwhal.h"
TEST(example)
{
MOCK(time)->mock_return(42);
ASSERT_EQ(time(NULL), 42);
}
This example is a test written with Narwhal but Narmock can be used with other test frameworks and anywhere in regular source code.
Installation
The package can be installed with pip
.
$ pip install narmock
Getting started
The command-line utility provides two essential commands that should make it possible to integrate Narmock in any kind of build system.
usage: narmock [-h] (-g [<code>] | -f) [-d <directory>] [-k [<regex>]]
A minimal mocking utility for C projects.
optional arguments:
-h, --help show this help message and exit
-g [<code>] generate mocks
-f output linker flags
-d <directory> mocks directory
-k [<regex>] keep argument names
Check out the basic example for a simple Makefile that integrates both Narwhal and Narmock.
Generating mocks
The narmock -g
command finds the functions mocked in your code and generates a __mocks__.c
file and a __mocks__.h
file that respectively define and declare all the required mocks.
$ gcc -E *.c | narmock -g
Narmock requires source code to be expanded by the preprocessor. You can directly pipe the output of gcc -E
to the command-line utility.
By default, __mocks__.c
and __mocks__.h
will be created in the current directory. You can specify a different output directory with the -d
option.
$ gcc -E tests/*.c | narmock -g -d tests
Retrieving linker flags
The narmock -f
command reads the generated __mocks__.h
file and outputs the necessary linker flags for linking all your source files together.
$ gcc $(narmock -f) *.c
By default, the command looks for __mocks__.h
in the current directory. You can specify a different directory with the -d
option.
$ gcc $(narmock -f -d tests) tests/*.c
Mock API
The MOCK
macro returns a pointer to the mock API of a given function.
MOCK(time);
Mocking the returned value
You can make a function return a specific value without calling its original implementation.
MOCK(time)->mock_return(42);
printf("%ld\n", time(NULL)); // Outputs 42
Mocking the implementation
You can switch the implementation of a function.
time_t time_stub(time_t *timer)
{
return 42;
}
MOCK(time)->mock_implementation(time_stub);
printf("%ld\n", time(NULL)); // Outputs 42
Mocking errno
You can make a function set errno
to a specific value.
MOCK(malloc)->mock_return(NULL)->mock_errno(ENOMEM);
char *ptr = malloc(42);
printf("%d\n", errno == ENOMEM); // Outputs 1
Disabling the mock
You can disable the mock and make the function call its original implementation.
MOCK(time)->disable_mock();
printf("%ld\n", time(NULL)); // Outputs the current time
Counting and inspecting calls
Narmock keeps track of the number of times mocked functions are called.
printf("%ld\n", time(NULL)); // Outputs the current time
printf("%ld\n", MOCK(time)->call_count); // Outputs 1
You can also inspect the last call of a function. Note that the last_call
pointer is NULL
until the function gets called for the first time.
printf("%ld\n", time(NULL)); // Outputs the current time
printf("%p\n", MOCK(time)->last_call->arg1); // Outputs (nil)
printf("%ld\n", MOCK(time)->last_call->return_value); // Outputs the current time
The value of errno
is captured and saved in the errsv
attribute.
fopen("does_not_exist.txt", "r");
printf("%d\n", MOCK(fopen)->last_call->errsv == ENOENT); // Outputs 1
By default, the arguments are accessible through the sequential arg1
, arg2
, ...
, argN
attributes. If you want to keep the original name of the arguments for a set of specific functions you can use the -k
option when generating the mocks.
$ gcc -E *.c | narmock -g -k "myprefix_.*"
The option takes a regular expression and generates mocks that use the original argument names for all the functions that match the regex.
$ gcc -E *.c | narmock -g -k
Note that the default regex is .*
so here every function would be affected.
Resetting everything
You can reset the mock to its initial state. This will make the function use its original implementation and reset call_count
to 0
and last_call
to NULL
.
MOCK(time)->mock_return(42);
printf("%ld\n", time(NULL)); // Outputs 42
MOCK(time)->reset();
printf("%ld\n", MOCK(time)->call_count); // Outputs 0
printf("%p\n", MOCK(time)->last_call); // Outputs (nil)
printf("%ld\n", time(NULL)); // Outputs the current time
You can also call the narmock_reset_all_mocks
function to reset all the mock.
narmock_reset_all_mocks();
Contributing
Contributions are welcome. Feel free to open issues and suggest improvements. This project uses poetry so you'll need to install it first if you want to be able to work with the project locally.
$ curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
You should now be able to install the required dependencies.
$ poetry install
The code follows the black code style.
$ poetry run black narmock
You can run the tests with poetry run make -C tests
. The test suite is built with Narwhal.
$ poetry run make -C tests
License - MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file narmock-0.2.16.tar.gz
.
File metadata
- Download URL: narmock-0.2.16.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | edbc097ecabea4f0943e513f67375dd2bf135b3e3d564bf045ef8665058d561d |
|
MD5 | 8dd5369b9ffe2becbaf5e70001dff01f |
|
BLAKE2b-256 | 9477ed9778e7a5a6426bd73b5481ce4e5e2936e9eac6be984d5f6cfb9c225dce |
File details
Details for the file narmock-0.2.16-py3-none-any.whl
.
File metadata
- Download URL: narmock-0.2.16-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 93131f506cb206ff2f01ac30df861c6efbccc3f4a3cf6082ea6df4158f283cff |
|
MD5 | b747a719c08b84d4f6468eb1cb0f4105 |
|
BLAKE2b-256 | 5e00dcecd33ec3e051e473e0ef6836d8e98a53a6fa2d393d606af84b7d9f93e4 |