202 lines
4.4 KiB
Go
202 lines
4.4 KiB
Go
package ficha
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func makeToken(perms ...string) *Token {
|
|
return &Token{
|
|
id: "tok_test",
|
|
issuedAt: time.Unix(1_700_000_000, 0),
|
|
expiresAt: time.Unix(1_700_003_600, 0),
|
|
permissions: perms,
|
|
}
|
|
}
|
|
|
|
func TestTokenAccessors(t *testing.T) {
|
|
tok := makeToken("read", "write")
|
|
|
|
if tok.ID() != "tok_test" {
|
|
t.Errorf("ID: got %q", tok.ID())
|
|
}
|
|
if got := tok.IssuedAt().Unix(); got != 1_700_000_000 {
|
|
t.Errorf("IssuedAt: got %d", got)
|
|
}
|
|
if got := tok.ExpiresAt().Unix(); got != 1_700_003_600 {
|
|
t.Errorf("ExpiresAt: got %d", got)
|
|
}
|
|
|
|
perms := tok.Permissions()
|
|
if len(perms) != 2 || perms[0] != "read" || perms[1] != "write" {
|
|
t.Errorf("Permissions: got %v", perms)
|
|
}
|
|
}
|
|
|
|
func TestTokenPermissionsIsCopy(t *testing.T) {
|
|
tok := makeToken("read", "write")
|
|
perms := tok.Permissions()
|
|
perms[0] = "tampered"
|
|
|
|
if tok.Has("tampered") {
|
|
t.Error("mutating returned slice affected token state")
|
|
}
|
|
}
|
|
|
|
func TestTokenHas(t *testing.T) {
|
|
tok := makeToken("read", "write", "admin")
|
|
|
|
cases := map[string]bool{
|
|
"read": true,
|
|
"write": true,
|
|
"admin": true,
|
|
"delete": false,
|
|
"": false,
|
|
}
|
|
for perm, want := range cases {
|
|
if got := tok.Has(perm); got != want {
|
|
t.Errorf("Has(%q): got %v, want %v", perm, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTokenHasAll(t *testing.T) {
|
|
tok := makeToken("a", "b", "c")
|
|
|
|
tests := []struct {
|
|
name string
|
|
perms []string
|
|
want bool
|
|
}{
|
|
{"all present", []string{"a", "b"}, true},
|
|
{"all three", []string{"a", "b", "c"}, true},
|
|
{"one missing", []string{"a", "z"}, false},
|
|
{"none present", []string{"x", "y"}, false},
|
|
{"empty input is vacuously true", []string{}, true},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := tok.HasAll(tc.perms...); got != tc.want {
|
|
t.Errorf("got %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTokenHasAny(t *testing.T) {
|
|
tok := makeToken("a", "b")
|
|
|
|
tests := []struct {
|
|
name string
|
|
perms []string
|
|
want bool
|
|
}{
|
|
{"one matches", []string{"a", "z"}, true},
|
|
{"all match", []string{"a", "b"}, true},
|
|
{"none match", []string{"x", "y"}, false},
|
|
{"empty input is false", []string{}, false},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := tok.HasAny(tc.perms...); got != tc.want {
|
|
t.Errorf("got %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTokenHasNone(t *testing.T) {
|
|
tok := makeToken("a", "b")
|
|
|
|
tests := []struct {
|
|
name string
|
|
perms []string
|
|
want bool
|
|
}{
|
|
{"none of them present", []string{"x", "y"}, true},
|
|
{"one is present", []string{"a", "y"}, false},
|
|
{"empty input is vacuously true", []string{}, true},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := tok.HasNone(tc.perms...); got != tc.want {
|
|
t.Errorf("got %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTokenUnmarshalData(t *testing.T) {
|
|
type meta struct {
|
|
UserID string `json:"user_id"`
|
|
Tier int `json:"tier"`
|
|
}
|
|
raw, _ := json.Marshal(meta{UserID: "u_42", Tier: 3})
|
|
|
|
tok := &Token{data: raw}
|
|
|
|
var got meta
|
|
if err := tok.UnmarshalData(&got); err != nil {
|
|
t.Fatalf("UnmarshalData: %v", err)
|
|
}
|
|
if got.UserID != "u_42" || got.Tier != 3 {
|
|
t.Errorf("got %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestTokenUnmarshalDataEmpty(t *testing.T) {
|
|
tok := &Token{}
|
|
var got map[string]any
|
|
if err := tok.UnmarshalData(&got); err != nil {
|
|
t.Errorf("expected nil error on empty data, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewToken(t *testing.T) {
|
|
p := payload{
|
|
ID: "tok_x",
|
|
Iat: 1_700_000_000,
|
|
Exp: 1_700_003_600,
|
|
Permissions: []string{"read"},
|
|
Data: json.RawMessage(`{"x":1}`),
|
|
}
|
|
tok := newToken(p)
|
|
|
|
if tok.ID() != "tok_x" {
|
|
t.Errorf("ID: got %q", tok.ID())
|
|
}
|
|
if !tok.Has("read") {
|
|
t.Error("expected Has(read)")
|
|
}
|
|
if tok.IssuedAt().Unix() != 1_700_000_000 {
|
|
t.Errorf("IssuedAt: %v", tok.IssuedAt())
|
|
}
|
|
}
|
|
|
|
func TestTokenRequiresAll(t *testing.T) {
|
|
tok := makeToken("a", "b", "c")
|
|
|
|
tests := []struct {
|
|
name string
|
|
perms []string
|
|
want bool
|
|
}{
|
|
{"all present", []string{"a", "b"}, true},
|
|
{"all three", []string{"a", "b", "c"}, true},
|
|
{"one missing", []string{"a", "z"}, false},
|
|
{"none present", []string{"x", "y"}, false},
|
|
{"empty input fails closed", []string{}, false},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := tok.RequiresAll(tc.perms...); got != tc.want {
|
|
t.Errorf("got %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|