Testing static functions

Static function are those you want to use only for internal driver use, and therefore their prototypes will never be written in a header file, however Ceedling wont be able to recognize these kind of functions at least you remove the static qualifier which is something you will only want to do when runs your tests. What should we do?.

A precompilation directive will do the trick. (you can use any word you want STATIC, fstatic, etc..), This code can be place it anywhere you need, for instance at bsp.h to make it global or locally if you need only in one of your files (which i doubt), for this example you can place it in app/dummy.h

#ifdef UTEST
  #define STATIC    
#else
  #define STATIC static 
#endif

At your app/dummy.c file write the private function using the macro defined instead of the reserve word static

/*private prototype*/
STATIC uint32_t mul( uint32_t a, uint32_t b );

/*private function only available to dummy.c file*/
STATIC uint32_t mul( uint32_t a, uint32_t b )
{
    return a * b;
}

Write the unit test as usual but including a reference for the private function in test/test_dummy.c

STATIC uint32_t mul( uint32_t a, uint32_t b );

void test__mul__two_integers(void)
{
    uint32_t res = mul( 2, 3 );
    TEST_ASSERT_EQUAL_MESSAGE( 6, res, "2 * 3 = 6" );
}

in file project.yml define the UTEST macro using the option :defines:

# Global defines applicable only when you run the code using ceedling
:defines:
  :test:
    - UTEST   #define the macro UTEST to remove the static qualifier

and voila!!, is working!!

$ ceedling test:all


Test 'test_dummy.c'
-------------------
Generating runner for test_dummy.c...
Compiling test_dummy_runner.c...
Compiling test_dummy.c...
Compiling dummy.c...
Linking test_dummy.exe...
Running test_dummy.exe...

--------------------
OVERALL TEST SUMMARY
--------------------
TESTED:  1
PASSED:  1
FAILED:  0
IGNORED: 0

Testing functions with static global variables

Pretty much the same you did with private functions and global variables, but in this case there is no reference to the variable in the header file to test. Let's take the example from the previous post, but this time variable subs will be local to dummy.c just like the functions instead of the qualifier static we place the STATIC define

app/dummy.c

#include <stdint.h>
#include "dummy.h"

/*global but local variable, only visible to dummy.c*/
STATIC uint32_t subs;

uint32_t substraction( uint32_t a )
{
    return a - subs;
}

In the header file we can define the precompilation directive to define STATIC that removes the static word when we apply unit testing. as you can see there is no external reference to variable subs

app/dummy.h

#ifndef __DUMMY_H__
#define __DUMMY_H__

/*Normally you will prefer to place this macro in some sort of 
config header to make it visible for all files under your application
like for isntace app_bsp.h*/
#ifdef UTEST
  #define STATIC    
#else
  #define STATIC static 
#endif

uint32_t substraction( uint32_t a );

#endif // __DUMMY_H__

In test file we add the reference to our global variable. In this way you can easily test static or no static functions with or without static variables

test/test_dummy.c

include "unity.h"
#include "dummy.h"

/*to be recognized by test_dummy, it is necesary to delare a
reference to variable subs*/
extern uint32_t subs;

void setUp(void)
{
}

void tearDown(void)
{
}

void test__substraction__two_integers(void)
{
    /*We give an initial value to our global variable, ceedling knows about
    the variable because the external reference is in this same file and because
    the static qualifier was remove by the macro STATIC in dummy.c*/
    subs = 10;
    /*call function under test that make use of global function*/
    uint32_t res = substraction( 20 );
    TEST_ASSERT_EQUAL_MESSAGE( 10, res, "20 - 10 = 10" );
}