Skip to content

Commit 81c0891

Browse files
feat(unity): Adds unit test ordering by file path and line number
Closes #15529
1 parent dc678de commit 81c0891

File tree

10 files changed

+131
-5
lines changed

10 files changed

+131
-5
lines changed

components/unity/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,18 @@ menu "Unity unit testing library"
5858
jumping back to the test menu. The jumping is usually occurs in assert
5959
functions such as TEST_ASSERT, TEST_FAIL etc.
6060

61+
config UNITY_TEST_ORDER_BY_FILE_PATH_AND_LINE
62+
bool "Order unit tests by file path and line number"
63+
default n
64+
help
65+
If enabled, the Unity test framework will automatically insert test cases
66+
in a sorted order at registration time (during constructor execution),
67+
based on their source file path and line number.
68+
69+
This ensures consistent execution order across platforms (e.g., Linux vs. on-chip),
70+
preserving the logical order in which tests are written in the source files.
71+
72+
Note, the file path used for sorting follows the full absolute path format.
73+
/IDF/examples/system/unit_test/components/testable/test/test_mean.c
74+
6175
endmenu # "Unity unit testing library"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
2+
3+
components/unity/test_apps:
4+
enable:
5+
- if: IDF_TARGET in["esp32", "linux"]
6+
reason: need to test on a chip and linux targets
7+
depends_components:
8+
- unity
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#This is the project CMakeLists.txt file for the test subproject
2+
cmake_minimum_required(VERSION 3.16)
3+
4+
set(COMPONENTS main)
5+
6+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
7+
project(unity_test_app)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| Supported Targets | ESP32 | Linux |
2+
| ----------------- | ----- | ----- |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(SRC_DIRS "."
2+
PRIV_REQUIRES unity
3+
WHOLE_ARCHIVE)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include "unity.h"
7+
8+
TEST_CASE("Test 1", "[test]")
9+
{
10+
TEST_ASSERT(1 == 1);
11+
}
12+
13+
TEST_CASE("Test 2", "[test]")
14+
{
15+
TEST_ASSERT(1 == 1);
16+
}
17+
18+
TEST_CASE("Test 3", "[test]")
19+
{
20+
TEST_ASSERT(1 == 1);
21+
}
22+
23+
TEST_CASE("Test 4", "[test]")
24+
{
25+
TEST_ASSERT(1 == 1);
26+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
#include "unity.h"
7+
8+
void app_main(void)
9+
{
10+
unity_run_menu();
11+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-License-Identifier: CC0-1.0
3+
import pytest
4+
from pytest_embedded import Dut
5+
from pytest_embedded_idf.utils import idf_parametrize
6+
7+
8+
def verify_test_order(dut: Dut) -> None:
9+
dut.expect_exact('Press ENTER to see the list of tests.')
10+
dut.write('\n')
11+
dut.expect('Test 1')
12+
dut.expect('Test 2')
13+
dut.expect('Test 3')
14+
dut.expect('Test 4')
15+
16+
17+
@pytest.mark.generic
18+
@idf_parametrize('target', ['esp32'], indirect=['target'])
19+
def test_unit_test_order(dut: Dut) -> None:
20+
verify_test_order(dut)
21+
22+
23+
@pytest.mark.host_test
24+
@idf_parametrize('target', ['linux'], indirect=['target'])
25+
def test_unit_test_order_linux(dut: Dut) -> None:
26+
verify_test_order(dut)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_ESP_TASK_WDT_EN=n
2+
CONFIG_UNITY_TEST_ORDER_BY_FILE_PATH_AND_LINE=y

components/unity/unity_runner.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -11,6 +11,7 @@
1111
#include <stdio.h>
1212
#include "unity.h"
1313
#include "esp_system.h"
14+
#include "sdkconfig.h"
1415

1516
/* similar to UNITY_PRINT_EOL */
1617
#define UNITY_PRINT_TAB() UNITY_OUTPUT_CHAR('\t')
@@ -24,11 +25,37 @@ void unity_testcase_register(test_desc_t *desc)
2425
if (!s_unity_tests_first) {
2526
s_unity_tests_first = desc;
2627
s_unity_tests_last = desc;
27-
} else {
28-
test_desc_t *temp = s_unity_tests_first;
29-
s_unity_tests_first = desc;
30-
s_unity_tests_first->next = temp;
28+
return;
3129
}
30+
#if CONFIG_UNITY_TEST_ORDER_BY_FILE_PATH_AND_LINE
31+
test_desc_t *prev = NULL;
32+
test_desc_t *current = s_unity_tests_first;
33+
34+
while (current) {
35+
int file_cmp = strcmp(desc->file, current->file);
36+
if (file_cmp < 0 || (file_cmp == 0 && desc->line < current->line)) {
37+
// Insert before current
38+
if (prev) {
39+
prev->next = desc;
40+
} else {
41+
// Inserting at the head
42+
s_unity_tests_first = desc;
43+
}
44+
desc->next = current;
45+
return;
46+
}
47+
prev = current;
48+
current = current->next;
49+
}
50+
51+
// Insert at the end
52+
prev->next = desc;
53+
s_unity_tests_last = desc;
54+
#else
55+
// Insert at head (original behavior)
56+
desc->next = s_unity_tests_first;
57+
s_unity_tests_first = desc;
58+
#endif
3259
}
3360

3461
/* print the multiple function case name and its sub-menu

0 commit comments

Comments
 (0)