Files
homelab-frontend/internal/serviceadapter/validate_test.go
T

217 lines
4.8 KiB
Go
Raw Normal View History

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
}