66 "fmt"
77 "net/http"
88 "net/http/httptest"
9+ "os"
10+ "path/filepath"
911 "testing"
1012
1113 "github.com/malamtime/cli/model"
@@ -76,7 +78,7 @@ func TestFetchAnthropicUsage_NonOKStatus(t *testing.T) {
7678func TestParseKeychainJSON (t * testing.T ) {
7779 raw := `{"claudeAiOauth":{"accessToken":"sk-ant-test-token-123"}}`
7880
79- var creds keychainCredentials
81+ var creds claudeCodeCredentials
8082 err := json .Unmarshal ([]byte (raw ), & creds )
8183 assert .NoError (t , err )
8284 assert .NotNil (t , creds .ClaudeAiOauth )
@@ -86,7 +88,7 @@ func TestParseKeychainJSON(t *testing.T) {
8688func TestParseKeychainJSON_MissingOAuth (t * testing.T ) {
8789 raw := `{"someOtherKey":"value"}`
8890
89- var creds keychainCredentials
91+ var creds claudeCodeCredentials
9092 err := json .Unmarshal ([]byte (raw ), & creds )
9193 assert .NoError (t , err )
9294 assert .Nil (t , creds .ClaudeAiOauth )
@@ -95,7 +97,7 @@ func TestParseKeychainJSON_MissingOAuth(t *testing.T) {
9597func TestParseKeychainJSON_EmptyAccessToken (t * testing.T ) {
9698 raw := `{"claudeAiOauth":{"accessToken":""}}`
9799
98- var creds keychainCredentials
100+ var creds claudeCodeCredentials
99101 err := json .Unmarshal ([]byte (raw ), & creds )
100102 assert .NoError (t , err )
101103 assert .NotNil (t , creds .ClaudeAiOauth )
@@ -164,3 +166,78 @@ func TestAnthropicRateLimitCache_GetCachedRateLimit_ReturnsCopy(t *testing.T) {
164166 assert .Equal (t , 0.5 , service .rateLimitCache .usage .FiveHourUtilization )
165167 service .rateLimitCache .mu .RUnlock ()
166168}
169+
170+ func TestParseOAuthTokenFromJSON_Valid (t * testing.T ) {
171+ raw := `{"claudeAiOauth":{"accessToken":"sk-ant-test-token-123","refreshToken":"sk-ref","expiresAt":1773399176544,"scopes":["user:inference"],"subscriptionType":"max","rateLimitTier":"default_claude_max_5x"}}`
172+ token , err := parseOAuthTokenFromJSON ([]byte (raw ))
173+ assert .NoError (t , err )
174+ assert .Equal (t , "sk-ant-test-token-123" , token )
175+ }
176+
177+ func TestParseOAuthTokenFromJSON_MissingOAuth (t * testing.T ) {
178+ raw := `{"someOtherKey":"value"}`
179+ token , err := parseOAuthTokenFromJSON ([]byte (raw ))
180+ assert .Error (t , err )
181+ assert .Contains (t , err .Error (), "no OAuth access token found" )
182+ assert .Empty (t , token )
183+ }
184+
185+ func TestParseOAuthTokenFromJSON_EmptyToken (t * testing.T ) {
186+ raw := `{"claudeAiOauth":{"accessToken":""}}`
187+ token , err := parseOAuthTokenFromJSON ([]byte (raw ))
188+ assert .Error (t , err )
189+ assert .Contains (t , err .Error (), "no OAuth access token found" )
190+ assert .Empty (t , token )
191+ }
192+
193+ func TestParseOAuthTokenFromJSON_InvalidJSON (t * testing.T ) {
194+ raw := `not-json`
195+ token , err := parseOAuthTokenFromJSON ([]byte (raw ))
196+ assert .Error (t , err )
197+ assert .Contains (t , err .Error (), "failed to parse credentials JSON" )
198+ assert .Empty (t , token )
199+ }
200+
201+ func TestFetchOAuthTokenFromCredentialsFile_Valid (t * testing.T ) {
202+ tmpDir := t .TempDir ()
203+ t .Setenv ("HOME" , tmpDir )
204+
205+ claudeDir := filepath .Join (tmpDir , ".claude" )
206+ err := os .MkdirAll (claudeDir , 0700 )
207+ assert .NoError (t , err )
208+
209+ content := `{"claudeAiOauth":{"accessToken":"sk-test-linux-token","refreshToken":"sk-ref","expiresAt":1773399176544}}`
210+ err = os .WriteFile (filepath .Join (claudeDir , ".credentials.json" ), []byte (content ), 0600 )
211+ assert .NoError (t , err )
212+
213+ token , err := fetchOAuthTokenFromCredentialsFile ()
214+ assert .NoError (t , err )
215+ assert .Equal (t , "sk-test-linux-token" , token )
216+ }
217+
218+ func TestFetchOAuthTokenFromCredentialsFile_MissingFile (t * testing.T ) {
219+ tmpDir := t .TempDir ()
220+ t .Setenv ("HOME" , tmpDir )
221+
222+ token , err := fetchOAuthTokenFromCredentialsFile ()
223+ assert .Error (t , err )
224+ assert .Contains (t , err .Error (), "credentials file read failed" )
225+ assert .Empty (t , token )
226+ }
227+
228+ func TestFetchOAuthTokenFromCredentialsFile_InvalidJSON (t * testing.T ) {
229+ tmpDir := t .TempDir ()
230+ t .Setenv ("HOME" , tmpDir )
231+
232+ claudeDir := filepath .Join (tmpDir , ".claude" )
233+ err := os .MkdirAll (claudeDir , 0700 )
234+ assert .NoError (t , err )
235+
236+ err = os .WriteFile (filepath .Join (claudeDir , ".credentials.json" ), []byte ("not-json" ), 0600 )
237+ assert .NoError (t , err )
238+
239+ token , err := fetchOAuthTokenFromCredentialsFile ()
240+ assert .Error (t , err )
241+ assert .Contains (t , err .Error (), "failed to parse credentials JSON" )
242+ assert .Empty (t , token )
243+ }
0 commit comments