refactor (cxx): changed cxx unit tests to component unit tests

This commit is contained in:
Jakob Hasse 2022-03-22 16:20:51 +08:00
parent 8ce997f02c
commit 9e25e0ed4b
31 changed files with 431 additions and 206 deletions

View File

@ -1,3 +0,0 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES cmock driver)

View File

@ -1,30 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#if CONFIG_COMPILER_STACK_CHECK
static void recur_and_smash_cxx()
{
static int cnt;
volatile uint8_t buf[50];
volatile int num = sizeof(buf)+10;
if (cnt++ < 1) {
recur_and_smash_cxx();
}
for (int i = 0; i < num; i++) {
buf[i] = 0;
}
}
TEST_CASE("stack smashing protection CXX", "[stack_check] [ignore]")
{
recur_and_smash_cxx();
}
#endif

View File

@ -0,0 +1,8 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_cxx_exception)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "test_exception.cpp"
REQUIRES test_utils
PRIV_REQUIRES unity driver)

View File

@ -3,51 +3,9 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <vector>
#include <numeric>
#include <stdexcept>
#include <string>
#include "unity.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "soc/soc.h"
TEST_CASE("can use new and delete", "[cxx]")
{
int* int_p = new int(10);
delete int_p;
int* int_array = new int[10];
delete[] int_array;
}
class Base
{
public:
virtual ~Base() {}
virtual void foo() = 0;
};
class Derived : public Base
{
public:
virtual void foo() { }
};
TEST_CASE("can call virtual functions", "[cxx]")
{
Derived d;
Base& b = static_cast<Base&>(d);
b.foo();
}
TEST_CASE("can use std::vector", "[cxx]")
{
std::vector<int> v(10, 1);
v[0] = 42;
TEST_ASSERT_EQUAL(51, std::accumulate(std::begin(v), std::end(v), 0));
}
#include "memory_checks.h"
/* Note: When first exception (in system) is thrown this test produces memory leaks report (~300 bytes):
- 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
@ -55,19 +13,27 @@ TEST_CASE("can use std::vector", "[cxx]")
- 88 bytes are allocated by pthread_setspecific() to init internal lock
- some more memory...
*/
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
#if CONFIG_IDF_TARGET_ESP32
#define LEAKS "300"
#define LEAKS (300)
#elif CONFIG_IDF_TARGET_ESP32S2
#define LEAKS "800"
#define LEAKS (800)
#elif CONFIG_IDF_TARGET_ESP32C3
#define LEAKS "700"
#define LEAKS (700)
#else
#error "unknown target in CXX tests, can't set leaks threshold"
#endif
TEST_CASE("c++ exceptions work", "[cxx] [exceptions] [leaks=" LEAKS "]")
extern "C" void setUp()
{
test_utils_record_free_mem();
}
extern "C" void tearDown()
{
test_utils_finish_and_evaluate_leaks(LEAKS, LEAKS);
}
TEST_CASE("c++ exceptions work", "[cxx] [exceptions]")
{
int thrown_value;
try {
@ -76,10 +42,9 @@ TEST_CASE("c++ exceptions work", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL(20, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ bool exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ bool exception", "[cxx] [exceptions]")
{
bool thrown_value = false;
try {
@ -88,10 +53,9 @@ TEST_CASE("c++ bool exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL(true, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ void exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ void exception", "[cxx] [exceptions]")
{
void* thrown_value = 0;
try {
@ -100,10 +64,9 @@ TEST_CASE("c++ void exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL(47, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ uint64_t exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ uint64_t exception", "[cxx] [exceptions]")
{
uint64_t thrown_value = 0;
try {
@ -112,10 +75,9 @@ TEST_CASE("c++ uint64_t exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL(47, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ char exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ char exception", "[cxx] [exceptions]")
{
char thrown_value = '0';
try {
@ -124,10 +86,9 @@ TEST_CASE("c++ char exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL('/', thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ wchar exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ wchar exception", "[cxx] [exceptions]")
{
wchar_t thrown_value = 0;
try {
@ -136,10 +97,9 @@ TEST_CASE("c++ wchar exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL((wchar_t) 47, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ float exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ float exception", "[cxx] [exceptions]")
{
float thrown_value = 0;
try {
@ -148,10 +108,9 @@ TEST_CASE("c++ float exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL(23.5, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ double exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ double exception", "[cxx] [exceptions]")
{
double thrown_value = 0;
try {
@ -160,10 +119,9 @@ TEST_CASE("c++ double exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL(23.5d, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ const char* exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ const char* exception", "[cxx] [exceptions]")
{
const char *thrown_value = 0;
try {
@ -172,7 +130,6 @@ TEST_CASE("c++ const char* exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e;
}
TEST_ASSERT_EQUAL_STRING("Hi :)", thrown_value);
printf("OK?\n");
}
struct NonExcTypeThrowee {
@ -181,7 +138,7 @@ public:
NonExcTypeThrowee(int value) : value(value) { }
};
TEST_CASE("c++ any class exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ any class exception", "[cxx] [exceptions]")
{
int thrown_value = 0;
try {
@ -190,7 +147,6 @@ TEST_CASE("c++ any class exception", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e.value;
}
TEST_ASSERT_EQUAL(47, thrown_value);
printf("OK?\n");
}
struct ExcTypeThrowee : public std::exception {
@ -199,7 +155,7 @@ public:
ExcTypeThrowee(int value) : value(value) { }
};
TEST_CASE("c++ std::exception child", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ std::exception child", "[cxx] [exceptions]")
{
int thrown_value = 0;
try {
@ -208,10 +164,9 @@ TEST_CASE("c++ std::exception child", "[cxx] [exceptions] [leaks=" LEAKS "]")
thrown_value = e.value;
}
TEST_ASSERT_EQUAL(47, thrown_value);
printf("OK?\n");
}
TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions] [leaks=" LEAKS "]")
TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions]")
{
void **p, **pprev = NULL;
int thrown_value = 0;
@ -257,72 +212,8 @@ TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions] [leaks=" LEAKS "]
#endif
}
#else // !CONFIG_COMPILER_CXX_EXCEPTIONS
TEST_CASE("std::out_of_range exception when -fno-exceptions", "[cxx][reset=abort,SW_CPU_RESET]")
extern "C" void app_main(void)
{
std::vector<int> v(10);
v.at(20) = 42;
TEST_FAIL_MESSAGE("Unreachable because we are aborted on the line above");
printf("CXX EXCEPTION TEST\n");
unity_run_menu();
}
TEST_CASE("std::bad_alloc exception when -fno-exceptions", "[cxx][reset=abort,SW_CPU_RESET]")
{
std::string s = std::string(2000000000, 'a');
(void)s;
TEST_FAIL_MESSAGE("Unreachable because we are aborted on the line above");
}
#endif
/* These test cases pull a lot of code from libstdc++ and are disabled for now
*/
#if 0
#include <iostream>
#include <functional>
TEST_CASE("can use iostreams", "[cxx]")
{
std::cout << "hello world";
}
TEST_CASE("can call std::function and bind", "[cxx]")
{
int outer = 1;
std::function<int(int)> fn = [&outer](int x) -> int {
return x + outer;
};
outer = 5;
TEST_ASSERT_EQUAL(6, fn(1));
auto bound = std::bind(fn, outer);
outer = 10;
TEST_ASSERT_EQUAL(15, bound());
}
#endif
/* Tests below are done in the compile time, don't actually get run. */
/* Check whether a enumerator flag can be used in C++ */
template<typename T> __attribute__((unused)) static void test_binary_operators()
{
T flag1 = (T)0;
T flag2 = (T)0;
flag1 = ~flag1;
flag1 = flag1 | flag2;
flag1 = flag1 & flag2;
flag1 = flag1 ^ flag2;
flag1 = flag1 >> 2;
flag1 = flag1 << 2;
flag1 |= flag2;
flag1 &= flag2;
flag1 ^= flag2;
flag1 >>= 2;
flag1 <<= 2;
}
//Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h
#include "driver/timer_types_legacy.h"
template void test_binary_operators<timer_intr_t>();

View File

@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
def test_cxx_exception(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()

View File

@ -0,0 +1,12 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_ESP_TASK_WDT=n
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000

View File

@ -0,0 +1,8 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_cxx_exception)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "test_exception_no_except.cpp"
REQUIRES test_utils
PRIV_REQUIRES unity driver)

View File

@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdexcept>
#include <vector>
#include "unity.h"
#include "memory_checks.h"
extern "C" void setUp()
{
}
extern "C" void tearDown()
{
}
TEST_CASE("std::out_of_range exception when -fno-exceptions", "[cxx][reset=abort,SW_CPU_RESET]")
{
std::vector<int> v(10);
v.at(20) = 42;
TEST_FAIL_MESSAGE("Unreachable because we are aborted on the line above");
}
TEST_CASE("std::bad_alloc exception when -fno-exceptions", "[cxx][reset=abort,SW_CPU_RESET]")
{
std::string s = std::string(2000000000, 'a');
(void)s;
TEST_FAIL_MESSAGE("Unreachable because we are aborted on the line above");
}
extern "C" void app_main(void)
{
printf("CXX NO EXCEPTION TEST\n");
unity_run_menu();
}

View File

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
def test_cxx_noexcept_out_of_range(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('1')
dut.expect_exact('abort() was called')
dut.expect_exact('Rebooting...')
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
def test_cxx_noexcept_bad_alloc(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('2')
dut.expect_exact('abort() was called')
dut.expect_exact('Rebooting...')

View File

@ -0,0 +1,12 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=n
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_ESP_TASK_WDT=n
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000

View File

@ -0,0 +1,8 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_cxx_general)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "test_cxx_general.cpp"
PRIV_REQUIRES unity test_utils driver)

View File

@ -1,18 +1,29 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <vector>
#include <numeric>
#include <stdexcept>
#include <string>
#include "unity.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "soc/soc.h"
#include "esp_log.h"
#include "unity.h"
#include "memory_checks.h"
extern "C" void setUp()
{
test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
test_utils_record_free_mem();
}
extern "C" void tearDown()
{
size_t leak_level = test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
test_utils_finish_and_evaluate_leaks(leak_level, leak_level);
}
static const char* TAG = "cxx";
@ -31,8 +42,10 @@ static int non_pod_test_helper(int new_val)
return ret;
}
TEST_CASE("can use static initializers for non-POD types", "[cxx]")
// Will fail if run twice
TEST_CASE("can use static initializers for non-POD types", "[restart_init]")
{
test_utils_set_leak_level(300, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
TEST_ASSERT_EQUAL(42, non_pod_test_helper(1));
TEST_ASSERT_EQUAL(1, non_pod_test_helper(0));
}
@ -84,8 +97,9 @@ static int start_slow_init_task(int id, int affinity)
reinterpret_cast<void*>(id), 3, NULL, affinity) ? 1 : 0;
}
TEST_CASE("static initialization guards work as expected", "[cxx]")
TEST_CASE("static initialization guards work as expected", "[misc]")
{
test_utils_set_leak_level(300, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
s_slow_init_sem = xSemaphoreCreateCounting(10, 0);
TEST_ASSERT_NOT_NULL(s_slow_init_sem);
int task_count = 0;
@ -128,7 +142,7 @@ GlobalInitTest g_init_test1;
GlobalInitTest g_init_test2;
GlobalInitTest g_init_test3;
TEST_CASE("global initializers run in the correct order", "[cxx]")
TEST_CASE("global initializers run in the correct order", "[misc]")
{
TEST_ASSERT_EQUAL(0, g_init_test1.index);
TEST_ASSERT_EQUAL(1, g_init_test2.index);
@ -158,7 +172,7 @@ StaticInitTestBeforeScheduler g_static_init_test1;
StaticInitTestBeforeScheduler g_static_init_test2;
StaticInitTestBeforeScheduler g_static_init_test3;
TEST_CASE("before scheduler has started, static initializers work correctly", "[cxx]")
TEST_CASE("before scheduler has started, static initializers work correctly", "[misc]")
{
TEST_ASSERT_EQUAL(1, g_static_init_test1.index);
TEST_ASSERT_EQUAL(1, g_static_init_test2.index);
@ -190,9 +204,119 @@ PriorityInitTest g_static_init_priority_test2;
PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000)));
PriorityInitTest g_static_init_priority_test0 __attribute__((init_priority(999)));
TEST_CASE("init_priority extension works", "[cxx]")
TEST_CASE("init_priority extension works", "[misc]")
{
TEST_ASSERT_EQUAL(0, g_static_init_priority_test0.index);
TEST_ASSERT_EQUAL(1, g_static_init_priority_test1.index);
TEST_ASSERT_EQUAL(2, g_static_init_priority_test2.index);
}
TEST_CASE("can use new and delete", "[misc]")
{
int* int_p = new int(10);
delete int_p;
int* int_array = new int[10];
delete[] int_array;
}
class Base
{
public:
virtual ~Base() = default;
virtual void foo() = 0;
};
class Derived : public Base
{
public:
virtual void foo() { }
};
TEST_CASE("can call virtual functions", "[misc]")
{
Derived d;
Base& b = static_cast<Base&>(d);
b.foo();
}
TEST_CASE("can use std::vector", "[misc]")
{
std::vector<int> v(10, 1);
v[0] = 42;
TEST_ASSERT_EQUAL(51, std::accumulate(std::begin(v), std::end(v), 0));
}
/* These test cases pull a lot of code from libstdc++ and are disabled for now
*/
#if 0
#include <iostream>
#include <functional>
TEST_CASE("can use iostreams", "[misc]")
{
std::cout << "hello world";
}
TEST_CASE("can call std::function and bind", "[misc]")
{
int outer = 1;
std::function<int(int)> fn = [&outer](int x) -> int {
return x + outer;
};
outer = 5;
TEST_ASSERT_EQUAL(6, fn(1));
auto bound = std::bind(fn, outer);
outer = 10;
TEST_ASSERT_EQUAL(15, bound());
}
#endif
static void recur_and_smash_cxx()
{
static int cnt;
volatile uint8_t buf[50];
volatile int num = sizeof(buf)+10;
if (cnt++ < 1) {
recur_and_smash_cxx();
}
for (int i = 0; i < num; i++) {
buf[i] = 0;
}
}
TEST_CASE("stack smashing protection CXX", "[stack_smash]")
{
recur_and_smash_cxx();
}
extern "C" void app_main(void)
{
printf("CXX GENERAL TEST\n");
unity_run_menu();
}
/* Tests below are done in the compile time, don't actually get run. */
/* Check whether a enumerator flag can be used in C++ */
template<typename T> __attribute__((unused)) static void test_binary_operators()
{
T flag1 = (T)0;
T flag2 = (T)0;
flag1 = ~flag1;
flag1 = flag1 | flag2;
flag1 = flag1 & flag2;
flag1 = flag1 ^ flag2;
flag1 = flag1 >> 2;
flag1 = flag1 << 2;
flag1 |= flag2;
flag1 &= flag2;
flag1 ^= flag2;
flag1 >>= 2;
flag1 <<= 2;
}
//Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h
#include "driver/timer_types_legacy.h"
template void test_binary_operators<timer_intr_t>();

View File

@ -0,0 +1,42 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
configurations = [
'noexcept',
'exceptions_rtti'
]
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
@pytest.mark.parametrize('config', configurations, indirect=True)
def test_cxx_static_init_non_pod(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('\"can use static initializers for non-POD types\"')
dut.expect_unity_test_output()
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
@pytest.mark.parametrize('config', configurations, indirect=True)
def test_cxx_misc(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('[misc]')
dut.expect_unity_test_output()
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
@pytest.mark.parametrize('config', configurations, indirect=True)
def test_cxx_stack_smash(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('\"stack smashing protection CXX\"')
dut.expect_exact('Stack smashing protect failure!')
dut.expect_exact('abort() was called')
dut.expect_exact('Rebooting...')

View File

@ -1,6 +1,3 @@
# Only need to test this for one target (e.g. ESP32)
CONFIG_IDF_TARGET="esp32"
TEST_COMPONENTS=cxx
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
CONFIG_COMPILER_CXX_RTTI=y

View File

@ -0,0 +1,10 @@
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_ESP_TASK_WDT=n
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000

View File

@ -0,0 +1,8 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_cxx_rtti)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "test_rtti.cpp"
REQUIRES test_utils
PRIV_REQUIRES unity driver)

View File

@ -1,12 +1,40 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdexcept>
#include <typeinfo>
#include "unity.h"
#include "memory_checks.h"
#ifdef CONFIG_COMPILER_CXX_RTTI
/* Note: When first exception (in system) is thrown this test produces memory leaks report (~300 bytes):
- 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
- 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
- 88 bytes are allocated by pthread_setspecific() to init internal lock
- some more memory...
*/
#if CONFIG_IDF_TARGET_ESP32
#define LEAKS (300)
#elif CONFIG_IDF_TARGET_ESP32S2
#define LEAKS (800)
#elif CONFIG_IDF_TARGET_ESP32C3
#define LEAKS (700)
#else
#error "unknown target in CXX tests, can't set leaks threshold"
#endif
extern "C" void setUp()
{
test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
test_utils_record_free_mem();
}
extern "C" void tearDown()
{
size_t leak_level = test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
test_utils_finish_and_evaluate_leaks(leak_level, leak_level);
}
using namespace std;
@ -67,9 +95,9 @@ TEST_CASE("typeid of function works", "[cxx]")
TEST_ASSERT_EQUAL(typeid(dummy_function1).hash_code(), typeid(dummy_function2).hash_code());
}
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
TEST_CASE("unsuccessful dynamic cast on reference throws exception", "[cxx]")
{
test_utils_set_leak_level(LEAKS, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL);
bool thrown = false;
DerivedA derived_a;
Base &base = derived_a;
@ -96,5 +124,8 @@ TEST_CASE("typeid on nullptr throws bad_typeid", "[cxx]")
TEST_ASSERT(thrown);
}
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS
#endif // CONFIG_COMPILER_CXX_RTTI
extern "C" void app_main(void)
{
printf("CXX RTTI TEST\n");
unity_run_menu();
}

View File

@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.generic
def test_cxx_rtti(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()

View File

@ -0,0 +1,13 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
CONFIG_COMPILER_CXX_RTTI=y
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_ESP_TASK_WDT=n
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000

View File

@ -1,5 +0,0 @@
# Only need to test this for one target (e.g. ESP32) per architecture
CONFIG_IDF_TARGET="esp32"
TEST_COMPONENTS=cxx
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024

View File

@ -1,5 +0,0 @@
# Only need to test this for one target (e.g. ESP32) per architecture
CONFIG_IDF_TARGET="esp32c3"
TEST_COMPONENTS=cxx
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024

View File

@ -1,6 +0,0 @@
# Only need to test this for one target (e.g. ESP32) per architecture
CONFIG_IDF_TARGET="esp32c3"
TEST_COMPONENTS=cxx
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
CONFIG_COMPILER_CXX_RTTI=y