httpheaders_test.go

  1package httpheaders
  2
  3import (
  4	"testing"
  5
  6	"github.com/stretchr/testify/assert"
  7	"github.com/stretchr/testify/require"
  8)
  9
 10func TestDefaultUserAgent(t *testing.T) {
 11	t.Parallel()
 12
 13	tests := []struct {
 14		name    string
 15		version string
 16		want    string
 17	}{
 18		{name: "basic version", version: "0.11.0", want: "Charm Fantasy/0.11.0"},
 19		{name: "another version", version: "1.0.0", want: "Charm Fantasy/1.0.0"},
 20	}
 21
 22	for _, tt := range tests {
 23		t.Run(tt.name, func(t *testing.T) {
 24			t.Parallel()
 25			got := DefaultUserAgent(tt.version)
 26			assert.Equal(t, tt.want, got)
 27		})
 28	}
 29}
 30
 31func TestResolveHeaders_Precedence(t *testing.T) {
 32	t.Parallel()
 33
 34	t.Run("explicit UA wins over headers and default", func(t *testing.T) {
 35		t.Parallel()
 36		headers := map[string]string{"User-Agent": "from-headers"}
 37		got := ResolveHeaders(headers, "explicit-ua", "default-ua")
 38		assert.Equal(t, "explicit-ua", got["User-Agent"])
 39	})
 40
 41	t.Run("header UA wins over default", func(t *testing.T) {
 42		t.Parallel()
 43		headers := map[string]string{"User-Agent": "from-headers"}
 44		got := ResolveHeaders(headers, "", "default-ua")
 45		assert.Equal(t, "from-headers", got["User-Agent"])
 46	})
 47
 48	t.Run("default UA used when nothing else set", func(t *testing.T) {
 49		t.Parallel()
 50		got := ResolveHeaders(nil, "", "default-ua")
 51		assert.Equal(t, "default-ua", got["User-Agent"])
 52	})
 53
 54	t.Run("explicit UA wins over case-insensitive header key", func(t *testing.T) {
 55		t.Parallel()
 56		headers := map[string]string{"user-agent": "from-headers"}
 57		got := ResolveHeaders(headers, "explicit-ua", "default-ua")
 58		assert.Equal(t, "explicit-ua", got["User-Agent"])
 59		_, hasLower := got["user-agent"]
 60		assert.False(t, hasLower, "old case-insensitive key should be removed")
 61	})
 62
 63	t.Run("case-insensitive header key canonicalized when no explicit UA", func(t *testing.T) {
 64		t.Parallel()
 65		headers := map[string]string{"user-agent": "from-headers"}
 66		got := ResolveHeaders(headers, "", "default-ua")
 67		assert.Equal(t, "from-headers", got["User-Agent"])
 68		_, hasLower := got["user-agent"]
 69		assert.False(t, hasLower, "non-canonical key should be removed")
 70	})
 71}
 72
 73func TestResolveHeaders_NoMutation(t *testing.T) {
 74	t.Parallel()
 75
 76	original := map[string]string{"X-Custom": "value"}
 77	_ = ResolveHeaders(original, "explicit", "default")
 78
 79	_, hasUA := original["User-Agent"]
 80	require.False(t, hasUA, "input map must not be mutated")
 81	assert.Equal(t, "value", original["X-Custom"])
 82}
 83
 84func TestResolveHeaders_PreservesOtherHeaders(t *testing.T) {
 85	t.Parallel()
 86
 87	headers := map[string]string{
 88		"X-Custom":      "custom-value",
 89		"Authorization": "Bearer token",
 90	}
 91	got := ResolveHeaders(headers, "", "Charm Fantasy/1.0.0")
 92	assert.Equal(t, "custom-value", got["X-Custom"])
 93	assert.Equal(t, "Bearer token", got["Authorization"])
 94	assert.Equal(t, "Charm Fantasy/1.0.0", got["User-Agent"])
 95}
 96
 97func TestResolveHeaders_DuplicateCaseInsensitiveKeys(t *testing.T) {
 98	t.Parallel()
 99
100	t.Run("explicit UA removes all variants", func(t *testing.T) {
101		t.Parallel()
102		headers := map[string]string{
103			"User-Agent": "canonical",
104			"user-agent": "lowercase",
105		}
106		got := ResolveHeaders(headers, "explicit", "default")
107		assert.Equal(t, "explicit", got["User-Agent"])
108		_, hasLower := got["user-agent"]
109		assert.False(t, hasLower, "all case-insensitive UA keys must be removed")
110	})
111
112	t.Run("no explicit UA collapses to single canonical key", func(t *testing.T) {
113		t.Parallel()
114		headers := map[string]string{
115			"User-Agent": "canonical",
116			"user-agent": "lowercase",
117		}
118		got := ResolveHeaders(headers, "", "default")
119		_, hasLower := got["user-agent"]
120		hasCanonical := got["User-Agent"]
121		assert.False(t, hasLower, "non-canonical key should be removed")
122		assert.NotEmpty(t, hasCanonical, "canonical User-Agent key must exist")
123	})
124}
125
126func TestCallUserAgent(t *testing.T) {
127	t.Parallel()
128
129	tests := []struct {
130		name   string
131		callUA string
132		wantUA string
133		wantOK bool
134	}{
135		{name: "no override", callUA: "", wantUA: "", wantOK: false},
136		{name: "explicit UA", callUA: "MyAgent/1.0", wantUA: "MyAgent/1.0", wantOK: true},
137	}
138	for _, tt := range tests {
139		t.Run(tt.name, func(t *testing.T) {
140			t.Parallel()
141			ua, ok := CallUserAgent(tt.callUA)
142			assert.Equal(t, tt.wantOK, ok)
143			assert.Equal(t, tt.wantUA, ua)
144		})
145	}
146}