How to integrate CMock unit test framework with Make - c

Is there a way around having to switch my project to use rake as its build system? I have a large project using Make as its build system and would like to add CMock functionality for unit testing (I'm already successfully using Unity), but have found no information about integrating CMock with Makefiles (instead, it seems the world has just accepted using Ruby's rake as their build system if they want CMock to work with their projects).
I have been able to run the CMock example tests, which include a (seemingly unfinished?) 'make' example.
I've modified the test code in the 'make_example' to the following:
#include "mock_foo.h"
#include "unity.h"
void setUp(void) {}
void tearDown(void) {}
void test_main_should_initialize_foo(void) {
foo_init_Ignore();
TEST_IGNORE_MESSAGE("TODO: Implement main!");
}
however, when running 'make' from the folder with the Makefile, it seems UNITY_LINE_TYPE is undefined (e.g. something is missing from my dependency chain):
make
mkdir -p ./build
mkdir -p ./build/obj
ruby ../../scripts/create_makefile.rb --silent
cc -o build/test/obj/test_main.o -c test/test_main.c -DTEST -I ./src -I /home/user/Documents/gitrepos/cmock/vendor/unity/src -I /home/user/Documents/gitrepos/cmock/src -I ./build/test/mocks
In file included from test/test_main.c:1:0:
./build/test/mocks/mock_foo.h:27:27: error: unknown type name ‘UNITY_LINE_TYPE’
void foo_init_CMockExpect(UNITY_LINE_TYPE cmock_line);
^
build/test/MakefileTestSupport:29: recipe for target 'build/test/obj/test_main.o' failed
make: *** [build/test/obj/test_main.o] Error 1
Has anyone successfully implemented a project using Makefiles and CMock?

