## test_variant_compiler.nim ## Tests for compiler flag resolution system ## Ensures proper flag resolution with priority ordering import std/[unittest, tables, strutils, sequtils] import ../src/nimpak/variant_compiler import ../src/nimpak/variant_types import ../src/nimpak/config suite "Compiler Flag Resolution Tests": let baseFlags = CompilerFlags( cflags: "-O2 -pipe", cxxflags: "-O2 -pipe", ldflags: "-Wl,-O1", makeflags: "-j4" ) test "Empty domains return base flags": var domains = initTable[string, seq[string]]() let resolved = resolveCompilerFlags(domains, baseFlags) check resolved.cflags == baseFlags.cflags check resolved.ldflags == baseFlags.ldflags test "Optimization LTO flag adds compiler flags": var domains = initTable[string, seq[string]]() domains["optimization"] = @["lto"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-flto=full" in resolved.cflags check "-flto" in resolved.ldflags check "-fuse-ld=mold" in resolved.ldflags test "Optimization march-native flag": var domains = initTable[string, seq[string]]() domains["optimization"] = @["march-native"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-march=native" in resolved.cflags test "Security PIE flag": var domains = initTable[string, seq[string]]() domains["security"] = @["pie"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-fPIE" in resolved.cflags check "-pie" in resolved.ldflags test "Security RELRO flag": var domains = initTable[string, seq[string]]() domains["security"] = @["relro"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-Wl,-z,relro,-z,now" in resolved.ldflags test "Security hardened flag": var domains = initTable[string, seq[string]]() domains["security"] = @["hardened"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-D_FORTIFY_SOURCE=2" in resolved.cflags check "-fstack-protector-strong" in resolved.cflags test "Multiple flags in same domain": var domains = initTable[string, seq[string]]() domains["security"] = @["pie", "relro", "hardened"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-fPIE" in resolved.cflags check "-D_FORTIFY_SOURCE=2" in resolved.cflags check "-pie" in resolved.ldflags check "-Wl,-z,relro,-z,now" in resolved.ldflags suite "Priority Ordering Tests": let baseFlags = CompilerFlags( cflags: "-O2", ldflags: "-Wl,-O1" ) test "Security flags applied before optimization": var domains = initTable[string, seq[string]]() domains["security"] = @["pie"] domains["optimization"] = @["lto"] let resolved = resolveCompilerFlags(domains, baseFlags) # Security flags should appear before optimization flags let cflagsStr = resolved.cflags let piePos = cflagsStr.find("-fPIE") let ltoPos = cflagsStr.find("-flto") check piePos >= 0 check ltoPos >= 0 check piePos < ltoPos # PIE should come before LTO test "Multiple domains with priority ordering": var domains = initTable[string, seq[string]]() domains["optimization"] = @["lto", "march-native"] domains["security"] = @["pie", "relro"] let resolved = resolveCompilerFlags(domains, baseFlags) # All flags should be present check "-fPIE" in resolved.cflags check "-flto=full" in resolved.cflags check "-march=native" in resolved.cflags check "-pie" in resolved.ldflags check "-Wl,-z,relro,-z,now" in resolved.ldflags suite "Flag Rule Query Tests": test "hasCompilerFlagRule detects existing rules": check hasCompilerFlagRule("optimization", "lto") == true check hasCompilerFlagRule("security", "pie") == true test "hasCompilerFlagRule returns false for non-existent rules": check hasCompilerFlagRule("optimization", "nonexistent") == false check hasCompilerFlagRule("nonexistent", "lto") == false test "getCompilerFlagRule returns correct rule": let rule = getCompilerFlagRule("optimization", "lto") check rule.condition == "lto" check rule.cflags == "-flto=full" check rule.ldflags == "-flto -fuse-ld=mold" test "getDomainRules returns all rules for domain": let rules = getDomainRules("optimization") check rules.hasKey("lto") check rules.hasKey("march-native") check rules.hasKey("pgo") test "getDomainRules returns empty for unknown domain": let rules = getDomainRules("unknown_domain") check rules.len == 0 suite "Flag Analysis Tests": test "analyzeCompilerFlags lists applied flags": var domains = initTable[string, seq[string]]() domains["optimization"] = @["lto"] domains["security"] = @["pie"] let analysis = analyzeCompilerFlags(domains) check analysis.len == 2 check any(analysis, proc(s: string): bool = "optimization.lto" in s) check any(analysis, proc(s: string): bool = "security.pie" in s) test "explainFlag provides detailed information": let explanation = explainFlag("optimization", "lto") check "lto" in explanation check "CFLAGS" in explanation check "LDFLAGS" in explanation check "-flto=full" in explanation test "explainFlag handles non-existent flag": let explanation = explainFlag("optimization", "nonexistent") check "No compiler flag rule" in explanation suite "Conflict Detection Tests": test "No conflicts in normal configuration": var domains = initTable[string, seq[string]]() domains["optimization"] = @["lto", "march-native"] domains["security"] = @["pie", "relro"] let conflicts = detectFlagConflicts(domains) check conflicts.len == 0 check hasConflicts(domains) == false test "Detect debug + strip conflict": var domains = initTable[string, seq[string]]() domains["optimization"] = @["debug", "strip"] let conflicts = detectFlagConflicts(domains) check conflicts.len > 0 check hasConflicts(domains) == true check any(conflicts, proc(s: string): bool = "debug" in s and "strip" in s) test "Detect debug + lto warning": var domains = initTable[string, seq[string]]() domains["optimization"] = @["debug", "lto"] let conflicts = detectFlagConflicts(domains) check conflicts.len > 0 check any(conflicts, proc(s: string): bool = "debug" in s and "lto" in s) suite "Helper Function Tests": test "mergeCompilerFlags combines flags": let base = CompilerFlags( cflags: "-O2", ldflags: "-Wl,-O1" ) let additional = CompilerFlags( cflags: "-march=native", ldflags: "-flto" ) let merged = mergeCompilerFlags(base, additional) check "-O2" in merged.cflags check "-march=native" in merged.cflags check "-Wl,-O1" in merged.ldflags check "-flto" in merged.ldflags test "cleanCompilerFlags removes extra spaces": let dirty = CompilerFlags( cflags: "-O2 -pipe -march=native", ldflags: "-Wl,-O1 -flto" ) let clean = cleanCompilerFlags(dirty) check clean.cflags == "-O2 -pipe -march=native" check clean.ldflags == "-Wl,-O1 -flto" suite "Real-World Configuration Tests": let baseFlags = CompilerFlags( cflags: "-O2 -pipe", ldflags: "-Wl,-O1" ) test "Fleet node configuration": var domains = initTable[string, seq[string]]() domains["security"] = @["pie", "relro", "hardened"] domains["optimization"] = @["lto", "march-native"] let resolved = resolveCompilerFlags(domains, baseFlags) # Security flags check "-fPIE" in resolved.cflags check "-D_FORTIFY_SOURCE=2" in resolved.cflags check "-pie" in resolved.ldflags check "-Wl,-z,relro,-z,now" in resolved.ldflags # Optimization flags check "-flto=full" in resolved.cflags check "-march=native" in resolved.cflags test "Debug build configuration": var domains = initTable[string, seq[string]]() domains["optimization"] = @["debug"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-g" in resolved.cflags check "-O0" in resolved.cflags test "Minimal configuration": var domains = initTable[string, seq[string]]() domains["security"] = @["pie"] let resolved = resolveCompilerFlags(domains, baseFlags) check "-fPIE" in resolved.cflags check "-pie" in resolved.ldflags # Base flags should still be present check "-O2" in resolved.cflags when isMainModule: echo "Running variant compiler tests..."