package engine import ( "reflect" "testing" ) func TestResolveCollectionPolicyReconcilesDeclarationsBeforeComposition(t *testing.T) { declarations := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] key: [namespace, id] mode: append - destination: [prompts] key: [id, namespace, id] - destination: [prompts] mode: append `, rootDirectiveContextSource).sequences resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, nil, nil) if len(diagnostics) != 0 { t.Fatalf("policy diagnostics = %#v", diagnostics) } if !resolved.modeDeclarationPresent { t.Fatalf("mode declaration was lost: %#v", resolved) } wantFields := []string{"id", "namespace"} if !reflect.DeepEqual(resolved.policy.identityFields, wantFields) || !reflect.DeepEqual(resolved.effectiveIdentityFields, wantFields) { t.Fatalf("effective identity = %#v / %#v, want %#v", resolved.policy.identityFields, resolved.effectiveIdentityFields, wantFields) } if !resolved.policy.identityPresent || !resolved.policy.explicitModePresent || resolved.policy.explicitMode != sequenceModeAppend || resolved.operation != sequenceModeAppend { t.Fatalf("resolved explicit policy = %#v, operation %d", resolved.policy, resolved.operation) } } func TestResolveCollectionPolicyRejectsConflictingPeersAtBothSites(t *testing.T) { tests := []struct { name string body string }{ { name: "identity fields", body: `configkit: sequences: - destination: [prompts] key: id - destination: [prompts] key: name `, }, { name: "explicit modes", body: `configkit: sequences: - destination: [prompts] mode: append - destination: [prompts] mode: replace `, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { declarations := extractSequenceDeclarationsYAML(t, test.body, rootDirectiveContextSource).sequences resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, nil, nil) if !reflect.DeepEqual(resolved, collectionPolicyResolution{}) || len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict { t.Fatalf("resolution/diagnostics = %#v / %#v", resolved, diagnostics) } diagnostic := diagnostics[0] if diagnostic.Path.String() != "/prompts" || diagnostic.Primary == nil || len(diagnostic.Related) != 1 { t.Fatalf("conflict does not identify both declaration sites: %#v", diagnostic) } if diagnostic.Primary.SourceID != "sequence-declarations" || diagnostic.Related[0].SourceID != "sequence-declarations" || diagnostic.Primary.Line == diagnostic.Related[0].Line { t.Fatalf("conflict locations = %#v and %#v", diagnostic.Primary, diagnostic.Related) } }) } } func TestResolveCollectionPolicySelectsCurrentThenRetainedExplicitMode(t *testing.T) { lower := &collectionPolicy{ identityFields: []string{"id"}, identityPresent: true, explicitMode: sequenceModeAppend, explicitModePresent: true, modeLocation: &Location{SourceID: "lower", Line: 2}, } current := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] mode: upsert `, rootDirectiveContextSource).sequences resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), current, nil, lower) if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || resolved.policy.explicitMode != sequenceModeUpsert || !resolved.policy.explicitModePresent { t.Fatalf("current mode did not override retained mode: %#v, %#v", resolved, diagnostics) } resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), nil, nil, lower) if len(diagnostics) != 0 || resolved.operation != sequenceModeAppend || resolved.policy.explicitMode != sequenceModeAppend || !resolved.policy.explicitModePresent { t.Fatalf("omitted current mode did not retain lower explicit mode: %#v, %#v", resolved, diagnostics) } if !reflect.DeepEqual(resolved.effectiveIdentityFields, []string{"id"}) { t.Fatalf("retained identity = %#v", resolved.effectiveIdentityFields) } } func TestResolveCollectionPolicyInfersWithoutPersistingMode(t *testing.T) { keyOnly := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] key: id `, rootDirectiveContextSource).sequences resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), keyOnly, nil, nil) if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || resolved.policy.explicitModePresent { t.Fatalf("identity-based mode inference = %#v, %#v", resolved, diagnostics) } resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), nil, []string{"id"}, nil) if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || resolved.policy.identityPresent || !resolved.applicationIdentityPresent { t.Fatalf("application identity was not kept distinct from YAML policy: %#v, %#v", resolved, diagnostics) } noIdentity := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] `, rootDirectiveContextSource).sequences resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), noIdentity, nil, nil) if len(diagnostics) != 0 || resolved.operation != sequenceModeReplace || resolved.policy.explicitModePresent { t.Fatalf("unkeyed mode inference = %#v, %#v", resolved, diagnostics) } explicitDefault := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] mode: replace `, rootDirectiveContextSource).sequences resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), explicitDefault, nil, nil) if len(diagnostics) != 0 || resolved.operation != sequenceModeReplace || !resolved.policy.explicitModePresent { t.Fatalf("explicit default mode lost its presence: %#v, %#v", resolved, diagnostics) } } func TestResolveCollectionPolicyChecksKeyOnlyAgainstApplicationConstraint(t *testing.T) { declarations := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] key: [namespace, id] `, rootDirectiveContextSource).sequences resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, []string{"id", "namespace", "id"}, nil) if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || !reflect.DeepEqual(resolved.effectiveIdentityFields, []string{"id", "namespace"}) { t.Fatalf("equivalent key-only declaration was rejected: %#v, %#v", resolved, diagnostics) } resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), declarations, []string{"slug"}, nil) if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict { t.Fatalf("conflicting key-only declaration = %#v, %#v", resolved, diagnostics) } if diagnostics[0].Primary == nil || diagnostics[0].Path.String() != "/prompts" || len(diagnostics[0].Related) != 0 { t.Fatalf("application conflict diagnostic = %#v", diagnostics[0]) } } func TestResolveCollectionPolicyChecksRetainedIdentityAgainstApplicationConstraint(t *testing.T) { lower := &collectionPolicy{identityFields: []string{"id"}, identityPresent: true} resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), nil, []string{"name"}, lower) if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict || diagnostics[0].Path.String() != "/prompts" { t.Fatalf("retained/application conflict = %#v, %#v", resolved, diagnostics) } } func TestResolveCollectionPolicyRequiresCurrentIdentityToAgreeWithRetainedIdentity(t *testing.T) { declarations := extractSequenceDeclarationsYAML(t, `configkit: sequences: - destination: [prompts] key: name `, rootDirectiveContextSource).sequences lower := &collectionPolicy{ identityFields: []string{"id"}, identityPresent: true, identityLocation: &Location{SourceID: "lower", Line: 4}, } resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, nil, lower) if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict || diagnostics[0].Path.String() != "/prompts" { t.Fatalf("current/retained identity conflict = %#v, %#v", resolved, diagnostics) } if diagnostics[0].Primary == nil || len(diagnostics[0].Related) != 1 || diagnostics[0].Related[0].SourceID != "lower" { t.Fatalf("current/retained conflict locations = %#v", diagnostics[0]) } }