package providers import ( "net/url" "strings" "testing" ) func TestAdditionalProviderStateGeneratorsProduceDistinctTokens(t *testing.T) { tests := []struct { name string generateState func() (string, error) }{ { name: "facebook", generateState: func() (string, error) { return NewFacebookProvider("app-id", "secret", "https://admin.example.com/callback").GenerateState() }, }, { name: "qq", generateState: func() (string, error) { return NewQQProvider("app-id", "secret", "https://admin.example.com/callback").GenerateState() }, }, { name: "weibo", generateState: func() (string, error) { return NewWeiboProvider("app-id", "secret", "https://admin.example.com/callback").GenerateState() }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { stateA, err := tc.generateState() if err != nil { t.Fatalf("GenerateState(first) failed: %v", err) } stateB, err := tc.generateState() if err != nil { t.Fatalf("GenerateState(second) failed: %v", err) } if stateA == "" || stateB == "" { t.Fatal("expected non-empty generated states") } if stateA == stateB { t.Fatal("expected generated states to differ between calls") } }) } } func TestAdditionalProviderAuthURLs(t *testing.T) { tests := []struct { name string buildURL func(t *testing.T) (string, string) expectedHost string expectedPath string expectedKey string expectedValue string expectedClause string }{ { name: "facebook", buildURL: func(t *testing.T) (string, string) { t.Helper() redirectURI := "https://admin.example.com/login/oauth/callback?from=fb" authURL, err := NewFacebookProvider("fb-app-id", "fb-secret", redirectURI).GetAuthURL("fb-state") if err != nil { t.Fatalf("GetAuthURL failed: %v", err) } return authURL.URL, redirectURI }, expectedHost: "www.facebook.com", expectedPath: "/v18.0/dialog/oauth", expectedKey: "client_id", expectedValue: "fb-app-id", expectedClause: "scope=email,public_profile", }, { name: "qq", buildURL: func(t *testing.T) (string, string) { t.Helper() redirectURI := "https://admin.example.com/login/oauth/callback?from=qq" authURL, err := NewQQProvider("qq-app-id", "qq-secret", redirectURI).GetAuthURL("qq-state") if err != nil { t.Fatalf("GetAuthURL failed: %v", err) } return authURL.URL, redirectURI }, expectedHost: "graph.qq.com", expectedPath: "/oauth2.0/authorize", expectedKey: "client_id", expectedValue: "qq-app-id", expectedClause: "scope=get_user_info", }, { name: "weibo", buildURL: func(t *testing.T) (string, string) { t.Helper() redirectURI := "https://admin.example.com/login/oauth/callback?from=weibo" authURL, err := NewWeiboProvider("wb-app-id", "wb-secret", redirectURI).GetAuthURL("wb-state") if err != nil { t.Fatalf("GetAuthURL failed: %v", err) } return authURL.URL, redirectURI }, expectedHost: "api.weibo.com", expectedPath: "/oauth2/authorize", expectedKey: "client_id", expectedValue: "wb-app-id", expectedClause: "response_type=code", }, { name: "douyin", buildURL: func(t *testing.T) (string, string) { t.Helper() redirectURI := "https://admin.example.com/login/oauth/callback?from=douyin" authURL, err := NewDouyinProvider("dy-client", "dy-secret", redirectURI).GetAuthURL("dy-state") if err != nil { t.Fatalf("GetAuthURL failed: %v", err) } return authURL, redirectURI }, expectedHost: "open.douyin.com", expectedPath: "/platform/oauth/connect", expectedKey: "client_key", expectedValue: "dy-client", expectedClause: "scope=user_info", }, { name: "alipay", buildURL: func(t *testing.T) (string, string) { t.Helper() redirectURI := "https://admin.example.com/login/oauth/callback?from=alipay" authURL, err := NewAlipayProvider("ali-app-id", "private-key", redirectURI, false).GetAuthURL("ali-state") if err != nil { t.Fatalf("GetAuthURL failed: %v", err) } return authURL, redirectURI }, expectedHost: "openauth.alipay.com", expectedPath: "/oauth2/publicAppAuthorize.htm", expectedKey: "app_id", expectedValue: "ali-app-id", expectedClause: "scope=auth_user", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { authURL, redirectURI := tc.buildURL(t) parsed, err := url.Parse(authURL) if err != nil { t.Fatalf("parse auth url failed: %v", err) } if parsed.Host != tc.expectedHost { t.Fatalf("expected host %q, got %q", tc.expectedHost, parsed.Host) } if parsed.Path != tc.expectedPath { t.Fatalf("expected path %q, got %q", tc.expectedPath, parsed.Path) } query := parsed.Query() if query.Get(tc.expectedKey) != tc.expectedValue { t.Fatalf("expected %s=%q, got %q", tc.expectedKey, tc.expectedValue, query.Get(tc.expectedKey)) } if query.Get("redirect_uri") != redirectURI { t.Fatalf("expected redirect_uri %q, got %q", redirectURI, query.Get("redirect_uri")) } if !strings.Contains(authURL, tc.expectedClause) { t.Fatalf("expected auth url to contain %q, got %q", tc.expectedClause, authURL) } }) } } func TestAlipayProviderUsesExpectedGatewayForSandboxAndProduction(t *testing.T) { productionProvider := NewAlipayProvider("prod-app-id", "private-key", "https://admin.example.com/callback", false) if gateway := productionProvider.getGateway(); gateway != "https://openapi.alipay.com/gateway.do" { t.Fatalf("expected production gateway, got %q", gateway) } sandboxProvider := NewAlipayProvider("sandbox-app-id", "private-key", "https://admin.example.com/callback", true) if gateway := sandboxProvider.getGateway(); gateway != "https://openapi-sandbox.dl.alipaydev.com/gateway.do" { t.Fatalf("expected sandbox gateway, got %q", gateway) } }