# tests/test_dependency.nim # Unit tests for dependency resolution system import unittest, tables, sets import ../src/nimpak/[dependency, types, errors] suite "Dependency Resolution Tests": setup: # Create test fragments let pkgA = PackageId(name: "pkgA", version: "1.0", stream: Stable) let pkgB = PackageId(name: "pkgB", version: "1.0", stream: Stable) let pkgC = PackageId(name: "pkgC", version: "1.0", stream: Stable) let pkgD = PackageId(name: "pkgD", version: "1.0", stream: Stable) let fragmentA = Fragment( id: pkgA, dependencies: @[pkgB, pkgC], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package A"), acul: AculCompliance(required: false) ) let fragmentB = Fragment( id: pkgB, dependencies: @[pkgD], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package B"), acul: AculCompliance(required: false) ) let fragmentC = Fragment( id: pkgC, dependencies: @[], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package C"), acul: AculCompliance(required: false) ) let fragmentD = Fragment( id: pkgD, dependencies: @[], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package D"), acul: AculCompliance(required: false) ) var fragments = initTable[PackageId, Fragment]() fragments[pkgA] = fragmentA fragments[pkgB] = fragmentB fragments[pkgC] = fragmentC fragments[pkgD] = fragmentD test "Simple dependency resolution": let result = resolveDependencies(pkgA, fragments) check result.isOk let installOrder = result.get() check installOrder.packages.len == 4 check installOrder.totalSteps == 4 # Dependencies should be installed before dependents let pkgIndices = installOrder.packages.mapIt((it.name, installOrder.packages.find(it))) check pkgIndices.filterIt(it[0] == "pkgD")[0][1] < pkgIndices.filterIt(it[0] == "pkgB")[0][1] check pkgIndices.filterIt(it[0] == "pkgB")[0][1] < pkgIndices.filterIt(it[0] == "pkgA")[0][1] check pkgIndices.filterIt(it[0] == "pkgC")[0][1] < pkgIndices.filterIt(it[0] == "pkgA")[0][1] test "Missing dependency detection": let pkgMissing = PackageId(name: "missing", version: "1.0", stream: Stable) let fragmentMissing = Fragment( id: pkgMissing, dependencies: @[PackageId(name: "nonexistent", version: "1.0", stream: Stable)], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package with missing dep"), acul: AculCompliance(required: false) ) var testFragments = fragments testFragments[pkgMissing] = fragmentMissing let result = resolveDependencies(pkgMissing, testFragments) check result.isErr check result.error.code == PackageNotFound check result.error.missingDependencies.len > 0 test "Circular dependency detection": # Create circular dependency: E -> F -> E let pkgE = PackageId(name: "pkgE", version: "1.0", stream: Stable) let pkgF = PackageId(name: "pkgF", version: "1.0", stream: Stable) let fragmentE = Fragment( id: pkgE, dependencies: @[pkgF], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package E"), acul: AculCompliance(required: false) ) let fragmentF = Fragment( id: pkgF, dependencies: @[pkgE], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Test package F"), acul: AculCompliance(required: false) ) var testFragments = initTable[PackageId, Fragment]() testFragments[pkgE] = fragmentE testFragments[pkgF] = fragmentF let result = resolveDependencies(pkgE, testFragments) check result.isErr check result.error.code == DependencyConflict check result.error.cyclicDependencies.len > 0 test "Dependency tree generation": let treeResult = getDependencyTree(pkgA, fragments) check treeResult.isOk let tree = treeResult.get() check "pkgA" in tree check "pkgB" in tree check "pkgC" in tree check "pkgD" in tree test "Version constraint resolution stub": let result = resolveVersionConstraint("testpkg", "~> 1.0") check result.isOk check result.get().name == "testpkg" test "Dependency validation": let result = validateDependencies(fragments) check result.isOk # Test with missing dependency var invalidFragments = fragments let invalidPkg = PackageId(name: "invalid", version: "1.0", stream: Stable) invalidFragments[invalidPkg] = Fragment( id: invalidPkg, dependencies: @[PackageId(name: "missing", version: "1.0", stream: Stable)], source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http), buildSystem: CMake, metadata: PackageMetadata(description: "Invalid package"), acul: AculCompliance(required: false) ) let invalidResult = validateDependencies(invalidFragments) check invalidResult.isErr check invalidResult.error.missingDependencies.len > 0 test "Error formatting": let error = DependencyError( code: DependencyConflict, msg: "Test error", missingDependencies: @[pkgA], cyclicDependencies: @[pkgB], conflictingPackages: @[pkgC] ) let formatted = formatDependencyError(error) check "Test error" in formatted check "Missing Dependencies" in formatted check "Circular Dependencies" in formatted check "Conflicting Packages" in formatted