diff --git a/backend/internal/handler/dto/public_settings_injection_schema_test.go b/backend/internal/handler/dto/public_settings_injection_schema_test.go deleted file mode 100644 index 24853c7d..00000000 --- a/backend/internal/handler/dto/public_settings_injection_schema_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package dto - -import ( - "reflect" - "strings" - "testing" - - "github.com/Wei-Shaw/sub2api/internal/service" -) - -// TestPublicSettingsInjectionPayload_SchemaDoesNotDrift guarantees the SSR -// injection struct exposes every JSON field consumed by the frontend. -// -// Why this test exists: before we extracted a named PublicSettingsInjectionPayload -// type, the inline struct was manually kept in sync with dto.PublicSettings and -// drifted — ChannelMonitorEnabled / AvailableChannelsEnabled were missing, which -// made the frontend read `undefined` on refresh and hide the "可用渠道" menu -// until the async /api/v1/settings/public round-trip finished. -// -// This test compares the two JSON-tag sets and fails if injection is missing -// any field that dto.PublicSettings exposes. Adding a new feature flag with -// only a DTO entry will fail this test until the injection struct is updated. -// -// Intentional exclusions (fields present on dto.PublicSettings that SSR does -// not need to inject) are listed in `dtoOnlyFields` below with a reason. -func TestPublicSettingsInjectionPayload_SchemaDoesNotDrift(t *testing.T) { - injection := jsonTags(reflect.TypeOf(service.PublicSettingsInjectionPayload{})) - dtoKeys := jsonTags(reflect.TypeOf(PublicSettings{})) - - // Fields that legitimately live only on the DTO. Keep tiny; document each. - dtoOnlyFields := map[string]string{ - // sora_client_enabled is an upstream-only field the fork does not surface. - "sora_client_enabled": "upstream-only field, not used on this fork", - } - - var missing []string - for key := range dtoKeys { - if _, ok := injection[key]; ok { - continue - } - if _, allowed := dtoOnlyFields[key]; allowed { - continue - } - missing = append(missing, key) - } - if len(missing) > 0 { - t.Fatalf("service.PublicSettingsInjectionPayload is missing JSON fields present on dto.PublicSettings: %s\n"+ - "add the field to PublicSettingsInjectionPayload (and GetPublicSettingsForInjection), or "+ - "document the exclusion in dtoOnlyFields with a reason.", strings.Join(missing, ", ")) - } -} - -func jsonTags(t reflect.Type) map[string]struct{} { - out := make(map[string]struct{}) - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - tag := f.Tag.Get("json") - if tag == "" || tag == "-" { - continue - } - name := strings.SplitN(tag, ",", 2)[0] - if name == "" { - continue - } - out[name] = struct{}{} - } - return out -}