mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
refactor (cxx): changed cxx unit tests to component unit tests
This commit is contained in:
parent
8ce997f02c
commit
9e25e0ed4b
@ -1,3 +0,0 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES cmock driver)
|
@ -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
|
8
components/cxx/test_apps/exception/CMakeLists.txt
Normal file
8
components/cxx/test_apps/exception/CMakeLists.txt
Normal 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)
|
2
components/cxx/test_apps/exception/README.md
Normal file
2
components/cxx/test_apps/exception/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
3
components/cxx/test_apps/exception/main/CMakeLists.txt
Normal file
3
components/cxx/test_apps/exception/main/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "test_exception.cpp"
|
||||
REQUIRES test_utils
|
||||
PRIV_REQUIRES unity driver)
|
@ -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>();
|
14
components/cxx/test_apps/exception/pytest_cxx_exception.py
Normal file
14
components/cxx/test_apps/exception/pytest_cxx_exception.py
Normal 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()
|
12
components/cxx/test_apps/exception/sdkconfig.defaults
Normal file
12
components/cxx/test_apps/exception/sdkconfig.defaults
Normal 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
|
@ -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)
|
2
components/cxx/test_apps/exception_no_except/README.md
Normal file
2
components/cxx/test_apps/exception_no_except/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "test_exception_no_except.cpp"
|
||||
REQUIRES test_utils
|
||||
PRIV_REQUIRES unity driver)
|
@ -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();
|
||||
}
|
@ -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...')
|
@ -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
|
8
components/cxx/test_apps/general/CMakeLists.txt
Normal file
8
components/cxx/test_apps/general/CMakeLists.txt
Normal 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)
|
2
components/cxx/test_apps/general/README.md
Normal file
2
components/cxx/test_apps/general/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
2
components/cxx/test_apps/general/main/CMakeLists.txt
Normal file
2
components/cxx/test_apps/general/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "test_cxx_general.cpp"
|
||||
PRIV_REQUIRES unity test_utils driver)
|
@ -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>();
|
42
components/cxx/test_apps/general/pytest_cxx_general.py
Normal file
42
components/cxx/test_apps/general/pytest_cxx_general.py
Normal 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...')
|
@ -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
|
10
components/cxx/test_apps/general/sdkconfig.defaults
Normal file
10
components/cxx/test_apps/general/sdkconfig.defaults
Normal 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
|
8
components/cxx/test_apps/rtti/CMakeLists.txt
Normal file
8
components/cxx/test_apps/rtti/CMakeLists.txt
Normal 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)
|
2
components/cxx/test_apps/rtti/README.md
Normal file
2
components/cxx/test_apps/rtti/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
3
components/cxx/test_apps/rtti/main/CMakeLists.txt
Normal file
3
components/cxx/test_apps/rtti/main/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "test_rtti.cpp"
|
||||
REQUIRES test_utils
|
||||
PRIV_REQUIRES unity driver)
|
@ -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();
|
||||
}
|
14
components/cxx/test_apps/rtti/pytest_cxx_rtti.py
Normal file
14
components/cxx/test_apps/rtti/pytest_cxx_rtti.py
Normal 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()
|
13
components/cxx/test_apps/rtti/sdkconfig.defaults
Normal file
13
components/cxx/test_apps/rtti/sdkconfig.defaults
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user