package pipeline import ( "reflect" "testing" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" ) func TestOutputEncoderRegistryBehavior(t *testing.T) { runRegistryBehaviorTests(t, registryBehaviorCase[contracts.OutputEncoder]{ name: "OutputEncoderRegistry", key: "generic-output", stage: StageOutput, wrongStage: StageExtract, newRegistry: func() any { return NewOutputEncoderRegistry() }, register: func(registry any, key string, constructor func() (contracts.OutputEncoder, error)) error { return registry.(*OutputEncoderRegistry).RegisterWithSpec(ModuleSpec{ Key: key, Stage: StageOutput, ExecutionClass: contracts.ExecutionClassDeterministic, }, constructor) }, registerWithSpec: func(registry any, spec ModuleSpec, constructor func() (contracts.OutputEncoder, error)) error { return registry.(*OutputEncoderRegistry).RegisterWithSpec(spec, constructor) }, build: func(registry any, key string) (contracts.OutputEncoder, error) { return registry.(*OutputEncoderRegistry).Build(key) }, spec: func(registry any, key string) (ModuleSpec, bool) { return registry.(*OutputEncoderRegistry).Spec(key) }, registeredKeys: func(registry any) []string { return registry.(*OutputEncoderRegistry).RegisteredKeys() }, nilRegister: func(key string, constructor func() (contracts.OutputEncoder, error)) error { var registry *OutputEncoderRegistry return registry.RegisterWithSpec(ModuleSpec{ Key: key, Stage: StageOutput, ExecutionClass: contracts.ExecutionClassDeterministic, }, constructor) }, nilBuild: func(key string) (contracts.OutputEncoder, error) { var registry *OutputEncoderRegistry return registry.Build(key) }, nilSpec: func(key string) (ModuleSpec, bool) { var registry *OutputEncoderRegistry return registry.Spec(key) }, nilRegisteredKey: func() []string { var registry *OutputEncoderRegistry return registry.RegisteredKeys() }, constructor: func(key string) func() (contracts.OutputEncoder, error) { return func() (contracts.OutputEncoder, error) { return registryOutputEncoder{key: key}, nil } }, moduleKey: func(module contracts.OutputEncoder) string { return module.Key() }, }) } func TestOutputProfileValidationReceivesOwnedOptionsAndLaneIDs(t *testing.T) { registry := NewOutputEncoderRegistry() if err := registry.RegisterBuilderWithProfileValidation(testModuleSpec("profile-output", StageOutput), func(options map[string]any) error { options["nested"].(map[string]any)["value"] = "changed" return nil }, func(context OutputProfileOptionContext, options map[string]any) error { context.LaneIDs[0] = "changed" options["nested"].(map[string]any)["value"] = "changed-again" return nil }, func(BuildRequest) (contracts.OutputEncoder, error) { return registryOutputEncoder{key: "profile-output"}, nil }); err != nil { t.Fatal(err) } options := map[string]any{"nested": map[string]any{"value": "original"}} if err := registry.ValidateOptions("profile-output", options); err != nil { t.Fatal(err) } context := OutputProfileOptionContext{LaneIDs: []string{"artifact"}} if err := registry.ValidateProfileOptions("profile-output", context, options); err != nil { t.Fatal(err) } if got := options["nested"].(map[string]any)["value"]; got != "original" { t.Fatalf("options mutated by validator: %q", got) } if want := []string{"artifact"}; !reflect.DeepEqual(context.LaneIDs, want) { t.Fatalf("lane ids mutated by validator: %#v, want %#v", context.LaneIDs, want) } }