| ... | ... | @@ -608,313 +608,3 @@ fn expandVariablesCmake( |
| 608 | 608 | |
| 609 | 609 | return result.toOwnedSliceAssert(); |
| 610 | 610 | } |
| 611 | | |
| 612 | | fn testReplaceVariablesAutoconfAt( |
| 613 | | arena: Allocator, |
| 614 | | contents: []const u8, |
| 615 | | expected: []const u8, |
| 616 | | value_map: *const ValueMap, |
| 617 | | ) !void { |
| 618 | | var aw: Writer.Allocating = .init(arena); |
| 619 | | defer aw.deinit(); |
| 620 | | |
| 621 | | const used = try arena.alloc(bool, value_map.count()); |
| 622 | | for (used) |*u| u.* = false; |
| 623 | | |
| 624 | | try expandVariablesAutoconfAt(&aw.writer, contents, value_map, used); |
| 625 | | |
| 626 | | for (used) |u| if (!u) return error.UnusedValue; |
| 627 | | try std.testing.expectEqualStrings(expected, aw.written()); |
| 628 | | } |
| 629 | | |
| 630 | | fn testReplaceVariablesCMake( |
| 631 | | arena: Allocator, |
| 632 | | contents: []const u8, |
| 633 | | expected: []const u8, |
| 634 | | value_map: *const ValueMap, |
| 635 | | ) !void { |
| 636 | | const actual = try expandVariablesCmake(arena, contents, value_map); |
| 637 | | |
| 638 | | try std.testing.expectEqualStrings(expected, actual); |
| 639 | | } |
| 640 | | |
| 641 | | test "expandVariablesAutoconfAt simple cases" { |
| 642 | | const allocator = std.testing.allocator; |
| 643 | | var value_map: ValueMap = .empty; |
| 644 | | defer value_map.deinit(); |
| 645 | | |
| 646 | | // empty strings are preserved |
| 647 | | try testReplaceVariablesAutoconfAt(allocator, "", "", value_map); |
| 648 | | |
| 649 | | // line with misc content is preserved |
| 650 | | try testReplaceVariablesAutoconfAt(allocator, "no substitution", "no substitution", value_map); |
| 651 | | |
| 652 | | // empty @ sigils are preserved |
| 653 | | try testReplaceVariablesAutoconfAt(allocator, "@", "@", value_map); |
| 654 | | try testReplaceVariablesAutoconfAt(allocator, "@@", "@@", value_map); |
| 655 | | try testReplaceVariablesAutoconfAt(allocator, "@@@", "@@@", value_map); |
| 656 | | try testReplaceVariablesAutoconfAt(allocator, "@@@@", "@@@@", value_map); |
| 657 | | |
| 658 | | // simple substitution |
| 659 | | try value_map.putNoClobber("undef", .undef); |
| 660 | | try testReplaceVariablesAutoconfAt(allocator, "@undef@", "", value_map); |
| 661 | | value_map.clearRetainingCapacity(); |
| 662 | | |
| 663 | | try value_map.putNoClobber("defined", .defined); |
| 664 | | try testReplaceVariablesAutoconfAt(allocator, "@defined@", "", value_map); |
| 665 | | value_map.clearRetainingCapacity(); |
| 666 | | |
| 667 | | try value_map.putNoClobber("true", Value{ .boolean = true }); |
| 668 | | try testReplaceVariablesAutoconfAt(allocator, "@true@", "1", value_map); |
| 669 | | value_map.clearRetainingCapacity(); |
| 670 | | |
| 671 | | try value_map.putNoClobber("false", Value{ .boolean = false }); |
| 672 | | try testReplaceVariablesAutoconfAt(allocator, "@false@", "0", value_map); |
| 673 | | value_map.clearRetainingCapacity(); |
| 674 | | |
| 675 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 676 | | try testReplaceVariablesAutoconfAt(allocator, "@int@", "42", value_map); |
| 677 | | value_map.clearRetainingCapacity(); |
| 678 | | |
| 679 | | try value_map.putNoClobber("ident", Value{ .string = "value" }); |
| 680 | | try testReplaceVariablesAutoconfAt(allocator, "@ident@", "value", value_map); |
| 681 | | value_map.clearRetainingCapacity(); |
| 682 | | |
| 683 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 684 | | try testReplaceVariablesAutoconfAt(allocator, "@string@", "text", value_map); |
| 685 | | value_map.clearRetainingCapacity(); |
| 686 | | |
| 687 | | // double packed substitution |
| 688 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 689 | | try testReplaceVariablesAutoconfAt(allocator, "@string@@string@", "texttext", value_map); |
| 690 | | value_map.clearRetainingCapacity(); |
| 691 | | |
| 692 | | // triple packed substitution |
| 693 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 694 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 695 | | try testReplaceVariablesAutoconfAt(allocator, "@string@@int@@string@", "text42text", value_map); |
| 696 | | value_map.clearRetainingCapacity(); |
| 697 | | |
| 698 | | // double separated substitution |
| 699 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 700 | | try testReplaceVariablesAutoconfAt(allocator, "@int@.@int@", "42.42", value_map); |
| 701 | | value_map.clearRetainingCapacity(); |
| 702 | | |
| 703 | | // triple separated substitution |
| 704 | | try value_map.putNoClobber("true", Value{ .boolean = true }); |
| 705 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 706 | | try testReplaceVariablesAutoconfAt(allocator, "@int@.@true@.@int@", "42.1.42", value_map); |
| 707 | | value_map.clearRetainingCapacity(); |
| 708 | | |
| 709 | | // misc prefix is preserved |
| 710 | | try value_map.putNoClobber("false", Value{ .boolean = false }); |
| 711 | | try testReplaceVariablesAutoconfAt(allocator, "false is @false@", "false is 0", value_map); |
| 712 | | value_map.clearRetainingCapacity(); |
| 713 | | |
| 714 | | // misc suffix is preserved |
| 715 | | try value_map.putNoClobber("true", Value{ .boolean = true }); |
| 716 | | try testReplaceVariablesAutoconfAt(allocator, "@true@ is true", "1 is true", value_map); |
| 717 | | value_map.clearRetainingCapacity(); |
| 718 | | |
| 719 | | // surrounding content is preserved |
| 720 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 721 | | try testReplaceVariablesAutoconfAt(allocator, "what is 6*7? @int@!", "what is 6*7? 42!", value_map); |
| 722 | | value_map.clearRetainingCapacity(); |
| 723 | | |
| 724 | | // incomplete key is preserved |
| 725 | | try testReplaceVariablesAutoconfAt(allocator, "@undef", "@undef", value_map); |
| 726 | | |
| 727 | | // unknown key leads to an error |
| 728 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesAutoconfAt(allocator, "@bad@", "", value_map)); |
| 729 | | |
| 730 | | // unused key leads to an error |
| 731 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 732 | | try value_map.putNoClobber("false", Value{ .boolean = false }); |
| 733 | | try std.testing.expectError(error.UnusedValue, testReplaceVariablesAutoconfAt(allocator, "@int", "", value_map)); |
| 734 | | value_map.clearRetainingCapacity(); |
| 735 | | } |
| 736 | | |
| 737 | | test "expandVariablesAutoconfAt edge cases" { |
| 738 | | const allocator = std.testing.allocator; |
| 739 | | var value_map: std.array_hash_map.String(Value) = .init(allocator); |
| 740 | | defer value_map.deinit(); |
| 741 | | |
| 742 | | // @-vars resolved only when they wrap valid characters, otherwise considered literals |
| 743 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 744 | | try testReplaceVariablesAutoconfAt(allocator, "@@string@@", "@text@", value_map); |
| 745 | | value_map.clearRetainingCapacity(); |
| 746 | | |
| 747 | | // expanded variables are considered strings after expansion |
| 748 | | try value_map.putNoClobber("string_at", Value{ .string = "@string@" }); |
| 749 | | try testReplaceVariablesAutoconfAt(allocator, "@string_at@", "@string@", value_map); |
| 750 | | value_map.clearRetainingCapacity(); |
| 751 | | } |
| 752 | | |
| 753 | | test "expandVariablesCmake simple cases" { |
| 754 | | const allocator = std.testing.allocator; |
| 755 | | var value_map: std.array_hash_map.String(Value) = .init(allocator); |
| 756 | | defer value_map.deinit(); |
| 757 | | |
| 758 | | try value_map.putNoClobber("undef", .undef); |
| 759 | | try value_map.putNoClobber("defined", .defined); |
| 760 | | try value_map.putNoClobber("true", Value{ .boolean = true }); |
| 761 | | try value_map.putNoClobber("false", Value{ .boolean = false }); |
| 762 | | try value_map.putNoClobber("int", Value{ .int = 42 }); |
| 763 | | try value_map.putNoClobber("ident", Value{ .string = "value" }); |
| 764 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 765 | | |
| 766 | | // empty strings are preserved |
| 767 | | try testReplaceVariablesCMake(allocator, "", "", value_map); |
| 768 | | |
| 769 | | // line with misc content is preserved |
| 770 | | try testReplaceVariablesCMake(allocator, "no substitution", "no substitution", value_map); |
| 771 | | |
| 772 | | // empty ${} wrapper leads to an error |
| 773 | | try std.testing.expectError(error.MissingKey, testReplaceVariablesCMake(allocator, "${}", "", value_map)); |
| 774 | | |
| 775 | | // empty @ sigils are preserved |
| 776 | | try testReplaceVariablesCMake(allocator, "@", "@", value_map); |
| 777 | | try testReplaceVariablesCMake(allocator, "@@", "@@", value_map); |
| 778 | | try testReplaceVariablesCMake(allocator, "@@@", "@@@", value_map); |
| 779 | | try testReplaceVariablesCMake(allocator, "@@@@", "@@@@", value_map); |
| 780 | | |
| 781 | | // simple substitution |
| 782 | | try testReplaceVariablesCMake(allocator, "@undef@", "", value_map); |
| 783 | | try testReplaceVariablesCMake(allocator, "${undef}", "", value_map); |
| 784 | | try testReplaceVariablesCMake(allocator, "@defined@", "", value_map); |
| 785 | | try testReplaceVariablesCMake(allocator, "${defined}", "", value_map); |
| 786 | | try testReplaceVariablesCMake(allocator, "@true@", "1", value_map); |
| 787 | | try testReplaceVariablesCMake(allocator, "${true}", "1", value_map); |
| 788 | | try testReplaceVariablesCMake(allocator, "@false@", "0", value_map); |
| 789 | | try testReplaceVariablesCMake(allocator, "${false}", "0", value_map); |
| 790 | | try testReplaceVariablesCMake(allocator, "@int@", "42", value_map); |
| 791 | | try testReplaceVariablesCMake(allocator, "${int}", "42", value_map); |
| 792 | | try testReplaceVariablesCMake(allocator, "@ident@", "value", value_map); |
| 793 | | try testReplaceVariablesCMake(allocator, "${ident}", "value", value_map); |
| 794 | | try testReplaceVariablesCMake(allocator, "@string@", "text", value_map); |
| 795 | | try testReplaceVariablesCMake(allocator, "${string}", "text", value_map); |
| 796 | | |
| 797 | | // double packed substitution |
| 798 | | try testReplaceVariablesCMake(allocator, "@string@@string@", "texttext", value_map); |
| 799 | | try testReplaceVariablesCMake(allocator, "${string}${string}", "texttext", value_map); |
| 800 | | |
| 801 | | // triple packed substitution |
| 802 | | try testReplaceVariablesCMake(allocator, "@string@@int@@string@", "text42text", value_map); |
| 803 | | try testReplaceVariablesCMake(allocator, "@string@${int}@string@", "text42text", value_map); |
| 804 | | try testReplaceVariablesCMake(allocator, "${string}@int@${string}", "text42text", value_map); |
| 805 | | try testReplaceVariablesCMake(allocator, "${string}${int}${string}", "text42text", value_map); |
| 806 | | |
| 807 | | // double separated substitution |
| 808 | | try testReplaceVariablesCMake(allocator, "@int@.@int@", "42.42", value_map); |
| 809 | | try testReplaceVariablesCMake(allocator, "${int}.${int}", "42.42", value_map); |
| 810 | | |
| 811 | | // triple separated substitution |
| 812 | | try testReplaceVariablesCMake(allocator, "@int@.@true@.@int@", "42.1.42", value_map); |
| 813 | | try testReplaceVariablesCMake(allocator, "@int@.${true}.@int@", "42.1.42", value_map); |
| 814 | | try testReplaceVariablesCMake(allocator, "${int}.@true@.${int}", "42.1.42", value_map); |
| 815 | | try testReplaceVariablesCMake(allocator, "${int}.${true}.${int}", "42.1.42", value_map); |
| 816 | | |
| 817 | | // misc prefix is preserved |
| 818 | | try testReplaceVariablesCMake(allocator, "false is @false@", "false is 0", value_map); |
| 819 | | try testReplaceVariablesCMake(allocator, "false is ${false}", "false is 0", value_map); |
| 820 | | |
| 821 | | // misc suffix is preserved |
| 822 | | try testReplaceVariablesCMake(allocator, "@true@ is true", "1 is true", value_map); |
| 823 | | try testReplaceVariablesCMake(allocator, "${true} is true", "1 is true", value_map); |
| 824 | | |
| 825 | | // surrounding content is preserved |
| 826 | | try testReplaceVariablesCMake(allocator, "what is 6*7? @int@!", "what is 6*7? 42!", value_map); |
| 827 | | try testReplaceVariablesCMake(allocator, "what is 6*7? ${int}!", "what is 6*7? 42!", value_map); |
| 828 | | |
| 829 | | // incomplete key is preserved |
| 830 | | try testReplaceVariablesCMake(allocator, "@undef", "@undef", value_map); |
| 831 | | try testReplaceVariablesCMake(allocator, "${undef", "${undef", value_map); |
| 832 | | try testReplaceVariablesCMake(allocator, "{undef}", "{undef}", value_map); |
| 833 | | try testReplaceVariablesCMake(allocator, "undef@", "undef@", value_map); |
| 834 | | try testReplaceVariablesCMake(allocator, "undef}", "undef}", value_map); |
| 835 | | |
| 836 | | // unknown key leads to an error |
| 837 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "@bad@", "", value_map)); |
| 838 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${bad}", "", value_map)); |
| 839 | | } |
| 840 | | |
| 841 | | test "expandVariablesCmake edge cases" { |
| 842 | | const allocator = std.testing.allocator; |
| 843 | | var value_map: std.array_hash_map.String(Value) = .init(allocator); |
| 844 | | defer value_map.deinit(); |
| 845 | | |
| 846 | | // special symbols |
| 847 | | try value_map.putNoClobber("at", Value{ .string = "@" }); |
| 848 | | try value_map.putNoClobber("dollar", Value{ .string = "$" }); |
| 849 | | try value_map.putNoClobber("underscore", Value{ .string = "_" }); |
| 850 | | |
| 851 | | // basic value |
| 852 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 853 | | |
| 854 | | // proxy case value_map |
| 855 | | try value_map.putNoClobber("string_proxy", Value{ .string = "string" }); |
| 856 | | try value_map.putNoClobber("string_at", Value{ .string = "@string@" }); |
| 857 | | try value_map.putNoClobber("string_curly", Value{ .string = "{string}" }); |
| 858 | | try value_map.putNoClobber("string_var", Value{ .string = "${string}" }); |
| 859 | | |
| 860 | | // stack case value_map |
| 861 | | try value_map.putNoClobber("nest_underscore_proxy", Value{ .string = "underscore" }); |
| 862 | | try value_map.putNoClobber("nest_proxy", Value{ .string = "nest_underscore_proxy" }); |
| 863 | | |
| 864 | | // @-vars resolved only when they wrap valid characters, otherwise considered literals |
| 865 | | try testReplaceVariablesCMake(allocator, "@@string@@", "@text@", value_map); |
| 866 | | try testReplaceVariablesCMake(allocator, "@${string}@", "@text@", value_map); |
| 867 | | |
| 868 | | // @-vars are resolved inside ${}-vars |
| 869 | | try testReplaceVariablesCMake(allocator, "${@string_proxy@}", "text", value_map); |
| 870 | | |
| 871 | | // expanded variables are considered strings after expansion |
| 872 | | try testReplaceVariablesCMake(allocator, "@string_at@", "@string@", value_map); |
| 873 | | try testReplaceVariablesCMake(allocator, "${string_at}", "@string@", value_map); |
| 874 | | try testReplaceVariablesCMake(allocator, "$@string_curly@", "${string}", value_map); |
| 875 | | try testReplaceVariablesCMake(allocator, "$${string_curly}", "${string}", value_map); |
| 876 | | try testReplaceVariablesCMake(allocator, "${string_var}", "${string}", value_map); |
| 877 | | try testReplaceVariablesCMake(allocator, "@string_var@", "${string}", value_map); |
| 878 | | try testReplaceVariablesCMake(allocator, "${dollar}{${string}}", "${text}", value_map); |
| 879 | | try testReplaceVariablesCMake(allocator, "@dollar@{${string}}", "${text}", value_map); |
| 880 | | try testReplaceVariablesCMake(allocator, "@dollar@{@string@}", "${text}", value_map); |
| 881 | | |
| 882 | | // when expanded variables contain invalid characters, they prevent further expansion |
| 883 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${${string_var}}", "", value_map)); |
| 884 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${@string_var@}", "", value_map)); |
| 885 | | |
| 886 | | // nested expanded variables are expanded from the inside out |
| 887 | | try testReplaceVariablesCMake(allocator, "${string${underscore}proxy}", "string", value_map); |
| 888 | | try testReplaceVariablesCMake(allocator, "${string@underscore@proxy}", "string", value_map); |
| 889 | | |
| 890 | | // nested vars are only expanded when ${} is closed |
| 891 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "@nest@underscore@proxy@", "", value_map)); |
| 892 | | try testReplaceVariablesCMake(allocator, "${nest${underscore}proxy}", "nest_underscore_proxy", value_map); |
| 893 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "@nest@@nest_underscore@underscore@proxy@@proxy@", "", value_map)); |
| 894 | | try testReplaceVariablesCMake(allocator, "${nest${${nest_underscore${underscore}proxy}}proxy}", "nest_underscore_proxy", value_map); |
| 895 | | |
| 896 | | // invalid characters lead to an error |
| 897 | | try std.testing.expectError(error.InvalidCharacter, testReplaceVariablesCMake(allocator, "${str*ing}", "", value_map)); |
| 898 | | try std.testing.expectError(error.InvalidCharacter, testReplaceVariablesCMake(allocator, "${str$ing}", "", value_map)); |
| 899 | | try std.testing.expectError(error.InvalidCharacter, testReplaceVariablesCMake(allocator, "${str@ing}", "", value_map)); |
| 900 | | } |
| 901 | | |
| 902 | | test "expandVariablesCmake escaped characters" { |
| 903 | | const allocator = std.testing.allocator; |
| 904 | | var value_map: std.array_hash_map.String(Value) = .init(allocator); |
| 905 | | defer value_map.deinit(); |
| 906 | | |
| 907 | | try value_map.putNoClobber("string", Value{ .string = "text" }); |
| 908 | | |
| 909 | | // backslash is an invalid character for @ lookup |
| 910 | | try testReplaceVariablesCMake(allocator, "\\@string\\@", "\\@string\\@", value_map); |
| 911 | | |
| 912 | | // backslash is preserved, but doesn't affect ${} variable expansion |
| 913 | | try testReplaceVariablesCMake(allocator, "\\${string}", "\\text", value_map); |
| 914 | | |
| 915 | | // backslash breaks ${} opening bracket identification |
| 916 | | try testReplaceVariablesCMake(allocator, "$\\{string}", "$\\{string}", value_map); |
| 917 | | |
| 918 | | // backslash is skipped when checking for invalid characters, yet it mangles the key |
| 919 | | try std.testing.expectError(error.MissingValue, testReplaceVariablesCMake(allocator, "${string\\}", "", value_map)); |
| 920 | | } |