nip/tests/test_dependency.nim

171 lines
6.0 KiB
Nim

# 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