feat(unity): Adds unit test ordering by file path and line number

Closes https://github.com/espressif/esp-idf/issues/15529
This commit is contained in:
Konstantin Kondrashov
2025-04-22 13:09:52 +03:00
parent dc678decf7
commit 81c08911f0
10 changed files with 131 additions and 5 deletions

View File

@ -58,4 +58,18 @@ menu "Unity unit testing library"
jumping back to the test menu. The jumping is usually occurs in assert
functions such as TEST_ASSERT, TEST_FAIL etc.
config UNITY_TEST_ORDER_BY_FILE_PATH_AND_LINE
bool "Order unit tests by file path and line number"
default n
help
If enabled, the Unity test framework will automatically insert test cases
in a sorted order at registration time (during constructor execution),
based on their source file path and line number.
This ensures consistent execution order across platforms (e.g., Linux vs. on-chip),
preserving the logical order in which tests are written in the source files.
Note, the file path used for sorting follows the full absolute path format.
/IDF/examples/system/unit_test/components/testable/test/test_mean.c
endmenu # "Unity unit testing library"

View File

@ -0,0 +1,8 @@
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
components/unity/test_apps:
enable:
- if: IDF_TARGET in["esp32", "linux"]
reason: need to test on a chip and linux targets
depends_components:
- unity

View File

@ -0,0 +1,7 @@
#This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(unity_test_app)

View File

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

View File

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES unity
WHOLE_ARCHIVE)

View File

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
TEST_CASE("Test 1", "[test]")
{
TEST_ASSERT(1 == 1);
}
TEST_CASE("Test 2", "[test]")
{
TEST_ASSERT(1 == 1);
}
TEST_CASE("Test 3", "[test]")
{
TEST_ASSERT(1 == 1);
}
TEST_CASE("Test 4", "[test]")
{
TEST_ASSERT(1 == 1);
}

View File

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity.h"
void app_main(void)
{
unity_run_menu();
}

View File

@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
def verify_test_order(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests.')
dut.write('\n')
dut.expect('Test 1')
dut.expect('Test 2')
dut.expect('Test 3')
dut.expect('Test 4')
@pytest.mark.generic
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_unit_test_order(dut: Dut) -> None:
verify_test_order(dut)
@pytest.mark.host_test
@idf_parametrize('target', ['linux'], indirect=['target'])
def test_unit_test_order_linux(dut: Dut) -> None:
verify_test_order(dut)

View File

@ -0,0 +1,2 @@
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_UNITY_TEST_ORDER_BY_FILE_PATH_AND_LINE=y

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -11,6 +11,7 @@
#include <stdio.h>
#include "unity.h"
#include "esp_system.h"
#include "sdkconfig.h"
/* similar to UNITY_PRINT_EOL */
#define UNITY_PRINT_TAB() UNITY_OUTPUT_CHAR('\t')
@ -24,11 +25,37 @@ void unity_testcase_register(test_desc_t *desc)
if (!s_unity_tests_first) {
s_unity_tests_first = desc;
s_unity_tests_last = desc;
} else {
test_desc_t *temp = s_unity_tests_first;
s_unity_tests_first = desc;
s_unity_tests_first->next = temp;
return;
}
#if CONFIG_UNITY_TEST_ORDER_BY_FILE_PATH_AND_LINE
test_desc_t *prev = NULL;
test_desc_t *current = s_unity_tests_first;
while (current) {
int file_cmp = strcmp(desc->file, current->file);
if (file_cmp < 0 || (file_cmp == 0 && desc->line < current->line)) {
// Insert before current
if (prev) {
prev->next = desc;
} else {
// Inserting at the head
s_unity_tests_first = desc;
}
desc->next = current;
return;
}
prev = current;
current = current->next;
}
// Insert at the end
prev->next = desc;
s_unity_tests_last = desc;
#else
// Insert at head (original behavior)
desc->next = s_unity_tests_first;
s_unity_tests_first = desc;
#endif
}
/* print the multiple function case name and its sub-menu