// Copyright 2025 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validation

import (
	"context"
	"strings"
	"testing"

	"k8s.io/apimachinery/pkg/api/operation"
	"k8s.io/apimachinery/pkg/util/validation/field"
	"k8s.io/utils/ptr"

	azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"

	"github.com/Azure/ARO-HCP/internal/api/metadataapi"
	"github.com/Azure/ARO-HCP/internal/utils"
)

func TestOpenshiftVersion(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("version")

	tests := []struct {
		name         string
		value        *string
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "empty string - valid",
			value:        ptr.To(""),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:  "semver with patch - invalid",
			value: ptr.To("4.15.1"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "version", Message: "must be specified as MAJOR.MINOR"},
			},
		},
		{
			name:         "valid major.minor - valid",
			value:        ptr.To("4.15"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:  "invalid version - invalid",
			value: ptr.To("not-a-version"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "version", Message: "Short version cannot contain PreRelease/Build meta data"},
			},
		},
		{
			name:  "invalid format - invalid",
			value: ptr.To("invalid.version.format"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "version", Message: "Invalid character(s) found in major number"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := OpenshiftVersionWithoutMicro(ctx, op, fldPath, tt.value, nil)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)
		})
	}
}

func TestMaxItems(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("items")

	tests := []struct {
		name         string
		value        []string
		maxLen       int
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil slice - valid",
			value:        nil,
			maxLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "empty slice - valid",
			value:        []string{},
			maxLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "under limit - valid",
			value:        []string{"a", "b", "c"},
			maxLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "at limit - valid",
			value:        []string{"a", "b", "c", "d", "e"},
			maxLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:   "over limit - invalid",
			value:  []string{"a", "b", "c", "d", "e", "f"},
			maxLen: 5,
			expectErrors: []utils.ExpectedError{
				{FieldPath: "items", Message: "must have at most 5 items"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := MaxItems(ctx, op, fldPath, tt.value, nil, tt.maxLen)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)
		})
	}
}

func TestMaxLen(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("field")

	tests := []struct {
		name         string
		value        *string
		maxLen       int
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			maxLen:       10,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "empty string - valid",
			value:        ptr.To(""),
			maxLen:       10,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "under limit - valid",
			value:        ptr.To("test"),
			maxLen:       10,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "at limit - valid",
			value:        ptr.To("1234567890"),
			maxLen:       10,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:   "over limit - invalid",
			value:  ptr.To("12345678901"),
			maxLen: 10,
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "may not be more than 10 bytes"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := MaxLen(ctx, op, fldPath, tt.value, nil, tt.maxLen)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)
		})
	}
}

func TestMinLen(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("field")

	tests := []struct {
		name         string
		value        *string
		minLen       int
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			minLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:   "under limit - invalid",
			value:  ptr.To("test"),
			minLen: 5,
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be at least 5 characters long"},
			},
		},
		{
			name:         "at limit - valid",
			value:        ptr.To("tests"),
			minLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "over limit - valid",
			value:        ptr.To("testing"),
			minLen:       5,
			expectErrors: []utils.ExpectedError{},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := MinLen(ctx, op, fldPath, tt.value, nil, tt.minLen)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)
		})
	}
}

func TestMaximum(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("field")

	tests := []struct {
		name         string
		value        *int32
		max          int32
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			max:          100,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "under limit - valid",
			value:        ptr.To(int32(50)),
			max:          100,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "at limit - valid",
			value:        ptr.To(int32(100)),
			max:          100,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:  "over limit - invalid",
			value: ptr.To(int32(101)),
			max:   100,
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be less than or equal to 100"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := Maximum(ctx, op, fldPath, tt.value, nil, tt.max)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)
		})
	}
}

func TestMatchesRegex(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("field")

	tests := []struct {
		name         string
		value        *string
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid rfc1035 label - valid",
			value:        ptr.To("test-label"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid single char - valid",
			value:        ptr.To("a"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:  "starts with number - invalid",
			value: ptr.To("1test"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be a valid DNS RFC 1035 label"},
			},
		},
		{
			name:  "contains uppercase - invalid",
			value: ptr.To("Test"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be a valid DNS RFC 1035 label"},
			},
		},
		{
			name:  "starts with hyphen - invalid",
			value: ptr.To("-test"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be a valid DNS RFC 1035 label"},
			},
		},
		{
			name:  "ends with hyphen - invalid",
			value: ptr.To("test-"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be a valid DNS RFC 1035 label"},
			},
		},
		{
			name:  "contains special chars - invalid",
			value: ptr.To("test_label"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "field", Message: "must be a valid DNS RFC 1035 label"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := MatchesRegex(ctx, op, fldPath, tt.value, nil, rfc1035LabelRegex, rfc1035ErrorString)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)

		})
	}
}

