Skip to content

Commit 70bbe26

Browse files
committed
test(model): enhance tests for web token claims
• Refactor tests to use table-driven approach for better readability • Add comprehensive cases for first name, last name, and error handling
1 parent e2fb38e commit 70bbe26

File tree

2 files changed

+347
-224
lines changed

2 files changed

+347
-224
lines changed

jwt/model_test.go

Lines changed: 179 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -11,140 +11,191 @@ import (
1111
var signatureAlgorithms = []jose.SignatureAlgorithm{jose.HS256}
1212
var joseTestKey = []byte("0123456789abcdef0123456789abcdef") // 32 bytes
1313

14-
func TestNew(t *testing.T) {
15-
issuer := "my-issuer"
16-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.RegisteredClaims{
17-
Issuer: issuer,
18-
})
19-
tokenString, err := token.SignedString(joseTestKey)
20-
assert.NoError(t, err)
21-
22-
webToken, err := New(tokenString, signatureAlgorithms)
23-
assert.NoError(t, err)
24-
assert.NotNil(t, webToken)
25-
assert.Equal(t, issuer, webToken.Issuer)
26-
}
27-
28-
func TestNewAndFail(t *testing.T) {
29-
tokenString := "just a string"
30-
_, err := New(tokenString, signatureAlgorithms)
31-
assert.Error(t, err)
32-
}
33-
34-
func TestNew_DeserializationError(t *testing.T) {
35-
// Create a valid JWT header and signature, but with a payload that is not valid JSON
36-
// or cannot be unmarshaled into the expected struct.
37-
// We'll use jose to construct a token with a payload that is not a JSON object.
38-
invalidPayload := "not-a-json-object"
39-
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: joseTestKey}, nil)
40-
assert.NoError(t, err)
41-
42-
object, err := signer.Sign([]byte(invalidPayload))
43-
assert.NoError(t, err)
44-
45-
tokenString, err := object.CompactSerialize()
46-
assert.NoError(t, err)
47-
48-
_, err = New(tokenString, signatureAlgorithms)
49-
assert.Error(t, err)
50-
assert.Contains(t, err.Error(), "unable to deserialize claims")
51-
}
52-
53-
func TestNew_WithFirstNameAndLastName(t *testing.T) {
54-
claims := map[string]interface{}{
55-
"iss": "test-issuer",
56-
"sub": "test-subject",
57-
"first_name": "John",
58-
"last_name": "Doe",
14+
func TestNew_Success(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
claims map[string]interface{}
18+
expectedWT WebToken
19+
}{
20+
{
21+
name: "basic issuer claim",
22+
claims: map[string]interface{}{
23+
"iss": "my-issuer",
24+
},
25+
expectedWT: WebToken{
26+
IssuerAttributes: IssuerAttributes{
27+
Issuer: "my-issuer",
28+
},
29+
},
30+
},
31+
{
32+
name: "with first_name and last_name",
33+
claims: map[string]interface{}{
34+
"iss": "test-issuer",
35+
"sub": "test-subject",
36+
"first_name": "John",
37+
"last_name": "Doe",
38+
},
39+
expectedWT: WebToken{
40+
IssuerAttributes: IssuerAttributes{
41+
Issuer: "test-issuer",
42+
Subject: "test-subject",
43+
},
44+
UserAttributes: UserAttributes{
45+
FirstName: "John",
46+
LastName: "Doe",
47+
},
48+
},
49+
},
50+
{
51+
name: "with given_name and family_name",
52+
claims: map[string]interface{}{
53+
"iss": "test-issuer",
54+
"sub": "test-subject",
55+
"given_name": "Jonathan",
56+
"family_name": "Smith",
57+
},
58+
expectedWT: WebToken{
59+
IssuerAttributes: IssuerAttributes{
60+
Issuer: "test-issuer",
61+
Subject: "test-subject",
62+
},
63+
UserAttributes: UserAttributes{
64+
FirstName: "Jonathan",
65+
LastName: "Smith",
66+
},
67+
},
68+
},
69+
{
70+
name: "prefer first_name/last_name over given_name/family_name",
71+
claims: map[string]interface{}{
72+
"iss": "test-issuer",
73+
"sub": "test-subject",
74+
"first_name": "John",
75+
"last_name": "Doe",
76+
"given_name": "Jonathan",
77+
"family_name": "Smith",
78+
},
79+
expectedWT: WebToken{
80+
IssuerAttributes: IssuerAttributes{
81+
Issuer: "test-issuer",
82+
Subject: "test-subject",
83+
},
84+
UserAttributes: UserAttributes{
85+
FirstName: "John",
86+
LastName: "Doe",
87+
},
88+
},
89+
},
90+
{
91+
name: "fallback to given_name/family_name when first_name/last_name are empty",
92+
claims: map[string]interface{}{
93+
"iss": "test-issuer",
94+
"sub": "test-subject",
95+
"first_name": "",
96+
"last_name": "",
97+
"given_name": "Jonathan",
98+
"family_name": "Smith",
99+
},
100+
expectedWT: WebToken{
101+
IssuerAttributes: IssuerAttributes{
102+
Issuer: "test-issuer",
103+
Subject: "test-subject",
104+
},
105+
UserAttributes: UserAttributes{
106+
FirstName: "Jonathan",
107+
LastName: "Smith",
108+
},
109+
},
110+
},
111+
{
112+
name: "partial fallback - first_name present, last_name empty",
113+
claims: map[string]interface{}{
114+
"iss": "test-issuer",
115+
"sub": "test-subject",
116+
"first_name": "John",
117+
"last_name": "",
118+
"given_name": "Jonathan",
119+
"family_name": "Smith",
120+
},
121+
expectedWT: WebToken{
122+
IssuerAttributes: IssuerAttributes{
123+
Issuer: "test-issuer",
124+
Subject: "test-subject",
125+
},
126+
UserAttributes: UserAttributes{
127+
FirstName: "John",
128+
LastName: "Smith",
129+
},
130+
},
131+
},
59132
}
60133

61-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))
62-
tokenString, err := token.SignedString(joseTestKey)
63-
assert.NoError(t, err)
64-
65-
webToken, err := New(tokenString, signatureAlgorithms)
66-
assert.NoError(t, err)
67-
assert.Equal(t, "John", webToken.FirstName)
68-
assert.Equal(t, "Doe", webToken.LastName)
69-
}
70-
71-
func TestNew_WithGivenNameAndFamilyName(t *testing.T) {
72-
claims := map[string]interface{}{
73-
"iss": "test-issuer",
74-
"sub": "test-subject",
75-
"given_name": "Jonathan",
76-
"family_name": "Smith",
134+
for _, tt := range tests {
135+
t.Run(tt.name, func(t *testing.T) {
136+
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(tt.claims))
137+
tokenString, err := token.SignedString(joseTestKey)
138+
assert.NoError(t, err)
139+
140+
webToken, err := New(tokenString, signatureAlgorithms)
141+
assert.NoError(t, err)
142+
assert.NotNil(t, webToken)
143+
assert.Equal(t, tt.expectedWT.Issuer, webToken.Issuer)
144+
assert.Equal(t, tt.expectedWT.Subject, webToken.Subject)
145+
assert.Equal(t, tt.expectedWT.FirstName, webToken.FirstName)
146+
assert.Equal(t, tt.expectedWT.LastName, webToken.LastName)
147+
})
77148
}
78-
79-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))
80-
tokenString, err := token.SignedString(joseTestKey)
81-
assert.NoError(t, err)
82-
83-
webToken, err := New(tokenString, signatureAlgorithms)
84-
assert.NoError(t, err)
85-
assert.Equal(t, "Jonathan", webToken.FirstName)
86-
assert.Equal(t, "Smith", webToken.LastName)
87-
}
88-
89-
func TestNew_PreferFirstLastNameOverGivenFamilyName(t *testing.T) {
90-
claims := map[string]interface{}{
91-
"iss": "test-issuer",
92-
"sub": "test-subject",
93-
"first_name": "John",
94-
"last_name": "Doe",
95-
"given_name": "Jonathan",
96-
"family_name": "Smith",
97-
}
98-
99-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))
100-
tokenString, err := token.SignedString(joseTestKey)
101-
assert.NoError(t, err)
102-
103-
webToken, err := New(tokenString, signatureAlgorithms)
104-
assert.NoError(t, err)
105-
// Should prefer first_name/last_name over given_name/family_name
106-
assert.Equal(t, "John", webToken.FirstName)
107-
assert.Equal(t, "Doe", webToken.LastName)
108149
}
109150

