diff --git a/lib/compiler/Maker/Step/ConfigHeader.zig b/lib/compiler/Maker/Step/ConfigHeader.zig index 762b0ff483856df1aaa2a5ddad3d19b5c47199e7..8f4f677ee3bd4cef5f42541673823e9377185c86 100644 --- a/lib/compiler/Maker/Step/ConfigHeader.zig +++ b/lib/compiler/Maker/Step/ConfigHeader.zig @@ -608,313 +608,3 @@ fn expandVariablesCmake( return result.toOwnedSliceAssert(); } - -fn testReplaceVariablesAutoconfAt( - arena: Allocator, - contents: []const u8, - expected: []const u8, - value_map: *const ValueMap, -) !void { - var aw: Writer.Allocating = .init(arena); - defer aw.deinit(); - - const used = try arena.alloc(bool, value_map.count()); - for (used) |*u| u.* = false; - - try expandVariablesAutoconfAt(&aw.writer, contents, value_map, used); - - for (used) |u| if (!u) return error.UnusedValue; - try std.testing.expectEqualStrings(expected, aw.written()); -} - -fn testReplaceVariablesCMake( - arena: Allocator, - contents: []const u8, - expected: []const u8, - value_map: *const ValueMap, -) !void { - const actual = try expandVariablesCmake(arena, contents, value_map); - - try std.testing.expectEqualStrings(expected, actual); -} - -test "expandVariablesAutoconfAt simple cases" { - const allocator = std.testing.allocator; - var value_map: ValueMap = .empty; - defer value_map.deinit(); - - // empty strings are preserved - try testReplaceVariablesAutoconfAt(allocator, "", "", value_map); - - // line with misc content is preserved - try testReplaceVariablesAutoconfAt(allocator, "no substitution", "no substitution", value_map); - - // empty @ sigils are preserved - try testReplaceVariablesAutoconfAt(allocator, "@", "@", value_map); - try testReplaceVariablesAutoconfAt(allocator, "@@", "@@", value_map); - try testReplaceVariablesAutoconfAt(allocator, "@@@", "@@@", value_map); - try testReplaceVariablesAutoconfAt(allocator, "@@@@", "@@@@", value_map); - - // simple substitution - try value_map.putNoClobber("undef", .undef); - try testReplaceVariablesAutoconfAt(allocator, "@undef@", "", value_map); - value_map.clearRetainingCapacity(); - - try value_map.putNoClobber("defined", .defined); - try testReplaceVariablesAutoconfAt(allocator, "@defined@", "", value_map); - value_map.clearRetainingCapacity(); - - try value_map.putNoClobber("true", Value{ .boolean = true }); - try testReplaceVariablesAutoconfAt(allocator, "@true@", "1", value_map); - value_map.clearRetainingCapacity(); - - try value_map.putNoClobber("false", Value{ .boolean = false }); - try testReplaceVariablesAutoconfAt(allocator, "@false@", "0", value_map); - value_map.clearRetainingCapacity(); - - try value_map.putNoClobber("int", Value{ .int = 42 }); - try testReplaceVariablesAutoconfAt(allocator, "@int@", "42", value_map); - value_map.clearRetainingCapacity(); - - try value_map.putNoClobber("ident", Value{ .string = "value" }); - try testReplaceVariablesAutoconfAt(allocator, "@ident@", "value", value_map); - value_map.clearRetainingCapacity(); - - try value_map.putNoClobber("string", Value{ .string = "text" }); - try testReplaceVariablesAutoconfAt(allocator, "@string@", "text", value_map); - value_map.clearRetainingCapacity(); - - // double packed substitution - try value_map.putNoClobber("string", Value{ .string = "text" }); - try testReplaceVariablesAutoconfAt(allocator, "@string@@string@", "texttext", value_map); - value_map.clearRetainingCapacity(); - - // triple packed substitution - try value_map.putNoClobber("int", Value{ .int = 42 }); - try value_map.putNoClobber("string", Value{ .string = "text" }); - try testReplaceVariablesAutoconfAt(allocator, "@string@@int@@string@", "text42text", value_map); - value_map.clearRetainingCapacity(); - - // double separated substitution - try value_map.putNoClobber("int", Value{ .int = 42 }); - try testReplaceVariablesAutoconfAt(allocator, "@int@.@int@", "42.42", value_map); - value_map.clearRetainingCapacity(); - - // triple separated substitution - try value_map.putNoClobber("true", Value{ .boolean = true }); - try value_map.putNoClobber("int", Value{ .int = 42 }); - try testReplaceVariablesAutoconfAt(allocator, "@int@.@true@.@int@", "42.1.42", value_map); - value_map.clearRetainingCapacity(); - - // misc prefix is preserved - try value_map.putNoClobber("false", Value{ .boolean = false }); - try testReplaceVariablesAutoconfAt(allocator, "false is @false@", "false is 0", value_map); - value_map.clearRetainingCapacity(); - - // misc suffix is preserved - try value_map.putNoClobber("true", Value{ .boolean = true }); - try testReplaceVariablesAutoconfAt(allocator, "@true@ is true", "1 is true", value_map); - value_map.clearRetainingCapacity(); - - // surrounding content is preserved - try value_map.putNoClobber("int", Value{ .int = 42 }); - try testReplaceVariablesAutoconfAt(allocator, "what is 6*7? @int@!", "what is 6*7? 42!", value_map); - value_map.clearRetainingCapacity(); - - // incomplete key is preserved - try testReplaceVariablesAutoconfAt(allocator, "@undef", "@undef", value_map); - - // unknown key leads to an error - try std.testing.expectError(error.MissingValue, testReplaceVariablesAutoconfAt(allocator, "@bad@", "", value_map)); - - // unused key leads to an error - try value_map.putNoClobber("int", Value{ .int = 42 }); - try value_map.putNoClobber("false", Value{ .boolean = false }); - try std.testing.expectError(error.UnusedValue, testReplaceVariablesAutoconfAt(allocator, "@int", "", value_map)); - value_map.clearRetainingCapacity(); -} - -test "expandVariablesAutoconfAt edge cases" { - const allocator = std.testing.allocator; - var value_map: std.array_hash_map.String(Value) = .init(allocator); - defer value_map.deinit(); - - // @-vars resolved only when they wrap valid characters, otherwise considered literals - try value_map.putNoClobber("string", Value{ .string = "text" }); - try testReplaceVariablesAutoconfAt(allocator, "@@string@@", "@text@", value_map); - value_map.clearRetainingCapacity(); - - // expanded variables are considered strings after expansion - try value_map.putNoClobber("string_at", Value{ .string = "@string@" }); - try testReplaceVariablesAutoconfAt(allocator, "@string_at@", "@string@", value_map); - value_map.clearRetainingCapacity(); -} - -test "expandVariablesCmake simple cases" { - const allocator = std.testing.allocator; - var value_map: std.array_hash_map.String(Value) = .init(allocator); - defer value_map.deinit(); - - try value_map.putNoClobber("undef", .undef); - try value_map.putNoClobber("defined", .defined); - try value_map.putNoClobber("true", Value{ .boolean = true }); - try value_map.putNoClobber("false", Value{ .boolean = false }); - try value_map.putNoClobber("int", Value{ .int = 42 }); - try value_map.putNoClobber("ident", Value{ .string = "value" }); - try value_map.putNoClobber("string", Value{ .string = "text" }); - - // empty strings are preserved - try testReplaceVariablesCMake(allocator, "", "", value_map); - - // line with misc content is preserved - try testReplaceVariablesCMake(allocator, "no substitution", "no substitution", value_map); - - // empty ${} wrapper leads to an error - try std.testing.expectError(error.MissingKey, testReplaceVariablesCMake(allocator, "${}", "", value_map)); - - // empty @ sigils are preserved - try testReplaceVariablesCMake(allocator, "@", "@", value_map); - try testReplaceVariablesCMake(allocator, "@@", "@@", value_map); - try testReplaceVariablesCMake(allocator, "@@@", "@@@", value_map); - try testReplaceVariablesCMake(allocator, "@@@@", "@@@@", value_map); - - // simple substitution - try testReplaceVariablesCMake(allocator, "@undef@", "", value_map); - try testReplaceVariablesCMake(allocator, "${undef}", "", value_map); - try testReplaceVariablesCMake(allocator, "@defined@", "", value_map); - try testReplaceVariablesCMake(allocator, "${defined}", "", value_map); - try testReplaceVariablesCMake(allocator, "@true@", "1", value_map); - try testReplaceVariablesCMake(allocator, "${true}", "1", value_map); - try testReplaceVariablesCMake(allocator, "@false@", "0", value_map); - try testReplaceVariablesCMake(allocator, "${false}", "0", value_map); - try testReplaceVariablesCMake(allocator, "@int@", "42", value_map); - try testReplaceVariablesCMake(allocator, "${int}", "42", value_map); - try testReplaceVariablesCMake(allocator, "@ident@", "value", value_map); - try testReplaceVariablesCMake(allocator, "${ident}", "value", value_map); - try testReplaceVariablesCMake(allocator, "@string@", "text", value_map); - try testReplaceVariablesCMake(allocator, "${string}", "text", value_map); - - // double packed substitution - try testReplaceVariablesCMake(allocator, "@string@@string@", "texttext", value_map); - try testReplaceVariablesCMake(allocator, "${string}${string}", "texttext", value_map); - - // triple packed substitution - try testReplaceVariablesCMake(allocator, "@string@@int@@string@", "text42text", value_map); - try testReplaceVariablesCMake(allocator, "@string@${int}@string@", "text42text", value_map); - try testReplaceVariablesCMake(allocator, "${string}@int@${string}", "text42text", value_map); - try testReplaceVariablesCMake(allocator, "${string}${int}${string}", "text42text", value_map); - - // double separated substitution - try testReplaceVariablesCMake(allocator, "@int@.@int@", "42.42", value_map); - try testReplaceVariablesCMake(allocator, "${int}.${int}", "42.42", value_map); - - // triple separated substitution - try testReplaceVariablesCMake(allocator, "@int@.@true@.@int@", "42.1.42", value_map); - try testReplaceVariablesCMake(allocator, "@int@.${true}.@int@", "42.1.42", value_map); - try testReplaceVariablesCMake(allocator, "${int}.@true@.${int}", "42.1.42", value_map); - try testReplaceVariablesCMake(allocator, "${int}.${true}.${int}", "42.1.42", value_map); - - // misc prefix is preserved - try testReplaceVariablesCMake(allocator, "false is @false@", "false is 0", value_map); - try testReplaceVariablesCMake(allocator, "false is ${false}", "false is 0", value_map); - - // misc suffix is preserved - try testReplaceVariablesCMake(allocator, "@true@ is true", "1 is true", value_map); - try testReplaceVariablesCMake(allocator, "${true} is true", "1 is true", value_map); - - // surrounding content is preserved - try testReplaceVariablesCMake(allocator, "what is 6*7? @int@!", "what is 6*7? 42!", value_map); - try testReplaceVariablesCMake(allocator, "what is 6*7? ${int}!", "what is 6*7? 42!", value_map); - - // incomplete key is preserved - try testReplaceVariablesCMake(allocator, "@undef", "@undef", value_map); - try testReplaceVariablesCMake(allocator, "${undef", "${undef", value_map); - try testReplaceVariablesCMake(allocator, "{undef}", "{undef}", value_map); - try testReplaceVariablesCMake(allocator, "undef@", "undef@", value_map); - try testReplaceVariablesCMake(allocator, "undef}", "undef}", value_map); - - // unknown key leads to an error - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "@bad@", "", value_map)); - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${bad}", "", value_map)); -} - -test "expandVariablesCmake edge cases" { - const allocator = std.testing.allocator; - var value_map: std.array_hash_map.String(Value) = .init(allocator); - defer value_map.deinit(); - - // special symbols - try value_map.putNoClobber("at", Value{ .string = "@" }); - try value_map.putNoClobber("dollar", Value{ .string = "$" }); - try value_map.putNoClobber("underscore", Value{ .string = "_" }); - - // basic value - try value_map.putNoClobber("string", Value{ .string = "text" }); - - // proxy case value_map - try value_map.putNoClobber("string_proxy", Value{ .string = "string" }); - try value_map.putNoClobber("string_at", Value{ .string = "@string@" }); - try value_map.putNoClobber("string_curly", Value{ .string = "{string}" }); - try value_map.putNoClobber("string_var", Value{ .string = "${string}" }); - - // stack case value_map - try value_map.putNoClobber("nest_underscore_proxy", Value{ .string = "underscore" }); - try value_map.putNoClobber("nest_proxy", Value{ .string = "nest_underscore_proxy" }); - - // @-vars resolved only when they wrap valid characters, otherwise considered literals - try testReplaceVariablesCMake(allocator, "@@string@@", "@text@", value_map); - try testReplaceVariablesCMake(allocator, "@${string}@", "@text@", value_map); - - // @-vars are resolved inside ${}-vars - try testReplaceVariablesCMake(allocator, "${@string_proxy@}", "text", value_map); - - // expanded variables are considered strings after expansion - try testReplaceVariablesCMake(allocator, "@string_at@", "@string@", value_map); - try testReplaceVariablesCMake(allocator, "${string_at}", "@string@", value_map); - try testReplaceVariablesCMake(allocator, "$@string_curly@", "${string}", value_map); - try testReplaceVariablesCMake(allocator, "$${string_curly}", "${string}", value_map); - try testReplaceVariablesCMake(allocator, "${string_var}", "${string}", value_map); - try testReplaceVariablesCMake(allocator, "@string_var@", "${string}", value_map); - try testReplaceVariablesCMake(allocator, "${dollar}{${string}}", "${text}", value_map); - try testReplaceVariablesCMake(allocator, "@dollar@{${string}}", "${text}", value_map); - try testReplaceVariablesCMake(allocator, "@dollar@{@string@}", "${text}", value_map); - - // when expanded variables contain invalid characters, they prevent further expansion - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${${string_var}}", "", value_map)); - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${@string_var@}", "", value_map)); - - // nested expanded variables are expanded from the inside out - try testReplaceVariablesCMake(allocator, "${string${underscore}proxy}", "string", value_map); - try testReplaceVariablesCMake(allocator, "${string@underscore@proxy}", "string", value_map); - - // nested vars are only expanded when ${} is closed - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "@nest@underscore@proxy@", "", value_map)); - try testReplaceVariablesCMake(allocator, "${nest${underscore}proxy}", "nest_underscore_proxy", value_map); - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "@nest@@nest_underscore@underscore@proxy@@proxy@", "", value_map)); - try testReplaceVariablesCMake(allocator, "${nest${${nest_underscore${underscore}proxy}}proxy}", "nest_underscore_proxy", value_map); - - // invalid characters lead to an error - try std.testing.expectError(error.InvalidCharacter, testReplaceVariablesCMake(allocator, "${str*ing}", "", value_map)); - try std.testing.expectError(error.InvalidCharacter, testReplaceVariablesCMake(allocator, "${str$ing}", "", value_map)); - try std.testing.expectError(error.InvalidCharacter, testReplaceVariablesCMake(allocator, "${str@ing}", "", value_map)); -} - -test "expandVariablesCmake escaped characters" { - const allocator = std.testing.allocator; - var value_map: std.array_hash_map.String(Value) = .init(allocator); - defer value_map.deinit(); - - try value_map.putNoClobber("string", Value{ .string = "text" }); - - // backslash is an invalid character for @ lookup - try testReplaceVariablesCMake(allocator, "\\@string\\@", "\\@string\\@", value_map); - - // backslash is preserved, but doesn't affect ${} variable expansion - try testReplaceVariablesCMake(allocator, "\\${string}", "\\text", value_map); - - // backslash breaks ${} opening bracket identification - try testReplaceVariablesCMake(allocator, "$\\{string}", "$\\{string}", value_map); - - // backslash is skipped when checking for invalid characters, yet it mangles the key - try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${string\\}", "", value_map)); -}