Skip to main content

A minimal mocking utility for C projects.

Project description

🎣 narmock

GitHub Actions PyPI PyPI - Python Version Code style: black

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>]] [-s <size>]

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
  -s <size>       stack size used to forward variadic arguments

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.

Variadic functions

Narmock can mock functions with variadic arguments. The generated code uses the GNU extension for constructing function calls to forward the arguments. If GNU extensions are unavailable the mock will simply ignore the variadic arguments and only forward the fixed arguments.

MOCK(open)->mock_return(1);

ASSERT_EQ(open("a", 0), 1);

open() is variadic because of the optional mode argument.

The functions provided by the GNU extension need to reserve some fixed space on the stack. By default, Narmock uses 512 bytes but you can specify a custom size by using the -s command-line argument when generating the mocks.

$ gcc -E *.c | narmock -g -s 1024

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

narmock-0.2.17.tar.gz (14.2 kB view details)

Uploaded Source

Built Distribution

narmock-0.2.17-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file narmock-0.2.17.tar.gz.

File metadata

  • Download URL: narmock-0.2.17.tar.gz
  • Upload date:
  • Size: 14.2 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

Hashes for narmock-0.2.17.tar.gz
Algorithm Hash digest
SHA256 04422f6cd5b52f7c552db42bdc0199a8479e3fdc9e225cf27d93d99ba1710811
MD5 e8369a858f96eeb3f35d0f93a4e05a4f
BLAKE2b-256 f0798b7da0a3e88c9a29b4a175ad1a2bd8bccdb413aad5dc49286902b5a6baf6

See more details on using hashes here.

File details

Details for the file narmock-0.2.17-py3-none-any.whl.

File metadata

  • Download URL: narmock-0.2.17-py3-none-any.whl
  • Upload date:
  • Size: 13.5 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

Hashes for narmock-0.2.17-py3-none-any.whl
Algorithm Hash digest
SHA256 b77a9a3694d27241ded46ceb3bb9089fca9c0e56fe4791c6c516c0296adc51a4
MD5 0c7bbad9c1d74c67bac5ca3c24430d1d
BLAKE2b-256 31d5c28004d30fb21bffe2008763c4fdca41839740dfabb85d181a7653b3715e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page