func TestCIDRv4(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("cidr")

	tests := []struct {
		name         string
		value        *string
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "empty string - valid",
			value:        ptr.To(""),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid IPv4 CIDR - valid",
			value:        ptr.To("10.0.0.0/16"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid /24 CIDR - valid",
			value:        ptr.To("192.168.1.0/24"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid /32 CIDR - valid",
			value:        ptr.To("172.16.0.1/32"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:  "IPv6 CIDR - invalid",
			value: ptr.To("2001:db8::/32"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "cidr", Message: "not IPv4"},
			},
		},
		{
			name:  "invalid CIDR format - invalid",
			value: ptr.To("10.0.0.0"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "cidr", Message: "invalid CIDR address"},
			},
		},
		{
			name:  "invalid IP - invalid",
			value: ptr.To("300.0.0.0/16"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "cidr", Message: "invalid CIDR address"},
			},
		},
		{
			name:  "host IP instead of network - invalid",
			value: ptr.To("10.0.0.1/16"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "cidr", Message: "not IPv4 CIDR"},
			},
		},
		{
			name:  "invalid prefix length - invalid",
			value: ptr.To("10.0.0.0/33"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "cidr", Message: "invalid CIDR address"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := CIDRv4(ctx, op, fldPath, tt.value, nil)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)

		})
	}
}

func TestIPv4(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("ip")

	tests := []struct {
		name      string
		value     *string
		expectErr bool
	}{
		{
			name:      "nil value - valid",
			value:     nil,
			expectErr: false,
		},
		{
			name:      "empty string - valid",
			value:     ptr.To(""),
			expectErr: false,
		},
		{
			name:      "valid IPv4 - valid",
			value:     ptr.To("192.168.1.1"),
			expectErr: false,
		},
		{
			name:      "valid localhost - valid",
			value:     ptr.To("127.0.0.1"),
			expectErr: false,
		},
		{
			name:      "valid zero IP - valid",
			value:     ptr.To("0.0.0.0"),
			expectErr: false,
		},
		{
			name:      "IPv6 address - invalid",
			value:     ptr.To("2001:db8::1"),
			expectErr: true,
		},
		{
			name:      "invalid IP format - invalid",
			value:     ptr.To("300.0.0.1"),
			expectErr: true,
		},
		{
			name:      "not an IP - invalid",
			value:     ptr.To("not-an-ip"),
			expectErr: true,
		},
		{
			name:      "CIDR notation - invalid",
			value:     ptr.To("192.168.1.1/24"),
			expectErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := IPv4(ctx, op, fldPath, tt.value, nil)

			if tt.expectErr && len(errs) == 0 {
				t.Error("expected error but got none")
			}
			if !tt.expectErr && len(errs) > 0 {
				t.Errorf("expected no error but got: %v", errs)
			}
		})
	}
}

