package serviceadapter import ( "testing" ) func TestValidateString(t *testing.T) { schema := &FieldSchema{Type: "string"} v := &Validator{schema: schema} errs := v.Validate("hello") if len(errs) != 0 { t.Errorf("expected no errors for valid string, got %v", errs) } errs = v.Validate(42) if len(errs) == 0 { t.Errorf("expected error for non-string") } if len(errs) > 0 && !stringContains(errs[0].Reason, "type_mismatch") { t.Errorf("expected type_mismatch error, got %s", errs[0].Reason) } } func TestValidateNumber(t *testing.T) { schema := &FieldSchema{Type: "number"} v := &Validator{schema: schema} errs := v.Validate(42.0) if len(errs) != 0 { t.Errorf("expected no errors for float64, got %v", errs) } errs = v.Validate("not a number") if len(errs) == 0 { t.Errorf("expected error for non-number") } } func TestValidateNullable(t *testing.T) { schemaNullable := &FieldSchema{Type: "string", Nullable: true} vNullable := &Validator{schema: schemaNullable} errs := vNullable.Validate(nil) if len(errs) != 0 { t.Errorf("expected no errors for null on nullable field, got %v", errs) } schemaNotNullable := &FieldSchema{Type: "string", Nullable: false} vNotNullable := &Validator{schema: schemaNotNullable} errs = vNotNullable.Validate(nil) if len(errs) == 0 { t.Errorf("expected error for null on non-nullable field") } } func TestValidateObject(t *testing.T) { schema := &FieldSchema{ Type: "object", Required: []string{"name"}, Fields: map[string]FieldSchema{ "name": {Type: "string"}, "age": {Type: "number"}, }, } v := &Validator{schema: schema} // Valid object obj := map[string]interface{}{ "name": "Alice", "age": 30.0, } errs := v.Validate(obj) if len(errs) != 0 { t.Errorf("expected no errors for valid object, got %v", errs) } // Missing required field objMissing := map[string]interface{}{ "age": 30.0, } errs = v.Validate(objMissing) if len(errs) == 0 { t.Errorf("expected error for missing required field") } if len(errs) > 0 && errs[0].Reason != "missing" { t.Errorf("expected 'missing' error, got %s", errs[0].Reason) } // Type mismatch objBadType := map[string]interface{}{ "name": "Alice", "age": "thirty", } errs = v.Validate(objBadType) if len(errs) == 0 { t.Errorf("expected error for type mismatch") } } func TestValidateObjectStrict(t *testing.T) { schema := &FieldSchema{ Type: "object", Strict: true, Fields: map[string]FieldSchema{ "name": {Type: "string"}, }, } v := &Validator{schema: schema} // Unknown field rejected in strict mode obj := map[string]interface{}{ "name": "Alice", "unknown": "field", } errs := v.Validate(obj) if len(errs) == 0 { t.Errorf("expected error for unknown field in strict mode") } found := false for _, err := range errs { if err.Reason == "unknown_field" { found = true break } } if !found { t.Errorf("expected unknown_field error") } } func TestValidateArray(t *testing.T) { schema := &FieldSchema{ Type: "array", Items: &FieldSchema{ Type: "string", }, } v := &Validator{schema: schema} // Valid array arr := []interface{}{"a", "b", "c"} errs := v.Validate(arr) if len(errs) != 0 { t.Errorf("expected no errors for valid string array, got %v", errs) } // Invalid element type arrBad := []interface{}{"a", 42, "c"} errs = v.Validate(arrBad) if len(errs) == 0 { t.Errorf("expected error for wrong type in array") } } func TestValidateArrayOfObjects(t *testing.T) { schema := &FieldSchema{ Type: "array", Items: &FieldSchema{ Type: "object", Fields: map[string]FieldSchema{ "id": {Type: "number"}, "name": {Type: "string"}, }, }, } v := &Validator{schema: schema} arr := []interface{}{ map[string]interface{}{"id": 1.0, "name": "Alice"}, map[string]interface{}{"id": 2.0, "name": "Bob"}, } errs := v.Validate(arr) if len(errs) != 0 { t.Errorf("expected no errors for valid array of objects, got %v", errs) } } func TestValidateNoSchema(t *testing.T) { // No schema means no validation v := &Validator{schema: nil} errs := v.Validate(map[string]interface{}{"anything": "goes"}) if len(errs) != 0 { t.Errorf("expected no errors when schema is nil") } } func TestParseSchema(t *testing.T) { schema, err := parseSchema("name: string, age: number") if err != nil { t.Fatalf("parse error: %v", err) } if schema.Type != "object" { t.Errorf("expected type object, got %s", schema.Type) } if len(schema.Fields) != 2 { t.Errorf("expected 2 fields, got %d", len(schema.Fields)) } if f, ok := schema.Fields["name"]; !ok || f.Type != "string" { t.Errorf("expected name: string in parsed schema") } } func stringContains(s, substr string) bool { for i := 0; i < len(s); i++ { if i+len(substr) <= len(s) && s[i:i+len(substr)] == substr { return true } } return false }