package billing import "testing" func TestIsLegacyPlanName(t *testing.T) { t.Parallel() cases := map[string]bool{ "Legacy": true, "legacy": true, "A1": true, "A1 Slovenija": true, "a1-deal": true, "A1 Deal": true, "My Legacy Co": false, // exact "legacy" only — substring must not match "Free": false, "Enterprise": false, "Merkur": false, "": false, } for in, want := range cases { if got := IsLegacyPlanName(in); got != want { t.Fatalf("IsLegacyPlanName(%q)=%v want %v", in, got, want) } } } func TestDefaultPlanFeaturesLegacyMatrix(t *testing.T) { t.Parallel() for _, name := range []string{"A1", "Legacy", "A1 Slovenija"} { m := DefaultPlanFeatures(name, false) if len(m) != len(FeatureCatalogKeys) { t.Fatalf("%s size=%d want %d", name, len(m), len(FeatureCatalogKeys)) } for _, k := range []string{ "dashboard.overview", "catalog.products", "feeds.list", "feeds.export_feeds", "catalog.categories", "catalog.attributes", "catalog.standard_fields", "billing.overview", "settings.profile", "capability.ai_processing", "catalog.products.process_ai_titles", "capability.storage_limit", "dashboard.migrated_checklist", "dashboard.etl_gaps", } { if !m[k] { t.Fatalf("%s should allow %s", name, k) } } for _, k := range []string{ "processing.monitor", "stores.hub", "marketing.campaigns", "integrations.ai", "support.center", "shell.support_notifications", "capability.byok", } { if m[k] { t.Fatalf("%s should deny %s", name, k) } } } // Explicit Legacy package (or is_legacy on non-custom) forces legacy matrix. flagged := DefaultPlanFeaturesEx("Legacy", false, true) if flagged["processing.monitor"] { t.Fatal("is_legacy flag must apply legacy matrix when not custom") } // is_custom wins over is_legacy for PAYG core, but Stores/Marketing/Integrations stay denied. customWins := DefaultPlanFeaturesEx("A1", true, true) if !customWins["processing.monitor"] { t.Fatal("is_custom must win over is_legacy for PAYG core features") } if customWins["stores.hub"] || customWins["marketing.campaigns"] || customWins["integrations.ai"] || customWins["integrations.email"] { t.Fatal("A1 PAYG must still deny Stores, Marketing, and Integrations") } if customWins["dashboard.etl_gaps"] || customWins["dashboard.store_reconnect"] || customWins["dashboard.migrated_checklist"] { t.Fatal("A1 PAYG must deny cutover honesty chrome (ETL gaps / reconnect / migrated checklist)") } } func TestResolvePlanProfile(t *testing.T) { t.Parallel() if ResolvePlanProfile("A1", false, false) != PlanProfileLegacy { t.Fatal("A1 without is_custom → legacy") } if ResolvePlanProfile("A1", true, false) != PlanProfileCustom { t.Fatal("A1 is_custom PAYG → custom") } if ResolvePlanProfile("A1", true, true) != PlanProfileCustom { t.Fatal("A1 is_custom wins over is_legacy flag") } if ResolvePlanProfile("Free", false, false) != PlanProfileFree { t.Fatal("Free → free") } if ResolvePlanProfile("Growth", false, false) != PlanProfileGrowth { t.Fatal("Growth → growth") } if ResolvePlanProfile("Enterprise", true, false) != PlanProfileEnterprise { t.Fatal("Enterprise → enterprise") } if ResolvePlanProfile("Merkur", false, false) != PlanProfileCustom { t.Fatal("Merkur → custom") } } func TestIsLegacyCompanyID(t *testing.T) { t.Parallel() if !IsLegacyCompanyID(A1LegacyCompanyID) { t.Fatal("A1 id should match") } if IsLegacyCompanyID("other") { t.Fatal("other id should not match") } } func TestIsA1CohortCompany(t *testing.T) { t.Parallel() if !IsA1CohortCompany(A1LegacyCompanyID, "Anything") { t.Fatal("legacy id must match") } // Mutable display names must never grant cohort privileges (register/rename). for _, name := range []string{"A1 Slovenija", "Local Demo Co", "A1", "a1", "Retail A1", "Baikal"} { if IsA1CohortCompany("", name) { t.Fatalf("name-only %q must not match", name) } } } func TestShouldWriteLegacySparse(t *testing.T) { t.Parallel() if !shouldWriteLegacySparse(nil) || !shouldWriteLegacySparse(map[string]bool{}) { t.Fatal("empty should write") } if !shouldWriteLegacySparse(AllRegistryFeatures(true)) { t.Fatal("enable-all should repair") } partial := map[string]bool{"catalog.products": false} if shouldWriteLegacySparse(partial) { t.Fatal("admin partial customization must not be wiped") } }