func TestImageRegistry(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("registry")

	tests := []struct {
		name      string
		value     *string
		expectErr bool
	}{
		{
			name:      "nil value - valid",
			value:     nil,
			expectErr: false,
		},
		{
			name:      "empty string - invalid",
			value:     ptr.To(""),
			expectErr: true,
		},
		{
			name:      "string too long - invalid",
			value:     ptr.To(strings.Repeat("a", 256)),
			expectErr: true,
		},
		{
			name:      "hostname - valid",
			value:     ptr.To("registry.example.com"),
			expectErr: false,
		},
		{
			name:      "hostname with port - valid",
			value:     ptr.To("registry.example.com:5000"),
			expectErr: false,
		},
		{
			name:      "hostname with port and path - valid",
			value:     ptr.To("registry.example.com:5000/namespace/repo"),
			expectErr: false,
		},
		{
			name:      "localhost - valid",
			value:     ptr.To("localhost"),
			expectErr: false,
		},
		{
			name:      "localhost and port - valid",
			value:     ptr.To("localhost:5000"),
			expectErr: false,
		},
		{
			name:      "hostname with wildcard - valid",
			value:     ptr.To("*.registry.example.com"),
			expectErr: false,
		},
		{
			name:      "hostname with wildcard and path - valid",
			value:     ptr.To("*.registry.example.com/namespace/repo"),
			expectErr: false,
		},
		{
			name:      "hostname with wildcard and port - valid",
			value:     ptr.To("*.registry.example.com:5000"),
			expectErr: false,
		},
		{
			name:      "hostname with wildcard and port and path - valid",
			value:     ptr.To("*.registry.example.com:5000/namespace/repo"),
			expectErr: false,
		},
		{
			name:      "hostname with http prefix - invalid",
			value:     ptr.To("http://registry.example.com"),
			expectErr: true,
		},
		{
			name:      "hostname with https prefix - invalid",
			value:     ptr.To("https://registry.exmaple.com"),
			expectErr: true,
		},
		{
			name:      "hostname with upppercase letters - invalid",
			value:     ptr.To("REGISTRY.EXAMPLE.COM"),
			expectErr: true,
		},
		{
			name:      "hostname with spaces - invalid",
			value:     ptr.To("registry example.com"),
			expectErr: true,
		},
		{
			name:      "hostname with tab characters - invalid",
			value:     ptr.To("registry\texample.com"),
			expectErr: true,
		},
		{
			name:      "hostname with newline characters - invalid",
			value:     ptr.To("registry\nexample.com"),
			expectErr: true,
		},
		{
			name:      "hostname with carriage return characters - invalid",
			value:     ptr.To("registry\rexample.com"),
			expectErr: true,
		},
		{
			name:      "hostname with form feed characters - invalid",
			value:     ptr.To("registry\fexample.com"),
			expectErr: true,
		},
		{
			name:      "hostname with vertical tab characters - invalid",
			value:     ptr.To("registry\vexample.com"),
			expectErr: true,
		},
		{
			name:      "hostname with empty port - invalid",
			value:     ptr.To("registry.example.com:"),
			expectErr: true,
		},
		{
			name:      "hostname with multiple colons - invalid",
			value:     ptr.To("registry.example.com:5000:extra"),
			expectErr: true,
		},
		{
			name:      "hostname starting with dash - invalid",
			value:     ptr.To("-invalidhost.com"),
			expectErr: true,
		},
		{
			name:      "hostname ending with dash - invalid",
			value:     ptr.To("invalidhost-.com"),
			expectErr: true,
		},
		{
			name:      "hostname with underscore - invalid",
			value:     ptr.To("invalid_host.com"),
			expectErr: true,
		},
		{
			name:      "IPv4 address - valid",
			value:     ptr.To("192.168.1.1"),
			expectErr: false,
		},
		{
			name:      "IPv4 address with port - valid",
			value:     ptr.To("192.168.1.1:5000"),
			expectErr: false,
		},
		{
			name:      "IPv4 address with port and path - valid",
			value:     ptr.To("192.168.1.1:5000/namespace/repo"),
			expectErr: false,
		},
		{
			name:      "IPv4 loopback address - valid",
			value:     ptr.To("127.0.0.1"),
			expectErr: false,
		},
		{
			name:      "IPv4 loopback address with port - valid",
			value:     ptr.To("127.0.0.1:8080"),
			expectErr: false,
		},
		{
			name:      "IPv6 address with brackets - valid",
			value:     ptr.To("[2001:db8::1]"),
			expectErr: false,
		},
		{
			name:      "IPv6 address with brackets and port - valid",
			value:     ptr.To("[2001:db8::1]:5000"),
			expectErr: false,
		},
		{
			name:      "IPv6 address with brackets and port and path - valid",
			value:     ptr.To("[2001:db8::1]:5000/namespace/repo"),
			expectErr: false,
		},
		{
			name:      "IPv6 loopback address with brackets",
			value:     ptr.To("[::1]"),
			expectErr: false,
		},
		{
			name:      "IPv6 loopback address with brackets and port",
			value:     ptr.To("[::1]:8080"),
			expectErr: false,
		},
		{
			name:      "IPv6 address without brackets - valid",
			value:     ptr.To("2001:db8::1"),
			expectErr: false,
		},
		{
			name:      "IPv6 loopback address without brackets - valid",
			value:     ptr.To("::1"),
			expectErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := ImageRegistry(ctx, op, fldPath, tt.value, nil)

			if tt.expectErr && len(errs) == 0 {
				t.Error("expected error but got none")
			}
			if !tt.expectErr && len(errs) > 0 {
				t.Errorf("expected no error but got: %v", errs)
			}
		})
	}
}

