github.com/opentofu/opentofu@v1.7.1/internal/registry/regsrc/friendly_host_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package regsrc 7 8 import ( 9 "strings" 10 "testing" 11 ) 12 13 func TestFriendlyHost(t *testing.T) { 14 tests := []struct { 15 name string 16 source string 17 wantHost string 18 wantDisplay string 19 wantNorm string 20 wantValid bool 21 }{ 22 { 23 name: "simple ascii", 24 source: "registry.opentofu.org", 25 wantHost: "registry.opentofu.org", 26 wantDisplay: "registry.opentofu.org", 27 wantNorm: "registry.opentofu.org", 28 wantValid: true, 29 }, 30 { 31 name: "mixed-case ascii", 32 source: "Registry.OpenTofu.org", 33 wantHost: "Registry.OpenTofu.org", 34 wantDisplay: "registry.opentofu.org", // Display case folded 35 wantNorm: "registry.opentofu.org", 36 wantValid: true, 37 }, 38 { 39 name: "IDN", 40 source: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io", 41 wantHost: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io", 42 wantDisplay: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io", 43 wantNorm: "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io", 44 wantValid: true, 45 }, 46 { 47 name: "IDN TLD", 48 source: "zhongwen.中国", 49 wantHost: "zhongwen.中国", 50 wantDisplay: "zhongwen.中国", 51 wantNorm: "zhongwen.xn--fiqs8s", 52 wantValid: true, 53 }, 54 { 55 name: "IDN Case Folding", 56 source: "Испытание.com", 57 wantHost: "Испытание.com", // Raw input retains case 58 wantDisplay: "испытание.com", // Display form is unicode but case-folded 59 wantNorm: "xn--80akhbyknj4f.com", 60 wantValid: true, 61 }, 62 { 63 name: "Punycode is invalid as an input format", 64 source: "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io", 65 wantHost: "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io", 66 wantDisplay: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io", 67 wantNorm: InvalidHostString, 68 wantValid: false, 69 }, 70 { 71 name: "non-host prefix is left alone", 72 source: "foo/bar/baz", 73 wantHost: "", 74 wantDisplay: "", 75 wantNorm: "", 76 wantValid: false, 77 }, 78 } 79 for _, tt := range tests { 80 // Matrix each test with prefix and total match variants 81 for _, sfx := range []string{"", "/", "/foo/bar/baz"} { 82 t.Run(tt.name+" suffix:"+sfx, func(t *testing.T) { 83 gotHost, gotRest := ParseFriendlyHost(tt.source + sfx) 84 85 if gotHost == nil { 86 if tt.wantHost != "" { 87 t.Fatalf("ParseFriendlyHost() gotHost = nil, want %v", tt.wantHost) 88 } 89 // If we return nil host, the whole input string should be in rest 90 if gotRest != (tt.source + sfx) { 91 t.Fatalf("ParseFriendlyHost() was nil rest = %s, want %v", gotRest, tt.source+sfx) 92 } 93 return 94 } 95 96 if tt.wantHost == "" { 97 t.Fatalf("ParseFriendlyHost() gotHost.Raw = %v, want nil", gotHost.Raw) 98 } 99 100 if v := gotHost.String(); v != tt.wantHost { 101 t.Fatalf("String() = %v, want %v", v, tt.wantHost) 102 } 103 if v := gotHost.Display(); v != tt.wantDisplay { 104 t.Fatalf("Display() = %v, want %v", v, tt.wantDisplay) 105 } 106 if v := gotHost.Normalized(); v != tt.wantNorm { 107 t.Fatalf("Normalized() = %v, want %v", v, tt.wantNorm) 108 } 109 if v := gotHost.Valid(); v != tt.wantValid { 110 t.Fatalf("Valid() = %v, want %v", v, tt.wantValid) 111 } 112 if gotRest != strings.TrimLeft(sfx, "/") { 113 t.Fatalf("ParseFriendlyHost() rest = %v, want %v", gotRest, strings.TrimLeft(sfx, "/")) 114 } 115 116 // Also verify that host compares equal with all the variants. 117 if gotHost.Valid() && !gotHost.Equal(&FriendlyHost{Raw: tt.wantDisplay}) { 118 t.Fatalf("Equal() should be true for %s and %s", tt.wantHost, tt.wantDisplay) 119 } 120 }) 121 } 122 } 123 } 124 125 func TestInvalidHostEquals(t *testing.T) { 126 invalid := NewFriendlyHost("NOT_A_HOST_NAME") 127 valid := PublicRegistryHost 128 129 // invalid hosts are not comparable 130 if invalid.Equal(invalid) { 131 t.Fatal("invalid host names are not comparable") 132 } 133 134 if valid.Equal(invalid) { 135 t.Fatalf("%q is not equal to %q", valid, invalid) 136 } 137 138 puny := NewFriendlyHost("xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io") 139 display := NewFriendlyHost("ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io") 140 141 // The pre-normalized host is not a valid source, and therefore not 142 // comparable to the display version. 143 if display.Equal(puny) { 144 t.Fatalf("invalid host %q should not be comparable", puny) 145 } 146 }