## tests/test_build_system.nim ## Unit tests for the Nimplate build system ## ## Tests type-safe build templates, build execution, caching, ## and environment isolation for all supported build systems. import std/[unittest, os, times, strutils] import ../src/nimpak/build_system import ../src/nimpak/recipes suite "Nimplate Build System Tests": setup: # Create temporary test directory let testDir = getTempDir() / "nip_test_build" createDir(testDir) teardown: # Clean up test directory let testDir = getTempDir() / "nip_test_build" if dirExists(testDir): removeDir(testDir) test "Build environment creation": let sourceDir = getTempDir() / "test_source" createDir(sourceDir) let env = newBuildEnvironment(sourceDir, isolated = true) check env.sourceDir == sourceDir check env.isolated == true check env.environment.hasKey("PREFIX") check env.environment.hasKey("MAKEFLAGS") check env.workDir.contains("nimpak_build_") test "Nimplate executor creation": let sourceDir = getTempDir() / "test_source" createDir(sourceDir) let buildTmpl = getBuildSystemDefaults(CMake) let executor = newNimplateExecutor(buildTmpl, sourceDir) check executor.buildTemplate.system == CMake check executor.cacheEnabled == true check executor.sandboxed == true check executor.environment.sourceDir == sourceDir test "CMake build template defaults": let buildTmpl = getBuildSystemDefaults(CMake) check buildTmpl.system == CMake check "-DCMAKE_BUILD_TYPE=Release" in buildTmpl.configureArgs check "--parallel" in buildTmpl.buildArgs test "Autotools build template defaults": let buildTmpl = getBuildSystemDefaults(Autotools) check buildTmpl.system == Autotools check "--prefix=/usr" in buildTmpl.configureArgs check "-j" in buildTmpl.buildArgs[0] # Should contain -j for parallel make test "Meson build template defaults": let buildTmpl = getBuildSystemDefaults(Meson) check buildTmpl.system == Meson check "setup" in buildTmpl.configureArgs check "--buildtype=release" in buildTmpl.configureArgs test "Cargo build template defaults": let buildTmpl = getBuildSystemDefaults(Cargo) check buildTmpl.system == Cargo check "--release" in buildTmpl.buildArgs test "Nim build template defaults": let buildTmpl = getBuildSystemDefaults(NimBuild) check buildTmpl.system == NimBuild check "-d:release" in buildTmpl.buildArgs test "Build hash calculation": let sourceDir = getTempDir() / "test_source" createDir(sourceDir) let buildTmpl = getBuildSystemDefaults(CMake) let hash1 = calculateBuildHash(sourceDir, buildTmpl) let hash2 = calculateBuildHash(sourceDir, buildTmpl) check hash1 == hash2 # Same source and template should produce same hash check hash1.startsWith("build-") test "Build cache detection": let cacheDir = getTempDir() / "build_cache" createDir(cacheDir) let buildHash = "test-build-hash" # Initially not cached check isBuildCached(buildHash, cacheDir) == false # Create cache file let cacheFile = cacheDir / buildHash & ".cache" writeFile(cacheFile, "cached build result") # Now should be cached check isBuildCached(buildHash, cacheDir) == true test "Build environment isolation setup": let sourceDir = getTempDir() / "test_source" var env = newBuildEnvironment(sourceDir, isolated = true) setupSandbox(env) check env.environment.hasKey("SANDBOX") check env.environment["SANDBOX"] == "true" check env.environment.hasKey("HOME") check env.environment.hasKey("TMPDIR") suite "Nimplate Build Execution Tests": test "Mock CMake build execution": # Create a mock CMake project let sourceDir = getTempDir() / "cmake_project" createDir(sourceDir) # Create a minimal CMakeLists.txt writeFile(sourceDir / "CMakeLists.txt", """ cmake_minimum_required(VERSION 3.10) project(TestProject) add_executable(test main.cpp) """) # Create a minimal main.cpp writeFile(sourceDir / "main.cpp", """ #include int main() { std::cout << "Hello World!" << std::endl; return 0; } """) let buildTmpl = getBuildSystemDefaults(CMake) let executor = newNimplateExecutor(buildTmpl, sourceDir) # This will fail in CI without CMake, but we can test the setup check executor.buildTemplate.system == CMake check executor.environment.sourceDir == sourceDir test "Mock Nim build execution": # Create a mock Nim project let sourceDir = getTempDir() / "nim_project" createDir(sourceDir) # Create a minimal nim file writeFile(sourceDir / "main.nim", """ echo "Hello from Nim!" """) let buildTmpl = getBuildSystemDefaults(NimBuild) let executor = newNimplateExecutor(buildTmpl, sourceDir) check executor.buildTemplate.system == NimBuild check executor.environment.sourceDir == sourceDir test "Build result structure": # Test BuildResult type var result = BuildResult( success: true, buildTime: 1.5, outputSize: 1024, buildLog: "Build completed successfully", artifacts: @["/path/to/binary"], phase: PhaseInstall, exitCode: 0 ) check result.success == true check result.buildTime == 1.5 check result.outputSize == 1024 check result.phase == PhaseInstall check result.artifacts.len == 1 suite "Build System Integration Tests": test "Build template validation": let buildTmpl = getBuildSystemDefaults(CMake) let warnings = validateBuildInstructions(buildTmpl) # CMake template should be valid check warnings.len == 0 test "Custom build template creation": let customTmpl = createBuildTemplate( system = Custom, configureArgs = @["./configure", "--enable-feature"], buildArgs = @["make", "-j4"], installArgs = @["make", "install"] ) check customTmpl.system == Custom check customTmpl.configureArgs.len == 2 check customTmpl.buildArgs.len == 2 check customTmpl.installArgs.len == 2 test "Build environment cleanup": let sourceDir = getTempDir() / "test_source" createDir(sourceDir) let env = newBuildEnvironment(sourceDir, isolated = true) let workDir = env.workDir # Work directory should exist check dirExists(workDir) # Clean up cleanupBuildEnvironment(env) # Work directory should be removed (if isolated) # Note: This might not work in all test environments # check not dirExists(workDir) test "Build cache save and load": let cacheDir = getTempDir() / "build_cache_test" let buildHash = "test-hash-123" let result = BuildResult( success: true, buildTime: 2.0, buildLog: "Test build log", phase: PhaseInstall ) # Save to cache saveBuildCache(result, buildHash, cacheDir) # Check cache exists check isBuildCached(buildHash, cacheDir) == true suite "Build System Error Handling": test "Invalid source directory handling": let invalidDir = "/nonexistent/directory" let buildTmpl = getBuildSystemDefaults(CMake) # Should handle gracefully let executor = newNimplateExecutor(buildTmpl, invalidDir) check executor.environment.sourceDir == invalidDir test "Build failure handling": # Test that build failures are properly captured var result = BuildResult( success: false, exitCode: 1, buildLog: "Build failed with error", phase: PhaseBuild ) check result.success == false check result.exitCode == 1 check "failed" in result.buildLog when isMainModule: echo "🧪 Running Build System Tests..." echo "Testing Nimplate build templates and execution..." # This will run all the test suites discard