cunit-testingembeddedcmockceedling

Ceedling/CMock: Adding va_list to :treat_as_array: produces a TypeError


I am working on developing some unit tests for some non-open source inherited code. For now I have just been testing the ceedling framework, using the autogenerated tests to ensure everything runs as it should.

Everything works fine when I run tests for the modules with no dependencies, but when running a test for one of the modules with a bunch of dependencies (that I had to include as mocks):

#ifdef TEST

#include "unity.h"

#include "conn.h"
#include "mock_log.h"
#include "mock_memory.h"
#include "mock_rxbuffer.h"
#include "mock_txbuffer.h"


void setUp(void)
{
}

void tearDown(void)
{
}

void test_conn_NeedToImplement(void)
{
    TEST_IGNORE_MESSAGE("Need to Implement conn");
}

#endif // TEST

Ceedling encounters an error when mocking the following function:

void tx_push (struct txbuffer *tx, const char *format, va_list ap)

The error sais as follows:

Test 'test_conn.c'
------------------
Generating runner for test_conn.c...
Compiling test_conn_runner.c...
Compiling mock_txbuffer.c...
build/test/mocks/mock_txbuffer.c: In function ‘CMockExpectParameters_tx_push’:
build/test/mocks/mock_txbuffer.c:420:31: warning: ‘sizeof’ on array function parameter ‘ap’ will return size of ‘__va_list_tag *’ [-Wsizeof-array-argument]
          sizeof(va_list[sizeof(ap) == sizeof(va_list) ? 1 : -1])); /* add va_list to :treat_as_array if this causes an error */
                               ^
build/test/mocks/mock_txbuffer.c:414:149: note: declared here
 void CMockExpectParameters_tx_push(CMOCK_tx_push_CALL_INSTANCE* cmock_call_instance, struct txbuffer* tx, int tx_Depth, const char* format, va_list ap)
                                                                                                                                                     ^~
build/test/mocks/mock_txbuffer.c:420:24: error: size of unnamed array is negative
          sizeof(va_list[sizeof(ap) == sizeof(va_list) ? 1 : -1])); /* add va_list to :treat_as_array if this causes an error */
                        ^
ERROR: Shell command failed.

So as suggested by the message I added va_list to :treat_as_array :

:cmock:
  :mock_prefix: mock_
  :when_no_prototypes: :warn
  :enforce_strict_ordering: TRUE
  :plugins:
    - :array
    - :ignore
    - :callback
  :treat_as:
    uint8:    HEX8
    uint16:   HEX16
    uint32:   UINT32
    int8:     INT8
    bool:     UINT8
  :treat_as_array:
      - va_list
  :includes:
    - <assert.h>
    - <getopt.h>
    - <libgen.h>
    - <stdbool.h>
    - <stdint.h>
    - <stdio.h>
    - <stdlib.h>
    - <string.h>

After doing this I ended up getting a new error (running ceedling in debug) in the form of:

TypeError: no implicit conversion of String into Integer

** Invoke test:conn (first_time)
** Invoke test/test_conn.c (first_time, not_needed)
** Execute test:conn
** Invoke test_deps (first_time)
** Invoke directories (first_time)
** Invoke build/test/mocks (first_time, not_needed)
** Invoke build/artifacts (first_time, not_needed)
** Invoke build/test (first_time, not_needed)
** Invoke build/artifacts/test (first_time, not_needed)
** Invoke build/test/runners (first_time, not_needed)
** Invoke build/test/results (first_time, not_needed)
** Invoke build/test/out (first_time, not_needed)
** Invoke build/test/out/asm (first_time, not_needed)
** Invoke build/test/out/c (first_time, not_needed)
** Invoke build/test/cache (first_time, not_needed)
** Invoke build/test/dependencies (first_time, not_needed)
** Invoke build/logs (first_time, not_needed)
** Invoke build/temp (first_time, not_needed)
** Invoke build/test/preprocess/includes (first_time, not_needed)
** Invoke build/test/preprocess/files (first_time, not_needed)
** Invoke build/gcov/out (first_time, not_needed)
** Invoke build/gcov/results (first_time, not_needed)
** Invoke build/gcov/dependencies (first_time, not_needed)
** Invoke build/artifacts/gcov (first_time, not_needed)
** Execute directories
** Execute test_deps


Test 'test_conn.c'
------------------
Verbose: exec(): gcc -E -MM -MG -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "build/temp/_test_conn.c"
> Shell executed command:
'gcc -E -MM -MG -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "build/temp/_test_conn.c"'
> Produced output:
_test_conn.o: build/temp/_test_conn.c \
 /var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src/unity.h \
 /var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src/unity_internals.h \
 @@@@unity.h src/conn.h @@@@conn.h mock_log.h @@@@mock_log.h \
 mock_memory.h @@@@mock_memory.h mock_rxbuffer.h @@@@mock_rxbuffer.h \
 mock_txbuffer.h @@@@mock_txbuffer.h

