package entity import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestToken_IsExpired(t *testing.T) { tests := []struct { name string token *Token expected bool }{ { name: "expired token", token: &Token{ ID: "test-id", UID: "test-uid", ExpiresIn: int(time.Now().Add(-time.Hour).Unix()), }, expected: true, }, { name: "valid token", token: &Token{ ID: "test-id", UID: "test-uid", ExpiresIn: int(time.Now().Add(time.Hour).Unix()), }, expected: false, }, { name: "token expiring now", token: &Token{ ID: "test-id", UID: "test-uid", ExpiresIn: int(time.Now().Unix()) - 1, }, expected: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.token.IsExpired() assert.Equal(t, tt.expected, result) }) } } func TestToken_IsRefreshExpired(t *testing.T) { tests := []struct { name string token *Token expected bool }{ { name: "expired refresh token", token: &Token{ ID: "test-id", UID: "test-uid", RefreshExpiresIn: int(time.Now().Add(-time.Hour).Unix()), }, expected: true, }, { name: "valid refresh token", token: &Token{ ID: "test-id", UID: "test-uid", RefreshExpiresIn: int(time.Now().Add(time.Hour).Unix()), }, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.token.IsRefreshExpired() assert.Equal(t, tt.expected, result) }) } } func TestToken_RedisRefreshExpiredSec(t *testing.T) { tests := []struct { name string token *Token expected int }{ { name: "token with future expiry", token: &Token{ ID: "test-id", UID: "test-uid", RefreshExpiresIn: int(time.Now().Add(time.Hour).Unix()), }, expected: 3600, // Approximately 1 hour in seconds }, { name: "token already expired", token: &Token{ ID: "test-id", UID: "test-uid", RefreshExpiresIn: int(time.Now().Add(-time.Hour).Unix()), }, expected: 0, }, { name: "token expiring now", token: &Token{ ID: "test-id", UID: "test-uid", RefreshExpiresIn: int(time.Now().Unix()), }, expected: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.token.RedisRefreshExpiredSec() if tt.expected == 0 { assert.Equal(t, 0, result) } else { // Allow some margin for test execution time assert.InDelta(t, tt.expected, result, 5) } }) } } func TestToken_Validate(t *testing.T) { tests := []struct { name string token *Token wantErr bool expectedErr error }{ { name: "valid token", token: &Token{ ID: "test-id", UID: "test-uid", AccessToken: "test-access-token", ExpiresIn: int(time.Now().Add(time.Hour).Unix()), }, wantErr: false, }, { name: "missing ID", token: &Token{ ID: "", UID: "test-uid", AccessToken: "test-access-token", }, wantErr: true, expectedErr: ErrInvalidTokenID, }, { name: "missing UID", token: &Token{ ID: "test-id", UID: "", AccessToken: "test-access-token", }, wantErr: true, expectedErr: ErrInvalidUID, }, { name: "missing AccessToken", token: &Token{ ID: "test-id", UID: "test-uid", AccessToken: "", }, wantErr: true, expectedErr: ErrInvalidAccessToken, }, { name: "all fields missing", token: &Token{ ID: "", UID: "", AccessToken: "", }, wantErr: true, expectedErr: ErrInvalidTokenID, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.token.Validate() if tt.wantErr { assert.Error(t, err) if tt.expectedErr != nil { assert.Equal(t, tt.expectedErr, err) } } else { assert.NoError(t, err) } }) } } func TestTicket(t *testing.T) { t.Run("ticket with data", func(t *testing.T) { ticket := Ticket{ Data: map[string]string{ "uid": "user123", "role": "admin", }, Token: Token{ ID: "token123", UID: "user123", AccessToken: "access-token", }, } assert.NotNil(t, ticket.Data) assert.Equal(t, "user123", ticket.Data["uid"]) assert.Equal(t, "admin", ticket.Data["role"]) assert.Equal(t, "token123", ticket.Token.ID) }) t.Run("empty ticket", func(t *testing.T) { ticket := Ticket{} assert.Nil(t, ticket.Data) assert.Empty(t, ticket.Token.ID) }) } func TestToken_DeviceID(t *testing.T) { tests := []struct { name string deviceID string }{ { name: "with device ID", deviceID: "device123", }, { name: "empty device ID", deviceID: "", }, { name: "UUID device ID", deviceID: "550e8400-e29b-41d4-a716-446655440000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { token := &Token{ ID: "test-id", UID: "test-uid", DeviceID: tt.deviceID, AccessToken: "test-token", } assert.Equal(t, tt.deviceID, token.DeviceID) }) } } func TestToken_RefreshToken(t *testing.T) { tests := []struct { name string refreshToken string }{ { name: "with refresh token", refreshToken: "refresh-token-123", }, { name: "empty refresh token", refreshToken: "", }, { name: "long refresh token", refreshToken: "very-long-refresh-token-with-hash-abcdef1234567890", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { token := &Token{ ID: "test-id", UID: "test-uid", AccessToken: "access-token", RefreshToken: tt.refreshToken, } assert.Equal(t, tt.refreshToken, token.RefreshToken) }) } } func TestToken_Timestamps(t *testing.T) { now := time.Now() token := &Token{ ID: "test-id", UID: "test-uid", AccessToken: "access-token", AccessCreateAt: now, RefreshCreateAt: now.Add(time.Second), } assert.Equal(t, now, token.AccessCreateAt) assert.True(t, token.RefreshCreateAt.After(token.AccessCreateAt)) }