Package: narmock
🎣 narmockA 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 withNarwhalbut Narmock can be used with other test frameworks and anywhere in regular source code.InstallationThe package can be installed withpip.$pipinstallnarmockGetting startedThe 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 argumentsCheck out thebasic examplefor a simple Makefile that integrates bothNarwhaland Narmock.Generating mocksThenarmock -gcommand finds the functions mocked in your code and generates a__mocks__.cfile and a__mocks__.hfile that respectively define and declare all the required mocks.$gcc-E*.c|narmock-gNarmock requires source code to be expanded by the preprocessor. You can directly pipe the output ofgcc -Eto the command-line utility.By default,__mocks__.cand__mocks__.hwill be created in the current directory. You can specify a different output directory with the-doption.$gcc-Etests/*.c|narmock-g-dtestsRetrieving linker flagsThenarmock -fcommand reads the generated__mocks__.hfile and outputs the necessary linker flags for linking all your source files together.$gcc$(narmock-f)*.cBy default, the command looks for__mocks__.hin the current directory. You can specify a different directory with the-doption.$gcc$(narmock-f-dtests)tests/*.cMock APITheMOCKmacro returns a pointer to the mock API of a given function.MOCK(time);Mocking the returned valueYou can make a function return a specific value without calling its original implementation.MOCK(time)->mock_return(42);printf("%ld\n",time(NULL));// Outputs 42Mocking the implementationYou can switch the implementation of a function.time_ttime_stub(time_t*timer){return42;}MOCK(time)->mock_implementation(time_stub);printf("%ld\n",time(NULL));// Outputs 42Mocking errnoYou can make a function seterrnoto a specific value.MOCK(malloc)->mock_return(NULL)->mock_errno(ENOMEM);char*ptr=malloc(42);printf("%d\n",errno==ENOMEM);// Outputs 1Disabling the mockYou can disable the mock and make the function call its original implementation.MOCK(time)->disable_mock();printf("%ld\n",time(NULL));// Outputs the current timeCounting and inspecting callsNarmock keeps track of the number of times mocked functions are called.printf("%ld\n",time(NULL));// Outputs the current timeprintf("%ld\n",MOCK(time)->call_count);// Outputs 1You can also inspect the last call of a function. Note that thelast_callpointer isNULLuntil the function gets called for the first time.printf("%ld\n",time(NULL));// Outputs the current timeprintf("%p\n",MOCK(time)->last_call->arg1);// Outputs (nil)printf("%ld\n",MOCK(time)->last_call->return_value);// Outputs the current timeThe value oferrnois captured and saved in theerrsvattribute.fopen("does_not_exist.txt","r");printf("%d\n",MOCK(fopen)->last_call->errsv==ENOENT);// Outputs 1By default, the arguments are accessible through the sequentialarg1,arg2,...,argNattributes. If you want to keep the original name of the arguments for a set of specific functions you can use the-koption 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-kNote that the default regex is.*so here every function would be affected.Variadic functionsNarmock can mock functions with variadic arguments. The generated code uses the GNU extension forconstructing function callsto 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 optionalmodeargument.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-scommand-line argument when generating the mocks.$gcc-E*.c|narmock-g-s1024Resetting everythingYou can reset the mock to its initial state. This will make the function use its original implementation and resetcall_countto0andlast_calltoNULL.MOCK(time)->mock_return(42);printf("%ld\n",time(NULL));// Outputs 42MOCK(time)->reset();printf("%ld\n",MOCK(time)->call_count);// Outputs 0printf("%p\n",MOCK(time)->last_call);// Outputs (nil)printf("%ld\n",time(NULL));// Outputs the current timeYou can also call thenarmock_reset_all_mocksfunction to reset all the mock.narmock_reset_all_mocks();ContributingContributions are welcome. Feel free to open issues and suggest improvements. This project usespoetryso you'll need to install it first if you want to be able to work with the project locally.$curl-sSLhttps://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py|pythonYou should now be able to install the required dependencies.$poetryinstallThe code follows theblackcode style.$poetryrunblacknarmockYou can run the tests withpoetry run make -C tests. The test suite is built withNarwhal.$poetryrunmake-CtestsLicense -MIT