** Invoke build/test/preprocess/includes/log.h (first_time, not_needed)
** Invoke src/log.h (first_time, not_needed)
Verbose: exec(): gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/log.h" -o "build/test/preprocess/files/log.h"
> Shell executed command:
'gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/log.h" -o "build/test/preprocess/files/log.h"'

** Invoke build/test/preprocess/includes/memory.h (first_time, not_needed)
** Invoke src/memory.h (first_time, not_needed)
Verbose: exec(): gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/memory.h" -o "build/test/preprocess/files/memory.h"
> Shell executed command:
'gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/memory.h" -o "build/test/preprocess/files/memory.h"'

** Invoke build/test/preprocess/includes/rxbuffer.h (first_time, not_needed)
** Invoke src/rxbuffer.h (first_time, not_needed)
Verbose: exec(): gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/rxbuffer.h" -o "build/test/preprocess/files/rxbuffer.h"
> Shell executed command:
'gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/rxbuffer.h" -o "build/test/preprocess/files/rxbuffer.h"'

** Invoke build/test/preprocess/includes/txbuffer.h (first_time, not_needed)
** Invoke src/txbuffer.h (first_time, not_needed)
Verbose: exec(): gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/txbuffer.h" -o "build/test/preprocess/files/txbuffer.h"
> Shell executed command:
'gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"build/test/mocks" -I"test" -I"test/support" -I"src" -DTEST -DTEST -DGNU_COMPILER "src/txbuffer.h" -o "build/test/preprocess/files/txbuffer.h"'

** Invoke build/test/mocks/mock_log.c (first_time)
** Invoke build/test/cache/log.h (first_time, not_needed)
** Execute build/test/mocks/mock_log.c
Creating mock for log...
rake aborted!
TypeError: no implicit conversion of String into Integer
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:421:in `block in parse_args'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:411:in `each'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:411:in `parse_args'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:588:in `parse_declaration'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:45:in `block in parse'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:44:in `map'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock_header_parser.rb:44:in `parse'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock.rb:48:in `generate_mock'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock.rb:32:in `block in setup_mocks'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock.rb:31:in `each'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/lib/cmock.rb:31:in `setup_mocks'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/generator.rb:50:in `generate_mock'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/rules_cmock.rake:8:in `block in <top (required)>'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/task_invoker.rb:60:in `block in invoke_test_mocks'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/task_invoker.rb:58:in `invoke_test_mocks'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/preprocessinator.rb:28:in `preprocess_test_and_invoke_test_mocks'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:84:in `block in setup_and_invoke'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:51:in `each'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:51:in `setup_and_invoke'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/rules_tests.rake:70:in `block (2 levels) in <top (required)>'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/bin/ceedling:345:in `block in <top (required)>'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/bin/ceedling:332:in `<top (required)>'
/usr/local/bin/ceedling:23:in `load'
/usr/local/bin/ceedling:23:in `<main>'
Tasks: TOP => build/test/mocks/mock_log.c
(See full trace by running task with --trace)

--------------------
OVERALL TEST SUMMARY
--------------------

No tests executed.

If I remove va_list from :treat_as_array I can succesfully test modules with dependencies, as long as they do not have functions that take va_list as an input. Otherwise I still get the same error even if there are no va_list functions:

TypeError: no implicit conversion of String into Integer

So it seems to me that there could be an issue with the way I include va_list to :treat_as_array?

Reaching this point I was more of less out of ideas on what to try. I have also opened an issue on the github for ceedling stating this very problem, but I'm hoping to get some input from other ceedling users that might have encountered this problem too.

My ceedling version is the following (Ubuntu 18.04.2):

   Ceedling:: 0.31.1
      Unity:: 2.5.4
      CMock:: 2.5.4
 CException:: 1.3.3

There is a similar question in stack exchange that I saw here, but whithout the extra step of adding va_list to :treat_as_array.

And there are several github issues talking about the lack of support for variatic functions:

So I guess I just want to figure out whether this is an unsupported feature or wether im doing something wrong.

Any help will be gratly appreaciated.

Best regards, GCT.


Solution

  • So it seems I was adding the va_list wrongly.

    It needs to be :

      :treat_as_array:
        va_list
    

    Now cmock is no longer complaining about the mocked module.

    I couldnt find any examples of how to add something to :treat_as_array:, so hopefully this helps.