func TestResourceID(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("resourceId")

	tests := []struct {
		name      string
		value     *azcorearm.ResourceID
		expectErr bool
	}{
		{
			name:      "nil value - valid",
			value:     nil,
			expectErr: false,
		},
		{
			name:      "valid resource ID - valid",
			value:     metadataapi.Must(azcorearm.ParseResourceID("/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet")),
			expectErr: false,
		},
		{
			name:      "valid subnet resource ID - valid",
			value:     metadataapi.Must(azcorearm.ParseResourceID("/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet")),
			expectErr: false,
		},
		// Note: Tests for invalid resource IDs (missing subscription, resource group, etc.)
		// are no longer possible since the type system now ensures only valid parsed
		// resource IDs can be passed to the validator.
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := ResourceID(ctx, op, fldPath, tt.value, nil)

			if tt.expectErr && len(errs) == 0 {
				t.Error("expected error but got none")
			}
			if !tt.expectErr && len(errs) > 0 {
				t.Errorf("expected no error but got: %v", errs)
			}
		})
	}
}

func TestRestrictedResourceID(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("resourceId")
	restrictedType := "Microsoft.Network/virtualNetworks"

	tests := []struct {
		name      string
		value     *azcorearm.ResourceID
		expectErr bool
	}{
		{
			name:      "nil value - valid",
			value:     nil,
			expectErr: false,
		},
		{
			name:      "valid matching resource type - valid",
			value:     metadataapi.Must(azcorearm.ParseResourceID("/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet")),
			expectErr: false,
		},
		{
			name:      "wrong resource type - invalid",
			value:     metadataapi.Must(azcorearm.ParseResourceID("/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg")),
			expectErr: true,
		},
		// Note: Tests for invalid resource IDs (missing subscription, etc.)
		// are no longer possible since the type system now ensures only valid parsed
		// resource IDs can be passed to the validator.
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := RestrictedResourceIDWithResourceGroup(ctx, op, fldPath, tt.value, nil, restrictedType)

			if tt.expectErr && len(errs) == 0 {
				t.Error("expected error but got none")
			}
			if !tt.expectErr && len(errs) > 0 {
				t.Errorf("expected no error but got: %v", errs)
			}
		})
	}
}

func TestURL(t *testing.T) {
	ctx := context.Background()
	op := operation.Operation{Type: operation.Create}
	fldPath := field.NewPath("url")

	tests := []struct {
		name         string
		value        *string
		expectErrors []utils.ExpectedError
	}{
		{
			name:         "nil value - valid",
			value:        nil,
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "empty string - valid (url.Parse accepts empty string)",
			value:        ptr.To(""),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid HTTP URL - valid",
			value:        ptr.To("http://example.com"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid HTTPS URL - valid",
			value:        ptr.To("https://example.com"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid URL with path - valid",
			value:        ptr.To("https://example.com/path/to/resource"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid URL with query parameters - valid",
			value:        ptr.To("https://example.com/path?key=value&other=param"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid URL with fragment - valid",
			value:        ptr.To("https://example.com/path#fragment"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid URL with port - valid",
			value:        ptr.To("https://example.com:8080/path"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "valid URL with user info - valid",
			value:        ptr.To("https://user:pass@example.com/path"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:         "invalid URL - missing scheme - valid",
			value:        ptr.To("example.com/path"),
			expectErrors: []utils.ExpectedError{},
		},
		{
			name:  "invalid URL - invalid",
			value: ptr.To("://invalid"),
			expectErrors: []utils.ExpectedError{
				{FieldPath: "url", Message: "parse"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			errs := URL(ctx, op, fldPath, tt.value, nil)
			utils.VerifyErrorsMatch(t, tt.expectErrors, errs)
		})
	}
}
