diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a9efe3fc..6055c0e6 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,3 @@ # ruff, ruff-format 3f0008207d272b7fa4329d86a157f4533f1a441f +a90b0d0c35a8e1c6896130e23c46cedee48b4158 diff --git a/pytest-embedded-arduino/tests/test_arduino.py b/pytest-embedded-arduino/tests/test_arduino.py index 8b3c7302..ee47751f 100644 --- a/pytest-embedded-arduino/tests/test_arduino.py +++ b/pytest-embedded-arduino/tests/test_arduino.py @@ -17,9 +17,12 @@ def test_arduino_app(app, dut): result = testdir.runpytest( '-s', - '--embedded-services', 'arduino,esp', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_arduino'), - '--build-dir', 'build', + '--embedded-services', + 'arduino,esp', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_arduino'), + '--build-dir', + 'build', ) result.assert_outcomes(passed=1) diff --git a/pytest-embedded-idf/pytest_embedded_idf/unity_tester.py b/pytest-embedded-idf/pytest_embedded_idf/unity_tester.py index c5074d19..25e15a39 100644 --- a/pytest-embedded-idf/pytest_embedded_idf/unity_tester.py +++ b/pytest-embedded-idf/pytest_embedded_idf/unity_tester.py @@ -288,7 +288,9 @@ def wrapper(self, *args, **kwargs): finally: _end_at = time.perf_counter() self._add_single_unity_test_case( - _case, _log, additional_attrs={'time': round(_end_at - _start_at, 3)} + _case, + _log, + additional_attrs={'app_path': self.app.app_path, 'time': round(_end_at - _start_at, 3)}, ) return wrapper @@ -695,6 +697,8 @@ def process_raw_report_data(self, raw_data_to_report) -> t.Dict: if log: attrs.update({'stdout': log}) + attrs.update({'app_path': self.dut.app.app_path}) + return attrs def add_to_report(self, attrs): @@ -765,9 +769,6 @@ def gather(self): for _t in self.workers: _t.close() - def get_processed_report_data(self, res: t.List[t.Any]) -> t.List[t.Dict]: - return [self.workers[i].process_raw_report_data(res[i]) for i in range(len(res))] - @staticmethod def get_merge_data(test_cases_attr: t.List[t.Dict]) -> t.Dict: output = {} @@ -794,6 +795,8 @@ def get_merge_data(test_cases_attr: t.List[t.Dict]) -> t.Dict: for k, val in output.items(): if k in ('file', 'line'): output[k] = val[0] + elif k == 'app_path': + output[k] = '|'.join(val) else: output[k] = '<------------------->\n'.join(val) diff --git a/pytest-embedded-idf/tests/test_idf.py b/pytest-embedded-idf/tests/test_idf.py index e14c239a..7a9d8c56 100644 --- a/pytest-embedded-idf/tests/test_idf.py +++ b/pytest-embedded-idf/tests/test_idf.py @@ -28,8 +28,10 @@ def test_idf_serial_flash(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), ) result.assert_outcomes(passed=1) @@ -46,8 +48,10 @@ def test_idf_serial_flash(dut): """) result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), '--esp-flash-force', ) @@ -65,8 +69,10 @@ def test_idf_serial_flash(dut): """) result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), ) result.assert_outcomes(passed=1) @@ -94,8 +100,10 @@ def test_no_matching_word_pass_rest(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), ) result.assert_outcomes(passed=2, failed=2) @@ -122,8 +130,10 @@ def test_no_matching_word_pass_rest(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), ) result.assert_outcomes(passed=2, failed=2) @@ -164,9 +174,12 @@ def test_idf_run_all_single_board_cases(): result = testdir.runpytest( '-s', - '--app-path', p, - '--embedded-services', 'esp,idf', - '--junitxml', 'report.xml', + '--app-path', + p, + '--embedded-services', + 'esp,idf', + '--junitxml', + 'report.xml', ) result.assert_outcomes(passed=4, errors=0) @@ -194,10 +207,14 @@ def test_idf_serial_flash_with_erase_nvs(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), - '--erase-nvs', 'y', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--erase-nvs', + 'y', ) result.assert_outcomes(passed=1) @@ -219,9 +236,12 @@ def test_idf_serial_flash(dut): """) result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), - '--erase-nvs', 'y', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--erase-nvs', + 'y', ) result.assert_outcomes(errors=1) @@ -242,8 +262,10 @@ def test_idf_app(app, dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32c3'), + '--embedded-services', + 'idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32c3'), ) result.assert_outcomes(passed=1) @@ -267,11 +289,12 @@ def test_multi_dut_app(app, dut): result = testdir.runpytest( '-s', - '--count', 2, - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}' - f'|' - f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3")}', - '--embedded-services', 'esp,idf|idf', + '--count', + 2, + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}|{os.path.join(testdir.tmpdir, "hello_world_esp32c3")}', + '--embedded-services', + 'esp,idf|idf', ) result.assert_outcomes(passed=1) @@ -292,13 +315,16 @@ def test_multi_dut_autoflash(app, dut): result = testdir.runpytest( '-s', - '--count', 2, - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}' - f'|' - f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3")}', - '--skip-autoflash', 'y|false', - '--embedded-services', 'esp,idf', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--count', + 2, + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}|{os.path.join(testdir.tmpdir, "hello_world_esp32c3")}', + '--skip-autoflash', + 'y|false', + '--embedded-services', + 'esp,idf', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), ) result.assert_outcomes(passed=1) @@ -319,10 +345,14 @@ def test_autoflash_again(app, dut): result = testdir.runpytest( '-s', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--embedded-services', 'esp,idf', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), - '--log-cli-level', 'DEBUG', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--embedded-services', + 'esp,idf', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--log-cli-level', + 'DEBUG', ) result.assert_outcomes(passed=2) @@ -334,7 +364,7 @@ def test_autoflash_again(app, dut): first_index_of_messages( re.compile(r'^hit port-app cache:.+hello_world_esp32[\\/]build$', re.MULTILINE), caplog.messages, - set_app_cache_i + 1 + set_app_cache_i + 1, ) @@ -353,11 +383,16 @@ def test_autoflash_again(app, dut): result = testdir.runpytest( '-s', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--embedded-services', 'esp,idf', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), - '--log-cli-level', 'DEBUG', - '--confirm-target-elf-sha256', 'y', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--embedded-services', + 'esp,idf', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--log-cli-level', + 'DEBUG', + '--confirm-target-elf-sha256', + 'y', ) result.assert_outcomes(passed=2) @@ -369,7 +404,7 @@ def test_autoflash_again(app, dut): hit_app_cache_i = first_index_of_messages( re.compile(r'^hit port-app cache:.+hello_world_esp32[\\/]build$', re.MULTILINE), caplog.messages, - set_app_cache_i + 1 + set_app_cache_i + 1, ) first_index_of_messages( re.compile(r'Confirmed target elf file sha256 the same as your local one\.$', re.MULTILINE), @@ -379,8 +414,10 @@ def test_autoflash_again(app, dut): def test_different_build_dir(testdir): - os.rename(os.path.join(testdir.tmpdir, 'hello_world_esp32', 'build'), - os.path.join(testdir.tmpdir, 'hello_world_esp32', 'test_new_name')) + os.rename( + os.path.join(testdir.tmpdir, 'hello_world_esp32', 'build'), + os.path.join(testdir.tmpdir, 'hello_world_esp32', 'test_new_name'), + ) testdir.makepyfile(""" import pytest @@ -392,18 +429,24 @@ def test_multi_dut_app(app, dut): result = testdir.runpytest( '-s', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), - '--build-dir', 'test_new_name', - '--embedded-services', 'idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--build-dir', + 'test_new_name', + '--embedded-services', + 'idf', ) result.assert_outcomes(passed=1) result = testdir.runpytest( '-s', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), - '--build-dir', os.path.join(testdir.tmpdir, 'hello_world_esp32', 'test_new_name'), - '--embedded-services', 'idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--build-dir', + os.path.join(testdir.tmpdir, 'hello_world_esp32', 'test_new_name'), + '--embedded-services', + 'idf', ) result.assert_outcomes(passed=1) @@ -430,19 +473,22 @@ def test_multi_dut_read_flash(app, serial, dut): result = testdir.runpytest( '-s', - '--count', 2, - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}' - f'|' - f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3")}', - '--embedded-services', 'esp,idf', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--count', + 2, + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}|{os.path.join(testdir.tmpdir, "hello_world_esp32c3")}', + '--embedded-services', + 'esp,idf', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), ) result.assert_outcomes(passed=1) def test_flash_another_app(testdir): - testdir.makepyfile(r""" + testdir.makepyfile( + r""" import pytest import pexpect @@ -452,13 +498,17 @@ def test_flash_another_app(dut): dut.serial.flash(IdfApp('{}')) dut.expect('Hash of data verified.', timeout=5) dut.expect_exact('Hello world!', timeout=5) - """.format(os.path.join(testdir.tmpdir, 'hello_world_esp32'))) + """.format(os.path.join(testdir.tmpdir, 'hello_world_esp32')) + ) result = testdir.runpytest( '-s', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--embedded-services', 'esp,idf', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--embedded-services', + 'esp,idf', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), ) result.assert_outcomes(passed=1) @@ -478,9 +528,12 @@ def test_flash_with_no_elf_file(dut): result = testdir.runpytest( '-s', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--embedded-services', 'esp,idf', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--embedded-services', + 'esp,idf', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), ) result.assert_outcomes(passed=1) @@ -497,10 +550,14 @@ def test_detect_port(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--target', 'esp32', - '--erase-all', 'y', + '--embedded-services', + 'esp,idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--target', + 'esp32', + '--erase-all', + 'y', ) result.assert_outcomes(passed=1) @@ -517,9 +574,12 @@ def test_detect_port(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--target', 'esp32', + '--embedded-services', + 'esp,idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--target', + 'esp32', ) result.assert_outcomes(passed=1) @@ -540,9 +600,12 @@ def test_hello_world_linux(dut): """) result = testdir.runpytest( '-s', - '--embedded-services', 'idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_linux")}', - '--target', 'linux', + '--embedded-services', + 'idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_linux")}', + '--target', + 'linux', ) result.assert_outcomes(passed=1) @@ -554,15 +617,18 @@ def test_unity_tester_with_linux(testdir): def test_unity_tester_with_linux(dut): dut.run_all_single_board_cases() - """ - ) + """) result = testdir.runpytest( '-s', - '--embedded-services', 'idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "unit_test_app_linux")}', - '--target', 'linux', - '--junitxml', 'report.xml', + '--embedded-services', + 'idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "unit_test_app_linux")}', + '--target', + 'linux', + '--junitxml', + 'report.xml', ) result.assert_outcomes(passed=1) @@ -587,11 +653,16 @@ def test_check_coredump(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3_panic")}', - '--target', 'esp32c3', - '--panic-output-decode-script', os.path.join(testdir.tmpdir, 'gdb_panic_server.py'), - '--log-cli-level', 'INFO', + '--embedded-services', + 'esp,idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3_panic")}', + '--target', + 'esp32c3', + '--panic-output-decode-script', + os.path.join(testdir.tmpdir, 'gdb_panic_server.py'), + '--log-cli-level', + 'INFO', ) first_index_of_messages( re.compile(r'app_main \(\) at /COMPONENT_MAIN_DIR/hello_world_main.c:17', re.MULTILINE), @@ -613,11 +684,16 @@ def test_skip_check_coredump(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3_panic")}', - '--panic-output-decode-script', os.path.join(testdir.tmpdir, 'gdb_panic_server.py'), - '--skip-check-coredump', 'True', - '--log-cli-level', 'INFO', + '--embedded-services', + 'esp,idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32c3_panic")}', + '--panic-output-decode-script', + os.path.join(testdir.tmpdir, 'gdb_panic_server.py'), + '--skip-check-coredump', + 'True', + '--log-cli-level', + 'INFO', ) with pytest.raises(AssertionError): first_index_of_messages( @@ -629,14 +705,14 @@ def test_skip_check_coredump(dut): def test_idf_parse_test_menu(): - s = '''(1)\t"adc1 and i2s work with wifi" [adc][ignore] + s = """(1)\t"adc1 and i2s work with wifi" [adc][ignore] (2)\t"I2C master write slave test" [i2c][test_env=UT_T2_I2C][timeout=150][multi_device] \t(1)\t"i2c_master_write_test" \t(2)\t"i2c_slave_read_test" (3)\t"LEDC continue work after software reset" [ledc][multi_stage] \t(1)\t"ledc_cpu_reset_test_first_stage" \t(2)\t"ledc_cpu_reset_test_second_stage" -''' +""" test_menu = IdfDut._parse_unity_menu_from_str(s) assert len(test_menu) == 3 @@ -674,9 +750,12 @@ def test_idf_hard_reset_and_expect(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--log-cli-level', 'DEBUG', + '--embedded-services', + 'esp,idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--log-cli-level', + 'DEBUG', ) result.assert_outcomes(passed=1) @@ -685,65 +764,37 @@ def test_idf_hard_reset_and_expect(dut): def test_select_to_run(): from pytest_embedded_idf.unity_tester import IdfUnityDutMixin - assert IdfUnityDutMixin._select_to_run( - None, None, None, - None, None, None - ) + assert IdfUnityDutMixin._select_to_run(None, None, None, None, None, None) - assert IdfUnityDutMixin._select_to_run( - None, ['name_hello', 'name_world'], None, - None, 'name_hello', None - ) + assert IdfUnityDutMixin._select_to_run(None, ['name_hello', 'name_world'], None, None, 'name_hello', None) - assert not IdfUnityDutMixin._select_to_run( - None, ['name_hello', 'name_world'], None, - None, 'name_hel', None - ) + assert not IdfUnityDutMixin._select_to_run(None, ['name_hello', 'name_world'], None, None, 'name_hel', None) - assert IdfUnityDutMixin._select_to_run( - None, None, {"red": 255}, - None, None, {"red": 255, "green": 10, "blue": 33} - ) + assert IdfUnityDutMixin._select_to_run(None, None, {'red': 255}, None, None, {'red': 255, 'green': 10, 'blue': 33}) assert not IdfUnityDutMixin._select_to_run( - None, None, {"red": 25}, - None, None, {"red": 255, "green": 10, "blue": 33} + None, None, {'red': 25}, None, None, {'red': 255, 'green': 10, 'blue': 33} ) assert IdfUnityDutMixin._select_to_run( - None, None, {"red": 255, "green": 10}, - None, None, {"red": 255, "green": 10, "blue": 33} + None, None, {'red': 255, 'green': 10}, None, None, {'red': 255, 'green': 10, 'blue': 33} ) assert not IdfUnityDutMixin._select_to_run( - None, None, {"red": 255, "green": 0}, - None, None, {"red": 255, "green": 10, "blue": 33} + None, None, {'red': 255, 'green': 0}, None, None, {'red': 255, 'green': 10, 'blue': 33} ) - assert IdfUnityDutMixin._select_to_run( - [['hello']], None, None, - ['hello', 'world'], None, None - ) + assert IdfUnityDutMixin._select_to_run([['hello']], None, None, ['hello', 'world'], None, None) - assert not IdfUnityDutMixin._select_to_run( - [['!hello']], None, None, - ['hello', 'world'], None, None - ) + assert not IdfUnityDutMixin._select_to_run([['!hello']], None, None, ['hello', 'world'], None, None) - assert not IdfUnityDutMixin._select_to_run( - [['hello', '!world']], None, None, - ['hello', 'world'], None, None - ) + assert not IdfUnityDutMixin._select_to_run([['hello', '!world']], None, None, ['hello', 'world'], None, None) assert IdfUnityDutMixin._select_to_run( - [['hello', '!world'], ['sun']], None, None, - ['hello', 'world', 'sun'], None, None + [['hello', '!world'], ['sun']], None, None, ['hello', 'world', 'sun'], None, None ) - assert IdfUnityDutMixin._select_to_run( - [['hello', '!w']], None, None, - ['hello', 'world'], None, None - ) + assert IdfUnityDutMixin._select_to_run([['hello', '!w']], None, None, ['hello', 'world'], None, None) def test_dut_run_all_single_board_cases(testdir): @@ -753,10 +804,14 @@ def test_dut_run_all_single_board_cases(dut): """) testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32c3'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32c3'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -787,10 +842,14 @@ def test_dut_run_all_single_board_cases(dut): """) testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -799,6 +858,10 @@ def test_dut_run_all_single_board_cases(dut): assert junit_report.attrib['failures'] == '1' assert junit_report.attrib['skipped'] == '0' assert junit_report.attrib['tests'] == '1' + cases = junit_report.findall('.//testcase') + assert len(cases) == 2 + assert cases[0].attrib['app_path'] == os.path.join(testdir.tmpdir, 'unit_test_app_esp32') + assert cases[1].attrib['app_path'] == os.path.join(testdir.tmpdir, 'unit_test_app_esp32') def test_dut_run_all_single_board_cases_invert_group(testdir): @@ -808,10 +871,14 @@ def test_dut_run_all_single_board_cases(dut): """) testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -829,10 +896,14 @@ def test_dut_run_all_single_board_cases(dut): """) testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -851,13 +922,18 @@ def test_unity_test_case_runner(unity_tester): testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--count', 2, - '--app-path', f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32")}' - f'|' - f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32c3")}', - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml' + '--embedded-services', + 'esp,idf', + '--count', + 2, + '--app-path', + f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32")}' + f'|' + f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32c3")}', + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -867,14 +943,24 @@ def test_unity_test_case_runner(unity_tester): assert junit_report.attrib['skipped'] == '0' assert junit_report.attrib['tests'] == '3' + # single-dut app_path should be the dut[0] one assert junit_report[0].get('name') == 'normal_case1' assert junit_report[0].find('failure') is None + assert junit_report[0].get('app_path') == os.path.join(testdir.tmpdir, 'unit_test_app_esp32') assert junit_report[1].get('name') == 'normal_case2' assert junit_report[1].find('failure') is not None + assert junit_report[1].get('app_path') == os.path.join(testdir.tmpdir, 'unit_test_app_esp32') assert junit_report[2].get('name') == 'multiple_stages_test' assert junit_report[2].find('failure') is None + assert junit_report[2].get('app_path') == os.path.join(testdir.tmpdir, 'unit_test_app_esp32') + # multi-dut app_path should be concatenated assert junit_report[3].get('name') == 'multiple_devices_test' assert junit_report[3].find('failure') is None + assert ( + junit_report[3].get('app_path') == f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32")}' + f'|' + f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32c3")}' + ) def test_erase_all_with_port_cache(testdir): @@ -890,10 +976,14 @@ def test_erase_all_with_port_cache_case2(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', - '--target', 'esp32', - '--erase-all', 'y', + '--embedded-services', + 'esp,idf', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}', + '--target', + 'esp32', + '--erase-all', + 'y', ) result.assert_outcomes(passed=2) @@ -907,10 +997,14 @@ def test_python_case(dut): testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -919,6 +1013,7 @@ def test_python_case(dut): for testcase in junit_report.findall('testcase'): assert testcase.attrib['is_unity_case'] == '1' + def test_preserve_python_tests(testdir): testdir.makepyfile(r""" def test_python_case(dut): @@ -927,11 +1022,16 @@ def test_python_case(dut): testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', - '--unity-test-report-mode', 'merge', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', + '--unity-test-report-mode', + 'merge', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -950,11 +1050,16 @@ def test_python_case(dut): testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', - '--unity-test-report-mode', 'merge', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', + '--unity-test-report-mode', + 'merge', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -975,11 +1080,16 @@ def test_python_case(dut): testdir.runpytest( '-s', - '--embedded-services', 'esp,idf', - '--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), - '--log-cli-level', 'DEBUG', - '--junitxml', 'report.xml', - '--unity-test-report-mode', 'merge', + '--embedded-services', + 'esp,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'unit_test_app_esp32'), + '--log-cli-level', + 'DEBUG', + '--junitxml', + 'report.xml', + '--unity-test-report-mode', + 'merge', ) junit_report = ET.parse('report.xml').getroot()[0] @@ -988,9 +1098,11 @@ def test_python_case(dut): for testcase in junit_report[1:]: assert testcase.attrib['is_unity_case'] == '1' # Other test cases -def test_esp_bool_parser_returned_values(testdir, copy_mock_esp_idf, monkeypatch): # noqa: ARG001 + +def test_esp_bool_parser_returned_values(testdir, copy_mock_esp_idf, monkeypatch): # noqa: ARG001 monkeypatch.setenv('IDF_PATH', str(testdir)) from esp_bool_parser import SOC_HEADERS, SUPPORTED_TARGETS + assert SOC_HEADERS == { 'esp32': {'SOC_A': 0, 'SOC_B': 1, 'SOC_C': 0}, 'esp32s2': {'SOC_A': 0, 'SOC_B': 0, 'SOC_C': 0}, @@ -1003,12 +1115,12 @@ def test_esp_bool_parser_returned_values(testdir, copy_mock_esp_idf, monkeypatch 'linux': {}, 'esp32c5': {'SOC_A': 1, 'SOC_B': 1, 'SOC_C': 0}, 'esp32c61': {'SOC_A': 0, 'SOC_B': 0, 'SOC_C': 1}, - 'esp32h21': {'SOC_A': 0, 'SOC_B': 0, 'SOC_C': 0} + 'esp32h21': {'SOC_A': 0, 'SOC_B': 0, 'SOC_C': 0}, } assert SUPPORTED_TARGETS == ['esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4'] -def test_skip_if_soc(testdir, copy_mock_esp_idf, monkeypatch): # noqa: ARG001 +def test_skip_if_soc(testdir, copy_mock_esp_idf, monkeypatch): # noqa: ARG001 monkeypatch.setenv('IDF_PATH', str(testdir)) from esp_bool_parser import SOC_HEADERS, SUPPORTED_TARGETS @@ -1028,13 +1140,15 @@ def test_skip_if_for_condition(): result = testdir.runpytest('-s', '--embedded-services', 'esp,idf') result.assert_outcomes(passed=to_pass, skipped=to_skip) - for c, cf in [ ('SOC_A == 1', lambda h: h['SOC_A'] == 1), ('SOC_A == 1 or SOC_B == 1', lambda h: h['SOC_A'] == 1 or h['SOC_B'] == 1), ('SOC_A == 1 and SOC_B == 1', lambda h: h['SOC_A'] == 1 and h['SOC_B'] == 1), ('SOC_A == 1 or SOC_B == 1 and SOC_C == 1', lambda h: h['SOC_A'] == 1 or (h['SOC_B'] == 1 and h['SOC_C'] == 1)), - ('SOC_A == 1 and SOC_B == 0 or SOC_C == 1 ', lambda h: (h['SOC_A'] == 1 and h['SOC_B'] == 0) or h['SOC_C'] == 1), # noqa: E501 + ( + 'SOC_A == 1 and SOC_B == 0 or SOC_C == 1 ', + lambda h: (h['SOC_A'] == 1 and h['SOC_B'] == 0) or h['SOC_C'] == 1, + ), ]: run_test_for_condition(c, cf) @@ -1044,7 +1158,7 @@ def test_skip_if_soc_target_in_args(testdir, copy_mock_esp_idf, monkeypatch): # def run_pytest_with_target(target): count = len(target.split('|')) - return testdir.runpytest( '--embedded-services', 'esp,idf', '--target', target, '--count', count) + return testdir.runpytest('--embedded-services', 'esp,idf', '--target', target, '--count', count) testdir.makepyfile(""" import pytest diff --git a/pytest-embedded-jtag/tests/test_jtag.py b/pytest-embedded-jtag/tests/test_jtag.py index 4566c42f..77f06f02 100644 --- a/pytest-embedded-jtag/tests/test_jtag.py +++ b/pytest-embedded-jtag/tests/test_jtag.py @@ -4,7 +4,7 @@ jtag_connection_required = pytest.mark.skipif( os.getenv('DONT_SKIP_JTAG_TESTS', False) is False, - reason='Connect the board to a JTAG adapter then ' 'use "DONT_SKIP_JTAG_TESTS" to run this test.', + reason='Connect the board to a JTAG adapter then use "DONT_SKIP_JTAG_TESTS" to run this test.', ) @@ -24,10 +24,14 @@ def test_pexpect_by_jtag(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'jtag,idf', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), - '--port', '/dev/ttyUSB1', - '--part-tool', os.path.join(testdir.tmpdir, 'gen_esp32part.py'), + '--embedded-services', + 'jtag,idf', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--port', + '/dev/ttyUSB1', + '--part-tool', + os.path.join(testdir.tmpdir, 'gen_esp32part.py'), ) result.assert_outcomes(passed=1) diff --git a/pytest-embedded-nuttx/tests/test_nuttx.py b/pytest-embedded-nuttx/tests/test_nuttx.py index f9b49c0d..6383f3b6 100644 --- a/pytest-embedded-nuttx/tests/test_nuttx.py +++ b/pytest-embedded-nuttx/tests/test_nuttx.py @@ -27,9 +27,12 @@ def test_hello(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'nuttx,esp', - '--target', 'esp32', - '--app-path', os.path.join(testdir.tmpdir, "hello_world_nuttx") + '--embedded-services', + 'nuttx,esp', + '--target', + 'esp32', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_nuttx'), ) result.assert_outcomes(passed=3) @@ -59,9 +62,12 @@ def test_hello_mcuboot(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'nuttx,esp', - '--target', 'esp32', - '--app-path', os.path.join(testdir.tmpdir, "hello_world_nuttx_mcuboot") + '--embedded-services', + 'nuttx,esp', + '--target', + 'esp32', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_nuttx_mcuboot'), ) result.assert_outcomes(passed=3) @@ -70,9 +76,10 @@ def test_hello_mcuboot(dut): qemu_bin_required = pytest.mark.skipif( shutil.which('qemu-system-xtensa') is None, reason='Please make sure that `qemu-system-xtensa` is in your PATH env var. Build QEMU for ESP32 locally and then ' - 'run `pytest` again' + 'run `pytest` again', ) + @qemu_bin_required def test_nuttx_app_qemu(testdir): testdir.makepyfile(""" @@ -86,19 +93,25 @@ def test_nuttx_app_qemu(dut): dut.expect("console") """) - efuse_path = os.path.join(testdir.tmpdir, "hello_world_nuttx_qemu", "qemu_efuse.bin") + efuse_path = os.path.join(testdir.tmpdir, 'hello_world_nuttx_qemu', 'qemu_efuse.bin') qemu_extra = f'-drive file={efuse_path},if=none,format=raw,id=efuse ' qemu_extra += '-global driver=nvram.esp32.efuse,property=drive,value=efuse' print(qemu_extra) result = testdir.runpytest( '-s', - '--embedded-services', 'nuttx,qemu', - '--target', 'esp32', - '--app-path', os.path.join(testdir.tmpdir, "hello_world_nuttx_qemu"), - '--qemu-image-path', os.path.join(testdir.tmpdir, "hello_world_nuttx_qemu", "nuttx.merged.bin"), - '--qemu-extra-args', qemu_extra, - '--qemu-prog-path', 'qemu-system-xtensa', + '--embedded-services', + 'nuttx,qemu', + '--target', + 'esp32', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_nuttx_qemu'), + '--qemu-image-path', + os.path.join(testdir.tmpdir, 'hello_world_nuttx_qemu', 'nuttx.merged.bin'), + '--qemu-extra-args', + qemu_extra, + '--qemu-prog-path', + 'qemu-system-xtensa', ) result.assert_outcomes(passed=1) diff --git a/pytest-embedded-qemu/tests/test_qemu.py b/pytest-embedded-qemu/tests/test_qemu.py index 7b0b3625..53d25f7b 100644 --- a/pytest-embedded-qemu/tests/test_qemu.py +++ b/pytest-embedded-qemu/tests/test_qemu.py @@ -7,7 +7,7 @@ qemu_bin_required = pytest.mark.skipif( shutil.which('qemu-system-xtensa') is None, reason='Please make sure that `qemu-system-xtensa` is in your PATH env var. Build QEMU for ESP32 locally and then ' - 'run `pytest` again' + 'run `pytest` again', ) @@ -26,8 +26,10 @@ def test_pexpect_by_qemu(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf,qemu', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'idf,qemu', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), ) result.assert_outcomes(passed=1) @@ -51,8 +53,10 @@ def test_pexpect_by_qemu(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf,qemu', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'idf,qemu', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), '--qemu-cli-args="-machine esp32 -nographic"', ) @@ -74,8 +78,10 @@ def test_pexpect_by_qemu(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf,qemu', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32c3'), + '--embedded-services', + 'idf,qemu', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32c3'), ) result.assert_outcomes(passed=1) @@ -94,10 +100,14 @@ def test_pexpect_by_qemu(dut): result = testdir.runpytest( '-s', - '--count', 2, - '--embedded-services', 'idf,qemu|qemu', - '--app-path', f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}|', - '--qemu-image-path', f'|{os.path.join(testdir.tmpdir, "esp32_qemu.bin")}', + '--count', + 2, + '--embedded-services', + 'idf,qemu|qemu', + '--app-path', + f'{os.path.join(testdir.tmpdir, "hello_world_esp32")}|', + '--qemu-image-path', + f'|{os.path.join(testdir.tmpdir, "esp32_qemu.bin")}', ) result.assert_outcomes(passed=1) @@ -122,12 +132,17 @@ def test_pexpect_by_qemu(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf,qemu', - '--app-path', app_path, - '--qemu-extra-args', f'-drive file={efuses_path},if=none,format=raw,id=efuse' + '--embedded-services', + 'idf,qemu', + '--app-path', + app_path, + '--qemu-extra-args', + f'-drive file={efuses_path},if=none,format=raw,id=efuse' ' -global driver=nvram.esp32.efuse,property=drive,value=efuse', - '--encrypt', 'true', - '--keyfile', keyfile_path, + '--encrypt', + 'true', + '--keyfile', + keyfile_path, ) result.assert_outcomes(passed=1) @@ -145,9 +160,12 @@ def test_qemu_use_idf_mixin_methods(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf,qemu', - '--app-path', f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32")}', - '--junitxml', 'report.xml', + '--embedded-services', + 'idf,qemu', + '--app-path', + f'{os.path.join(testdir.tmpdir, "unit_test_app_esp32")}', + '--junitxml', + 'report.xml', ) result.assert_outcomes(failed=1) diff --git a/pytest-embedded-serial-esp/tests/test_esp.py b/pytest-embedded-serial-esp/tests/test_esp.py index 4b729bf2..baf21921 100644 --- a/pytest-embedded-serial-esp/tests/test_esp.py +++ b/pytest-embedded-serial-esp/tests/test_esp.py @@ -14,9 +14,12 @@ def test_detect_port(dut): result = testdir.runpytest( '-s', - '--count', 2, - '--embedded-services', 'esp', - '--target', 'esp32s2|esp32', + '--count', + 2, + '--embedded-services', + 'esp', + '--target', + 'esp32s2|esp32', ) result.assert_outcomes(passed=1) @@ -37,10 +40,14 @@ def test_detect_port_again(dut): result = testdir.runpytest( '-s', - '--count', 2, - '--embedded-services', 'esp', - '--target', 'esp32s2|esp32', - '--log-cli-level', 'DEBUG', + '--count', + 2, + '--embedded-services', + 'esp', + '--target', + 'esp32s2|esp32', + '--log-cli-level', + 'DEBUG', ) result.assert_outcomes(passed=2) @@ -77,9 +84,12 @@ def test_empty_port_target_cache_after_init_devices(port_target_cache): """) result = testdir.runpytest( '-s', - '--embedded-services', 'esp', - '--cache-dir', './cache-test', - '--count', '2', + '--embedded-services', + 'esp', + '--cache-dir', + './cache-test', + '--count', + '2', ) result.assert_outcomes(passed=3) @@ -91,8 +101,11 @@ def test_load_local_saved_port_target_cache(port_target_cache): """) result = testdir.runpytest( '-s', - '--embedded-services', 'esp', - '--cache-dir', './cache-test', - '--count', '2', + '--embedded-services', + 'esp', + '--cache-dir', + './cache-test', + '--count', + '2', ) result.assert_outcomes(passed=1) diff --git a/pytest-embedded-serial/tests/test_serial.py b/pytest-embedded-serial/tests/test_serial.py index 49b12ecb..de395d4e 100644 --- a/pytest-embedded-serial/tests/test_serial.py +++ b/pytest-embedded-serial/tests/test_serial.py @@ -27,8 +27,10 @@ def test_custom_dut(): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,serial', - '--count', 2, + '--embedded-services', + 'esp,serial', + '--count', + 2, ) result.assert_outcomes(passed=2, errors=0) @@ -55,8 +57,10 @@ def test_serial_device_created_dut_count_1(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'esp,serial', - '--count', 1, + '--embedded-services', + 'esp,serial', + '--count', + 1, ) result.assert_outcomes(passed=1, errors=0) @@ -81,8 +85,10 @@ def test_serial_port(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'serial', - '--port', 'socket://localhost:9876', + '--embedded-services', + 'serial', + '--port', + 'socket://localhost:9876', ) result.assert_outcomes(passed=1) diff --git a/pytest-embedded-wokwi/tests/test_wokwi.py b/pytest-embedded-wokwi/tests/test_wokwi.py index c1e10228..60843724 100644 --- a/pytest-embedded-wokwi/tests/test_wokwi.py +++ b/pytest-embedded-wokwi/tests/test_wokwi.py @@ -6,12 +6,12 @@ wokwi_cli_required = pytest.mark.skipif( shutil.which('wokwi-cli') is None, reason='Please make sure that `wokwi-cli` is in your PATH env var. ' - + 'To install: https://docs.wokwi.com/wokwi-ci/getting-started#cli-installation' + + 'To install: https://docs.wokwi.com/wokwi-ci/getting-started#cli-installation', ) wokwi_token_required = pytest.mark.skipif( os.getenv('WOKWI_CLI_TOKEN') is None, - reason='Please make sure that `WOKWI_CLI_TOKEN` env var is set. Get a token here: https://wokwi.com/dashboard/ci' + reason='Please make sure that `WOKWI_CLI_TOKEN` env var is set. Get a token here: https://wokwi.com/dashboard/ci', ) @@ -31,8 +31,10 @@ def test_pexpect_by_wokwi(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'idf,wokwi', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + '--embedded-services', + 'idf,wokwi', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_esp32'), ) result.assert_outcomes(passed=1) @@ -52,9 +54,12 @@ def test_pexpect_by_wokwi(dut): result = testdir.runpytest( '-s', - '--embedded-services', 'arduino,wokwi', - '--app-path', os.path.join(testdir.tmpdir, 'hello_world_arduino'), - '--wokwi-diagram', os.path.join(testdir.tmpdir, 'hello_world_arduino/esp32.diagram.json'), + '--embedded-services', + 'arduino,wokwi', + '--app-path', + os.path.join(testdir.tmpdir, 'hello_world_arduino'), + '--wokwi-diagram', + os.path.join(testdir.tmpdir, 'hello_world_arduino/esp32.diagram.json'), ) result.assert_outcomes(passed=1) diff --git a/pytest-embedded/pytest_embedded/dut.py b/pytest-embedded/pytest_embedded/dut.py index 5a3a573c..a7583fa3 100644 --- a/pytest-embedded/pytest_embedded/dut.py +++ b/pytest-embedded/pytest_embedded/dut.py @@ -203,7 +203,12 @@ def expect_unity_test_output( if remove_asci_escape_code: log = remove_asci_color_code(log) - self.testsuite.add_unity_test_cases(log) + self.testsuite.add_unity_test_cases( + log, + additional_attrs={ + 'app_path': self.app.app_path, + }, + ) @_InjectMixinCls.require_services('idf') def run_all_single_board_cases( diff --git a/pytest-embedded/pytest_embedded/plugin.py b/pytest-embedded/pytest_embedded/plugin.py index 1c568352..9859cdae 100644 --- a/pytest-embedded/pytest_embedded/plugin.py +++ b/pytest-embedded/pytest_embedded/plugin.py @@ -1377,7 +1377,7 @@ def pytest_sessionfinish(self, session: Session, exitstatus: int) -> None: _stash_session_tempdir = session.config.stash.get(_session_tempdir_key, None) _stash_junit_report_path = session.config.stash.get(_junit_report_path_key, None) if _stash_session_tempdir is not None: - modifier.merge(find_by_suffix('.xml', _stash_session_tempdir)) + modifier.merge(sorted(find_by_suffix('.xml', _stash_session_tempdir))) if _stash_junit_report_path: # before we only modified the junit report generated by the unity test cases diff --git a/pytest-embedded/tests/test_base.py b/pytest-embedded/tests/test_base.py index 7f4e9553..b322e725 100644 --- a/pytest-embedded/tests/test_base.py +++ b/pytest-embedded/tests/test_base.py @@ -457,26 +457,33 @@ def test_expect_unity_test_output_multi_dut_with_illegal_chars(testdir): import pytest import inspect - output = inspect.cleandoc( + output1 = inspect.cleandoc( u''' - TEST(group, test_case)foo.c:100::FAIL:Expected 2 \x00 was 1 + TEST(group, test_case_1)foo.c:100::FAIL:Expected 2 \x00 was 1 ------------------- 4 Tests 3 Failures 0 Ignored FAIL ''') + output2 = inspect.cleandoc( + u''' + TEST(group, test_case_2)foo.c:100::FAIL:Expected 2 \x00 was 1 + ------------------- + 5 Tests 2 Failures 0 Ignored + FAIL + ''') @pytest.mark.parametrize('count', [2], indirect=True) def test_expect_unity_test_output_multi_dut_with_illegal_chars(dut): dut_0 = dut[0] dut_1 = dut[1] - dut_0.write(output) - dut_1.write(output) + dut_0.write(output1) + dut_1.write(output2) dut_0.expect_unity_test_output() dut_1.expect_unity_test_output() """) - result = testdir.runpytest('--junitxml', 'report.xml') + result = testdir.runpytest('--app-path', f'{testdir.tmpdir}/foo|{testdir.tmpdir}/bar', '--junitxml', 'report.xml') try: result.assert_outcomes(failed=1) @@ -490,10 +497,12 @@ def test_expect_unity_test_output_multi_dut_with_illegal_chars(dut): assert junit_report.attrib['skipped'] == '0' assert junit_report.attrib['tests'] == '2' - assert junit_report[0].get('name') == 'test_case' + assert junit_report[0].get('name') == 'test_case_1' assert junit_report[0].find('failure') is not None - assert junit_report[1].get('name') == 'test_case' + assert junit_report[0].get('app_path') == f'{testdir.tmpdir}/foo' + assert junit_report[1].get('name') == 'test_case_2' assert junit_report[1].find('failure') is not None + assert junit_report[1].get('app_path') == f'{testdir.tmpdir}/bar' def test_expect_before_match(testdir):