## Tests for NPK Package Format Handler ## ## This module tests the NPK package format creation, validation, and conversion ## capabilities with CAS integration and digital signature support. import unittest, os, times, json, options import ../src/nimpak/[types, packages, cas] suite "NPK Package Format Handler": setup: let testDir = getTempDir() / "nimpak_test_npk" let casDir = testDir / "cas" let sourceDir = testDir / "source" let outputDir = testDir / "output" # Clean up and create test directories if dirExists(testDir): removeDir(testDir) createDir(testDir) createDir(casDir) createDir(sourceDir) createDir(outputDir) # Initialize CAS manager let cas = initCasManager(casDir, casDir) # Create test files in source directory writeFile(sourceDir / "test.txt", "Hello, NimPak!") writeFile(sourceDir / "config.conf", "setting=value\nother=123") createDir(sourceDir / "subdir") writeFile(sourceDir / "subdir" / "nested.dat", "nested file content") teardown: let testDir = getTempDir() / "nimpak_test_npk" if dirExists(testDir): removeDir(testDir) test "create NPK package from Fragment and source directory": leagment = Fragment( id: PackageId(name: "test-package", version: "1.0.0", stream: Stable), source: Source( url: "https://example.com/test-package-1.0.0.tar.gz", hash: "blake2b-test123", hashAlgorithm: "blake2b", sourceMethod: Http, timestamp: now() ), dependencies: @[], buildSystem: Custom, metadata: PackageMetadata( description: "Test package for NPK format", license: "MIT", maintainer: "test@example.com", tags: @["test"], runtime: RuntimeProfile( libc: Musl, allocator: Jemalloc, systemdAware: false, reproducible: true, tags: @["cli"] ) ), acul: AculCompliance( required: false, membership: "", attribution: "", buildLog: "" ) ) let result = createNpkPackage(fragment, sourceDir, cas) check result.isOk let npk = result.get() check npk.metadata.id.name == "test-package" check npk.metadata.id.version == "1.0.0" check npk.files.len == 3 # test.txt, config.conf, subdir/nested.dat check npk.manifest.totalSize > 0 check npk.manifest.merkleRoot.len > 0 check npk.manifest.merkleRoot.startsWith("blake2b-") test "validate NPK package metadata and structure": let fragment = Fragment( id: PackageId(name: "valid-package", version: "2.0.0", stream: Testing), source: Source( url: "https://example.com/valid-package.tar.gz", hash: "blake2b-valid123", hashAlgorithm: "blake2b", sourceMethod: Git, timestamp: now() ), dependencies: @[PackageId(name: "dep1", version: "1.0", stream: Stable)], buildSystem: CMake, metadata: PackageMetadata( description: "Valid test package", license: "ACUL", maintainer: "maintainer@example.com", tags: @["valid", "test"], runtime: RuntimeProfile( libc: Glibc, allocator: System, systemdAware: true, reproducible: true, tags: @["system"] ) ), acul: AculCompliance( required: true, membership: "NexusOS-Community", attribution: "Original work", buildLog: "Build completed successfully" ) ) let createResult = createNpkPackage(fragment, sourceDir, cas) check createResult.isOk let npk = createResult.get() let validation = validateNpkPackage(npk) check validation.valid == true check validation.errors.len == 0 # May have warnings about non-standard hash algorithms, but should be valid test "serialize NPK package to KDL format": let fragment = Fragment( id: PackageId(name: "kdl-test", version: "1.5.0", stream: Stable), source: Source( url: "https://example.com/kdl-test.tar.gz", hash: "blake2b-kdltest123", hashAlgorithm: "blake2b", sourceMethod: Http, timestamp: now() ), dependencies: @[], buildSystem: Meson, metadata: PackageMetadata( description: "KDL serialization test", license: "MIT", maintainer: "test@kdl.com", tags: @["kdl"], runtime: RuntimeProfile( libc: Musl, allocator: Jemalloc, systemdAware: false, reproducible: true, tags: @["serialization"] ) ), acul: AculCompliance( required: false, membership: "", attribution: "", buildLog: "" ) ) let createResult = createNpkPackage(fragment, sourceDir, cas) check createResult.isOk let npk = createResult.get() let kdlContent = serializeToKdl(npk) # Check that KDL content contains expected sections check kdlContent.contains("package \"kdl-test\"") check kdlContent.contains("version \"1.5.0\"") check kdlContent.contains("stream \"Stable\"") check kdlContent.contains("source {") check kdlContent.contains("integrity {") check kdlContent.contains("runtime {") check kdlContent.contains("acul {") check kdlContent.contains("manifest {") check kdlContent.contains("files {") check kdlContent.contains("algorithm \"BLAKE2b\"") test "create and validate .npk.zst archive": let fragment = Fragment( id: PackageId(name: "archive-test", version: "3.0.0", stream: Dev), source: Source( url: "https://example.com/archive-test.tar.gz", hash: "blake2b-archive123", hashAlgorithm: "blake2b", sourceMethod: Local, timestamp: now() ), dependencies: @[], buildSystem: Autotools, metadata: PackageMetadata( description: "Archive format test", license: "EUPL-1.2", maintainer: "archive@test.com", tags: @["archive"], runtime: RuntimeProfile( libc: Musl, allocator: Internal, systemdAware: false, reproducible: true, tags: @["compression"] ) ), acul: AculCompliance( required: true, membership: "NexusOS", attribution: "Test archive", buildLog: "Archive test build" ) ) let createResult = createNpkPackage(fragment, sourceDir, cas) check createResult.isOk let npk = createResult.get() let archivePath = outputDir / "test-archive" # Test .npk.zst format (default) let archiveResult = createNpkArchive(npk, archivePath, NpkZst) check archiveResult.isOk let finalPath = archivePath & ".npk.zst" check fileExists(finalPath) # Verify archive is not empty let archiveInfo = getFileInfo(finalPath) check archiveInfo.size > 0 test "create uncompressed .npk.tar archive for debugging": let fragment = Fragment( id: PackageId(name: "debug-test", version: "1.0.0", stream: Dev), source: Source( url: "file:///tmp/debug-test", hash: "blake2b-debug123", hashAlgorithm: "blake2b", sourceMethod: Local, timestamp: now() ), dependencies: @[], buildSystem: Custom, metadata: PackageMetadata( description: "Debug archive test", license: "MIT", maintainer: "debug@test.com", tags: @["debug"], runtime: RuntimeProfile( libc: None, allocator: System, systemdAware: false, reproducible: true, tags: @["debug"] ) ), acul: AculCompliance( required: false, membership: "", attribution: "", buildLog: "" ) ) let createResult = createNpkPackage(fragment, sourceDir, cas) check createResult.isOk let npk = createResult.get() let archivePath = outputDir / "debug-archive" # Test .npk.tar format (uncompressed) let archiveResult = createNpkArchive(npk, archivePath, NpkTar) check archiveResult.isOk let finalPath = archivePath & ".npk.tar" check fileExists(finalPath) test "extract NPK package using CAS": let fragment = Fragment( id: PackageId(name: "extract-test", version: "2.5.0", stream: Stable), source: Source( url: "https://example.com/extract-test.tar.gz", hash: "blake2b-extract123", hashAlgorithm: "blake2b", sourceMethod: Http, timestamp: now() ), dependencies: @[], buildSystem: Nim, metadata: PackageMetadata( description: "Extraction test package", license: "MIT", maintainer: "extract@test.com", tags: @["extract"], runtime: RuntimeProfile( libc: Musl, allocator: Jemalloc, systemdAware: false, reproducible: true, tags: @["extraction"] ) ), acul: AculCompliance( required: false, membership: "", attribution: "", buildLog: "" ) ) let createResult = createNpkPackage(fragment, sourceDir, cas) check createResult.isOk let npk = createResult.get() let extractDir = outputDir / "extracted" let extractResult = extractNpkPackage(npk, extractDir, cas) check extractResult.isOk # Verify extracted files exist check fileExists(extractDir / "test.txt") check fileExists(extractDir / "config.conf") check fileExists(extractDir / "subdir" / "nested.dat") # Verify file contents check readFile(extractDir / "test.txt") == "Hello, NimPak!" check readFile(extractDir / "config.conf") == "setting=value\nother=123" check readFile(extractDir / "subdir" / "nested.dat") == "nested file content" test "validate NPK package with missing required fields": # Create an invalid fragment with missing required fields let invalidFragment = Fragment( id: PackageId(name: "", version: "", stream: Stable), # Empty name and version source: Source( url: "", # Empty URL hash: "", # Empty hash hashAlgorithm: "blake2b", sourceMethod: Http, timestamp: now() ), dependencies: @[], buildSystem: Custom, metadata: PackageMetadata( description: "Invalid test package", license: "MIT", maintainer: "invalid@test.com", tags: @[], runtime: RuntimeProfile( libc: Musl, allocator: System, systemdAware: false, reproducible: false, tags: @[] ) ), acul: AculCompliance( required: false, membership: "", attribution: "", buildLog: "" ) ) let createResult = createNpkPackage(invalidFragment, sourceDir, cas) check createResult.isOk # Creation should succeed even with invalid metadata let npk = createResult.get() let validation = validateNpkPackage(npk) check validation.valid == false check validation.errors.len > 0 # Check for specific validation errors var hasNameError = false var hasVersionError = false var hasUrlError = false var hasHashError = false for error in validation.errors: if error.field == "metadata.id.name": hasNameError = true elif error.field == "metadata.id.version": hasVersionError = true elif error.field == "metadata.source.url": hasUrlError = true elif error.field == "metadata.source.hash": hasHashError = true check hasNameError check hasVersionError check hasUrlError check hasHashError test "get human-readable NPK package information": let fragment = Fragment( id: PackageId(name: "info-test", version: "4.2.1", stream: LTS), source: Source( url: "https://example.com/info-test.tar.gz", hash: "blake2b-info123", hashAlgorithm: "blake2b", sourceMethod: Git, timestamp: now() ), dependencies: @[], buildSystem: Cargo, metadata: PackageMetadata( description: "Package info test", license: "Apache-2.0", maintainer: "info@test.com", tags: @["info"], runtime: RuntimeProfile( libc: Glibc, allocator: Jemalloc, systemdAware: true, reproducible: true, tags: @["information"] ) ), acul: AculCompliance( required: true, membership: "NexusOS-Pro", attribution: "Info test package", buildLog: "Info build completed" ) ) let createResult = createNpkPackage(fragment, sourceDir, cas) check createResult.isOk let npk = createResult.get() let info = getNpkInfo(npk) check info.contains("NPK Package: info-test v4.2.1") check info.contains("Stream: LTS") check info.contains("Files: 3") check info.contains("Total Size:") check info.contains("Created:") check info.contains("Merkle Root: blake2b-") check info.contains("Signed: No") when isMainModule: # Run the tests echo "Running NPK Package Format Handler tests..."