From 3bc0e74e6e276a8cdef52c2f11a7eb185446533b Mon Sep 17 00:00:00 2001 From: Predrag Radenkovic Date: Sat, 18 Jul 2026 19:17:39 +0200 Subject: [PATCH 1/2] add fetch_all_existing_conformance_test_files helper to ConformanceTests --- render_machine/conformance_tests.py | 20 ++++++++ tests/test_conformance_tests.py | 78 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 tests/test_conformance_tests.py diff --git a/render_machine/conformance_tests.py b/render_machine/conformance_tests.py index 520980a1..6bce88c5 100644 --- a/render_machine/conformance_tests.py +++ b/render_machine/conformance_tests.py @@ -144,6 +144,26 @@ def store_conformance_tests_files( style=console.OUTPUT_STYLE, ) + def fetch_all_existing_conformance_test_files(self, module_name: str) -> dict[str, str]: + """Fetch the content of all existing conformance test files of the module. + + Files are collected from every conformance test subfolder of the module (one subfolder + per functional requirement) and keyed as "/" so each + file's suite remains identifiable. Hidden subfolders (copies of required modules' tests) + and the conformance tests definition file (stored at the module folder root) are not + included. Returns an empty dict when the module has no conformance tests yet. + """ + all_files_content: dict[str, str] = {} + module_folder = self.get_module_conformance_tests_folder(module_name) + for folder_name in sorted(self.fetch_existing_conformance_test_folder_names(module_name)): + folder_path = os.path.join(module_folder, folder_name) + file_names = file_utils.list_all_text_files(folder_path) + files_content = file_utils.get_existing_files_content(folder_path, file_names) + for file_name, content in files_content.items(): + all_files_content[os.path.join(folder_name, file_name)] = content + + return all_files_content + def fetch_existing_conformance_test_files( self, module_name: str, diff --git a/tests/test_conformance_tests.py b/tests/test_conformance_tests.py new file mode 100644 index 00000000..69d75222 --- /dev/null +++ b/tests/test_conformance_tests.py @@ -0,0 +1,78 @@ +import json +import os +import tempfile + +import pytest + +from render_machine.conformance_tests import CONFORMANCE_TESTS_DEFINITION_FILE_NAME, ConformanceTests + +MODULE_NAME = "my_module" + + +@pytest.fixture +def conformance_tests_dir(): + with tempfile.TemporaryDirectory() as d: + yield d + + +@pytest.fixture +def conformance_tests(conformance_tests_dir): + return ConformanceTests(conformance_tests_dir, CONFORMANCE_TESTS_DEFINITION_FILE_NAME) + + +def _write_file(base_dir, relative_path, content): + full_path = os.path.join(base_dir, relative_path) + os.makedirs(os.path.dirname(full_path), exist_ok=True) + with open(full_path, "w") as f: + f.write(content) + + +def test_fetch_all_existing_conformance_test_files_empty_when_module_folder_missing(conformance_tests): + assert conformance_tests.fetch_all_existing_conformance_test_files(MODULE_NAME) == {} + + +def test_fetch_all_existing_conformance_test_files_multiple_folders(conformance_tests, conformance_tests_dir): + module_folder = os.path.join(conformance_tests_dir, MODULE_NAME) + _write_file(module_folder, os.path.join("first_functionality", "test_first.py"), "first test") + _write_file(module_folder, os.path.join("second_functionality", "test_second.py"), "second test") + _write_file(module_folder, os.path.join("second_functionality", "helpers", "util.py"), "helper") + + files_content = conformance_tests.fetch_all_existing_conformance_test_files(MODULE_NAME) + + assert files_content == { + os.path.join("first_functionality", "test_first.py"): "first test", + os.path.join("second_functionality", "test_second.py"): "second test", + os.path.join("second_functionality", "helpers", "util.py"): "helper", + } + + +def test_fetch_all_existing_conformance_test_files_excludes_hidden_folders(conformance_tests, conformance_tests_dir): + module_folder = os.path.join(conformance_tests_dir, MODULE_NAME) + _write_file(module_folder, os.path.join("own_functionality", "test_own.py"), "own test") + _write_file(module_folder, os.path.join(".required_module", "some_frid", "test_required.py"), "required test") + + files_content = conformance_tests.fetch_all_existing_conformance_test_files(MODULE_NAME) + + assert files_content == {os.path.join("own_functionality", "test_own.py"): "own test"} + + +def test_fetch_all_existing_conformance_test_files_excludes_definition_file(conformance_tests, conformance_tests_dir): + module_folder = os.path.join(conformance_tests_dir, MODULE_NAME) + _write_file(module_folder, os.path.join("some_functionality", "test_some.py"), "some test") + _write_file(module_folder, CONFORMANCE_TESTS_DEFINITION_FILE_NAME, json.dumps({"frid": {}})) + + files_content = conformance_tests.fetch_all_existing_conformance_test_files(MODULE_NAME) + + assert files_content == {os.path.join("some_functionality", "test_some.py"): "some test"} + + +def test_fetch_all_existing_conformance_test_files_skips_binary_files(conformance_tests, conformance_tests_dir): + module_folder = os.path.join(conformance_tests_dir, MODULE_NAME) + _write_file(module_folder, os.path.join("some_functionality", "test_some.py"), "some test") + binary_file_path = os.path.join(module_folder, "some_functionality", "fixture.bin") + with open(binary_file_path, "wb") as f: + f.write(b"\x89PNG\r\n\x1a\n\x00\x00\xff\xfe\xfd") + + files_content = conformance_tests.fetch_all_existing_conformance_test_files(MODULE_NAME) + + assert files_content == {os.path.join("some_functionality", "test_some.py"): "some test"} From b074d00e863f133a03670f4826d4a262c7fa4102 Mon Sep 17 00:00:00 2001 From: Predrag Radenkovic Date: Sat, 18 Jul 2026 20:06:54 +0200 Subject: [PATCH 2/2] send existing conformance test files as context when rendering conformance tests --- codeplain_REST_api.py | 2 ++ render_machine/actions/render_conformance_tests.py | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/codeplain_REST_api.py b/codeplain_REST_api.py index 33542d2e..7a86ec59 100644 --- a/codeplain_REST_api.py +++ b/codeplain_REST_api.py @@ -316,6 +316,7 @@ def render_conformance_tests( conformance_tests_folder_name, conformance_tests_json, all_acceptance_tests, + existing_conformance_tests_files, run_state: RunState, ): endpoint_url = f"{self.api_url}/render_conformance_tests" @@ -333,6 +334,7 @@ def render_conformance_tests( "conformance_tests_folder_name": conformance_tests_folder_name, "conformance_tests_json": conformance_tests_json, "all_acceptance_tests": all_acceptance_tests, + "existing_conformance_tests_files": existing_conformance_tests_files, } response = self.post_request(endpoint_url, headers, payload, run_state) diff --git a/render_machine/actions/render_conformance_tests.py b/render_machine/actions/render_conformance_tests.py index 178a9716..95ffe32a 100644 --- a/render_machine/actions/render_conformance_tests.py +++ b/render_machine/actions/render_conformance_tests.py @@ -111,6 +111,18 @@ def _render_conformance_tests(self, render_context: RenderContext): all_acceptance_tests = render_context.frid_context.specifications.get(plain_spec.ACCEPTANCE_TESTS, []) + # Existing conformance tests are sent as context so new tests don't duplicate their + # coverage. The current functionality's own subfolder is excluded - when re-rendering, + # its tests are the ones being replaced, not previous tests to deduplicate against. + current_subfolder_prefix = os.path.basename(conformance_tests_folder_name) + os.sep + existing_conformance_tests_files = { + file_name: content + for file_name, content in render_context.conformance_tests.fetch_all_existing_conformance_test_files( + render_context.module_name + ).items() + if not file_name.startswith(current_subfolder_prefix) + } + response_files, implementation_plan_summary = render_context.codeplain_api.render_conformance_tests( render_context.frid_context.frid, render_context.conformance_tests_running_context.current_testing_frid, @@ -125,6 +137,7 @@ def _render_conformance_tests(self, render_context: RenderContext): render_context.conformance_tests_running_context.current_testing_module_name ), all_acceptance_tests, + existing_conformance_tests_files, run_state=render_context.run_state, )