import XCTest @testable import CxIDE // MARK: - EditorViewModel Tests @MainActor final class EditorViewModelTests: XCTestCase { func testInitialState() { let vm = EditorViewModel() XCTAssertFalse(vm.content.isEmpty) XCTAssertEqual(vm.fontSize, 13) XCTAssertTrue(vm.showSidebar) XCTAssertFalse(vm.isRunning) XCTAssertEqual(vm.bottomPanel, .console) XCTAssertEqual(vm.activePanel, .explorer) XCTAssertFalse(vm.showCommandPalette) } func testTabManagement() { let vm = EditorViewModel() let initialCount = vm.tabs.count XCTAssertGreaterThanOrEqual(initialCount, 1) // Open a new tab let tab = EditorTab(name: "test.swift", content: "let x = 1") vm.tabs.append(tab) vm.activeTabID = tab.id XCTAssertEqual(vm.tabs.count, initialCount + 1) // Close tab vm.closeTab(tab) XCTAssertEqual(vm.tabs.count, initialCount) } func testCloseAllTabs() { let vm = EditorViewModel() vm.tabs.append(EditorTab(name: "a.swift", content: "a")) vm.tabs.append(EditorTab(name: "b.swift", content: "b")) vm.closeAllTabs() XCTAssertEqual(vm.tabs.count, 1, "Should have one default tab after closing all") } func testPerformSearch() { let vm = EditorViewModel() vm.content = "Hello world! Hello Swift!" vm.searchState.query = "Hello" vm.performSearch() XCTAssertEqual(vm.searchState.matchCount, 2) vm.searchState.query = "hello" vm.searchState.isCaseSensitive = true vm.performSearch() XCTAssertEqual(vm.searchState.matchCount, 0) vm.searchState.isCaseSensitive = false vm.performSearch() XCTAssertEqual(vm.searchState.matchCount, 2) } func testPerformSearchEmpty() { let vm = EditorViewModel() vm.searchState.query = "" vm.performSearch() XCTAssertEqual(vm.searchState.matchCount, 0) } func testReplaceNext() { let vm = EditorViewModel() vm.content = "foo bar foo" vm.searchState.query = "foo" vm.searchState.replacement = "baz" vm.performSearch() XCTAssertEqual(vm.searchState.matchCount, 2) vm.replaceNext() XCTAssertEqual(vm.content, "baz bar foo") XCTAssertEqual(vm.searchState.matchCount, 1) } func testReplaceAll() { let vm = EditorViewModel() vm.content = "foo bar foo baz foo" vm.searchState.query = "foo" vm.searchState.replacement = "qux" vm.performSearch() vm.replaceAll() XCTAssertEqual(vm.content, "qux bar qux baz qux") XCTAssertEqual(vm.searchState.matchCount, 0) } func testClearConsole() { let vm = EditorViewModel() XCTAssertFalse(vm.consoleEntries.isEmpty) vm.clearConsole() // clearConsole adds a "Console cleared." system message XCTAssertEqual(vm.consoleEntries.count, 1) XCTAssertEqual(vm.consoleEntries.first?.level, .system) } func testToggleSearch() { let vm = EditorViewModel() XCTAssertFalse(vm.searchState.isActive) vm.toggleSearch() XCTAssertTrue(vm.searchState.isActive) vm.toggleSearch() XCTAssertFalse(vm.searchState.isActive) } func testBottomPanelEnum() { let panels = EditorViewModel.BottomPanel.allCases XCTAssertEqual(panels.count, 6) for panel in panels { XCTAssertFalse(panel.rawValue.isEmpty) XCTAssertFalse(panel.iconName.isEmpty) } } func testCppAnalysis() { let vm = EditorViewModel() vm.content = "import Foundation\nfunc hello() {\n print(\"Hello\")\n}\n" vm.runCppAnalysis() XCTAssertNotEqual(vm.cppAnalysis, "Ready") } func testCommandPalette() { let vm = EditorViewModel() XCTAssertFalse(vm.commands.isEmpty) XCTAssertTrue(vm.commands.count > 20) let filtered = vm.filteredCommands XCTAssertEqual(filtered.count, vm.commands.count) vm.commandSearch = "run" let runFiltered = vm.filteredCommands XCTAssertLessThan(runFiltered.count, vm.commands.count) } func testBuildConfig() { let vm = EditorViewModel() XCTAssertEqual(vm.buildConfig.name, "Debug") XCTAssertEqual(vm.buildConfig.optimizationLevel, .debug) } func testTheme() { let vm = EditorViewModel() XCTAssertEqual(vm.currentTheme.name, "Dark+ (VSCode)") XCTAssertNotNil(vm.currentTheme.editorBackground) XCTAssertNotNil(vm.currentTheme.sidebarBackground) } func testNotifications() { let vm = EditorViewModel() let initialCount = vm.notifications.count vm.notify(.info("Test")) XCTAssertEqual(vm.notifications.count, initialCount + 1) XCTAssertEqual(vm.notifications.last?.message, "Test") } } // MARK: - Engine Tests final class EngineTests: XCTestCase { func testCppEngineMetrics() { let engine = CppEngineController() let code = "import Foundation\n\nfunc hello() {\n print(\"Hello\")\n}\n\nfunc goodbye() {\n print(\"Bye\")\n}\n" XCTAssertGreaterThan(engine.lineCount(code), 0) XCTAssertGreaterThan(engine.codeLineCount(code), 0) XCTAssertGreaterThanOrEqual(engine.functionCount(code), 1) XCTAssertEqual(engine.classCount(code), 0) } func testCppEngineChecksum() { let engine = CppEngineController() let code = "let x = 1" let checksum1 = engine.checksum(code) let checksum2 = engine.checksum(code) XCTAssertEqual(checksum1, checksum2, "Same input should produce same checksum") let checksum3 = engine.checksum("let x = 2") XCTAssertNotEqual(checksum1, checksum3, "Different input should produce different checksum") } func testCppEngineStructuredAnalysis() { let engine = CppEngineController() let code = "struct MyStruct {\n var value: Int\n}\n" let result = engine.runStructuredAnalysis(code) XCTAssertFalse(result.isEmpty) } func testCppEngineConfig() { let engine = CppEngineController() var config = CppAnalysisConfig() config.maxLineLength = 80 config.detectForceUnwraps = false engine.applyConfig(config) // Should not crash let result = engine.runAnalysis("let x = 1") XCTAssertFalse(result.isEmpty) } func testCppEngineBlankLines() { let engine = CppEngineController() let code = "line1\n\nline3\n\n\nline6\n" let blanks = engine.blankLineCount(code) XCTAssertGreaterThanOrEqual(blanks, 3) } func testSwiftRuntimeEngine() async throws { let tmpDir = FileManager.default.temporaryDirectory.appendingPathComponent("CxIDETest-\(UUID().uuidString)") try FileManager.default.createDirectory(at: tmpDir, withIntermediateDirectories: true) defer { try? FileManager.default.removeItem(at: tmpDir) } let engine = SwiftRuntimeEngine(projectDirectory: tmpDir) let result = try await engine.execute(script: "print(42)") XCTAssertTrue(result.contains("42")) } func testEngineFactory() { let engine = EngineFactory.make(.sandbox) XCTAssertNotNil(engine) let fullEngine = EngineFactory.make(.swift) XCTAssertNotNil(fullEngine) } } // MARK: - Service Tests @MainActor final class ServiceTests: XCTestCase { func testGitServiceInit() { let service = GitService() XCTAssertEqual(service.status.branch, "main") XCTAssertTrue(service.status.isClean) XCTAssertFalse(service.isGitRepo) } func testWorkspaceServiceInit() { let service = WorkspaceService() XCTAssertNil(service.currentWorkspace) XCTAssertTrue(service.fileTree.isEmpty) XCTAssertFalse(service.isLoading) } func testAgentServiceInit() { let service = AgentService() XCTAssertTrue(service.messages.isEmpty) XCTAssertEqual(service.status, .idle) XCTAssertFalse(service.isInitialized) } func testAgentServiceToolCount() { let service = AgentService() XCTAssertGreaterThanOrEqual(service.toolCount, 0) } }