package configs import ( "strings" "testing" ) // ─── normalizeOrigin ───────────────────────────────────────────────────────── func TestNormalizeOrigin_ValidHTTP(t *testing.T) { if got := normalizeOrigin("http://localhost:3000"); got != "http://localhost:3000" { t.Fatalf("got %q", got) } } func TestNormalizeOrigin_ValidHTTPS(t *testing.T) { if got := normalizeOrigin("https://example.com"); got != "https://example.com" { t.Fatalf("got %q", got) } } func TestNormalizeOrigin_StripsTrailingSlash(t *testing.T) { got := normalizeOrigin("https://example.com/") // url.Parse keeps the trailing slash on host-only URLs, so we just check host is preserved if !strings.HasPrefix(got, "https://example.com") { t.Fatalf("unexpected result: %q", got) } } func TestNormalizeOrigin_UppercaseNormalized(t *testing.T) { got := normalizeOrigin("HTTP://EXAMPLE.COM") if got != "http://example.com" { t.Fatalf("expected lowercase, got %q", got) } } func TestNormalizeOrigin_Empty(t *testing.T) { if got := normalizeOrigin(""); got != "" { t.Fatalf("expected empty, got %q", got) } } func TestNormalizeOrigin_Whitespace(t *testing.T) { if got := normalizeOrigin(" "); got != "" { t.Fatalf("expected empty for whitespace, got %q", got) } } func TestNormalizeOrigin_NoScheme(t *testing.T) { if got := normalizeOrigin("example.com"); got != "" { t.Fatalf("expected empty for missing scheme, got %q", got) } } func TestNormalizeOrigin_QuotedValue(t *testing.T) { if got := normalizeOrigin(`'http://localhost:8080'`); got != "http://localhost:8080" { t.Fatalf("got %q", got) } } // ─── parseOriginList ───────────────────────────────────────────────────────── func TestParseOriginList_MultipleEntries(t *testing.T) { list := parseOriginList("http://localhost:3000,https://example.com") if len(list) != 2 { t.Fatalf("expected 2 entries, got %d", len(list)) } } func TestParseOriginList_EmptyString(t *testing.T) { list := parseOriginList("") if len(list) != 0 { t.Fatalf("expected 0 entries, got %d: %v", len(list), list) } } func TestParseOriginList_InvalidEntriesSkipped(t *testing.T) { list := parseOriginList("http://good.com,not-a-url,http://also-good.com") if len(list) != 2 { t.Fatalf("expected 2 valid entries, got %d: %v", len(list), list) } } func TestParseOriginList_DuplicatesPassThrough(t *testing.T) { // parseOriginList itself does NOT deduplicate; bootstrapWhitelistOrigins does. list := parseOriginList("http://dup.com,http://dup.com") if len(list) != 2 { t.Fatalf("parseOriginList should keep duplicates, got %d", len(list)) } } // ─── envIntOr ──────────────────────────────────────────────────────────────── func TestEnvIntOr_MissingUsesDefault(t *testing.T) { t.Setenv("__TEST_INT_MISSING__", "") if got := envIntOr("__TEST_INT_MISSING__", 42); got != 42 { t.Fatalf("expected 42, got %d", got) } } func TestEnvIntOr_ValidValue(t *testing.T) { t.Setenv("__TEST_INT__", "99") if got := envIntOr("__TEST_INT__", 1); got != 99 { t.Fatalf("expected 99, got %d", got) } } func TestEnvIntOr_InvalidStringUsesDefault(t *testing.T) { t.Setenv("__TEST_INT_BAD__", "abc") if got := envIntOr("__TEST_INT_BAD__", 7); got != 7 { t.Fatalf("expected fallback 7, got %d", got) } } func TestEnvIntOr_ZeroUsesDefault(t *testing.T) { t.Setenv("__TEST_INT_ZERO__", "0") if got := envIntOr("__TEST_INT_ZERO__", 5); got != 5 { t.Fatalf("expected fallback for 0, got %d", got) } } func TestEnvIntOr_NegativeUsesDefault(t *testing.T) { t.Setenv("__TEST_INT_NEG__", "-1") if got := envIntOr("__TEST_INT_NEG__", 3); got != 3 { t.Fatalf("expected fallback for negative, got %d", got) } } // ─── envInt64Or ────────────────────────────────────────────────────────────── func TestEnvInt64Or_MissingUsesDefault(t *testing.T) { t.Setenv("__TEST_I64_MISSING__", "") if got := envInt64Or("__TEST_I64_MISSING__", 100); got != 100 { t.Fatalf("expected 100, got %d", got) } } func TestEnvInt64Or_ValidValue(t *testing.T) { t.Setenv("__TEST_I64__", "999") if got := envInt64Or("__TEST_I64__", 1); got != 999 { t.Fatalf("expected 999, got %d", got) } } func TestEnvInt64Or_InvalidUsesDefault(t *testing.T) { t.Setenv("__TEST_I64_BAD__", "not-a-number") if got := envInt64Or("__TEST_I64_BAD__", 50); got != 50 { t.Fatalf("expected fallback 50, got %d", got) } } // ─── bootstrapRateLimitRules ───────────────────────────────────────────────── func TestBootstrapRateLimitRules_ContainsThreeRules(t *testing.T) { rules := bootstrapRateLimitRules() if len(rules) != 3 { t.Fatalf("expected 3 rules, got %d", len(rules)) } } func TestBootstrapRateLimitRules_DefaultFallbacks(t *testing.T) { // Env vars temizlenerek varsayılan değerler test edilir. t.Setenv("RL_BOOTSTRAP_LOGIN_MAX_REQUESTS", "") t.Setenv("RL_BOOTSTRAP_LOGIN_WINDOW_SECONDS", "") rules := bootstrapRateLimitRules() loginRule := rules[0] if loginRule.MaxRequests != 10 { t.Fatalf("expected default MaxRequests=10, got %d", loginRule.MaxRequests) } if loginRule.WindowSeconds != 60 { t.Fatalf("expected default WindowSeconds=60, got %d", loginRule.WindowSeconds) } } func TestBootstrapRateLimitRules_EnvOverride(t *testing.T) { t.Setenv("RL_BOOTSTRAP_LOGIN_MAX_REQUESTS", "25") t.Setenv("RL_BOOTSTRAP_LOGIN_WINDOW_SECONDS", "120") rules := bootstrapRateLimitRules() loginRule := rules[0] if loginRule.MaxRequests != 25 { t.Fatalf("expected MaxRequests=25, got %d", loginRule.MaxRequests) } if loginRule.WindowSeconds != 120 { t.Fatalf("expected WindowSeconds=120, got %d", loginRule.WindowSeconds) } } func TestBootstrapRateLimitRules_AllNamesNonEmpty(t *testing.T) { for _, r := range bootstrapRateLimitRules() { if r.Name == "" { t.Errorf("rate limit rule has empty Name: %+v", r) } if r.Description == "" { t.Errorf("rate limit rule has empty Description: %+v", r) } } } // ─── bootstrapWhitelistOrigins ─────────────────────────────────────────────── func TestBootstrapWhitelistOrigins_ContainsLocalDefaults(t *testing.T) { t.Setenv("CORS_BOOTSTRAP_WHITELIST_ORIGINS", "") t.Setenv("APP_BASE_URL", "") origins := bootstrapWhitelistOrigins() required := []string{ "http://localhost:8080", "http://localhost:3000", "http://localhost:5173", } originSet := make(map[string]struct{}, len(origins)) for _, o := range origins { originSet[o] = struct{}{} } for _, want := range required { if _, ok := originSet[want]; !ok { t.Errorf("expected default origin %q to be present", want) } } } func TestBootstrapWhitelistOrigins_NoDuplicates(t *testing.T) { t.Setenv("CORS_BOOTSTRAP_WHITELIST_ORIGINS", "http://localhost:3000,http://localhost:3000") origins := bootstrapWhitelistOrigins() seen := map[string]int{} for _, o := range origins { seen[o]++ } for origin, count := range seen { if count > 1 { t.Errorf("duplicate origin in whitelist: %q (x%d)", origin, count) } } } func TestBootstrapWhitelistOrigins_AppBaseURLIncluded(t *testing.T) { t.Setenv("APP_BASE_URL", "https://myapp.example.com") defer t.Setenv("APP_BASE_URL", "") origins := bootstrapWhitelistOrigins() for _, o := range origins { if o == "https://myapp.example.com" { return } } t.Fatal("APP_BASE_URL origin not found in whitelist") }