## test_graft_coordinator.nim ## Unit tests for GraftCoordinator ## Tests package spec parsing, source detection, and adapter selection import std/[unittest, os, json, tables, strutils] import ../src/nimpak/graft_coordinator import ../src/nimpak/install_manager import ../src/nimpak/config suite "GraftCoordinator - Package Spec Parsing": test "Parse package spec - simple name": let (source, name) = parsePackageSpec("firefox") check source == Auto check name == "firefox" test "Parse package spec - nix source": let (source, name) = parsePackageSpec("nix:firefox") check source == Nix check name == "firefox" test "Parse package spec - pkgsrc source": let (source, name) = parsePackageSpec("pkgsrc:vim") check source == PKGSRC check name == "vim" test "Parse package spec - pacman source": let (source, name) = parsePackageSpec("pacman:htop") check source == Pacman check name == "htop" test "Parse package spec - uppercase source": let (source, name) = parsePackageSpec("NIX:firefox") check source == Nix check name == "firefox" test "Parse package spec - mixed case source": let (source, name) = parsePackageSpec("PkgSrc:vim") check source == PKGSRC check name == "vim" test "Parse package spec - package name with hyphens": let (source, name) = parsePackageSpec("nix:my-package-name") check source == Nix check name == "my-package-name" test "Parse package spec - package name with underscores": let (source, name) = parsePackageSpec("pkgsrc:my_package_name") check source == PKGSRC check name == "my_package_name" test "Parse package spec - package name with numbers": let (source, name) = parsePackageSpec("nix:package123") check source == Nix check name == "package123" test "Parse package spec - invalid source defaults to auto": let (source, name) = parsePackageSpec("invalid:firefox") check source == Auto check name == "firefox" test "Parse package spec - multiple colons uses first": let (source, name) = parsePackageSpec("nix:package:with:colons") check source == Nix check name == "package:with:colons" test "Parse package spec - empty name": let (source, name) = parsePackageSpec("nix:") check source == Nix check name == "" test "Parse package spec - colon only": let (source, name) = parsePackageSpec(":") check source == Auto check name == "" suite "GraftCoordinator - Source Detection": setup: let testCacheDir = getTempDir() / "nip-graft-coord-test" let testProgramsDir = getTempDir() / "Programs-coord-test" let testLinksDir = getTempDir() / "System-coord-test" / "Links" # Clean up from previous runs if dirExists(testCacheDir): removeDir(testCacheDir) if dirExists(testProgramsDir): removeDir(testProgramsDir) if dirExists(testLinksDir): removeDir(testLinksDir) # Create test directories createDir(testCacheDir) createDir(testProgramsDir) createDir(testLinksDir / "Executables") createDir(testLinksDir / "Libraries") let installConfig = InstallConfig( programsDir: testProgramsDir, linksDir: testLinksDir, cacheDir: testCacheDir, dbFile: testCacheDir / "test.db", autoSymlink: true, checkConflicts: false, verbose: false ) let coordinator = newGraftCoordinator(installConfig, false) test "Detect source - returns valid source": # Test with aage that might exist let source = coordinator.detectSource("hello") # Should return one of the valid sources check source in [Nix, PKGSRC, Pacman] test "Detect source - consistency": # Same package should return same source let source1 = coordinator.detectSource("test-package") let source2 = coordinator.detectSource("test-package") check source1 == source2 test "Detect source - different packages": # Different packages might have different sources let source1 = coordinator.detectSource("package-a") let source2 = coordinator.detectSource("package-b") # Both should be valid sources check source1 in [Nix, PKGSRC, Pacman] check source2 in [Nix, PKGSRC, Pacman] test "Detect source - priority order": # Detection should follow priority: Nix > PKGSRC > Pacman # If Nix is available, it should be preferred let source = coordinator.detectSource("common-package") # Should return a valid source check source in [Nix, PKGSRC, Pacman] test "Detect source - empty package name": # Should handle empty package name gracefully let source = coordinator.detectSource("") # Should still return a valid source (defaults to Nix) check source in [Nix, PKGSRC, Pacman] test "Detect source - package with special characters": let source = coordinator.detectSource("package-with-hyphens") check source in [Nix, PKGSRC, Pacman] teardown: # Clean up test directories try: if dirExists(testCacheDir): removeDir(testCacheDir) if dirExists(testProgramsDir): removeDir(testProgramsDir) if dirExists(testLinksDir): removeDir(testLinksDir) except: discard # Cleanup failures are not critical suite "GraftCoordinator - Adapter Selection": setup: let testCacheDir = getTempDir() / "nip-graft-adapt-test" let testProgramsDir = getTempDir() / "Programs-adapt-test" let testLinksDir = getTempDir() / "System-adapt-test" / "Links" # Clean up from previous runs if dirExists(testCacheDir): removeDir(testCacheDir) if dirExists(testProgramsDir): removeDir(testProgramsDir) if dirExists(testLinksDir): removeDir(testLinksDir) # Create test directories createDir(testCacheDir) createDir(testProgramsDir) createDir(testLinksDir / "Executables") createDir(testLinksDir / "Libraries") let installConfig = InstallConfig( programsDir: testProgramsDir, linksDir: testLinksDir, cacheDir: testCacheDir, dbFile: testCacheDir / "test.db", autoSymlink: true, checkConflicts: false, verbose: false ) let coordinator = newGraftCoordinator(installConfig, false) test "Coordinator has Nix adapter": check coordinator.nixAdapter != nil test "Coordinator has PKGSRC adapter": check coordinator.pkgsrcAdapter != nil test "Graft with Auto source - uses detection": # This will fail because we don't have actual packages # But it tests that the auto-detection path is taken let result = coordinator.graft("nonexistent-package", Auto) # Should attempt to graft (will fail, but that's expected) check result.packageName == "nonexistent-package" check result.source in ["nix", "pkgsrc", "pacman"] test "Graft with Nix source - uses Nix adapter": let result = coordinator.graft("nonexistent-package", Nix) check result.packageName == "nonexistent-package" check result.source == "nix" # Will fail because package doesn't exist check result.success == false test "Graft with PKGSRC source - uses PKGSRC adapter": let result = coordinator.graft("nonexistent-package", PKGSRC) check result.packageName == "nonexistent-package" check result.source == "pkgsrc" # Will fail because package doesn't exist check result.success == false test "Graft with Pacman source - not implemented": let result = coordinator.graft("nonexistent-package", Pacman) check result.packageName == "nonexistent-package" check result.source == "pacman" check result.success == false check result.errors.len > 0 check "not yet implemented" in result.errors[0].toLower() test "Parse and graft - nix:package": let (source, name) = parsePackageSpec("nix:test-package") let result = coordinator.graft(name, source) check result.packageName == "test-package" check result.source == "nix" test "Parse and graft - pkgsrc:package": let (source, name) = parsePackageSpec("pkgsrc:test-package") let result = coordinator.graft(name, source) check result.packageName == "test-package" check result.source == "pkgsrc" test "Parse and graft - auto detection": let (source, name) = parsePackageSpec("test-package") let result = coordinator.graft(name, source) check result.packageName == "test-package" check result.source in ["nix", "pkgsrc", "pacman"] test "Coordinator verbose mode": let verboseConfig = InstallConfig( programsDir: testProgramsDir, linksDir: testLinksDir, cacheDir: testCacheDir, dbFile: testCacheDir / "test-verbose.db", autoSymlink: true, checkConflicts: false, verbose: true ) let verboseCoordinator = newGraftCoordinator(verboseConfig, true) check verboseCoordinator.verbose == true test "List installed packages - empty": let packages = coordinator.list() # Should return empty list for new coordinator check packages.len == 0 test "List installed packages - filtered by source": let nixPackages = coordinator.list("nix") let pkgsrcPackages = coordinator.list("pkgsrc") # Should return empty lists for new coordinator check nixPackages.len == 0 check pkgsrcPackages.len == 0 test "Check if package is installed - not installed": let installed = coordinator.isInstalled("nonexistent-package") check installed == false test "Get status - returns JSON": let status = coordinator.status() check status != nil check status.kind == JObject teardown: # Clean up test directories try: if dirExists(testCacheDir): removeDir(testCacheDir) if dirExists(testProgramsDir): removeDir(testProgramsDir) if dirExists(testLinksDir): removeDir(testLinksDir) except: discard # Cleanup failures are not critical suite "GraftCoordinator - Integration": setup: let testCacheDir = getTempDir() / "nip-graft-integ-test" let testProgramsDir = getTempDir() / "Programs-integ-test" let testLinksDir = getTempDir() / "System-integ-test" / "Links" # Clean up from previous runs if dirExists(testCacheDir): removeDir(testCacheDir) if dirExists(testProgramsDir): removeDir(testProgramsDir) if dirExists(testLinksDir): removeDir(testLinksDir) # Create test directories createDir(testCacheDir) createDir(testProgramsDir) createDir(testLinksDir / "Executables") createDir(testLinksDir / "Libraries") let installConfig = InstallConfig( programsDir: testProgramsDir, linksDir: testLinksDir, cacheDir: testCacheDir, dbFile: testCacheDir / "test.db", autoSymlink: true, checkConflicts: false, verbose: false ) let coordinator = newGraftCoordinator(installConfig, false) test "Full workflow - parse, detect, graft": # Parse package spec let (source, name) = parsePackageSpec("nix:test-package") check source == Nix check name == "test-package" # Detect source (should use parsed source) let detectedSource = if source == Auto: coordinator.detectSource(name) else: source check detectedSource == Nix # Attempt to graft (will fail, but tests the flow) let result = coordinator.graft(name, detectedSource) check result.packageName == "test-package" check result.source == "nix" test "Full workflow - auto detection": let (source, name) = parsePackageSpec("test-package") check source == Auto # Auto-detect source let detectedSource = coordinator.detectSource(name) check detectedSource in [Nix, PKGSRC, Pacman] # Graft with detected source let result = coordinator.graft(name, detectedSource) check result.packageName == "test-package" test "Error handling - invalid package": let result = coordinator.graft("", Nix) # Should handle empty package name check result.success == false test "Error handling - nonexistent package": let result = coordinator.graft("definitely-does-not-exist-12345", Nix) # Should fail gracefully check result.success == false check result.errors.len > 0 teardown: # Clean up test directories try: if dirExists(testCacheDir): removeDir(testCacheDir) if dirExists(testProgramsDir): removeDir(testProgramsDir) if dirExists(testLinksDir): removeDir(testLinksDir) except: discard # Cleanup failures are not critical