ThrowTheSwitch / Ceedling

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

Test crash writting test result #586

Open JuPrgn opened 3 years ago

JuPrgn commented 3 years ago

Hi

I'm having strange behavior while testing a particular simple function that interacts with micro registers.

My setup is XC16 compiler running on the mdb simulator.

   Ceedling:: 0.31.0
      Unity:: 2.5.2
      CMock:: 2.5.3
 CException:: 1.3.3

Simple test crash :

C :

#include "DebugInit.h"

STATIC void INIT_1(void)
{
    TMR2 = 0;
}
STATIC void INIT_2(void)
{
    PR2 = CO_FCY - 1U; // Period register
}
STATIC void INIT_3(void)
{
    T2CON = 0x8000U;    // start timer (TON=1)
}
STATIC void INIT_4(void)
{
    _T2IF = 0;     // clear interrupt flag
}
STATIC void INIT_5(void)
{
    _T2IE = 1;   // enable interrupt
}
STATIC void INIT_6(void)
{
    _C1IF = 0;   // CAN1 Interrupt - Clear flag
}
STATIC void INIT_7(void)
{
    _C1IE = 1; // CAN1 Interrupt - Enable interrupt
}

H :

#ifndef DEBUGINIT_H
#define DEBUGINIT_H

#include <p33EP256MC506.h>

#define CO_FCY 48000U

#ifdef TEST
#define STATIC
#else
#define STATIC static
#endif

#endif // DEBUGINIT_H

TEST :

#include "unity.h"

//#include "mock_init.h"
#include "DebugInit.h"

STATIC void INIT_1(void);
STATIC void INIT_2(void);
STATIC void INIT_3(void);
STATIC void INIT_4(void);
STATIC void INIT_5(void);
STATIC void INIT_6(void);
STATIC void INIT_7(void);

void setUp(void)
{
}

void tearDown(void)
{
}

void test_DebugInit_1(void)
{
    TMR2 = 1;
    INIT_1();
    TEST_ASSERT_EQUAL_UINT16(0U, TMR2);
}

void test_DebugInit_2(void)
{
    PR2 = 0;
    INIT_2();
    TEST_ASSERT_EQUAL_UINT16(CO_FCY - 1U, PR2);
}

void test_DebugInit_3(void)
{
    T2CON = 0;
    INIT_3();
    TEST_ASSERT_EQUAL_UINT16(0x8000U, T2CON);
}

void test_DebugInit_4(void)
{
    _T2IF = 1;
    INIT_4();
    TEST_ASSERT_EQUAL_UINT16(0U, _T2IF);
}

void test_DebugInit_5(void)
{
    _T2IE = 0;
    INIT_5();
    TEST_ASSERT_EQUAL_UINT16(1U, _T2IE);
}

void test_DebugInit_6(void)
{
    _C1IF = 1;
    INIT_6();
    TEST_ASSERT_EQUAL_UINT16(0U, _C1IF);
}

void test_DebugInit_7(void)
{
    _C1IE = 0;
    INIT_7();
    TEST_ASSERT_EQUAL_UINT16(1U, _C1IE);
}

Output :

test_DebugInit.c:50:test_DebugInit_1:PASS
test_DebugInit.c:58:test_DebugInit_2:PASS
test_DebugInit.c:66:test_DebugInit_3:PASS
test_DebugInit.c:74:test_DebugInit_4:PASS
tes

Something crash the simulator before the end, could this be related to memory ? After many attempts, the output stops at the same character for the same code but changes depending on the code being tested.

Any hint would be appreciated.

Tests run fine on GCC using a custom PIC header that define register as : volatile uint16_t TMR2; ...

Config details

Some sections from my project.yml (I can post full config if required) :

:project:
  :use_exceptions: FALSE
  :use_test_preprocessor: TRUE
  :use_deep_dependencies: TRUE
  :use_auxiliary_dependencies: TRUE
  :build_root: build_test
  :test_file_prefix: test_
  :which_ceedling: vendor/ceedling

:defines:
  :commmon: &common_defines
    - UNITY_INT_WIDTH=16
    - CMOCK_MEM_INDEX_TYPE=uint16_t
    - CMOCK_MEM_ALIGN=1
    - CMOCK_MEM_SIZE=4096

sim_test_fixture.rb :

require 'rbconfig'
is_windows = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)

OUT_FILE = "test/simulation/out.txt"
File.delete OUT_FILE if File.exists? OUT_FILE 

sim_io = IO.popen('"C:\Program Files (x86)\Microchip\MPLABX\v5.10\mplab_platform\bin\mdb.bat" test/simulation/mdb_instructions.txt')
Process.wait(sim_io.pid)

if File.exists? OUT_FILE 
    file_contents = File.read OUT_FILE
    print file_contents
end

sim_instructions.txt :

LD dspic33epsuper 
LC build_test/release/TestBuild.out
IO NULL test/simulation/out.txt
RP
E
quit
JuPrgn commented 3 years ago

Changing INIT_5() register on previous C example :

STATIC void INIT_5(void)
{
    _T2IE = 1;   // enable interrupt
}

to

STATIC void INIT_5(void)
{
    _T3IE = 1;   // enable interrupt
}

Output :

test_DebugInit.c:50:test_DebugInit_1:PASS
test_DebugInit.c:57:test_DebugInit_2:PASS
test_DebugInit.c:64:test_DebugInit_3:PASS
test_DebugInit.c:71:test_DebugInit_4:PASS
test_DebugInit.c:82:test_DebugInit_5:FAIL: Expected 1 Was 0
test_DebugInit.c:85:test_DebugInit_6:PASS
test_DebugInit.c:92:test_DebugInit_7:PASS

-----------------------
7 Tests 1 Failures 0 Ignored 
FAIL

Please note T2IE and T3IE are on the same register :

#define IEC0 IEC0
extern volatile uint16_t  IEC0 __attribute__((__sfr__));
typedef struct tagIEC0BITS {
  uint16_t INT0IE:1;
  uint16_t IC1IE:1;
  uint16_t OC1IE:1;
  uint16_t T1IE:1;
  uint16_t DMA0IE:1;
  uint16_t IC2IE:1;
  uint16_t OC2IE:1;
  uint16_t T2IE:1;
  uint16_t T3IE:1;
  uint16_t SPI1EIE:1;
  uint16_t SPI1IE:1;
  uint16_t U1RXIE:1;
  uint16_t U1TXIE:1;
  uint16_t AD1IE:1;
  uint16_t DMA1IE:1;
} IEC0BITS;
extern volatile IEC0BITS IEC0bits __attribute__((__sfr__));

This seems to be related to memory sometimes this is on TIMER 2 (T2CON, PR2...) registers and when I modify the code the problem move to another register.

JuPrgn commented 3 years ago

Still present on latest versions : MPLAB X v5.45 and XC16 v1.70