nip/tests/test_variant_fingerprint.nim

288 lines
9.2 KiB
Nim

## test_variant_fingerprint.nim
## Tests for variant fingerprint calculation
## Ensures determinism, uniqueness, and correctness
import std/[unittest, tables, strutils]
import ../src/nimpak/variant_fingerprint
import ../src/nimpak/variant_types
import ../src/nimpak/config
suite "Variant Fingerprint Tests":
# Test data
let testToolchain = newToolchainInfo("gcc", "13.2.0")
let testTarget = newTargetInfo("x86_64", "linux")
let testCompilerFlags = CompilerFlags(
cflags: "-O2 -pipe",
cxxflags: "-O2 -pipe",
ldflags: "-Wl,-O1",
makeflags: "-j4"
)
test "Same inputs produce identical fingerprints":
# Create two identical configurations
var domains1 = initTable[string, seq[string]]()
domains1["init"] = @["dinit"]
domains1["security"] = @["pie", "relro"]
domains1["optimization"] = @["lto"]
var domains2 = initTable[string, seq[string]]()
domains2["init"] = @["dinit"]
domains2["security"] = @["pie", "relro"]
domains2["optimization"] = @["lto"]
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains1, testCompilerFlags, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains2, testCompilerFlags, testToolchain, testTarget
)
check fp1 == fp2
check fp1.len == 20 # "blake2b-" + 12 chars
check fp1.startsWith("blake2b-")
test "Different package names produce different fingerprints":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"apache", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
check fp1 != fp2
test "Different versions produce different fingerprints":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.29.0", domains, testCompilerFlags, testToolchain, testTarget
)
check fp1 != fp2
test "Different domain flags produce different fingerprints":
var domains1 = initTable[string, seq[string]]()
domains1["init"] = @["dinit"]
domains1["security"] = @["pie", "relro"]
var domains2 = initTable[string, seq[string]]()
domains2["init"] = @["systemd"]
domains2["security"] = @["pie", "relro"]
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains1, testCompilerFlags, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains2, testCompilerFlags, testToolchain, testTarget
)
check fp1 != fp2
test "Flag order independence - same flags different order produce same fingerprint":
# Test that domain flags are sorted before hashing
var domains1 = initTable[string, seq[string]]()
domains1["security"] = @["pie", "relro", "hardened"]
domains1["optimization"] = @["lto", "pgo"]
domains1["init"] = @["dinit"]
var domains2 = initTable[string, seq[string]]()
domains2["init"] = @["dinit"]
domains2["optimization"] = @["lto", "pgo"]
domains2["security"] = @["pie", "relro", "hardened"]
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains1, testCompilerFlags, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains2, testCompilerFlags, testToolchain, testTarget
)
check fp1 == fp2
test "Value order within domain affects fingerprint":
# Different order of values within a domain should produce same result
# because values are sorted
var domains1 = initTable[string, seq[string]]()
domains1["security"] = @["relro", "pie", "hardened"]
var domains2 = initTable[string, seq[string]]()
domains2["security"] = @["pie", "relro", "hardened"]
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains1, testCompilerFlags, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains2, testCompilerFlags, testToolchain, testTarget
)
check fp1 == fp2
test "Different compiler flags produce different fingerprints":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
let flags1 = CompilerFlags(
cflags: "-O2 -pipe",
cxxflags: "-O2 -pipe",
ldflags: "-Wl,-O1",
makeflags: "-j4"
)
let flags2 = CompilerFlags(
cflags: "-O3 -march=native",
cxxflags: "-O3 -march=native",
ldflags: "-Wl,-O1",
makeflags: "-j4"
)
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, flags1, testToolchain, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, flags2, testToolchain, testTarget
)
check fp1 != fp2
test "Different toolchains produce different fingerprints":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
let toolchain1 = newToolchainInfo("gcc", "13.2.0")
let toolchain2 = newToolchainInfo("clang", "17.0.0")
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, toolchain1, testTarget
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, toolchain2, testTarget
)
check fp1 != fp2
test "Different targets produce different fingerprints":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
let target1 = newTargetInfo("x86_64", "linux")
let target2 = newTargetInfo("aarch64", "linux")
let fp1 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, target1
)
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, target2
)
check fp1 != fp2
test "buildVariantFingerprint creates complete object":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
domains["security"] = @["pie", "relro"]
let fp = buildVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
check fp.packageName == "nginx"
check fp.version == "1.28.0"
check fp.domainFlags == domains
check fp.compilerFlags.cflags == testCompilerFlags.cflags
check fp.toolchain == testToolchain
check fp.target == testTarget
check fp.hash.len == 20
check fp.hash.startsWith("blake2b-")
test "isValidFingerprint validates format correctly":
check isValidFingerprint("blake2b-abc123def456") == true
check isValidFingerprint("blake2b-ABC123DEF456") == true
check isValidFingerprint("blake2b-0123456789ab") == true
# Invalid cases
check isValidFingerprint("blake2b-") == false
check isValidFingerprint("blake2b-abc") == false # Too short
check isValidFingerprint("blake2b-abc123def456xyz") == false # Too long
check isValidFingerprint("blake3-abc123def456") == false # Wrong prefix
check isValidFingerprint("abc123def456") == false # No prefix
check isValidFingerprint("blake2b-xyz123def456") == false # Invalid hex
test "extractFingerprintPrefix extracts 12-char prefix":
let fullHash = "blake2b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
let prefix = extractFingerprintPrefix(fullHash)
check prefix == "blake2b-0123456789ab"
check prefix.len == 20
test "getFingerprintInputString returns deterministic input":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
domains["security"] = @["pie", "relro"]
let input = getFingerprintInputString(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
check input.contains("nginx")
check input.contains("1.28.0")
check input.contains("init:dinit")
check input.contains("security:")
check input.contains("pie")
check input.contains("relro")
check input.contains("cflags:-O2 -pipe")
check input.contains("toolchain:gcc-13.2.0")
check input.contains("target:x86_64-linux")
test "Empty domains produce valid fingerprint":
var domains = initTable[string, seq[string]]()
let fp = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
check fp.len == 20
check fp.startsWith("blake2b-")
test "Multiple domains with multiple values":
var domains = initTable[string, seq[string]]()
domains["init"] = @["dinit"]
domains["runtime"] = @["ssl", "http3", "zstd", "ipv6"]
domains["security"] = @["pie", "relro", "hardened"]
domains["optimization"] = @["lto", "march-native"]
domains["network"] = @["ipv6", "wireguard"]
let fp = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
check fp.len == 20
check fp.startsWith("blake2b-")
# Verify it's deterministic
let fp2 = calculateVariantFingerprint(
"nginx", "1.28.0", domains, testCompilerFlags, testToolchain, testTarget
)
check fp == fp2
when isMainModule:
echo "Running variant fingerprint tests..."