github.com/opentofu/opentofu@v1.7.1/internal/registry/regsrc/module_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 "testing" 10 ) 11 12 func TestModule(t *testing.T) { 13 tests := []struct { 14 name string 15 source string 16 wantString string 17 wantDisplay string 18 wantNorm string 19 wantErr bool 20 }{ 21 { 22 name: "public registry", 23 source: "hashicorp/consul/aws", 24 wantString: "hashicorp/consul/aws", 25 wantDisplay: "hashicorp/consul/aws", 26 wantNorm: "hashicorp/consul/aws", 27 wantErr: false, 28 }, 29 { 30 name: "public registry, submodule", 31 source: "hashicorp/consul/aws//foo", 32 wantString: "hashicorp/consul/aws//foo", 33 wantDisplay: "hashicorp/consul/aws//foo", 34 wantNorm: "hashicorp/consul/aws//foo", 35 wantErr: false, 36 }, 37 { 38 name: "public registry, explicit host", 39 source: "registry.opentofu.org/hashicorp/consul/aws", 40 wantString: "registry.opentofu.org/hashicorp/consul/aws", 41 wantDisplay: "hashicorp/consul/aws", 42 wantNorm: "hashicorp/consul/aws", 43 wantErr: false, 44 }, 45 { 46 name: "public registry, mixed case", 47 source: "HashiCorp/Consul/aws", 48 wantString: "HashiCorp/Consul/aws", 49 wantDisplay: "hashicorp/consul/aws", 50 wantNorm: "hashicorp/consul/aws", 51 wantErr: false, 52 }, 53 { 54 name: "private registry, custom port", 55 source: "Example.com:1234/HashiCorp/Consul/aws", 56 wantString: "Example.com:1234/HashiCorp/Consul/aws", 57 wantDisplay: "example.com:1234/hashicorp/consul/aws", 58 wantNorm: "example.com:1234/hashicorp/consul/aws", 59 wantErr: false, 60 }, 61 { 62 name: "IDN registry", 63 source: "Испытание.com/HashiCorp/Consul/aws", 64 wantString: "Испытание.com/HashiCorp/Consul/aws", 65 wantDisplay: "испытание.com/hashicorp/consul/aws", 66 wantNorm: "xn--80akhbyknj4f.com/hashicorp/consul/aws", 67 wantErr: false, 68 }, 69 { 70 name: "IDN registry, submodule, custom port", 71 source: "Испытание.com:1234/HashiCorp/Consul/aws//Foo", 72 wantString: "Испытание.com:1234/HashiCorp/Consul/aws//Foo", 73 // Note we DO lowercase submodule names. This might causes issues on 74 // some filesystems (e.g. HFS+) that are case-sensitive where 75 ////modules/Foo and //modules/foo describe different paths, but 76 // it's less confusing in general just to not support that. Any user 77 // with a module with submodules in both cases is already asking for 78 // portability issues, and tofu can ensure it does 79 // case-insensitive search for the dir in those cases. 80 wantDisplay: "испытание.com:1234/hashicorp/consul/aws//foo", 81 wantNorm: "xn--80akhbyknj4f.com:1234/hashicorp/consul/aws//foo", 82 wantErr: false, 83 }, 84 { 85 name: "invalid host", 86 source: "---.com/HashiCorp/Consul/aws", 87 wantErr: true, 88 }, 89 { 90 name: "invalid format", 91 source: "foo/var/baz/qux", 92 wantErr: true, 93 }, 94 { 95 name: "invalid suffix", 96 source: "foo/var/baz?otherthing", 97 wantErr: true, 98 }, 99 { 100 name: "valid host, invalid format", 101 source: "foo.com/var/baz?otherthing", 102 wantErr: true, 103 }, 104 { 105 name: "disallow github", 106 source: "github.com/HashiCorp/Consul/aws", 107 wantErr: true, 108 }, 109 { 110 name: "disallow bitbucket", 111 source: "bitbucket.org/HashiCorp/Consul/aws", 112 wantErr: true, 113 }, 114 } 115 for _, tt := range tests { 116 t.Run(tt.name, func(t *testing.T) { 117 got, err := ParseModuleSource(tt.source) 118 119 if (err != nil) != tt.wantErr { 120 t.Fatalf("ParseModuleSource() error = %v, wantErr %v", err, tt.wantErr) 121 } 122 123 if err != nil { 124 return 125 } 126 127 if v := got.String(); v != tt.wantString { 128 t.Fatalf("String() = %v, want %v", v, tt.wantString) 129 } 130 if v := got.Display(); v != tt.wantDisplay { 131 t.Fatalf("Display() = %v, want %v", v, tt.wantDisplay) 132 } 133 if v := got.Normalized(); v != tt.wantNorm { 134 t.Fatalf("Normalized() = %v, want %v", v, tt.wantNorm) 135 } 136 137 gotDisplay, err := ParseModuleSource(tt.wantDisplay) 138 if err != nil { 139 t.Fatalf("ParseModuleSource(wantDisplay) error = %v", err) 140 } 141 if !got.Equal(gotDisplay) { 142 t.Fatalf("Equal() failed for %s and %s", tt.source, tt.wantDisplay) 143 } 144 }) 145 } 146 }