package entity import ( "testing" "time" ) // TestAccessTokenExpires 測試 AccessTokenExpires 方法是否能正確將 ExpiresIn 轉換成 time.Duration(秒) func TestAccessTokenExpires(t *testing.T) { tests := []struct { name string // 測試案例名稱 expiresIn int64 // 輸入的 ExpiresIn 值,單位為秒 want time.Duration // 預期返回的時間間隔 }{ {"zero expiration", 0, 0}, {"1 second expiration", 1, 1 * time.Second}, {"60 seconds expiration", 60, 60 * time.Second}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // 建立一個 Token 實例,僅設置 ExpiresIn 欄位 token := Token{ ExpiresIn: tt.expiresIn, } // 呼叫 AccessTokenExpires 方法 got := token.AccessTokenExpires() // ex 1m0s, 1s, 0s etc .... // 檢查返回值是否與預期相符 if got != tt.want { t.Errorf("AccessTokenExpires() = %v, want %v", got, tt.want) } }) } } // TestRefreshTokenExpires 測試 RefreshTokenExpires 方法是否能正確將 RefreshExpiresIn(秒)轉換成 time.Duration func TestRefreshTokenExpires(t *testing.T) { tests := []struct { name string refreshExpiresIn int64 want time.Duration }{ {"zero", 0, 0}, {"1 second", 1, 1 * time.Second}, {"60 seconds", 60, 60 * time.Second}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { token := Token{ RefreshExpiresIn: tt.refreshExpiresIn, } got := token.RefreshTokenExpires() if got != tt.want { t.Errorf("RefreshTokenExpires() = %v, want %v", got, tt.want) } }) } } // TestRefreshTokenExpiresUnix 測試 RefreshTokenExpiresUnix 方法返回的 UnixNano 時間戳是否大致符合預期 func TestRefreshTokenExpiresUnix(t *testing.T) { // 設定 refreshExpiresIn 為 60 秒 token := Token{ RefreshExpiresIn: 60, } // 取得測試開始時的時間 now := time.Now() // 預期值:now + 60 秒 expected := now.Add(60 * time.Second).UnixNano() got := token.RefreshTokenExpiresUnix() // 設定允許誤差 50 毫秒 tolerance := int64(50 * time.Millisecond) if got < expected-tolerance || got > expected+tolerance { t.Errorf("RefreshTokenExpiresUnix() = %v, want approx %v", got, expected) } } // TestIsExpires 測試 IsExpires 方法判斷 token 是否過期 func TestIsExpires(t *testing.T) { now := time.Now() // 測試未過期:token 創建時間為現在,過期時長為 10 秒 tokenValid := Token{ AccessCreateAt: now.UnixNano(), ExpiresIn: 10, // 此處 ExpiresIn 為有效時長(秒) } if tokenValid.IsExpires() { t.Errorf("IsExpires() 返回 true,但 token 尚未過期") } // 測試已過期:token 創建時間為 20 秒前,過期時長為 10 秒 tokenExpired := Token{ AccessCreateAt: now.Add(-20 * time.Second).UnixNano(), ExpiresIn: 10, } if !tokenExpired.IsExpires() { t.Errorf("IsExpires() 返回 false,但 token 已過期") } } // TestRedisExpiredSec 測試 RedisExpiredSec 方法 // 此方法根據 t.ExpiresIn (UnixNano 表示的到期時間) 與當前 UTC 時間計算剩餘秒數 func TestRedisExpiredSec(t *testing.T) { // 定義測試案例: // - expireOffset 為從當前時間的偏移量(正數表示未過期,負數表示已過期) // - minExpected 與 maxExpected 為允許的返回值範圍(因為執行期間會有少量延遲) tests := []struct { name string expireOffset time.Duration // token 過期時間相對於當前的偏移量 minExpected int64 // 預期返回值下限(秒) maxExpected int64 // 預期返回值上限(秒) }{ {"Not expired +10s", 10 * time.Second, 9, 10}, {"Expired -5s", -5 * time.Second, -6, -5}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { now := time.Now().UTC() // token 的到期時間設定為當前時間加上偏移量 expTime := now.Add(tt.expireOffset) token := Token{ ExpiresIn: expTime.UnixNano(), } got := token.RedisExpiredSec() if got < tt.minExpected || got > tt.maxExpected { t.Errorf("RedisExpiredSec() = %d, want between %d and %d", got, tt.minExpected, tt.maxExpected) } }) } } // TestRedisRefreshExpiredSec 測試 RedisRefreshExpiredSec 方法 // 此方法根據 t.RefreshExpiresIn (UnixNano 表示的刷新到期時間) 與當前 UTC 時間計算剩餘秒數 func TestRedisRefreshExpiredSec(t *testing.T) { tests := []struct { name string expireOffset time.Duration // 刷新 token 到期時間相對於當前的偏移量 minExpected int64 // 預期返回值下限(秒) maxExpected int64 // 預期返回值上限(秒) }{ {"Not expired +20s", 20 * time.Second, 19, 20}, {"Expired -5s", -5 * time.Second, -6, -5}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { now := time.Now().UTC() expTime := now.Add(tt.expireOffset) token := Token{ RefreshExpiresIn: expTime.UnixNano(), } got := token.RedisRefreshExpiredSec() if got < tt.minExpected || got > tt.maxExpected { t.Errorf("RedisRefreshExpiredSec() = %d, want between %d and %d", got, tt.minExpected, tt.maxExpected) } }) } }