chore(repo): replace app symlink/submodule with in-repo app directory; enable committing app/Dockerfile and tooling\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
a12270ad01
commit
ae2c674b81
25 files changed
+3417
-1
No files matched your search
@@ -0,0 +1,156 @@
|
||||
"""Test-file generation for migrated C++ code.
|
||||
|
||||
Strategy (B + C combined, no pre-existing test infrastructure):
|
||||
- QTest for Qt-heavy translation units (QObject / signals / slots)
|
||||
- gtest for pure-logic / non-UI code
|
||||
- Smoke CTest for every file (build + link + default-construction check)
|
||||
|
||||
Generated files are written to ``{worktree_root}/tests_generated/`` and
|
||||
registered in that directory's CMakeLists.txt (idempotent via a guard
|
||||
comment).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
|
||||
from migration_pipeline.api_client import call_api
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# System prompts
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_QTEST_SYSTEM = (
|
||||
"Du bist ein QA-Ingenieur für Qt6/C++20. "
|
||||
"Schreibe einen eigenständigen QTest Unit-Test für den folgenden migrierten Qt6-Code. "
|
||||
"Verwende QCOMPARE, QVERIFY und QTEST_MAIN. "
|
||||
"Gib NUR den C++ Quellcode zurück, ohne Markdown oder Erklärungen."
|
||||
)
|
||||
|
||||
_GTEST_SYSTEM = (
|
||||
"Du bist ein QA-Ingenieur für C++20. "
|
||||
"Schreibe einen eigenständigen Google Test (gtest) Unit-Test für den folgenden C++ Code. "
|
||||
"Gib NUR den C++ Quellcode zurück, ohne Markdown oder Erklärungen."
|
||||
)
|
||||
|
||||
_SMOKE_SYSTEM = (
|
||||
"Du bist ein QA-Ingenieur. "
|
||||
"Schreibe einen minimalen Smoke-Test mit Google Test, der sicherstellt, dass die Datei "
|
||||
"kompiliert, linkt und die Default-Konstruktion der Hauptklasse nicht crasht. "
|
||||
"Gib NUR den C++ Quellcode zurück, ohne Markdown oder Erklärungen."
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Qt-content heuristic
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_QT_MARKERS = (
|
||||
"QObject",
|
||||
"QWidget",
|
||||
"QApplication",
|
||||
"QMainWindow",
|
||||
"emit ",
|
||||
"signals:",
|
||||
"slots:",
|
||||
"Q_OBJECT",
|
||||
"Q_EMIT",
|
||||
)
|
||||
|
||||
|
||||
def _is_qt_heavy(code: str) -> bool:
|
||||
return any(marker in code for marker in _QT_MARKERS)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public API
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def generate_tests(
|
||||
client: httpx.AsyncClient,
|
||||
model: str,
|
||||
source_file_path: str,
|
||||
migrated_code: str,
|
||||
worktree_root: Path,
|
||||
track_id: str,
|
||||
) -> str:
|
||||
"""Generate unit + smoke tests for *migrated_code*.
|
||||
|
||||
Returns the CTest test-name prefix (e.g. ``test_track_a_conservative_MyClass``).
|
||||
Both the unit test and smoke test are registered under that prefix.
|
||||
"""
|
||||
base_name = Path(source_file_path).stem
|
||||
test_prefix = f"test_{track_id}_{base_name}"
|
||||
tests_dir = worktree_root / "tests_generated"
|
||||
tests_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
use_qtest = _is_qt_heavy(migrated_code)
|
||||
unit_system = _QTEST_SYSTEM if use_qtest else _GTEST_SYSTEM
|
||||
framework = "Qt6::Core Qt6::Test" if use_qtest else "GTest::gtest_main"
|
||||
|
||||
# Generate unit test and smoke test in parallel.
|
||||
unit_code, smoke_code = await asyncio.gather(
|
||||
call_api(
|
||||
client, model, unit_system,
|
||||
f"Erstelle einen Unit-Test für folgenden migrierten Qt6-Code:\n\n{migrated_code}",
|
||||
),
|
||||
call_api(
|
||||
client, model, _SMOKE_SYSTEM,
|
||||
f"Erstelle einen Smoke-Test für:\n\n{migrated_code}",
|
||||
),
|
||||
)
|
||||
|
||||
unit_file = tests_dir / f"{test_prefix}_unit.cpp"
|
||||
smoke_file = tests_dir / f"{test_prefix}_smoke.cpp"
|
||||
unit_file.write_text(unit_code)
|
||||
smoke_file.write_text(smoke_code)
|
||||
|
||||
_register_tests_in_cmake(
|
||||
tests_dir,
|
||||
test_prefix,
|
||||
unit_file.name,
|
||||
smoke_file.name,
|
||||
framework,
|
||||
)
|
||||
|
||||
return test_prefix
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CMakeLists.txt registration (idempotent)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_GUARD_PREFIX = "# MIGRATION_PIPELINE:"
|
||||
|
||||
|
||||
def _register_tests_in_cmake(
|
||||
tests_dir: Path,
|
||||
test_prefix: str,
|
||||
unit_filename: str,
|
||||
smoke_filename: str,
|
||||
framework_libs: str,
|
||||
) -> None:
|
||||
cmake_path = tests_dir / "CMakeLists.txt"
|
||||
guard = f"{_GUARD_PREFIX}{test_prefix}"
|
||||
|
||||
# Read existing content to avoid duplicate registrations.
|
||||
existing = cmake_path.read_text() if cmake_path.exists() else ""
|
||||
if guard in existing:
|
||||
return # already registered
|
||||
|
||||
entry = (
|
||||
f"\n{guard}\n"
|
||||
f"add_executable({test_prefix}_unit {unit_filename})\n"
|
||||
f"target_link_libraries({test_prefix}_unit PRIVATE {framework_libs})\n"
|
||||
f"add_test(NAME {test_prefix}_unit COMMAND {test_prefix}_unit)\n"
|
||||
f"\nadd_executable({test_prefix}_smoke {smoke_filename})\n"
|
||||
f"target_link_libraries({test_prefix}_smoke PRIVATE GTest::gtest_main)\n"
|
||||
f"add_test(NAME {test_prefix}_smoke COMMAND {test_prefix}_smoke)\n"
|
||||
)
|
||||
|
||||
with cmake_path.open("a") as fh:
|
||||
fh.write(entry)
|
||||
Reference in new issue
Block a user