blob: e320b273207e503197b6e5fcefbdbbc7c66b3f94 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package regsrc
import (
"strings"
"testing"
)
func TestFriendlyHost(t *testing.T) {
tests := []struct {
name string
source string
wantHost string
wantDisplay string
wantNorm string
wantValid bool
}{
{
name: "simple ascii",
source: "registry.terraform.io",
wantHost: "registry.terraform.io",
wantDisplay: "registry.terraform.io",
wantNorm: "registry.terraform.io",
wantValid: true,
},
{
name: "mixed-case ascii",
source: "Registry.TerraForm.io",
wantHost: "Registry.TerraForm.io",
wantDisplay: "registry.terraform.io", // Display case folded
wantNorm: "registry.terraform.io",
wantValid: true,
},
{
name: "IDN",
source: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
wantHost: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
wantDisplay: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
wantNorm: "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io",
wantValid: true,
},
{
name: "IDN TLD",
source: "zhongwen.中国",
wantHost: "zhongwen.中国",
wantDisplay: "zhongwen.中国",
wantNorm: "zhongwen.xn--fiqs8s",
wantValid: true,
},
{
name: "IDN Case Folding",
source: "Испытание.com",
wantHost: "Испытание.com", // Raw input retains case
wantDisplay: "испытание.com", // Display form is unicode but case-folded
wantNorm: "xn--80akhbyknj4f.com",
wantValid: true,
},
{
name: "Punycode is invalid as an input format",
source: "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io",
wantHost: "xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io",
wantDisplay: "ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io",
wantNorm: InvalidHostString,
wantValid: false,
},
{
name: "non-host prefix is left alone",
source: "foo/bar/baz",
wantHost: "",
wantDisplay: "",
wantNorm: "",
wantValid: false,
},
}
for _, tt := range tests {
// Matrix each test with prefix and total match variants
for _, sfx := range []string{"", "/", "/foo/bar/baz"} {
t.Run(tt.name+" suffix:"+sfx, func(t *testing.T) {
gotHost, gotRest := ParseFriendlyHost(tt.source + sfx)
if gotHost == nil {
if tt.wantHost != "" {
t.Fatalf("ParseFriendlyHost() gotHost = nil, want %v", tt.wantHost)
}
// If we return nil host, the whole input string should be in rest
if gotRest != (tt.source + sfx) {
t.Fatalf("ParseFriendlyHost() was nil rest = %s, want %v", gotRest, tt.source+sfx)
}
return
}
if tt.wantHost == "" {
t.Fatalf("ParseFriendlyHost() gotHost.Raw = %v, want nil", gotHost.Raw)
}
if v := gotHost.String(); v != tt.wantHost {
t.Fatalf("String() = %v, want %v", v, tt.wantHost)
}
if v := gotHost.Display(); v != tt.wantDisplay {
t.Fatalf("Display() = %v, want %v", v, tt.wantDisplay)
}
if v := gotHost.Normalized(); v != tt.wantNorm {
t.Fatalf("Normalized() = %v, want %v", v, tt.wantNorm)
}
if v := gotHost.Valid(); v != tt.wantValid {
t.Fatalf("Valid() = %v, want %v", v, tt.wantValid)
}
if gotRest != strings.TrimLeft(sfx, "/") {
t.Fatalf("ParseFriendlyHost() rest = %v, want %v", gotRest, strings.TrimLeft(sfx, "/"))
}
// Also verify that host compares equal with all the variants.
if gotHost.Valid() && !gotHost.Equal(&FriendlyHost{Raw: tt.wantDisplay}) {
t.Fatalf("Equal() should be true for %s and %s", tt.wantHost, tt.wantDisplay)
}
})
}
}
}
func TestInvalidHostEquals(t *testing.T) {
invalid := NewFriendlyHost("NOT_A_HOST_NAME")
valid := PublicRegistryHost
// invalid hosts are not comparable
if invalid.Equal(invalid) {
t.Fatal("invalid host names are not comparable")
}
if valid.Equal(invalid) {
t.Fatalf("%q is not equal to %q", valid, invalid)
}
puny := NewFriendlyHost("xn--s-fka0wmm0zea7g8b.xn--o-8ta85a3b1dwcda1k.io")
display := NewFriendlyHost("ʎɹʇsıƃǝɹ.ɯɹoɟɐɹɹǝʇ.io")
// The pre-normalized host is not a valid source, and therefore not
// comparable to the display version.
if display.Equal(puny) {
t.Fatalf("invalid host %q should not be comparable", puny)
}
}