110-
func TestNew_FallbackToGivenFamilyNameWhenFirstLastEmpty(t *testing.T) {
111-
claims := map[string]interface{}{
112-
"iss": "test-issuer",
113-
"sub": "test-subject",
114-
"first_name": "",
115-
"last_name": "",
116-
"given_name": "Jonathan",
117-
"family_name": "Smith",
151+
func TestNew_Errors(t *testing.T) {
152+
tests := []struct {
153+
name string
154+
tokenString string
155+
setupToken func() (string, error)
156+
expectedError string
157+
}{
158+
{
159+
name: "invalid token string",
160+
tokenString: "just a string",
161+
expectedError: "unable to parse id_token",
162+
},
163+
{
164+
name: "deserialization error with invalid payload",
165+
setupToken: func() (string, error) {
166+
// Create a valid JWT header and signature, but with a payload that is not valid JSON
167+
invalidPayload := "not-a-json-object"
168+
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: joseTestKey}, nil)
169+
if err != nil {
170+
return "", err
171+
}
172+
173+
object, err := signer.Sign([]byte(invalidPayload))
174+
if err != nil {
175+
return "", err
176+
}
177+
178+
return object.CompactSerialize()
179+
},
180+
expectedError: "unable to deserialize claims",
181+
},
118182
}
119183

120-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))
121-
tokenString, err := token.SignedString(joseTestKey)
122-
assert.NoError(t, err)
123-
124-
webToken, err := New(tokenString, signatureAlgorithms)
125-
assert.NoError(t, err)
126-
// Should fallback to given_name/family_name when first_name/last_name are empty
127-
assert.Equal(t, "Jonathan", webToken.FirstName)
128-
assert.Equal(t, "Smith", webToken.LastName)
129-
}
130-
131-
func TestNew_PartialFallback(t *testing.T) {
132-
claims := map[string]interface{}{
133-
"iss": "test-issuer",
134-
"sub": "test-subject",
135-
"first_name": "John",
136-
"last_name": "", // empty
137-
"given_name": "Jonathan",
138-
"family_name": "Smith",
184+
for _, tt := range tests {
185+
t.Run(tt.name, func(t *testing.T) {
186+
var tokenString string
187+
var err error
188+
189+
if tt.setupToken != nil {
190+
tokenString, err = tt.setupToken()
191+
assert.NoError(t, err)
192+
} else {
193+
tokenString = tt.tokenString
194+
}
195+
196+
_, err = New(tokenString, signatureAlgorithms)
197+
assert.Error(t, err)
198+
assert.Contains(t, err.Error(), tt.expectedError)
199+
})
139200
}
140-
141-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims))
142-
tokenString, err := token.SignedString(joseTestKey)
143-
assert.NoError(t, err)
144-
145-
webToken, err := New(tokenString, signatureAlgorithms)
146-
assert.NoError(t, err)
147-
// Should use first_name but fallback to family_name for last name
148-
assert.Equal(t, "John", webToken.FirstName)
149-
assert.Equal(t, "Smith", webToken.LastName)
150201
}

0 commit comments

Comments
 (0)