import os import unittest import tempfile from pathlib import Path from src import project_manager from src import models from src.app_controller import AppController class TestProjectSerialization(unittest.TestCase): def setUp(self): self.test_dir = tempfile.TemporaryDirectory() self.project_path = Path(self.test_dir.name) / "test_project.toml" def tearDown(self): self.test_dir.cleanup() def test_fileitem_roundtrip(self): """Verify that FileItem objects survive a save/load cycle.""" proj = project_manager.default_project("test") file1 = models.FileItem(path="src/main.py", auto_aggregate=True, force_full=False) file2 = models.FileItem(path="docs/readme.md", auto_aggregate=False, force_full=True) proj["files"]["paths"] = [file1, file2] # Save project_manager.save_project(proj, self.project_path) # Load loaded_proj = project_manager.load_project(self.project_path) paths = loaded_proj["files"]["paths"] self.assertEqual(len(paths), 2) self.assertIsInstance(paths[0], models.FileItem) self.assertEqual(paths[0].path, "src/main.py") self.assertTrue(paths[0].auto_aggregate) self.assertFalse(paths[0].force_full) self.assertIsInstance(paths[1], models.FileItem) self.assertEqual(paths[1].path, "docs/readme.md") self.assertFalse(paths[1].auto_aggregate) self.assertTrue(paths[1].force_full) def test_backward_compatibility_strings(self): """Verify that old-style string paths are converted to FileItem objects by AppController.""" # Create a project file manually with string paths content = """ [project] name = "legacy" [files] base_dir = "." paths = ["file1.py", "file2.md"] [discussion] roles = ["User", "AI"] """ with open(self.project_path, "w") as f: f.write(content) # Load via project_manager (should load as strings) proj = project_manager.load_project(self.project_path) self.assertEqual(proj["files"]["paths"], ["file1.py", "file2.md"]) # Initialize AppController state logic controller = AppController() controller.project = proj # Trigger deserialization (copied from init_state) raw_paths = controller.project.get("files", {}).get("paths", []) controller.files = [] for p in raw_paths: if isinstance(p, models.FileItem): controller.files.append(p) elif isinstance(p, dict): controller.files.append(models.FileItem.from_dict(p)) else: controller.files.append(models.FileItem(path=str(p))) self.assertEqual(len(controller.files), 2) self.assertIsInstance(controller.files[0], models.FileItem) self.assertEqual(controller.files[0].path, "file1.py") self.assertIsInstance(controller.files[1], models.FileItem) self.assertEqual(controller.files[1].path, "file2.md") def test_default_roles_include_context(self): """Verify that 'Context' is in default project roles.""" proj = project_manager.default_project("test") self.assertIn("Context", proj["discussion"]["roles"]) if __name__ == "__main__": unittest.main()