package registry import ( "strings" "testing" ) func boolPtr(b bool) *bool { return &b } func knownFns(ids ...string) map[string]bool { m := make(map[string]bool) for _, id := range ids { m[id] = true } return m } func knownTps(ids ...string) map[string]bool { return knownFns(ids...) } func TestValidateFunction_Valid(t *testing.T) { f := &Function{ ID: "filter_slice_go_core", Name: "filter_slice", Kind: KindFunction, Lang: "go", Domain: "core", Purity: PurityPure, Description: "Filtra un slice", Version: "1.0.0", } if err := ValidateFunction(f, knownFns(), knownTps()); err != nil { t.Errorf("expected valid, got: %v", err) } } func TestValidateFunction_PipelineMustBeImpure(t *testing.T) { f := &Function{ ID: "p_go_core", Name: "p", Kind: KindPipeline, Lang: "go", Domain: "core", Purity: PurityPure, Description: "bad pipeline", Version: "1.0.0", UsesFunctions: []string{"filter_slice_go_core"}, } err := ValidateFunction(f, knownFns("filter_slice_go_core"), knownTps()) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "pipeline must be impure") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_PipelineNeedsUsesFunctions(t *testing.T) { f := &Function{ ID: "p_go_core", Name: "p", Kind: KindPipeline, Lang: "go", Domain: "core", Purity: PurityImpure, Description: "bad pipeline", Version: "1.0.0", ErrorType: "error_go_core", } err := ValidateFunction(f, knownFns(), knownTps("error_go_core")) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "uses_functions cannot be empty") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_PureNoReturnsOptional(t *testing.T) { f := &Function{ ID: "f_go_core", Name: "f", Kind: KindFunction, Lang: "go", Domain: "core", Purity: PurityPure, Description: "bad", Version: "1.0.0", ReturnsOptional: true, } err := ValidateFunction(f, knownFns(), knownTps()) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "returns_optional") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_PureNoErrorType(t *testing.T) { f := &Function{ ID: "f_go_core", Name: "f", Kind: KindFunction, Lang: "go", Domain: "core", Purity: PurityPure, Description: "bad", Version: "1.0.0", ErrorType: "error_go_core", } err := ValidateFunction(f, knownFns(), knownTps("error_go_core")) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "pure function cannot have error_type") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_ImpureNeedsErrorType(t *testing.T) { f := &Function{ ID: "f_go_io", Name: "f", Kind: KindFunction, Lang: "go", Domain: "io", Purity: PurityImpure, Description: "bad", Version: "1.0.0", } err := ValidateFunction(f, knownFns(), knownTps()) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "impure function must declare error_type") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_TestedNeedsTestFile(t *testing.T) { f := &Function{ ID: "f_go_core", Name: "f", Kind: KindFunction, Lang: "go", Domain: "core", Purity: PurityPure, Description: "test", Version: "1.0.0", Tested: true, } err := ValidateFunction(f, knownFns(), knownTps()) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "test_file_path") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_NotTestedNoTests(t *testing.T) { f := &Function{ ID: "f_go_core", Name: "f", Kind: KindFunction, Lang: "go", Domain: "core", Purity: PurityPure, Description: "test", Version: "1.0.0", Tested: false, Tests: []string{"ghost test"}, TestFilePath: "test.go", } err := ValidateFunction(f, knownFns(), knownTps()) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "tested: false but tests is not empty") { t.Errorf("unexpected error: %v", err) } } func TestValidateFunction_OrphanRefs(t *testing.T) { f := &Function{ ID: "p_go_core", Name: "p", Kind: KindPipeline, Lang: "go", Domain: "core", Purity: PurityImpure, Description: "pipeline", Version: "1.0.0", UsesFunctions: []string{"nonexistent_go_core"}, UsesTypes: []string{"ghost_go_core"}, Returns: []string{"phantom_go_core"}, ErrorType: "missing_go_core", } err := ValidateFunction(f, knownFns(), knownTps()) if err == nil { t.Fatal("expected error") } if len(err.Errors) < 4 { t.Errorf("expected at least 4 errors, got %d: %v", len(err.Errors), err) } } func TestValidateFunction_ComponentRules(t *testing.T) { f := &Function{ ID: "dt_typescript_core", Name: "DataTable", Kind: KindComponent, Lang: "typescript", Domain: "core", Purity: PurityImpure, Description: "table", Version: "1.0.0", HasState: boolPtr(true), Framework: "react", } if err := ValidateFunction(f, knownFns(), knownTps()); err != nil { t.Errorf("expected valid, got: %v", err) } // Missing framework f2 := *f f2.Framework = "" if err := ValidateFunction(&f2, knownFns(), knownTps()); err == nil { t.Error("expected error for missing framework") } // Returns should be empty f3 := *f f3.Returns = []string{"some_go_core"} if err := ValidateFunction(&f3, knownFns(), knownTps("some_go_core")); err == nil { t.Error("expected error for non-empty returns on component") } // has_state: true but pure f4 := *f f4.Purity = PurityPure if err := ValidateFunction(&f4, knownFns(), knownTps()); err == nil { t.Error("expected error for stateful pure component") } } func TestValidateFunction_AbsoluteFilePath(t *testing.T) { f := &Function{ ID: "f_go_core", Name: "f", Kind: KindFunction, Lang: "go", Domain: "core", Purity: PurityPure, Description: "test", Version: "1.0.0", FilePath: "/absolute/path.go", } err := ValidateFunction(f, knownFns(), knownTps()) if err == nil { t.Fatal("expected error for absolute file_path") } } func TestValidateType_Valid(t *testing.T) { typ := &Type{ ID: "ohlcv_go_finance", Name: "ohlcv", Lang: "go", Domain: "finance", Algebraic: AlgebraicProduct, Description: "candle", Version: "1.0.0", } if err := ValidateType(typ, knownTps("ohlcv_go_finance")); err != nil { t.Errorf("expected valid, got: %v", err) } } func TestValidateType_BadAlgebraic(t *testing.T) { typ := &Type{ ID: "t_go_core", Name: "t", Lang: "go", Domain: "core", Algebraic: "wrong", Description: "bad", Version: "1.0.0", } err := ValidateType(typ, knownTps("t_go_core")) if err == nil { t.Fatal("expected error") } } func TestValidateType_SelfReference(t *testing.T) { typ := &Type{ ID: "t_go_core", Name: "t", Lang: "go", Domain: "core", Algebraic: AlgebraicProduct, Description: "self ref", Version: "1.0.0", UsesTypes: []string{"t_go_core"}, } err := ValidateType(typ, knownTps("t_go_core")) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "cannot reference itself") { t.Errorf("unexpected error: %v", err) } } func TestValidateType_OrphanRef(t *testing.T) { typ := &Type{ ID: "t_go_core", Name: "t", Lang: "go", Domain: "core", Algebraic: AlgebraicProduct, Description: "orphan ref", Version: "1.0.0", UsesTypes: []string{"nonexistent_go_core"}, } err := ValidateType(typ, knownTps("t_go_core")) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), "unknown type") { t.Errorf("unexpected error: %v", err) } }