Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ linters:
disable:
- depguard
- funlen
- goconst
- godox
- gomodguard
- gomodguard_v2
- exhaustruct
- exhaustruct_v5
- nlreturn
- nonamedreturns
- noinlineerr
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/go-openapi/jsonreference

require (
github.com/go-openapi/jsonpointer v1.0.0
github.com/go-openapi/jsonpointer v1.0.1
github.com/go-openapi/testify/v2 v2.7.0
)

go 1.25.0
go 1.26.0
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s=
github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y=
github.com/go-openapi/jsonpointer v1.0.1 h1:2KxywRmNwJkT/FMBa3iRNHEaAxSJvjqoufQZy3au1Mg=
github.com/go-openapi/jsonpointer v1.0.1/go.mod h1:wI7ZYsFmbIi9nBXOZqgDaS/bqOchRGZjqxFli7FBYxY=
github.com/go-openapi/testify/v2 v2.7.0 h1:bycOreEj6wfBvijg3YFogZ/sFjTCDmQnwSodSzHa3X8=
github.com/go-openapi/testify/v2 v2.7.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
81 changes: 51 additions & 30 deletions internal/normalize_url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,47 @@
package internal

import (
"fmt"
"iter"
"net/url"
"slices"
"testing"

"github.com/go-openapi/testify/v2/assert"
"github.com/go-openapi/testify/v2/require"
)

// URLs spelled in more than one test in this package.
func TestUrlnorm(t *testing.T) {
for testCase := range urlTestCases() {
t.Run(fmt.Sprintf("should normalize URL: %q", testCase.url), func(t *testing.T) {
u, err := url.Parse(testCase.url)
if testCase.expectErr {
require.Error(t, err, "expected url.Parse to fail")
return
}

require.NoError(t, err)

NormalizeURL(u)
normalized := u.String()
assert.EqualTf(t, testCase.expected, normalized, "got an unexpected normalization: %s", normalized)

_, err = url.Parse(normalized)
require.NoErrorf(t, err, "normalizing %q yielded an URL that no longer parses", testCase.url)
})
}
}

type urlTestCase struct {
url string
expected string // expected normalized url
expectErr bool // expected error when true
}

const (
// url.Parse reads these as the host ":a" on a default port, so dropping the port would
// leave "https://:a", which no longer parses.
degenerateHostHTTPS = "https://:a:443"
degenerateHostHTTPS = "https://:a:443" // since go1.26 this degenerate case is no longer tolerated
degenerateHostHTTP = "http://:a:80"

ipv6NonDefaultPort = "https://[2001:db8::1]:8443/folder"
Expand All @@ -30,11 +59,8 @@ const (
userinfoNormalized = "https://user:pw@xyz.com/folder"
)

func TestUrlnorm(t *testing.T) {
testCases := []struct {
url string
expected string
}{
func urlTestCases() iter.Seq[urlTestCase] {
return slices.Values([]urlTestCase{
{
url: mixedCaseDefaultPort,
expected: "https://xyz.com/folder/file",
Expand All @@ -60,12 +86,19 @@ func TestUrlnorm(t *testing.T) {
expected: ipv6NonDefaultPort,
},
{
url: degenerateHostHTTPS,
expected: degenerateHostHTTPS,
// Since go1.26, url.Parse rejects a colon outside a bracketed IPv6 host on an http or https URL
// (GODEBUG urlstrictcolons=1, the default from a go.mod declaring go 1.26 or later). Both $refs below
// used to parse - the first as the host ":a" on port 443, the second as "0:443" on port 443 - and both
// now fail. normalizeURI logs a warning, repairs the $ref to the empty URI and resolves it against the
// base, so the base itself comes back.
url: degenerateHostHTTPS,
expected: degenerateHostHTTPS,
expectErr: true,
},
{
url: degenerateHostHTTP,
expected: degenerateHostHTTP,
url: degenerateHostHTTP,
expected: degenerateHostHTTP,
expectErr: true,
},
{
// a run of slashes collapses to one, however long the run is
Expand All @@ -77,28 +110,16 @@ func TestUrlnorm(t *testing.T) {
expected: "https://xyz.com/",
},
{
url: "https://:]:443",
expected: "https://:]:443",
url: "https://:]:443",
expected: "https://:]:443",
expectErr: true,
},
{
// the host is ":80" on port 80, so the removal has to run twice. Emptying the host
// drops the "//" as well, which url.URL.String has always done.
url: "http://:80:80",
expected: "http:",
url: "http://:80:80",
expected: "http:",
expectErr: true,
},
}

for _, toPin := range testCases {
testCase := toPin

u, err := url.Parse(testCase.url)
require.NoError(t, err)

NormalizeURL(u)
normalized := u.String()
assert.EqualT(t, testCase.expected, normalized)

_, err = url.Parse(normalized)
require.NoErrorf(t, err, "normalizing %q yielded a URL that no longer parses", testCase.url)
}
})
}
Loading