package oauth import ( "github.com/bluesky-social/indigo/atproto/auth/oauth" "testing" ) func TestNewClientApp(t *testing.T) { keyPath := t.TempDir() + "/oauth-key.bin" store := oauth.NewMemStore() baseURL := "http://localhost:5000" scopes := GetDefaultScopes("*") clientApp, err := NewClientApp(baseURL, store, scopes, keyPath, "AT Container Registry") if err != nil { t.Fatalf("NewClientApp() error = %v", err) } if clientApp == nil { t.Fatal("Expected non-nil clientApp") } if clientApp.Dir == nil { t.Error("Expected directory to be set") } } func TestNewClientAppWithCustomScopes(t *testing.T) { keyPath := t.TempDir() + "/oauth-key.bin" store := oauth.NewMemStore() baseURL := "http://localhost:5000" scopes := []string{"atproto", "custom:scope"} clientApp, err := NewClientApp(baseURL, store, scopes, keyPath, "AT Container Registry") if err != nil { t.Fatalf("NewClientApp() error = %v", err) } if clientApp == nil { t.Fatal("Expected non-nil clientApp") } // Verify clientApp was created successfully // (Note: indigo's oauth.ClientApp doesn't expose scopes directly, // but we can verify it was created without error) if clientApp.Dir == nil { t.Error("Expected directory to be set") } } func TestScopesMatch(t *testing.T) { tests := []struct { name string stored []string desired []string expected bool }{ { name: "exact match", stored: []string{"atproto", "blob:image/png"}, desired: []string{"atproto", "blob:image/png"}, expected: true, }, { name: "different order", stored: []string{"blob:image/png", "atproto"}, desired: []string{"atproto", "blob:image/png"}, expected: true, }, { name: "missing scope in stored", stored: []string{"atproto"}, desired: []string{"atproto", "blob:image/png"}, expected: false, }, { name: "extra scope in stored", stored: []string{"atproto", "blob:image/png", "extra"}, desired: []string{"atproto", "blob:image/png"}, expected: false, }, { name: "both empty", stored: []string{}, desired: []string{}, expected: true, }, { name: "nil vs empty", stored: nil, desired: []string{}, expected: true, }, { name: "completely different", stored: []string{"foo", "bar"}, desired: []string{"baz", "qux"}, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := ScopesMatch(tt.stored, tt.desired) if result != tt.expected { t.Errorf("ScopesMatch(%v, %v) = %v, want %v", tt.stored, tt.desired, result, tt.expected) } }) } } // ---------------------------------------------------------------------------- // Session Management (Refresher) Tests // ---------------------------------------------------------------------------- func TestNewRefresher(t *testing.T) { store := oauth.NewMemStore() scopes := GetDefaultScopes("*") clientApp, err := NewClientApp("http://localhost:5000", store, scopes, "", "AT Container Registry") if err != nil { t.Fatalf("NewClientApp() error = %v", err) } refresher := NewRefresher(clientApp) if refresher == nil { t.Fatal("Expected non-nil refresher") } if refresher.clientApp == nil { t.Error("Expected clientApp to be set") } } func TestRefresher_SetUISessionStore(t *testing.T) { store := oauth.NewMemStore() scopes := GetDefaultScopes("*") clientApp, err := NewClientApp("http://localhost:5000", store, scopes, "", "AT Container Registry") if err != nil { t.Fatalf("NewClientApp() error = %v", err) } refresher := NewRefresher(clientApp) // Test that SetUISessionStore doesn't panic with nil // Full mock implementation requires implementing the interface refresher.SetUISessionStore(nil) // Verify nil is accepted if refresher.uiSessionStore != nil { t.Error("Expected UI session store to be nil after setting nil") } }