Files
CxIDE/CxIDETests/EditorViewModelTests.swift
T
cx-git-agent f71da0219b feat: enhance xcodeproj, xcassets, scheme, Info.plist, and entitlements
xcodeproj build settings:
- Add CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED for localization checks
- Add GCC_C_LANGUAGE_STANDARD=gnu17 for C language standard
- Add LLVM_LTO=YES for Release link-time optimization
- Add ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS
- Add ENABLE_INCOMING_NETWORK_CONNECTIONS for MCP agent server
- Add ENABLE_PREVIEWS for SwiftUI preview support

xcassets (14 new color sets):
- EditorBackground, SidebarBackground, ConsoleBackground
- KeywordColor, StringColor, CommentColor, TypeColor, NumberColor
- LineNumberColor, ToolbarTint, CurrentLineHighlight
- ErrorHighlight, WarningHighlight
- GitAddedColor, GitModifiedColor, GitDeletedColor
- All with proper light/dark mode variants
- Remove orphan icon_64x64.png and icon_base.png (fixed warnings)

xcscheme:
- Add targeted code coverage for CxIDE target only
- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Adv v- Ad- Ad- Ad- Ad- Ad- ALD_- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Ad- Aunch arg (disabled)

Info.plist:
- Add 12 new document types: C, ObjC, Python, Shell, JS, TS,
  HTML, CSS, YAML, XML, Plain Text, Property List

Entitlements:
- Add network.client and network.server for agent HTTP/WebSocket
- Add files.user-selec- Add files.user-selec- Add filads.read-write
- Add- Add- Add- Add- Aderminal com- Add- Add- Add- Add- Aderminal com- Add- Add- Add- Adrestore workspace state
All 53 tests passing
2026-04-21 17:46:39 -05:00

260 lines
8.2 KiB
Swift

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)
}
}