readysite / website / internal / content / validate_test.go
7.3 KB
validate_test.go
package content_test

import (
	"testing"

	"github.com/readysite/readysite/website/internal/content"
	"github.com/readysite/readysite/website/models"
)

func TestValidateDocumentNoSchema(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: "", // No schema
	}

	// Should accept any data when no schema
	data := map[string]any{
		"foo":    "bar",
		"number": 42,
	}

	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("expected no error for schemaless collection, got %v", err)
	}
}

func TestValidateDocumentRequiredField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"title","type":"text","required":true}]`,
	}

	// Missing required field
	data := map[string]any{}
	err := content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for missing required field")
	}

	// With required field
	data = map[string]any{"title": "Hello"}
	err = content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Empty string for required field
	data = map[string]any{"title": ""}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for empty required field")
	}
}

func TestValidateDocumentTextField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"title","type":"text","options":{"maxLength":10}}]`,
	}

	// Valid text
	data := map[string]any{"title": "Hello"}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Text too long
	data = map[string]any{"title": "This is way too long"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for text exceeding maxLength")
	}

	// Wrong type
	data = map[string]any{"title": 123}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for wrong type")
	}
}

func TestValidateDocumentNumberField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"count","type":"number","options":{"min":0,"max":100}}]`,
	}

	// Valid number
	data := map[string]any{"count": 50.0}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Below minimum
	data = map[string]any{"count": -5.0}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for number below min")
	}

	// Above maximum
	data = map[string]any{"count": 150.0}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for number above max")
	}

	// Wrong type
	data = map[string]any{"count": "fifty"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for wrong type")
	}
}

func TestValidateDocumentBoolField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"active","type":"bool"}]`,
	}

	// Valid bool
	data := map[string]any{"active": true}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	data = map[string]any{"active": false}
	err = content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Wrong type
	data = map[string]any{"active": "true"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for wrong type")
	}
}

func TestValidateDocumentDateField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"created","type":"date"}]`,
	}

	// RFC3339 format
	data := map[string]any{"created": "2024-01-15T10:30:00Z"}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error for RFC3339: %v", err)
	}

	// Date only format
	data = map[string]any{"created": "2024-01-15"}
	err = content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error for date-only: %v", err)
	}

	// Invalid date
	data = map[string]any{"created": "not-a-date"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for invalid date")
	}
}

func TestValidateDocumentEmailField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"email","type":"email"}]`,
	}

	// Valid email
	data := map[string]any{"email": "test@example.com"}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Invalid email
	data = map[string]any{"email": "not-an-email"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for invalid email")
	}
}

func TestValidateDocumentURLField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"website","type":"url"}]`,
	}

	// Valid URL
	data := map[string]any{"website": "https://example.com"}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// URL without scheme
	data = map[string]any{"website": "example.com"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for URL without scheme")
	}
}

func TestValidateDocumentSelectField(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"status","type":"select","options":{"values":["draft","published","archived"]}}]`,
	}

	// Valid option
	data := map[string]any{"status": "draft"}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Invalid option
	data = map[string]any{"status": "invalid"}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for invalid select option")
	}
}

func TestValidateDocumentMultipleSelect(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"tags","type":"select","options":{"values":["tech","news","sports"],"multiple":true}}]`,
	}

	// Valid multiple selection
	data := map[string]any{"tags": []any{"tech", "news"}}
	err := content.ValidateDocument(col, data)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Invalid option in array
	data = map[string]any{"tags": []any{"tech", "invalid"}}
	err = content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected error for invalid option in array")
	}
}

func TestValidateDocumentMultipleErrors(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"title","type":"text","required":true},{"name":"count","type":"number","required":true}]`,
	}

	// Both fields missing
	data := map[string]any{}
	err := content.ValidateDocument(col, data)
	if err == nil {
		t.Error("expected validation errors")
	}

	// Check it's a ValidationErrors
	if errors, ok := err.(content.ValidationErrors); ok {
		if len(errors) != 2 {
			t.Errorf("expected 2 errors, got %d", len(errors))
		}
	} else {
		t.Errorf("expected ValidationErrors, got %T", err)
	}
}

func TestValidateDocumentJSON(t *testing.T) {
	col := &models.Collection{
		Name:   "Test",
		Schema: `[{"name":"title","type":"text","required":true}]`,
	}

	// Valid JSON
	err := content.ValidateDocumentJSON(col, `{"title":"Hello"}`)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// Invalid JSON
	err = content.ValidateDocumentJSON(col, `{invalid json}`)
	if err == nil {
		t.Error("expected error for invalid JSON")
	}

	// Empty JSON string
	err = content.ValidateDocumentJSON(col, "")
	if err == nil {
		t.Error("expected error for empty JSON with required field")
	}
}
← Back