## test_pkgsrc_adapter.nim ## Unit tests for PkgsrcAdapter import std/[unittest, tables, os, strutils, options] import ../src/nimpak/build/[types, pkgsrc_adapter] suite "PkgsrcAdapter Tests": test "PkgsrcAdapter initialization": let adapter = newPkgsrcAdapter() check adapter != nil check adapter.name == "pkgsrc" check adapter.pkgsrcRoot == "/usr/pkgsrc" check adapter.makeConf == "/etc/mk.conf" check adapter.packageCount == 27000 test "PkgsrcAdapter availability check": let adapter = newPkgsrcAdapter() let available = adapter.isAvailable() # Should match actual system state check available == dirExists("/usr/pkgsrc") test "Package name validation - valid names": let adapter = newPkgsrcAdapter() let validNames = @[ "firefox", "my-package", "package_name", "package.with.dots", "Package123" ] for name in validNames: let request = BuildRequest( packageName: name, version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @[], cacheDir: getTempDir(), verbose: false ) # Should not raise ValidationError during name validation let result = adapter.buildPackage(request) # May fail for other reasons, but not validation if not result.success and result.errors.len > 0: check "Invalid package name" notin result.errors[0] test "Package name validation - invalid names": let adapter = newPkgsrcAdapter() let invalidNames = @[ "", "../etc/passwd", "/absolute/path", "package;rm -rf /", "package`whoami`", "package$(whoami)", "a" & "b".repeat(300) # Too long ] for name in invalidNames: let request = BuildRequest( packageName: name, version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @[], cacheDir: getTempDir(), verbose: false ) let result = adapter.buildPackage(request) check result.success == false check result.errors.len > 0 test "mk.conf generation - no options": let adapter = newPkgsrcAdapter() # We can't directly test the private generateMkConf, # but we can test it through buildPackage let request = BuildRequest( packageName: "test-package", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @[], cacheDir: getTempDir() / "nip-test-cache", verbose: false ) # This will generate the mk.conf file discard adapter.buildPackage(request) # Check that mk.conf file was created let mkConfFile = getTempDir() / "nip-test-cache" / "pkgsrc" / "mk.conf.test-package" if fileExists(mkConfFile): let content = readFile(mkConfFile) check "# Generated by NIP" in content test "mk.conf generation - with options": let adapter = newPkgsrcAdapter() let request = BuildRequest( packageName: "firefox", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @["wayland", "pulseaudio"], cacheDir: getTempDir() / "nip-test-cache", verbose: false ) discard adapter.buildPackage(request) let mkConfFile = getTempDir() / "nip-test-cache" / "pkgsrc" / "mk.conf.firefox" if fileExists(mkConfFile): let content = readFile(mkConfFile) check "# Generated by NIP" in content check "PKG_OPTIONS.firefox=" in content check "wayland" in content check "pulseaudio" in content test "PKG_OPTIONS validation - valid options": let adapter = newPkgsrcAdapter() let validOptions = @[ "wayland", "pulseaudio", "enable-feature", "with_option", "flag123" ] let request = BuildRequest( packageName: "test", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: validOptions, cacheDir: getTempDir() / "nip-test-cache", verbose: false ) # Should not raise ValidationError let result = adapter.buildPackage(request) # May fail at build stage, but not at validation if not result.success and result.errors.len > 0: check "Invalid PKG_OPTIONS" notin result.errors[0] test "PKG_OPTIONS validation - invalid options": let adapter = newPkgsrcAdapter() # Test with malicious option let request = BuildRequest( packageName: "test", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @["bad;option"], cacheDir: getTempDir() / "nip-test-cache", verbose: false ) let result = adapter.buildPackage(request) check result.success == false test "Build result structure": let adapter = newPkgsrcAdapter() let request = BuildRequest( packageName: "test-package", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @[], cacheDir: getTempDir() / "nip-test-cache", verbose: false ) let result = adapter.buildPackage(request) # Check result structure check result.source == "pkgsrc" check result.packageName == "test-package" # success may be false if package not found, which is expected test "Cache directory creation": let cacheDir = getTempDir() / "nip-test-cache-pkgsrc" # Remove if exists if dirExists(cacheDir): removeDir(cacheDir) let adapter = newPkgsrcAdapter() let request = BuildRequest( packageName: "test", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @["option1", "option2"], # Add options to trigger mk.conf generation cacheDir: cacheDir, verbose: false ) discard adapter.buildPackage(request) # Check that cache directory was created (even if build fails) # The mk.conf generation should create the directory check dirExists(cacheDir / "pkgsrc") or not dirExists("/usr/pkgsrc") test "Variant flags in build result": let adapter = newPkgsrcAdapter() var variantFlags = initTable[string, seq[string]]() variantFlags["graphics"] = @["wayland", "vulkan"] variantFlags["audio"] = @["pipewire"] let request = BuildRequest( packageName: "test", version: "", variantFlags: variantFlags, sourceFlags: @[], cacheDir: getTempDir() / "nip-test-cache", verbose: false ) let result = adapter.buildPackage(request) # Variant flags should be preserved in result check result.variantDomains.hasKey("graphics") check result.variantDomains.hasKey("audio") test "Error handling - package not found": let adapter = newPkgsrcAdapter() # Use a package name that will definitely not be found let request = BuildRequest( packageName: "this-package-definitely-does-not-exist-12345", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @[], cacheDir: getTempDir() / "nip-test-cache", verbose: false ) let result = adapter.buildPackage(request) # Should fail gracefully check result.success == false check result.errors.len > 0 check "not found" in result.errors[0].toLower() test "Verbose mode": let adapter = newPkgsrcAdapter() let request = BuildRequest( packageName: "test", version: "", variantFlags: initTable[string, seq[string]](), sourceFlags: @[], cacheDir: getTempDir() / "nip-test-cache", verbose: true ) # Should not crash with verbose mode discard adapter.buildPackage(request) # Only run search tests if PKGSRC is actually available if dirExists("/usr/pkgsrc"): suite "PkgsrcAdapter Search Tests (PKGSRC Available)": test "Search for package in common category": let adapter = newPkgsrcAdapter() # Try to search for a common package # Note: This test is system-dependent let result = adapter.searchPackage("bash") # May or may not find it depending on PKGSRC installation if result.isSome: let info = result.get() check info.name == "bash" check info.source == "pkgsrc" check info.available == true test "Search for non-existent package": let adapter = newPkgsrcAdapter() let result = adapter.searchPackage("this-package-does-not-exist-xyz123") # Should return none check result.isNone test "Search with invalid package name": let adapter = newPkgsrcAdapter() let result = adapter.searchPackage("../etc/passwd") # Should return none due to validation check result.isNone test "Extract package information from Makefile": let adapter = newPkgsrcAdapter() # Try a common package let result = adapter.searchPackage("bash") if result.isSome: let info = result.get() # Should have extracted some information check info.version != "" check info.category != ""