mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-29 13:13:57 +00:00
281 lines
7.5 KiB
Go
281 lines
7.5 KiB
Go
package jwt_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/therootcompany/golib/auth/jwt"
|
|
)
|
|
|
|
func TestNullBool_MarshalJSON(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
nb jwt.NullBool
|
|
want string
|
|
}{
|
|
{"true", jwt.NullBool{Bool: true, Valid: true}, "true"},
|
|
{"false", jwt.NullBool{Bool: false, Valid: true}, "false"},
|
|
{"null (zero value)", jwt.NullBool{}, "null"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := json.Marshal(tt.nb)
|
|
if err != nil {
|
|
t.Fatalf("Marshal error: %v", err)
|
|
}
|
|
if string(got) != tt.want {
|
|
t.Errorf("Marshal = %s, want %s", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNullBool_UnmarshalJSON(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
wantValue bool
|
|
wantValid bool
|
|
}{
|
|
{"true", "true", true, true},
|
|
{"false", "false", false, true},
|
|
{"null", "null", false, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var nb jwt.NullBool
|
|
if err := json.Unmarshal([]byte(tt.input), &nb); err != nil {
|
|
t.Fatalf("Unmarshal error: %v", err)
|
|
}
|
|
if nb.Bool != tt.wantValue {
|
|
t.Errorf("Value = %v, want %v", nb.Bool, tt.wantValue)
|
|
}
|
|
if nb.Valid != tt.wantValid {
|
|
t.Errorf("Valid = %v, want %v", nb.Valid, tt.wantValid)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNullBool_UnmarshalJSON_InvalidInput(t *testing.T) {
|
|
var nb jwt.NullBool
|
|
if err := json.Unmarshal([]byte(`"yes"`), &nb); err == nil {
|
|
t.Error("expected error for invalid input, got nil")
|
|
}
|
|
}
|
|
|
|
func TestNullBool_IsZero(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
nb jwt.NullBool
|
|
want bool
|
|
}{
|
|
{"zero value", jwt.NullBool{}, true},
|
|
{"true", jwt.NullBool{Bool: true, Valid: true}, false},
|
|
{"false", jwt.NullBool{Bool: false, Valid: true}, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.nb.IsZero(); got != tt.want {
|
|
t.Errorf("IsZero() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNullBool_RoundTrip(t *testing.T) {
|
|
values := []jwt.NullBool{
|
|
{Bool: true, Valid: true},
|
|
{Bool: false, Valid: true},
|
|
{Bool: false, Valid: false},
|
|
}
|
|
for _, orig := range values {
|
|
data, err := json.Marshal(orig)
|
|
if err != nil {
|
|
t.Fatalf("Marshal error: %v", err)
|
|
}
|
|
var got jwt.NullBool
|
|
if err := json.Unmarshal(data, &got); err != nil {
|
|
t.Fatalf("Unmarshal error: %v", err)
|
|
}
|
|
if got.Bool != orig.Bool || got.Valid != orig.Valid {
|
|
t.Errorf("round-trip: got {%v, %v}, want {%v, %v}",
|
|
got.Bool, got.Valid, orig.Bool, orig.Valid)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNullBool_ClaimsIntegration(t *testing.T) {
|
|
t.Run("marshal with email verified true", func(t *testing.T) {
|
|
claims := jwt.StandardClaims{
|
|
TokenClaims: jwt.TokenClaims{
|
|
Iss: "https://example.com",
|
|
Sub: "user123",
|
|
Exp: 9999999999,
|
|
IAt: 1000000000,
|
|
},
|
|
Email: "user@example.com",
|
|
EmailVerified: jwt.NullBool{Bool: true, Valid: true},
|
|
}
|
|
data, err := json.Marshal(claims)
|
|
if err != nil {
|
|
t.Fatalf("Marshal error: %v", err)
|
|
}
|
|
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(raw["email_verified"]) != "true" {
|
|
t.Errorf("email_verified = %s, want true", raw["email_verified"])
|
|
}
|
|
})
|
|
|
|
t.Run("marshal with email verified false", func(t *testing.T) {
|
|
claims := jwt.StandardClaims{
|
|
TokenClaims: jwt.TokenClaims{
|
|
Iss: "https://example.com",
|
|
Sub: "user123",
|
|
Exp: 9999999999,
|
|
IAt: 1000000000,
|
|
},
|
|
Email: "user@example.com",
|
|
EmailVerified: jwt.NullBool{Bool: false, Valid: true},
|
|
}
|
|
data, err := json.Marshal(claims)
|
|
if err != nil {
|
|
t.Fatalf("Marshal error: %v", err)
|
|
}
|
|
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(raw["email_verified"]) != "false" {
|
|
t.Errorf("email_verified = %s, want false", raw["email_verified"])
|
|
}
|
|
})
|
|
|
|
t.Run("marshal omits verified when no email", func(t *testing.T) {
|
|
claims := jwt.StandardClaims{
|
|
TokenClaims: jwt.TokenClaims{
|
|
Iss: "https://example.com",
|
|
Sub: "user123",
|
|
Exp: 9999999999,
|
|
IAt: 1000000000,
|
|
},
|
|
// No email, no EmailVerified -> field omitted via omitzero
|
|
}
|
|
data, err := json.Marshal(claims)
|
|
if err != nil {
|
|
t.Fatalf("Marshal error: %v", err)
|
|
}
|
|
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := raw["email_verified"]; ok {
|
|
t.Errorf("email_verified present = %s, want omitted", raw["email_verified"])
|
|
}
|
|
if _, ok := raw["phone_number_verified"]; ok {
|
|
t.Errorf("phone_number_verified present = %s, want omitted", raw["phone_number_verified"])
|
|
}
|
|
})
|
|
|
|
t.Run("unmarshal claims with verified fields", func(t *testing.T) {
|
|
input := `{
|
|
"iss": "https://example.com",
|
|
"sub": "user123",
|
|
"exp": 9999999999,
|
|
"iat": 1000000000,
|
|
"email": "user@example.com",
|
|
"email_verified": true,
|
|
"phone_number": "+1555000000",
|
|
"phone_number_verified": false
|
|
}`
|
|
var claims jwt.StandardClaims
|
|
if err := json.Unmarshal([]byte(input), &claims); err != nil {
|
|
t.Fatalf("Unmarshal error: %v", err)
|
|
}
|
|
if !claims.EmailVerified.Valid || !claims.EmailVerified.Bool {
|
|
t.Errorf("EmailVerified = {%v, %v}, want {true, true}",
|
|
claims.EmailVerified.Bool, claims.EmailVerified.Valid)
|
|
}
|
|
if !claims.PhoneNumberVerified.Valid || claims.PhoneNumberVerified.Bool {
|
|
t.Errorf("PhoneNumberVerified = {%v, %v}, want {false, true}",
|
|
claims.PhoneNumberVerified.Bool, claims.PhoneNumberVerified.Valid)
|
|
}
|
|
})
|
|
|
|
t.Run("unmarshal claims with null verified fields", func(t *testing.T) {
|
|
input := `{
|
|
"iss": "https://example.com",
|
|
"sub": "user123",
|
|
"exp": 9999999999,
|
|
"iat": 1000000000,
|
|
"email_verified": null,
|
|
"phone_number_verified": null
|
|
}`
|
|
var claims jwt.StandardClaims
|
|
if err := json.Unmarshal([]byte(input), &claims); err != nil {
|
|
t.Fatalf("Unmarshal error: %v", err)
|
|
}
|
|
if claims.EmailVerified.Valid {
|
|
t.Error("EmailVerified.Valid = true, want false")
|
|
}
|
|
if claims.PhoneNumberVerified.Valid {
|
|
t.Error("PhoneNumberVerified.Valid = true, want false")
|
|
}
|
|
})
|
|
|
|
t.Run("unmarshal claims with omitted verified fields", func(t *testing.T) {
|
|
input := `{
|
|
"iss": "https://example.com",
|
|
"sub": "user123",
|
|
"exp": 9999999999,
|
|
"iat": 1000000000
|
|
}`
|
|
var claims jwt.StandardClaims
|
|
if err := json.Unmarshal([]byte(input), &claims); err != nil {
|
|
t.Fatalf("Unmarshal error: %v", err)
|
|
}
|
|
// Omitted fields -> zero value: {false, false}
|
|
if claims.EmailVerified.Valid {
|
|
t.Error("EmailVerified.Valid = true, want false")
|
|
}
|
|
if claims.PhoneNumberVerified.Valid {
|
|
t.Error("PhoneNumberVerified.Valid = true, want false")
|
|
}
|
|
})
|
|
|
|
t.Run("round-trip claims", func(t *testing.T) {
|
|
orig := jwt.StandardClaims{
|
|
TokenClaims: jwt.TokenClaims{
|
|
Iss: "https://example.com",
|
|
Sub: "user123",
|
|
Exp: 9999999999,
|
|
IAt: 1000000000,
|
|
},
|
|
Email: "user@example.com",
|
|
EmailVerified: jwt.NullBool{Bool: true, Valid: true},
|
|
PhoneNumber: "+1555000000",
|
|
PhoneNumberVerified: jwt.NullBool{Bool: false, Valid: true},
|
|
}
|
|
data, err := json.Marshal(orig)
|
|
if err != nil {
|
|
t.Fatalf("Marshal error: %v", err)
|
|
}
|
|
var got jwt.StandardClaims
|
|
if err := json.Unmarshal(data, &got); err != nil {
|
|
t.Fatalf("Unmarshal error: %v", err)
|
|
}
|
|
if got.EmailVerified != orig.EmailVerified {
|
|
t.Errorf("EmailVerified = %+v, want %+v", got.EmailVerified, orig.EmailVerified)
|
|
}
|
|
if got.PhoneNumberVerified != orig.PhoneNumberVerified {
|
|
t.Errorf("PhoneNumberVerified = %+v, want %+v", got.PhoneNumberVerified, orig.PhoneNumberVerified)
|
|
}
|
|
})
|
|
}
|