Files
probo/pkg/uri/uri_test.go
Émile Ré 9156d6a16a Add wsl linter and fix
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-20 09:27:28 +04:00

294 lines
6.2 KiB
Go

// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package uri
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParse(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
want URI
wantErr bool
}{
{
name: "valid https url",
input: "https://example.com",
want: URI("https://example.com"),
},
{
name: "valid https url with path",
input: "https://example.com/callback",
want: URI("https://example.com/callback"),
},
{
name: "valid https url with port",
input: "https://localhost:8080/callback",
want: URI("https://localhost:8080/callback"),
},
{
name: "valid http url",
input: "http://localhost:3000/auth/callback",
want: URI("http://localhost:3000/auth/callback"),
},
{
name: "valid url with query",
input: "https://example.com/path?key=value",
want: URI("https://example.com/path?key=value"),
},
{
name: "valid custom scheme",
input: "myapp://callback",
want: URI("myapp://callback"),
},
{
name: "empty string",
input: "",
wantErr: true,
},
{
name: "no scheme",
input: "example.com/callback",
wantErr: true,
},
{
name: "no host",
input: "/callback",
wantErr: true,
},
{
name: "relative path",
input: "callback",
wantErr: true,
},
{
name: "scheme only",
input: "https://",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(
tt.name,
func(t *testing.T) {
t.Parallel()
got, err := Parse(tt.input)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, got)
},
)
}
}
func TestURIUnmarshalText(t *testing.T) {
t.Parallel()
t.Run(
"valid",
func(t *testing.T) {
t.Parallel()
var u URI
err := u.UnmarshalText([]byte("https://example.com/callback"))
require.NoError(t, err)
assert.Equal(t, URI("https://example.com/callback"), u)
},
)
t.Run(
"invalid",
func(t *testing.T) {
t.Parallel()
var u URI
err := u.UnmarshalText([]byte("not-a-url"))
require.Error(t, err)
},
)
}
func TestURIMarshalText(t *testing.T) {
t.Parallel()
u := URI("https://example.com/callback")
b, err := u.MarshalText()
require.NoError(t, err)
assert.Equal(t, []byte("https://example.com/callback"), b)
}
func TestURIJSON(t *testing.T) {
t.Parallel()
t.Run(
"marshal",
func(t *testing.T) {
t.Parallel()
v := struct {
URL URI `json:"url"`
}{URL: URI("https://example.com")}
data, err := json.Marshal(v)
require.NoError(t, err)
assert.JSONEq(t, `{"url":"https://example.com"}`, string(data))
},
)
t.Run(
"unmarshal valid",
func(t *testing.T) {
t.Parallel()
var v struct {
URL URI `json:"url"`
}
err := json.Unmarshal([]byte(`{"url":"https://example.com"}`), &v)
require.NoError(t, err)
assert.Equal(t, URI("https://example.com"), v.URL)
},
)
t.Run(
"unmarshal invalid",
func(t *testing.T) {
t.Parallel()
var v struct {
URL URI `json:"url"`
}
err := json.Unmarshal([]byte(`{"url":"not-a-url"}`), &v)
require.Error(t, err)
},
)
}
func TestURIScan(t *testing.T) {
t.Parallel()
t.Run(
"string",
func(t *testing.T) {
t.Parallel()
var u URI
err := u.Scan("https://example.com")
require.NoError(t, err)
assert.Equal(t, URI("https://example.com"), u)
},
)
t.Run(
"bytes",
func(t *testing.T) {
t.Parallel()
var u URI
err := u.Scan([]byte("https://example.com"))
require.NoError(t, err)
assert.Equal(t, URI("https://example.com"), u)
},
)
t.Run(
"invalid value",
func(t *testing.T) {
t.Parallel()
var u URI
err := u.Scan("not-a-url")
require.Error(t, err)
},
)
t.Run(
"unsupported type",
func(t *testing.T) {
t.Parallel()
var u URI
err := u.Scan(123)
require.Error(t, err)
},
)
}
func TestURIValue(t *testing.T) {
t.Parallel()
u := URI("https://example.com")
v, err := u.Value()
require.NoError(t, err)
assert.Equal(t, "https://example.com", v)
}
func TestExtractDomain(t *testing.T) {
t.Parallel()
tests := []struct {
name string
rawURL string
want string
}{
{"google tag manager", "https://www.googletagmanager.com/gtag/js?id=G-ABC123", "googletagmanager.com"},
{"google analytics", "https://www.google-analytics.com/analytics.js", "google-analytics.com"},
{"facebook pixel", "https://connect.facebook.net/en_US/fbevents.js", "facebook.net"},
{"segment cdn", "https://cdn.segment.io/v1/projects/abc/settings", "segment.io"},
{"hubspot", "https://js.hs-analytics.net/analytics/1234/abc.js", "hs-analytics.net"},
{"subdomain stripped", "https://static.ads.example.com/pixel.js", "example.com"},
{"co.uk tld", "https://tracker.example.co.uk/script.js", "example.co.uk"},
{"bare domain no path", "https://doubleclick.net", "doubleclick.net"},
{"case insensitive", "https://WWW.GoogleTagManager.COM/gtag/js", "googletagmanager.com"},
{"empty string", "", ""},
{"invalid url", "not a url at all", ""},
{"data uri", "data:text/html,<h1>Hello</h1>", ""},
{"ip address", "https://192.168.1.1/script.js", ""},
{"port number", "https://tracker.example.com:8443/pixel.js", "example.com"},
{"http scheme", "http://cdn.jsdelivr.net/npm/cookieconsent", "jsdelivr.net"},
}
for _, tt := range tests {
t.Run(
tt.name,
func(t *testing.T) {
t.Parallel()
assert.Equal(t, tt.want, ExtractDomain(tt.rawURL))
},
)
}
}