1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-01-10 00:43:36 +02:00
pocketbase/models/schema/schema_field_test.go
2023-08-29 18:41:20 +03:00

2253 lines
52 KiB
Go

package schema_test
import (
"encoding/json"
"fmt"
"testing"
"time"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tools/types"
)
func TestBaseModelFieldNames(t *testing.T) {
result := schema.BaseModelFieldNames()
expected := 3
if len(result) != expected {
t.Fatalf("Expected %d field names, got %d (%v)", expected, len(result), result)
}
}
func TestSystemFieldNames(t *testing.T) {
result := schema.SystemFieldNames()
expected := 3
if len(result) != expected {
t.Fatalf("Expected %d field names, got %d (%v)", expected, len(result), result)
}
}
func TestAuthFieldNames(t *testing.T) {
result := schema.AuthFieldNames()
expected := 8
if len(result) != expected {
t.Fatalf("Expected %d auth field names, got %d (%v)", expected, len(result), result)
}
}
func TestFieldTypes(t *testing.T) {
result := schema.FieldTypes()
expected := 11
if len(result) != expected {
t.Fatalf("Expected %d types, got %d (%v)", expected, len(result), result)
}
}
func TestArraybleFieldTypes(t *testing.T) {
result := schema.ArraybleFieldTypes()
expected := 3
if len(result) != expected {
t.Fatalf("Expected %d arrayble types, got %d (%v)", expected, len(result), result)
}
}
func TestSchemaFieldColDefinition(t *testing.T) {
scenarios := []struct {
field schema.SchemaField
expected string
}{
{
schema.SchemaField{Type: schema.FieldTypeText, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeNumber, Name: "test"},
"NUMERIC DEFAULT 0 NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeBool, Name: "test"},
"BOOLEAN DEFAULT FALSE NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeEmail, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeUrl, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeEditor, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeDate, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeJson, Name: "test"},
"JSON DEFAULT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeSelect, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeSelect, Name: "test_multiple", Options: &schema.SelectOptions{MaxSelect: 2}},
"JSON DEFAULT '[]' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeFile, Name: "test"},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeFile, Name: "test_multiple", Options: &schema.FileOptions{MaxSelect: 2}},
"JSON DEFAULT '[]' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeRelation, Name: "test", Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"TEXT DEFAULT '' NOT NULL",
},
{
schema.SchemaField{Type: schema.FieldTypeRelation, Name: "test_multiple", Options: &schema.RelationOptions{MaxSelect: nil}},
"JSON DEFAULT '[]' NOT NULL",
},
}
for i, s := range scenarios {
def := s.field.ColDefinition()
if def != s.expected {
t.Errorf("(%d) Expected definition %q, got %q", i, s.expected, def)
}
}
}
func TestSchemaFieldString(t *testing.T) {
f := schema.SchemaField{
Id: "abc",
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Presentable: true,
System: true,
Options: &schema.TextOptions{
Pattern: "test",
},
}
result := f.String()
expected := `{"system":true,"id":"abc","name":"test","type":"text","required":true,"presentable":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`
if result != expected {
t.Errorf("Expected \n%v, got \n%v", expected, result)
}
}
func TestSchemaFieldMarshalJSON(t *testing.T) {
scenarios := []struct {
field schema.SchemaField
expected string
}{
// empty
{
schema.SchemaField{},
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
// without defined options
{
schema.SchemaField{
Id: "abc",
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Presentable: true,
System: true,
},
`{"system":true,"id":"abc","name":"test","type":"text","required":true,"presentable":true,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
},
// with defined options
{
schema.SchemaField{
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Unique: false,
System: true,
Options: &schema.TextOptions{
Pattern: "test",
},
},
`{"system":true,"id":"","name":"test","type":"text","required":true,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
},
}
for i, s := range scenarios {
result, err := s.field.MarshalJSON()
if err != nil {
t.Fatalf("(%d) %v", i, err)
}
if string(result) != s.expected {
t.Errorf("(%d), Expected \n%v, got \n%v", i, s.expected, string(result))
}
}
}
func TestSchemaFieldUnmarshalJSON(t *testing.T) {
scenarios := []struct {
data []byte
expectError bool
expectJson string
}{
{
nil,
true,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte{},
true,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte(`{"system": true}`),
true,
`{"system":true,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte(`{"invalid"`),
true,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte(`{"type":"text","system":true}`),
false,
`{"system":true,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
},
{
[]byte(`{"type":"text","options":{"pattern":"test"}}`),
false,
`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
},
}
for i, s := range scenarios {
f := schema.SchemaField{}
err := f.UnmarshalJSON(s.data)
hasErr := err != nil
if hasErr != s.expectError {
t.Errorf("(%d) Expected hasErr %v, got %v (%v)", i, s.expectError, hasErr, err)
}
if f.String() != s.expectJson {
t.Errorf("(%d), Expected json \n%v, got \n%v", i, s.expectJson, f.String())
}
}
}
func TestSchemaFieldValidate(t *testing.T) {
scenarios := []struct {
name string
field schema.SchemaField
expectedErrors []string
}{
{
"empty field",
schema.SchemaField{},
[]string{"id", "options", "name", "type"},
},
{
"missing id",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "",
Name: "test",
},
[]string{"id"},
},
{
"invalid id length check",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234",
Name: "test",
},
[]string{"id"},
},
{
"valid id length check",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "12345",
Name: "test",
},
[]string{},
},
{
"invalid name format",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: "test!@#",
},
[]string{"name"},
},
{
"reserved name (null)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: "null",
},
[]string{"name"},
},
{
"reserved name (true)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: "null",
},
[]string{"name"},
},
{
"reserved name (false)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: "false",
},
[]string{"name"},
},
{
"reserved name (_rowid_)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: "_rowid_",
},
[]string{"name"},
},
{
"reserved name (id)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: schema.FieldNameId,
},
[]string{"name"},
},
{
"reserved name (created)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: schema.FieldNameCreated,
},
[]string{"name"},
},
{
"reserved name (updated)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: schema.FieldNameUpdated,
},
[]string{"name"},
},
{
"reserved name (collectionId)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: schema.FieldNameCollectionId,
},
[]string{"name"},
},
{
"reserved name (collectionName)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: schema.FieldNameCollectionName,
},
[]string{"name"},
},
{
"reserved name (expand)",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: schema.FieldNameExpand,
},
[]string{"name"},
},
{
"valid name",
schema.SchemaField{
Type: schema.FieldTypeText,
Id: "1234567890",
Name: "test",
},
[]string{},
},
{
"unique check for type file",
schema.SchemaField{
Type: schema.FieldTypeFile,
Id: "1234567890",
Name: "test",
Unique: true,
Options: &schema.FileOptions{MaxSelect: 1, MaxSize: 1},
},
[]string{"unique"},
},
{
"trigger options validator (auto init)",
schema.SchemaField{
Type: schema.FieldTypeFile,
Id: "1234567890",
Name: "test",
},
[]string{"options"},
},
{
"trigger options validator (invalid option field value)",
schema.SchemaField{
Type: schema.FieldTypeFile,
Id: "1234567890",
Name: "test",
Options: &schema.FileOptions{MaxSelect: 0, MaxSize: 0},
},
[]string{"options"},
},
{
"trigger options validator (valid option field value)",
schema.SchemaField{
Type: schema.FieldTypeFile,
Id: "1234567890",
Name: "test",
Options: &schema.FileOptions{MaxSelect: 1, MaxSize: 1},
},
[]string{},
},
}
for _, s := range scenarios {
result := s.field.Validate()
// parse errors
errs, ok := result.(validation.Errors)
if !ok && result != nil {
t.Errorf("[%s] Failed to parse errors %v", s.name, result)
continue
}
// check errors
if len(errs) > len(s.expectedErrors) {
t.Errorf("[%s] Expected error keys %v, got %v", s.name, s.expectedErrors, errs)
}
for _, k := range s.expectedErrors {
if _, ok := errs[k]; !ok {
t.Errorf("[%s] Missing expected error key %q in %v", s.name, k, errs)
}
}
}
}
func TestSchemaFieldInitOptions(t *testing.T) {
scenarios := []struct {
field schema.SchemaField
expectError bool
expectJson string
}{
{
schema.SchemaField{},
true,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
schema.SchemaField{Type: "unknown"},
true,
`{"system":false,"id":"","name":"","type":"unknown","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
schema.SchemaField{Type: schema.FieldTypeText},
false,
`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeNumber},
false,
`{"system":false,"id":"","name":"","type":"number","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"noDecimal":false}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeBool},
false,
`{"system":false,"id":"","name":"","type":"bool","required":false,"presentable":false,"unique":false,"options":{}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeEmail},
false,
`{"system":false,"id":"","name":"","type":"email","required":false,"presentable":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeUrl},
false,
`{"system":false,"id":"","name":"","type":"url","required":false,"presentable":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeEditor},
false,
`{"system":false,"id":"","name":"","type":"editor","required":false,"presentable":false,"unique":false,"options":{"convertUrls":false}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeDate},
false,
`{"system":false,"id":"","name":"","type":"date","required":false,"presentable":false,"unique":false,"options":{"min":"","max":""}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeSelect},
false,
`{"system":false,"id":"","name":"","type":"select","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"values":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeJson},
false,
`{"system":false,"id":"","name":"","type":"json","required":false,"presentable":false,"unique":false,"options":{}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeFile},
false,
`{"system":false,"id":"","name":"","type":"file","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"maxSize":0,"mimeTypes":null,"thumbs":null,"protected":false}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeRelation},
false,
`{"system":false,"id":"","name":"","type":"relation","required":false,"presentable":false,"unique":false,"options":{"collectionId":"","cascadeDelete":false,"minSelect":null,"maxSelect":null,"displayFields":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeUser},
false,
`{"system":false,"id":"","name":"","type":"user","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"cascadeDelete":false}}`,
},
{
schema.SchemaField{
Type: schema.FieldTypeText,
Options: &schema.TextOptions{Pattern: "test"},
},
false,
`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
},
}
for i, s := range scenarios {
err := s.field.InitOptions()
hasErr := err != nil
if hasErr != s.expectError {
t.Errorf("(%d) Expected %v, got %v (%v)", i, s.expectError, hasErr, err)
}
if s.field.String() != s.expectJson {
t.Errorf("(%d), Expected %v, got %v", i, s.expectJson, s.field.String())
}
}
}
func TestSchemaFieldPrepareValue(t *testing.T) {
scenarios := []struct {
field schema.SchemaField
value any
expectJson string
}{
{schema.SchemaField{Type: "unknown"}, "test", `"test"`},
{schema.SchemaField{Type: "unknown"}, 123, "123"},
{schema.SchemaField{Type: "unknown"}, []int{1, 2, 1}, "[1,2,1]"},
// text
{schema.SchemaField{Type: schema.FieldTypeText}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeText}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeText}, []int{1, 2}, `""`},
{schema.SchemaField{Type: schema.FieldTypeText}, "test", `"test"`},
{schema.SchemaField{Type: schema.FieldTypeText}, 123, `"123"`},
// email
{schema.SchemaField{Type: schema.FieldTypeEmail}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeEmail}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeEmail}, []int{1, 2}, `""`},
{schema.SchemaField{Type: schema.FieldTypeEmail}, "test", `"test"`},
{schema.SchemaField{Type: schema.FieldTypeEmail}, 123, `"123"`},
// url
{schema.SchemaField{Type: schema.FieldTypeUrl}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeUrl}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeUrl}, []int{1, 2}, `""`},
{schema.SchemaField{Type: schema.FieldTypeUrl}, "test", `"test"`},
{schema.SchemaField{Type: schema.FieldTypeUrl}, 123, `"123"`},
// editor
{schema.SchemaField{Type: schema.FieldTypeEditor}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeEditor}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeEditor}, []int{1, 2}, `""`},
{schema.SchemaField{Type: schema.FieldTypeEditor}, "test", `"test"`},
{schema.SchemaField{Type: schema.FieldTypeEditor}, 123, `"123"`},
// json
{schema.SchemaField{Type: schema.FieldTypeJson}, nil, "null"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "null", "null"},
{schema.SchemaField{Type: schema.FieldTypeJson}, 123, "123"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "123", "123"},
{schema.SchemaField{Type: schema.FieldTypeJson}, 123.456, "123.456"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "123.456", "123.456"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "123.456 abc", `"123.456 abc"`}, // invalid numeric string
{schema.SchemaField{Type: schema.FieldTypeJson}, true, "true"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "true", "true"},
{schema.SchemaField{Type: schema.FieldTypeJson}, false, "false"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "false", "false"},
{schema.SchemaField{Type: schema.FieldTypeJson}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `test`, `"test"`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `"test"`, `"test"`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `{test":1}`, `"{test\":1}"`}, // invalid object string
{schema.SchemaField{Type: schema.FieldTypeJson}, `[1 2 3]`, `"[1 2 3]"`}, // invalid array string
{schema.SchemaField{Type: schema.FieldTypeJson}, map[string]int{}, `{}`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `{}`, `{}`},
{schema.SchemaField{Type: schema.FieldTypeJson}, map[string]int{"test": 123}, `{"test":123}`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `{"test":123}`, `{"test":123}`},
{schema.SchemaField{Type: schema.FieldTypeJson}, []int{}, `[]`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `[]`, `[]`},
{schema.SchemaField{Type: schema.FieldTypeJson}, []int{1, 2, 1}, `[1,2,1]`},
{schema.SchemaField{Type: schema.FieldTypeJson}, `[1,2,1]`, `[1,2,1]`},
// number
{schema.SchemaField{Type: schema.FieldTypeNumber}, nil, "0"},
{schema.SchemaField{Type: schema.FieldTypeNumber}, "", "0"},
{schema.SchemaField{Type: schema.FieldTypeNumber}, "test", "0"},
{schema.SchemaField{Type: schema.FieldTypeNumber}, 1, "1"},
{schema.SchemaField{Type: schema.FieldTypeNumber}, 1.5, "1.5"},
{schema.SchemaField{Type: schema.FieldTypeNumber}, "1.5", "1.5"},
// bool
{schema.SchemaField{Type: schema.FieldTypeBool}, nil, "false"},
{schema.SchemaField{Type: schema.FieldTypeBool}, 1, "true"},
{schema.SchemaField{Type: schema.FieldTypeBool}, 0, "false"},
{schema.SchemaField{Type: schema.FieldTypeBool}, "", "false"},
{schema.SchemaField{Type: schema.FieldTypeBool}, "test", "false"},
{schema.SchemaField{Type: schema.FieldTypeBool}, "false", "false"},
{schema.SchemaField{Type: schema.FieldTypeBool}, "true", "true"},
{schema.SchemaField{Type: schema.FieldTypeBool}, false, "false"},
{schema.SchemaField{Type: schema.FieldTypeBool}, true, "true"},
// date
{schema.SchemaField{Type: schema.FieldTypeDate}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeDate}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeDate}, "test", `""`},
{schema.SchemaField{Type: schema.FieldTypeDate}, 1641024040, `"2022-01-01 08:00:40.000Z"`},
{schema.SchemaField{Type: schema.FieldTypeDate}, "2022-01-01 11:27:10.123", `"2022-01-01 11:27:10.123Z"`},
{schema.SchemaField{Type: schema.FieldTypeDate}, "2022-01-01 11:27:10.123Z", `"2022-01-01 11:27:10.123Z"`},
{schema.SchemaField{Type: schema.FieldTypeDate}, types.DateTime{}, `""`},
{schema.SchemaField{Type: schema.FieldTypeDate}, time.Time{}, `""`},
// select (single)
{schema.SchemaField{Type: schema.FieldTypeSelect}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeSelect}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeSelect}, 123, `"123"`},
{schema.SchemaField{Type: schema.FieldTypeSelect}, "test", `"test"`},
{schema.SchemaField{Type: schema.FieldTypeSelect}, []string{"test1", "test2"}, `"test2"`},
{
// no values validation/filtering
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{
Values: []string{"test1", "test2"},
},
},
"test",
`"test"`,
},
// select (multiple)
{
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
nil,
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
"",
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
[]string{},
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
123,
`["123"]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
"test",
`["test"]`,
},
{
// no values validation
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
[]string{"test1", "test2", "test3"},
`["test1","test2","test3"]`,
},
{
// duplicated values
schema.SchemaField{
Type: schema.FieldTypeSelect,
Options: &schema.SelectOptions{MaxSelect: 2},
},
[]string{"test1", "test2", "test1"},
`["test1","test2"]`,
},
// file (single)
{schema.SchemaField{Type: schema.FieldTypeFile}, nil, `""`},
{schema.SchemaField{Type: schema.FieldTypeFile}, "", `""`},
{schema.SchemaField{Type: schema.FieldTypeFile}, 123, `"123"`},
{schema.SchemaField{Type: schema.FieldTypeFile}, "test", `"test"`},
{schema.SchemaField{Type: schema.FieldTypeFile}, []string{"test1", "test2"}, `"test2"`},
// file (multiple)
{
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
nil,
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
"",
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
[]string{},
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
123,
`["123"]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
"test",
`["test"]`,
},
{
// no values validation
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
[]string{"test1", "test2", "test3"},
`["test1","test2","test3"]`,
},
{
// duplicated values
schema.SchemaField{
Type: schema.FieldTypeFile,
Options: &schema.FileOptions{MaxSelect: 2},
},
[]string{"test1", "test2", "test1"},
`["test1","test2"]`,
},
// relation (single)
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)},
},
nil,
`""`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)},
},
"",
`""`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)},
},
123,
`"123"`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)},
},
"abc",
`"abc"`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)},
},
"1ba88b4f-e9da-42f0-9764-9a55c953e724",
`"1ba88b4f-e9da-42f0-9764-9a55c953e724"`,
},
{
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
[]string{"1ba88b4f-e9da-42f0-9764-9a55c953e724", "2ba88b4f-e9da-42f0-9764-9a55c953e724"},
`"2ba88b4f-e9da-42f0-9764-9a55c953e724"`,
},
// relation (multiple)
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
nil,
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
"",
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
[]string{},
`[]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
123,
`["123"]`,
},
{
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
[]string{"", "abc"},
`["abc"]`,
},
{
// no values validation
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
[]string{"1ba88b4f-e9da-42f0-9764-9a55c953e724", "2ba88b4f-e9da-42f0-9764-9a55c953e724"},
`["1ba88b4f-e9da-42f0-9764-9a55c953e724","2ba88b4f-e9da-42f0-9764-9a55c953e724"]`,
},
{
// duplicated values
schema.SchemaField{
Type: schema.FieldTypeRelation,
Options: &schema.RelationOptions{MaxSelect: types.Pointer(2)},
},
[]string{"1ba88b4f-e9da-42f0-9764-9a55c953e724", "2ba88b4f-e9da-42f0-9764-9a55c953e724", "1ba88b4f-e9da-42f0-9764-9a55c953e724"},
`["1ba88b4f-e9da-42f0-9764-9a55c953e724","2ba88b4f-e9da-42f0-9764-9a55c953e724"]`,
},
}
for i, s := range scenarios {
result := s.field.PrepareValue(s.value)
encoded, err := json.Marshal(result)
if err != nil {
t.Errorf("(%d) %v", i, err)
continue
}
if string(encoded) != s.expectJson {
t.Errorf("(%d), Expected %v, got %v", i, s.expectJson, string(encoded))
}
}
}
func TestSchemaFieldPrepareValueWithModifier(t *testing.T) {
scenarios := []struct {
name string
field schema.SchemaField
baseValue any
modifier string
modifierValue any
expectJson string
}{
// text
{
"text with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeText},
"base",
"+",
"new",
`"base"`,
},
{
"text with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeText},
"base",
"-",
"new",
`"base"`,
},
{
"text with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeText},
"base",
"?",
"new",
`"base"`,
},
{
"text cast check",
schema.SchemaField{Type: schema.FieldTypeText},
123,
"?",
"new",
`"123"`,
},
// number
{
"number with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeNumber},
1,
"+",
4,
`5`,
},
{
"number with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeNumber},
1,
"-",
4,
`-3`,
},
{
"number with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeNumber},
"1",
"?",
4,
`1`,
},
{
"number cast check",
schema.SchemaField{Type: schema.FieldTypeNumber},
"test",
"+",
"4",
`4`,
},
// bool
{
"bool with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeBool},
true,
"+",
false,
`true`,
},
{
"bool with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeBool},
true,
"-",
false,
`true`,
},
{
"bool with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeBool},
true,
"?",
false,
`true`,
},
{
"bool cast check",
schema.SchemaField{Type: schema.FieldTypeBool},
"true",
"?",
false,
`true`,
},
// email
{
"email with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeEmail},
"base",
"+",
"new",
`"base"`,
},
{
"email with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeEmail},
"base",
"-",
"new",
`"base"`,
},
{
"email with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeEmail},
"base",
"?",
"new",
`"base"`,
},
{
"email cast check",
schema.SchemaField{Type: schema.FieldTypeEmail},
123,
"?",
"new",
`"123"`,
},
// url
{
"url with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeUrl},
"base",
"+",
"new",
`"base"`,
},
{
"url with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeUrl},
"base",
"-",
"new",
`"base"`,
},
{
"url with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeUrl},
"base",
"?",
"new",
`"base"`,
},
{
"url cast check",
schema.SchemaField{Type: schema.FieldTypeUrl},
123,
"-",
"new",
`"123"`,
},
// editor
{
"editor with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeEditor},
"base",
"+",
"new",
`"base"`,
},
{
"editor with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeEditor},
"base",
"-",
"new",
`"base"`,
},
{
"editor with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeEditor},
"base",
"?",
"new",
`"base"`,
},
{
"editor cast check",
schema.SchemaField{Type: schema.FieldTypeEditor},
123,
"-",
"new",
`"123"`,
},
// date
{
"date with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeDate},
"2023-01-01 00:00:00.123",
"+",
"2023-02-01 00:00:00.456",
`"2023-01-01 00:00:00.123Z"`,
},
{
"date with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeDate},
"2023-01-01 00:00:00.123Z",
"-",
"2023-02-01 00:00:00.456Z",
`"2023-01-01 00:00:00.123Z"`,
},
{
"date with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeDate},
"2023-01-01 00:00:00.123",
"?",
"2023-01-01 00:00:00.456",
`"2023-01-01 00:00:00.123Z"`,
},
{
"date cast check",
schema.SchemaField{Type: schema.FieldTypeDate},
1672524000, // 2022-12-31 22:00:00.000Z
"+",
100,
`"2022-12-31 22:00:00.000Z"`,
},
// json
{
"json with '+' modifier",
schema.SchemaField{Type: schema.FieldTypeJson},
10,
"+",
5,
`10`,
},
{
"json with '+' modifier (slice)",
schema.SchemaField{Type: schema.FieldTypeJson},
[]string{"a", "b"},
"+",
"c",
`["a","b"]`,
},
{
"json with '-' modifier",
schema.SchemaField{Type: schema.FieldTypeJson},
10,
"-",
5,
`10`,
},
{
"json with '-' modifier (slice)",
schema.SchemaField{Type: schema.FieldTypeJson},
`["a","b"]`,
"-",
"c",
`["a","b"]`,
},
{
"json with unknown modifier",
schema.SchemaField{Type: schema.FieldTypeJson},
`"base"`,
"?",
`"new"`,
`"base"`,
},
// single select
{
"single select with '+' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"",
"+",
"b",
`"b"`,
},
{
"single select with '+' modifier (nonempty base)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"a",
"+",
"b",
`"b"`,
},
{
"single select with '-' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"",
"-",
"a",
`""`,
},
{
"single select with '-' modifier (nonempty base and empty modifier value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"a",
"-",
"",
`"a"`,
},
{
"single select with '-' modifier (nonempty base and different value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"a",
"-",
"b",
`"a"`,
},
{
"single select with '-' modifier (nonempty base and matching value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"a",
"-",
"a",
`""`,
},
{
"single select with '-' modifier (nonempty base and matching value in a slice)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"a",
"-",
[]string{"b", "a", "c", "123"},
`""`,
},
{
"single select with unknown modifier (nonempty)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
"",
"?",
"a",
`""`,
},
// multi select
{
"multi select with '+' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
nil,
"+",
"b",
`["b"]`,
},
{
"multi select with '+' modifier (nonempty base)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
[]string{"a"},
"+",
[]string{"b", "c"},
`["a","b","c"]`,
},
{
"multi select with '+' modifier (nonempty base; already existing value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
[]string{"a", "b"},
"+",
"b",
`["a","b"]`,
},
{
"multi select with '-' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
nil,
"-",
[]string{"a"},
`[]`,
},
{
"multi select with '-' modifier (nonempty base and empty modifier value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
"a",
"-",
"",
`["a"]`,
},
{
"multi select with '-' modifier (nonempty base and different value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
"a",
"-",
"b",
`["a"]`,
},
{
"multi select with '-' modifier (nonempty base and matching value)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
[]string{"a", "b", "c", "d"},
"-",
"c",
`["a","b","d"]`,
},
{
"multi select with '-' modifier (nonempty base and matching value in a slice)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
[]string{"a", "b", "c", "d"},
"-",
[]string{"b", "a", "123"},
`["c","d"]`,
},
{
"multi select with unknown modifier (nonempty)",
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
[]string{"a", "b"},
"?",
"a",
`["a","b"]`,
},
// single relation
{
"single relation with '+' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"",
"+",
"b",
`"b"`,
},
{
"single relation with '+' modifier (nonempty base)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"a",
"+",
"b",
`"b"`,
},
{
"single relation with '-' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"",
"-",
"a",
`""`,
},
{
"single relation with '-' modifier (nonempty base and empty modifier value)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"a",
"-",
"",
`"a"`,
},
{
"single relation with '-' modifier (nonempty base and different value)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"a",
"-",
"b",
`"a"`,
},
{
"single relation with '-' modifier (nonempty base and matching value)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"a",
"-",
"a",
`""`,
},
{
"single relation with '-' modifier (nonempty base and matching value in a slice)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"a",
"-",
[]string{"b", "a", "c", "123"},
`""`,
},
{
"single relation with unknown modifier (nonempty)",
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
"",
"?",
"a",
`""`,
},
// multi relation
{
"multi relation with '+' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeRelation},
nil,
"+",
"b",
`["b"]`,
},
{
"multi relation with '+' modifier (nonempty base)",
schema.SchemaField{Type: schema.FieldTypeRelation},
[]string{"a"},
"+",
[]string{"b", "c"},
`["a","b","c"]`,
},
{
"multi relation with '+' modifier (nonempty base; already existing value)",
schema.SchemaField{Type: schema.FieldTypeRelation},
[]string{"a", "b"},
"+",
"b",
`["a","b"]`,
},
{
"multi relation with '-' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeRelation},
nil,
"-",
[]string{"a"},
`[]`,
},
{
"multi relation with '-' modifier (nonempty base and empty modifier value)",
schema.SchemaField{Type: schema.FieldTypeRelation},
"a",
"-",
"",
`["a"]`,
},
{
"multi relation with '-' modifier (nonempty base and different value)",
schema.SchemaField{Type: schema.FieldTypeRelation},
"a",
"-",
"b",
`["a"]`,
},
{
"multi relation with '-' modifier (nonempty base and matching value)",
schema.SchemaField{Type: schema.FieldTypeRelation},
[]string{"a", "b", "c", "d"},
"-",
"c",
`["a","b","d"]`,
},
{
"multi relation with '-' modifier (nonempty base and matching value in a slice)",
schema.SchemaField{Type: schema.FieldTypeRelation},
[]string{"a", "b", "c", "d"},
"-",
[]string{"b", "a", "123"},
`["c","d"]`,
},
{
"multi relation with unknown modifier (nonempty)",
schema.SchemaField{Type: schema.FieldTypeRelation},
[]string{"a", "b"},
"?",
"a",
`["a","b"]`,
},
// single file
{
"single file with '+' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"",
"+",
"b",
`""`,
},
{
"single file with '+' modifier (nonempty base)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"a",
"+",
"b",
`"a"`,
},
{
"single file with '-' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"",
"-",
"a",
`""`,
},
{
"single file with '-' modifier (nonempty base and empty modifier value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"a",
"-",
"",
`"a"`,
},
{
"single file with '-' modifier (nonempty base and different value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"a",
"-",
"b",
`"a"`,
},
{
"single file with '-' modifier (nonempty base and matching value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"a",
"-",
"a",
`""`,
},
{
"single file with '-' modifier (nonempty base and matching value in a slice)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"a",
"-",
[]string{"b", "a", "c", "123"},
`""`,
},
{
"single file with unknown modifier (nonempty)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
"",
"?",
"a",
`""`,
},
// multi file
{
"multi file with '+' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
nil,
"+",
"b",
`[]`,
},
{
"multi file with '+' modifier (nonempty base)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
[]string{"a"},
"+",
[]string{"b", "c"},
`["a"]`,
},
{
"multi file with '+' modifier (nonempty base; already existing value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
[]string{"a", "b"},
"+",
"b",
`["a","b"]`,
},
{
"multi file with '-' modifier (empty base)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
nil,
"-",
[]string{"a"},
`[]`,
},
{
"multi file with '-' modifier (nonempty base and empty modifier value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
"a",
"-",
"",
`["a"]`,
},
{
"multi file with '-' modifier (nonempty base and different value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
"a",
"-",
"b",
`["a"]`,
},
{
"multi file with '-' modifier (nonempty base and matching value)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
[]string{"a", "b", "c", "d"},
"-",
"c",
`["a","b","d"]`,
},
{
"multi file with '-' modifier (nonempty base and matching value in a slice)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
[]string{"a", "b", "c", "d"},
"-",
[]string{"b", "a", "123"},
`["c","d"]`,
},
{
"multi file with unknown modifier (nonempty)",
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
[]string{"a", "b"},
"?",
"a",
`["a","b"]`,
},
}
for _, s := range scenarios {
result := s.field.PrepareValueWithModifier(s.baseValue, s.modifier, s.modifierValue)
encoded, err := json.Marshal(result)
if err != nil {
t.Fatalf("[%s] %v", s.name, err)
}
if string(encoded) != s.expectJson {
t.Fatalf("[%s], Expected %v, got %v", s.name, s.expectJson, string(encoded))
}
}
}
// -------------------------------------------------------------------
type fieldOptionsScenario struct {
name string
options schema.FieldOptions
expectedErrors []string
}
func checkFieldOptionsScenarios(t *testing.T, scenarios []fieldOptionsScenario) {
for i, s := range scenarios {
result := s.options.Validate()
prefix := fmt.Sprintf("%d", i)
if s.name != "" {
prefix = s.name
}
// parse errors
errs, ok := result.(validation.Errors)
if !ok && result != nil {
t.Errorf("[%s] Failed to parse errors %v", prefix, result)
continue
}
// check errors
if len(errs) > len(s.expectedErrors) {
t.Errorf("[%s] Expected error keys %v, got %v", prefix, s.expectedErrors, errs)
}
for _, k := range s.expectedErrors {
if _, ok := errs[k]; !ok {
t.Errorf("[%s] Missing expected error key %q in %v", prefix, k, errs)
}
}
}
}
func TestTextOptionsValidate(t *testing.T) {
minus := -1
number0 := 0
number1 := 10
number2 := 20
scenarios := []fieldOptionsScenario{
{
"empty",
schema.TextOptions{},
[]string{},
},
{
"min - failure",
schema.TextOptions{
Min: &minus,
},
[]string{"min"},
},
{
"min - success",
schema.TextOptions{
Min: &number0,
},
[]string{},
},
{
"max - failure without min",
schema.TextOptions{
Max: &minus,
},
[]string{"max"},
},
{
"max - failure with min",
schema.TextOptions{
Min: &number2,
Max: &number1,
},
[]string{"max"},
},
{
"max - success",
schema.TextOptions{
Min: &number1,
Max: &number2,
},
[]string{},
},
{
"pattern - failure",
schema.TextOptions{Pattern: "(test"},
[]string{"pattern"},
},
{
"pattern - success",
schema.TextOptions{Pattern: `^\#?\w+$`},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestNumberOptionsValidate(t *testing.T) {
int1 := 10.0
int2 := 20.0
decimal1 := 10.5
decimal2 := 20.5
scenarios := []fieldOptionsScenario{
{
"empty",
schema.NumberOptions{},
[]string{},
},
{
"max - without min",
schema.NumberOptions{
Max: &int1,
},
[]string{},
},
{
"max - failure with min",
schema.NumberOptions{
Min: &int2,
Max: &int1,
},
[]string{"max"},
},
{
"max - success with min",
schema.NumberOptions{
Min: &int1,
Max: &int2,
},
[]string{},
},
{
"NoDecimal range failure",
schema.NumberOptions{
Min: &decimal1,
Max: &decimal2,
NoDecimal: true,
},
[]string{"min", "max"},
},
{
"NoDecimal range success",
schema.NumberOptions{
Min: &int1,
Max: &int2,
NoDecimal: true,
},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestBoolOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.BoolOptions{},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestEmailOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.EmailOptions{},
[]string{},
},
{
"ExceptDomains failure",
schema.EmailOptions{
ExceptDomains: []string{"invalid"},
},
[]string{"exceptDomains"},
},
{
"ExceptDomains success",
schema.EmailOptions{
ExceptDomains: []string{"example.com", "sub.example.com"},
},
[]string{},
},
{
"OnlyDomains check",
schema.EmailOptions{
OnlyDomains: []string{"invalid"},
},
[]string{"onlyDomains"},
},
{
"OnlyDomains success",
schema.EmailOptions{
OnlyDomains: []string{"example.com", "sub.example.com"},
},
[]string{},
},
{
"OnlyDomains + ExceptDomains at the same time",
schema.EmailOptions{
ExceptDomains: []string{"test1.com"},
OnlyDomains: []string{"test2.com"},
},
[]string{"exceptDomains", "onlyDomains"},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestUrlOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.UrlOptions{},
[]string{},
},
{
"ExceptDomains failure",
schema.UrlOptions{
ExceptDomains: []string{"invalid"},
},
[]string{"exceptDomains"},
},
{
"ExceptDomains success",
schema.UrlOptions{
ExceptDomains: []string{"example.com", "sub.example.com"},
},
[]string{},
},
{
"OnlyDomains check",
schema.UrlOptions{
OnlyDomains: []string{"invalid"},
},
[]string{"onlyDomains"},
},
{
"OnlyDomains success",
schema.UrlOptions{
OnlyDomains: []string{"example.com", "sub.example.com"},
},
[]string{},
},
{
"OnlyDomains + ExceptDomains at the same time",
schema.UrlOptions{
ExceptDomains: []string{"test1.com"},
OnlyDomains: []string{"test2.com"},
},
[]string{"exceptDomains", "onlyDomains"},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestEditorOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.EditorOptions{},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestDateOptionsValidate(t *testing.T) {
date1 := types.NowDateTime()
date2, _ := types.ParseDateTime(date1.Time().AddDate(1, 0, 0))
scenarios := []fieldOptionsScenario{
{
"empty",
schema.DateOptions{},
[]string{},
},
{
"min only",
schema.DateOptions{
Min: date1,
},
[]string{},
},
{
"max only",
schema.DateOptions{
Min: date1,
},
[]string{},
},
{
"zero min + max",
schema.DateOptions{
Min: types.DateTime{},
Max: date1,
},
[]string{},
},
{
"min + zero max",
schema.DateOptions{
Min: date1,
Max: types.DateTime{},
},
[]string{},
},
{
"min > max",
schema.DateOptions{
Min: date2,
Max: date1,
},
[]string{"max"},
},
{
"min == max",
schema.DateOptions{
Min: date1,
Max: date1,
},
[]string{"max"},
},
{
"min < max",
schema.DateOptions{
Min: date1,
Max: date2,
},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestSelectOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.SelectOptions{},
[]string{"values", "maxSelect"},
},
{
"MaxSelect <= 0",
schema.SelectOptions{
Values: []string{"test1", "test2"},
MaxSelect: 0,
},
[]string{"maxSelect"},
},
{
"MaxSelect > Values",
schema.SelectOptions{
Values: []string{"test1", "test2"},
MaxSelect: 3,
},
[]string{"maxSelect"},
},
{
"MaxSelect <= Values",
schema.SelectOptions{
Values: []string{"test1", "test2"},
MaxSelect: 2,
},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestSelectOptionsIsMultiple(t *testing.T) {
scenarios := []struct {
maxSelect int
expect bool
}{
{-1, false},
{0, false},
{1, false},
{2, true},
}
for i, s := range scenarios {
opt := schema.SelectOptions{
MaxSelect: s.maxSelect,
}
if v := opt.IsMultiple(); v != s.expect {
t.Errorf("[%d] Expected %v, got %v", i, s.expect, v)
}
}
}
func TestJsonOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.JsonOptions{},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestFileOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.FileOptions{},
[]string{"maxSelect", "maxSize"},
},
{
"MaxSelect <= 0 && maxSize <= 0",
schema.FileOptions{
MaxSize: 0,
MaxSelect: 0,
},
[]string{"maxSelect", "maxSize"},
},
{
"MaxSelect > 0 && maxSize > 0",
schema.FileOptions{
MaxSize: 2,
MaxSelect: 1,
},
[]string{},
},
{
"invalid thumbs format",
schema.FileOptions{
MaxSize: 1,
MaxSelect: 2,
Thumbs: []string{"100", "200x100"},
},
[]string{"thumbs"},
},
{
"invalid thumbs format - zero width and height",
schema.FileOptions{
MaxSize: 1,
MaxSelect: 2,
Thumbs: []string{"0x0", "0x0t", "0x0b", "0x0f"},
},
[]string{"thumbs"},
},
{
"valid thumbs format",
schema.FileOptions{
MaxSize: 1,
MaxSelect: 2,
Thumbs: []string{
"100x100", "200x100", "0x100", "100x0",
"10x10t", "10x10b", "10x10f",
},
},
[]string{},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestFileOptionsIsMultiple(t *testing.T) {
scenarios := []struct {
maxSelect int
expect bool
}{
{-1, false},
{0, false},
{1, false},
{2, true},
}
for i, s := range scenarios {
opt := schema.FileOptions{
MaxSelect: s.maxSelect,
}
if v := opt.IsMultiple(); v != s.expect {
t.Errorf("[%d] Expected %v, got %v", i, s.expect, v)
}
}
}
func TestRelationOptionsValidate(t *testing.T) {
scenarios := []fieldOptionsScenario{
{
"empty",
schema.RelationOptions{},
[]string{"collectionId"},
},
{
"empty CollectionId",
schema.RelationOptions{
CollectionId: "",
MaxSelect: types.Pointer(1),
},
[]string{"collectionId"},
},
{
"MinSelect < 0",
schema.RelationOptions{
CollectionId: "abc",
MinSelect: types.Pointer(-1),
},
[]string{"minSelect"},
},
{
"MinSelect >= 0",
schema.RelationOptions{
CollectionId: "abc",
MinSelect: types.Pointer(0),
},
[]string{},
},
{
"MaxSelect <= 0",
schema.RelationOptions{
CollectionId: "abc",
MaxSelect: types.Pointer(0),
},
[]string{"maxSelect"},
},
{
"MaxSelect > 0 && nonempty CollectionId",
schema.RelationOptions{
CollectionId: "abc",
MaxSelect: types.Pointer(1),
},
[]string{},
},
{
"MinSelect < MaxSelect",
schema.RelationOptions{
CollectionId: "abc",
MinSelect: nil,
MaxSelect: types.Pointer(1),
},
[]string{},
},
{
"MinSelect = MaxSelect (non-zero)",
schema.RelationOptions{
CollectionId: "abc",
MinSelect: types.Pointer(1),
MaxSelect: types.Pointer(1),
},
[]string{},
},
{
"MinSelect = MaxSelect (both zero)",
schema.RelationOptions{
CollectionId: "abc",
MinSelect: types.Pointer(0),
MaxSelect: types.Pointer(0),
},
[]string{"maxSelect"},
},
{
"MinSelect > MaxSelect",
schema.RelationOptions{
CollectionId: "abc",
MinSelect: types.Pointer(2),
MaxSelect: types.Pointer(1),
},
[]string{"maxSelect"},
},
}
checkFieldOptionsScenarios(t, scenarios)
}
func TestRelationOptionsIsMultiple(t *testing.T) {
scenarios := []struct {
maxSelect *int
expect bool
}{
{nil, true},
{types.Pointer(-1), false},
{types.Pointer(0), false},
{types.Pointer(1), false},
{types.Pointer(2), true},
}
for i, s := range scenarios {
opt := schema.RelationOptions{
MaxSelect: s.maxSelect,
}
if v := opt.IsMultiple(); v != s.expect {
t.Errorf("[%d] Expected %v, got %v", i, s.expect, v)
}
}
}