ThrowTheSwitch / Ceedling

Ruby-based unit testing and build system for C projects
http://throwtheswitch.org
Other
590 stars 247 forks source link

Mocking a function causes all tests to fail to execute due to possible "bad memory access in source code" #919

Closed yusufso closed 2 months ago

yusufso commented 2 months ago

Note: this is an STM32 microcontroller project.

I am writing a unit test for a function inside of a file called flapjuice.c. The function in question calls several hardware abstraction layer functions. So, I would need to mock these functions. The problem is, there is one mock function (HAL_ADC_DeInit()) where if I don't put it in, Ceedling runs the test but it fails because the function was "Called more times than expected" but if I do put it in, "No tests executed" due to "bad memory access". HAL_ADC_Init() and HAL_ADC_DeInit() are near-identical but the mocks with only the former are successful.

I am using the latest Ceedling docker container too.

Here is the test file. `

ifdef TEST

include "unity.h"

include "flapjuice.h"

include "mock_main.h"

include "mock_stm32wlxx_hal_adc.h"

include "mock_stm32wlxx_hal_adc_ex.h"

void setUp(void) { }

void tearDown(void) { }

void test_flapjuice_Dummy(void) { TEST_ASSERT_EQUAL(1, 1); }

void test_flapjuice_GetValue(void) { // Mocks for setting up and cleaning up. HAL_ADC_Init_IgnoreAndReturn(0); // !!! This is the mock function in question. !!! HAL_ADC_DeInit_IgnoreAndReturn(0); HAL_ADC_ConfigChannel_IgnoreAndReturn(0); HAL_ADCEx_Calibration_Start_IgnoreAndReturn(0);

// Mocks for getting ADC readings.
HAL_ADC_Start_IgnoreAndReturn(0);
HAL_ADC_PollForConversion_IgnoreAndReturn(0);
HAL_ADC_GetValue_IgnoreAndReturn(1000);
HAL_ADC_Stop_IgnoreAndReturn(0);

// Test
uint32_t reading = flapjuice_GetValue();
printf("\n\nFlapjuiceReading: %d\n\n", reading);
TEST_ASSERT_FLOAT_WITHIN(2000, 17500, reading);

}

endif // TEST

`

Here is the Ceedling output when I do put the mock function in ` Linking test_flapjuice.out... Running test_flapjuice.out...

ERROR: Test executable "test_flapjuice.out" failed.

Produced no final test result counts in $stdout: test_flapjuice.c:18:test_flapjuice_Dummy:PASS And exited with status: [0] (count of failed tests). This is often a symptom of a bad memory access in source or test code.

rake aborted!

/usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/generator_helper.rb:36:in test_results_error_handler' /usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/generator.rb:173:ingenerate_test_results' /usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/rules_tests.rake:55:in block in <top (required)>' /usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/task_invoker.rb:107:ininvoke_test_results' /usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:125:in block in setup_and_invoke' /usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:51:insetup_and_invoke' /usr/local/bundle/gems/ceedling-0.31.1/lib/ceedling/tasks_tests.rake:13:in block (2 levels) in <top (required)>' /usr/local/bundle/gems/ceedling-0.31.1/bin/ceedling:345:inblock in <top (required)>' /usr/local/bundle/gems/ceedling-0.31.1/bin/ceedling:332:in <top (required)>' /usr/local/bundle/bin/ceedling:23:inload' /usr/local/bundle/bin/ceedling:23:in `

' Tasks: TOP => build/test/results/test_flapjuice.pass (See full trace by running task with --trace)


OVERALL TEST SUMMARY

No tests executed. `

Letme commented 2 months ago

Tests are run on simulator, target or on PC?

mvandervoord commented 2 months ago

Very likely, it's something AFTER this mock gets called in your function under test which is causing the problem. Without an Ignore/Expect call, this test aborts as soon as it reaches this function. WITH an Ignore/Expect call, it can proceed from there.

"No final test results" is almost always a memory issue... so a pointer which isn't initialized or is pointing at something that has been freed... referencing a register by address, when you're not on a simulator, etc. etc.

yusufso commented 2 months ago

You were correct. There was a pointer later on in the function that was causing it. Thanks for your help. You replied quick.