package validate import ( "context" "os" "path/filepath" "testing" "gitea.maximumdirect.net/eric/scriptorium/internal/domain" ) func TestStandardValidatorNoneSkipped(t *testing.T) { v := NewStandardValidator("") res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte("ignored")}, domain.OutputContract{ ValidationMode: domain.ValidationNone, }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationSkipped { t.Fatalf("expected skipped, got %q", res.Status) } if !res.IsValid { t.Fatal("expected valid=true for skipped") } } func TestStandardValidatorBasicSuccess(t *testing.T) { v := NewStandardValidator("") res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte("hello")}, domain.OutputContract{ ValidationMode: domain.ValidationBasic, }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationPassed || !res.IsValid { t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid) } } func TestStandardValidatorBasicFailureEmpty(t *testing.T) { v := NewStandardValidator("") res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(" \n\t ")}, domain.OutputContract{ ValidationMode: domain.ValidationBasic, }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationFailed || res.IsValid { t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid) } if len(res.Errors) == 0 { t.Fatal("expected validation errors") } } func TestStandardValidatorJSONSuccess(t *testing.T) { v := NewStandardValidator("") res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"ok":true}`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSON, }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationPassed || !res.IsValid { t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid) } } func TestStandardValidatorJSONFailure(t *testing.T) { v := NewStandardValidator("") res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"ok":`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSON, }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationFailed || res.IsValid { t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid) } if len(res.Errors) == 0 { t.Fatal("expected parse errors") } } func TestStandardValidatorJSONSchemaSuccess(t *testing.T) { tmp := t.TempDir() schemaPath := filepath.Join(tmp, "schema.json") if err := os.WriteFile(schemaPath, []byte(`{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["name"], "properties": { "name": {"type": "string"} } }`), 0644); err != nil { t.Fatal(err) } v := NewStandardValidator(tmp) res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"name":"eris"}`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSONSchema, SchemaPath: "schema.json", }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationPassed || !res.IsValid { t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid) } } func TestStandardValidatorJSONSchemaNestedSchemaPathSuccess(t *testing.T) { tmp := t.TempDir() nestedDir := filepath.Join(tmp, "dnd") if err := os.MkdirAll(nestedDir, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(nestedDir, "schema.json"), []byte(`{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["name"], "properties": { "name": {"type": "string"} } }`), 0644); err != nil { t.Fatal(err) } v := NewStandardValidator(tmp) res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"name":"eris"}`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSONSchema, SchemaPath: filepath.Join("dnd", "schema.json"), }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationPassed || !res.IsValid { t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid) } } func TestStandardValidatorJSONSchemaNestedSchemaPathMissing(t *testing.T) { v := NewStandardValidator(t.TempDir()) _, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"name":"eris"}`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSONSchema, SchemaPath: filepath.Join("dnd", "missing.json"), }) if err == nil { t.Fatal("expected nested schema load error") } } func TestStandardValidatorJSONSchemaFailure(t *testing.T) { tmp := t.TempDir() schemaPath := filepath.Join(tmp, "schema.json") if err := os.WriteFile(schemaPath, []byte(`{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["name"], "properties": { "name": {"type": "string"} } }`), 0644); err != nil { t.Fatal(err) } v := NewStandardValidator(tmp) res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"count":1}`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSONSchema, SchemaPath: "schema.json", }) if err != nil { t.Fatalf("expected no error, got %v", err) } if res.Status != domain.ValidationFailed || res.IsValid { t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid) } if len(res.Errors) == 0 { t.Fatal("expected schema errors") } } func TestStandardValidatorJSONSchemaSchemaLoadError(t *testing.T) { v := NewStandardValidator(t.TempDir()) _, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(`{"name":"eris"}`)}, domain.OutputContract{ ValidationMode: domain.ValidationJSONSchema, SchemaPath: "missing.json", }) if err == nil { t.Fatal("expected schema load error") } } func TestStandardValidatorLoadSchemaDocumentSuccess(t *testing.T) { tmp := t.TempDir() if err := os.WriteFile(filepath.Join(tmp, "schema.json"), []byte(`{ "type": "object", "properties": { "name": {"type": "string"} } }`), 0644); err != nil { t.Fatal(err) } v := NewStandardValidator(tmp) loader, ok := v.(SchemaDocumentLoader) if !ok { t.Fatal("standard validator must implement SchemaDocumentLoader") } doc, err := loader.LoadSchemaDocument(context.Background(), "schema.json") if err != nil { t.Fatalf("expected no error, got %v", err) } obj, ok := doc.(map[string]any) if !ok { t.Fatalf("expected object document, got %#v", doc) } if obj["type"] != "object" { t.Fatalf("expected schema type=object, got %#v", obj["type"]) } } func TestStandardValidatorLoadSchemaDocumentInvalidJSON(t *testing.T) { tmp := t.TempDir() if err := os.WriteFile(filepath.Join(tmp, "schema.json"), []byte(`{`), 0644); err != nil { t.Fatal(err) } v := NewStandardValidator(tmp) loader, ok := v.(SchemaDocumentLoader) if !ok { t.Fatal("standard validator must implement SchemaDocumentLoader") } _, err := loader.LoadSchemaDocument(context.Background(), "schema.json") if err == nil { t.Fatal("expected decode error") } }