Turns out I was the victim of some of my own vim/clang-format configuration here.
The make_example (though not very useful out of the box) does compile and run tests properly using CMock's mocking framework if the 'unity.h' import is placed before the 'mock_xxx.h' in your test implementation (which I'm sure is called out in the documentation somewhere).
The following is an example of a working test (slightly modified test_main.c from cmock/examples/make_example):
#include "unity.h"
#include "mock_foo.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_main_should_initialize_foo(void)
{
foo_init_Expect();
foo_init();
}
However, since my vim/clang format was set to 'SortIncludes: true', my includes were reordered to produce:
#include "mock_foo.h" // <---- the mocks must be included *after* unity.h
#include "unity.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_main_should_initialize_foo(void)
{
foo_init_Expect();
foo_init();
}
just as I was :wq in vim.
This, of course, causes CMock problems, as it needs the unity.h definitions figured out before it tries to generate the mock_foo.h, so I was getting the error I posted above:
...
In file included from test/test_main.c:1:0:
./build/test/mocks/mock_foo.h:27:27: error: unknown type name ‘UNITY_LINE_TYPE’
void foo_init_CMockExpect(UNITY_LINE_TYPE cmock_line);
...
My Makefile (untouched from the CMock example), for posterity:
CC ?= gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
TEST_DIR ?= ./test
TEST_BUILD_DIR ?= ${BUILD_DIR}/test
TEST_MAKEFILE = ${TEST_BUILD_DIR}/MakefileTestSupport
OBJ ?= ${BUILD_DIR}/obj
OBJ_DIR = ${OBJ}
default: all
all: setup test ${BUILD_DIR}/main run
setup:
mkdir -p ${BUILD_DIR}
mkdir -p ${OBJ}
ruby ../../scripts/create_makefile.rb --silent
clean:
rm -rf ${BUILD_DIR}
${BUILD_DIR}/main: ${SRC_DIR}/main.c ${SRC_DIR}/foo.c
${CC} $< -o $#
run:
./build/main || true
test: setup
-include ${TEST_MAKEFILE}
I found this was happening by finding that UNITY_LINE_TYPE was defined in unity.h and paid attention to how that unity.h was being included in my test, saw it was included after 'mock_foo.h' (no problem apparant to me yet), then compared to some working rake examples (in ../temp_sensor) where I noticed that all the 'unity.h' includes were before all the 'mock_xxx.h' includes (I hadn't touched these with vim yet.)
Don't let your tools be fools.

This bug has just been fixed: https://github.com/ThrowTheSwitch/CMock/pull/211
Now you do not need to keep specific order of #include directives.

Your mileage may vary, but I've found that grouping my includes with newlines causes clang-format to sort within the groups, thus allowing me to preserve important headers at the beginning. Usually this makes a certain logical sense as well.
So for instance, in my test_xyz.c file:
#include "unity.h"
#include "support/logging.h"
#include "crc.h"
#include "mock_unistd.h"
Gets sorted to:
#include "unity.h"
#include "crc.h"
#include "mock_unistd.h"
#include "support/logging.h"

Related

Set Up Development Environment for Unit Testing C

I'm new to unit testing and have mostly programmed using IDEs, therefore I haven't created and/or modified makefiles before.
Now that I'm exploring Unit Testing and TDD in general; I'm not sure how to set up the development environment so that my unit tests automatically run on every build.
Please help. A general procedure to achieve this would do wonders.
I have not tried anything yet as I'm not very familiar with modifying C Make files.
Here is a simple Makefile I use for small TDD projects using criterion:
CC=gcc
RELEASE_CFLAGS=-ansi -pedantic -Wall -Werror -Wextra
TESTS_CFLAGS=-pedantic -Wall -Werror -Wextra
TESTS_LDFLAGS=-lcriterion
RELEASE_SRC=$(shell find src/ -type f -name '*.c')
RELEASE_OBJ=$(subst src/,obj/,$(RELEASE_SRC:.c=.o))
TESTS_SRC=$(shell find tests/src/ -type f -name '*.c')
TESTS_OBJ=$(subst src/,obj/,$(TESTS_SRC:.c=.o))
TESTS_BIN=$(subst src/,bin/,$(TESTS_SRC:.c=))
default: run-tests
obj/%.o: src/%.c
$(CC) $(RELEASE_CFLAGS) -c $^ -o $#
tests/obj/%.o: tests/src/%.c
$(CC) $(TESTS_CFLAGS) -c $^ -o $#
tests/bin/%: tests/obj/%.o $(RELEASE_OBJ)
$(CC) $(TESTS_LDFLAGS) $^ -o $#
# prevent deleting object in rules chain
$(TESTS_BIN): $(RELEASE_OBJ) $(TESTS_OBJ)
run-tests: $(TESTS_BIN)
./$^ || true
clean:
rm -f $(RELEASE_OBJ) $(TESTS_OBJ)
clean-all: clean
rm -f $(TESTS_BIN)
It compiles production code with C89 (-ansi) and tests code with unspecified standard.
Files in src/ are moved to obj/, same thing for tests/src/ and tests/obj/.
Tests binaries (AKA test suites) depends on every source files and are included in each test binary, making them bigger but it's not a problem for small projects. If binaries size is an issue, you'll have to specify which object to include for each binary.
Directory structure is made with this command:
mkdir -p src obj tests/{src,obj,bin}
An exemple test file:
#include <criterion/criterion.h>
#include "../../src/fibo.h"
Test(fibonacci, first_term_is_0)
{
// given
int term_to_compute = 0;
// when
int result = fibonacci(term_to_compute);
// then
cr_assert_eq(result, 0);
}
Test(fibonacci, second_term_is_1)
{
// given
int term_to_compute = 1;
// when
int result = fibonacci(term_to_compute);
// then
cr_assert_eq(result, 1);
}
And the associated production code:
#include "fibo.h"
unsigned long fibonacci(unsigned int term_to_compute)
{
return term_to_compute;
}
As you can see, production code is quite dumb and it needs more tests, because it only meets specified requirements (unit tests).
EDIT: Check the Make documentation to learn more about syntax, builtin functions, etc.
If you want to learn more about TDD, YouTube has a lot to offer (live codings, explanations, TDD katas): check Robert C Martin (Uncle Bob), Continuous Delivery channel, etc.
PS: returning a long is not the best option here, you could want fixed size integers to have same result on different platforms, but the question was about "how-to TDD". If you're new to TDD, writing the given/when/then might help. Write tests first, and think about edge cases (like, specify overflow ?).
I use similar setup when doing NASM TDD and testing with C.

Petalinux - Multiple Source File application

I'm pretty new to the 2020.2 version of Petalinux and I'm trying to create a simple application inside my project using the C template.
After creating the helloworld-app using the command:
petalinux-create -t apps --template c --name helloworld-app
After enabling the default application and building it successfully,I tried to add some functionality by creating a new directory under helloworld-app/files called Ethernet, containing 2 files Etherent.c and Ethernet.h
Finally, I added the Ethernet.o object to the list inside the auto-generated Makefile for the module, I also added a VPATH for simplicity.
Unfortunately the build fails, in fact bitbake tells me that no rule for the object Ethernet.o is specified.
How can I modify the makefile in order for this simple code to compile?
I can edit the .bb file? I would like not to, since in that way i would have to specify every src file...
Thank you for the support!
Ethernet.c:
#include "Ethernet.h"
//some C code
helloworld-app.c:
#include <stdio.h>
#include "Ethernet/Ethernet.h"
//some C code
Makefile:
APP = helloworld-app
VPATH=Ethernet
# Add any other object files to this list below
APP_OBJS = helloworld-app.o Ethernet.o
all: build
build: $(APP)
$(APP): $(APP_OBJS)
$(CC) -o $# $(APP_OBJS) $(LDFLAGS) $(LDLIBS)
clean:
rm -f $(APP) *.o
Below I included the output of the petalinux-build -c helloworld-app command:
A simple solution, but really cumbersome if the number of files increases, is to simply add the path to the source files to the variable SRC_URI inside the .bb file. I will leave this question without an accepted answer, waiting for a more sustainable solution.
Thanks to everyone!

Building library issue libudns

First of all thanks for your attention and help.
I have been trying to ./configure and build a program that use a lot of libraries, and specifically libudns. I have been installing several libraries that were needed or by apt-get or by compile, and all of them works, but libudns (which is freaking me out).
This program make use of a configure script that include the following lines of code that add the flag -ludns to the Makefile:
if [ "x$WITH_UDNS" == "xy" ]; then
mkl_lib_check "udns" HAVE_UDNS fail CC "-ludns" \
"#include <udns.h>
void *f();void *f(){return dns_init;}"
fi
When I type ./configure the script checks if all libraries are presents on the system by pkg-config and by compile, as you can see in the following snap:
As you can see, configure cannot see this library.
What I have done is try to install this package by the two different ways:
By pkg-config: sudo apt-get install libudns-dev
By compile:
git clone https://github.com/shadowsocks/libudns
cd libudns
./autogen.sh
./configure && make
sudo make install
With this two ways, I have both:
/usr/lib/x86_64-linux-gnu/libudns.so
/usr/local/include/udns.h
These paths are the same where others libraries are installed, for example PostgreSQL, which you can that is detected:
/usr/lib/x86_64-linux-gnu/libpq.so
/usr/include/postgresql/libpq-fe.h
But the result is always the same:
Does anybody knows how to link this library?
Also, I have try these other things:
Copy udns.h to /usr/include: sudo cp /usr/local/include/udns.h /usr/include/udns.h
Make a sample program only to emulate this check:
#include <stdio.h>
#include <udns.h>
struct dns_ctx* ctx;
void *f();
void * f(){return dns_init;}
int main(int argc, char** argv){
int do_open = 0;
printf("Hola, mundo\n");
f(ctx, do_open);
}
And when I try to build this program with:
gcc main.c -o hello_world -ludns
it WORKS!?!
I have also try to build this program without the -ludns flag, and it gives me the same error as before:
So, I do not understand where is the fail, considering that as you can see in the second image, the -ludns flag is present.
Thanks a lot for your time. Any advise will be welcomed.

Is it possible to call a postgres internal method from a util?

Is it possible to make a function call (function is in Postgres code like hash_estimate_size(long, long) from a util like pg_ctl or pg_dump?
hash_estimate_size (long, long) is defined in file src/backend/utils/hash/dynahash.c and is declared in src/include/utils/hsearch.h.
I created a new util folder: src/bin/test_code with Makefile and test_code.c.
contents of Makefile
PGFILEDESC = "test_code"
PGAPPICON=win32
subdir = src/bin/test_code
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS= test_code.o $(WIN32RES)
all: test_code
test_code: $(OBJS) | submake-libpgport
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $#$(X)
install: all installdirs
$(INSTALL_PROGRAM) test_code$(X) '$(DESTDIR)$(bindir)/test_code$(X)'
installdirs:
$(MKDIR_P) '$(DESTDIR)$(bindir)'
uninstall:
rm -f '$(DESTDIR)$(bindir)/test_code$(X)'
clean distclean maintainer-clean:
rm -f test_code$(X) $(OBJS)
test_code.c
#include "postgres.h"
#include "replication/walreceiver.h"
int main(int argc, char *argv[])
{
printf("Has estimate value is = %zu\n", hash_estimate_size(10, 10));
return 0;
}
When I am running "make", it errors out like
test_code.o: In function main':
test_code.c:(.text+0x17a): undefined reference tohash_estimate_size'
collect2: ld returned 1 exit status
make: *** [test_code] Error 1
Any help in solving this issue ?
Most backend code cannot be called from utilities because it's not linked to utility programs. Nor can it easily be, since frontend code doesn't have palloc and memory contexts, ereport, and the other stuff backend code tends to rely heavily on.
Only code in libpq, libpgcommon and libpgport can be used from utilities. src/backend cannot, with a few exceptions that are recompiled as frontend code and linked into source trees (like pg_xlogdump's use of the xlogdesc code).
If what you want to call is generic enough and will work when compiled as frontend code, consider submitting a patch to move it to libpgcommon (src/common).

GNU-make 4. Running an example for "Loading Dynamic Objects"

The latest version of GNU-Make http://www.gnu.org/software/make/
provides many advanced capabilities, including many useful functions.
(...) On systems which support dynamically loadable objects, you can
write your own extension in any language (which can be compiled into
such an object) and load it to provide extended capabilities... http://www.gnu.org/software/make/manual/make.html#Loading-Objects
I tried to run the simple example below (a $(hello string) function). It works if I first compile the hello.so. But it doesn't work if I run it as the example provided here (with a load directive) http://www.gnu.org/software/make/manual/make.html#Loading-Objects . Make4 is installed in the current directory.
./Makefile:
all:
echo $(hello world)
load hello.so
hello.so: hello.c
$(CC) -shared -I./include -fPIC -o $# $<
./hello.c:
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <gnumake.h>
int plugin_is_GPL_compatible;
char * hello(const char *nm, unsigned int argc, char **argv)
{
int len = strlen (argv[0]) + 7;
char *buf = gmk_alloc (len);
sprintf(buf,"Hello %s",argv[0]);
return buf;
}
int hello_gmk_setup ()
{
gmk_add_function("hello", hello, 1, 1, 1);
return 1;
}
running the example:
./bin/make -v
GNU Make 4.0
Built for i686-pc-linux-gnu
$ ./bin/make
Makefile:4: hello.so: cannot open shared object file: No such file or directory
Makefile:4: *** hello.so: failed to load. Stop.
How can I run this example with the 'load' directive ?
I suggest in a comment to use
-load hello.so
instead of just load hello.so; this is analog to using -include in a Makefile.
The logic is that make plugins are generally expected to exit before you run some make using them (often, you would use a recursive make, e.g. run $(MAKE) -C subdir in a toplevel Makefile and ensure that the plugin does exist when your run $(MAKE) -C subdir)
If hello.so does not exist when -load hello.so is parsed, the GNU make would ignore that directive. (I am not sure you want that for a real plugin).
I still think that make plugins should generally not be built by the Makefile which is load-ing them.
I also believe that using Guile extensions in make is wiser than using plugins.

Resources