mirror of
https://github.com/pocketbase/pocketbase.git
synced 2025-02-05 10:45:09 +02:00
466 lines
13 KiB
Go
466 lines
13 KiB
Go
package core_test
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/pocketbase/pocketbase/core"
|
|
)
|
|
|
|
func TestNewFieldsList(t *testing.T) {
|
|
fields := core.NewFieldsList(
|
|
&core.TextField{Id: "id1", Name: "test1"},
|
|
&core.TextField{Name: "test2"},
|
|
&core.TextField{Id: "id1", Name: "test1_new"}, // should replace the original id1 field
|
|
)
|
|
|
|
if len(fields) != 2 {
|
|
t.Fatalf("Expected 2 fields, got %d (%v)", len(fields), fields)
|
|
}
|
|
|
|
for _, f := range fields {
|
|
if f.GetId() == "" {
|
|
t.Fatalf("Expected field id to be set, found empty id for field %v", f)
|
|
}
|
|
}
|
|
|
|
if fields[0].GetName() != "test1_new" {
|
|
t.Fatalf("Expected field with name test1_new, got %s", fields[0].GetName())
|
|
}
|
|
|
|
if fields[1].GetName() != "test2" {
|
|
t.Fatalf("Expected field with name test2, got %s", fields[1].GetName())
|
|
}
|
|
}
|
|
|
|
func TestFieldsListClone(t *testing.T) {
|
|
f1 := &core.TextField{Name: "test1"}
|
|
f2 := &core.EmailField{Name: "test2"}
|
|
s1 := core.NewFieldsList(f1, f2)
|
|
|
|
s2, err := s1.Clone()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
s1Str := s1.String()
|
|
s2Str := s2.String()
|
|
|
|
if s1Str != s2Str {
|
|
t.Fatalf("Expected the cloned list to be equal, got \n%v\nVS\n%v", s1, s2)
|
|
}
|
|
|
|
// change in one list shouldn't result to change in the other
|
|
// (aka. check if it is a deep clone)
|
|
s1[0].SetName("test1_update")
|
|
if s2[0].GetName() != "test1" {
|
|
t.Fatalf("Expected s2 field name to not change, got %q", s2[0].GetName())
|
|
}
|
|
}
|
|
|
|
func TestFieldsListFieldNames(t *testing.T) {
|
|
f1 := &core.TextField{Name: "test1"}
|
|
f2 := &core.EmailField{Name: "test2"}
|
|
testFieldsList := core.NewFieldsList(f1, f2)
|
|
|
|
result := testFieldsList.FieldNames()
|
|
|
|
expected := []string{f1.Name, f2.Name}
|
|
|
|
if len(result) != len(expected) {
|
|
t.Fatalf("Expected %d slice elements, got %d\n%v", len(expected), len(result), result)
|
|
}
|
|
|
|
for _, name := range expected {
|
|
if !slices.Contains(result, name) {
|
|
t.Fatalf("Missing name %q in %v", name, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFieldsListAsMap(t *testing.T) {
|
|
f1 := &core.TextField{Name: "test1"}
|
|
f2 := &core.EmailField{Name: "test2"}
|
|
testFieldsList := core.NewFieldsList(f1, f2)
|
|
|
|
result := testFieldsList.AsMap()
|
|
|
|
expectedIndexes := []string{f1.Name, f2.Name}
|
|
|
|
if len(result) != len(expectedIndexes) {
|
|
t.Fatalf("Expected %d map elements, got %d\n%v", len(expectedIndexes), len(result), result)
|
|
}
|
|
|
|
for _, index := range expectedIndexes {
|
|
if _, ok := result[index]; !ok {
|
|
t.Fatalf("Missing index %q", index)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFieldsListGetById(t *testing.T) {
|
|
f1 := &core.TextField{Id: "id1", Name: "test1"}
|
|
f2 := &core.EmailField{Id: "id2", Name: "test2"}
|
|
testFieldsList := core.NewFieldsList(f1, f2)
|
|
|
|
// missing field id
|
|
result1 := testFieldsList.GetById("test1")
|
|
if result1 != nil {
|
|
t.Fatalf("Found unexpected field %v", result1)
|
|
}
|
|
|
|
// existing field id
|
|
result2 := testFieldsList.GetById("id2")
|
|
if result2 == nil || result2.GetId() != "id2" {
|
|
t.Fatalf("Cannot find field with id %q, got %v ", "id2", result2)
|
|
}
|
|
}
|
|
|
|
func TestFieldsListGetByName(t *testing.T) {
|
|
f1 := &core.TextField{Id: "id1", Name: "test1"}
|
|
f2 := &core.EmailField{Id: "id2", Name: "test2"}
|
|
testFieldsList := core.NewFieldsList(f1, f2)
|
|
|
|
// missing field name
|
|
result1 := testFieldsList.GetByName("id1")
|
|
if result1 != nil {
|
|
t.Fatalf("Found unexpected field %v", result1)
|
|
}
|
|
|
|
// existing field name
|
|
result2 := testFieldsList.GetByName("test2")
|
|
if result2 == nil || result2.GetName() != "test2" {
|
|
t.Fatalf("Cannot find field with name %q, got %v ", "test2", result2)
|
|
}
|
|
}
|
|
|
|
func TestFieldsListRemove(t *testing.T) {
|
|
testFieldsList := core.NewFieldsList(
|
|
&core.TextField{Id: "id1", Name: "test1"},
|
|
&core.TextField{Id: "id2", Name: "test2"},
|
|
&core.TextField{Id: "id3", Name: "test3"},
|
|
&core.TextField{Id: "id4", Name: "test4"},
|
|
&core.TextField{Id: "id5", Name: "test5"},
|
|
&core.TextField{Id: "id6", Name: "test6"},
|
|
)
|
|
|
|
// remove by id
|
|
testFieldsList.RemoveById("id2")
|
|
testFieldsList.RemoveById("test3") // should do nothing
|
|
|
|
// remove by name
|
|
testFieldsList.RemoveByName("test5")
|
|
testFieldsList.RemoveByName("id6") // should do nothing
|
|
|
|
expected := []string{"test1", "test3", "test4", "test6"}
|
|
|
|
if len(testFieldsList) != len(expected) {
|
|
t.Fatalf("Expected %d, got %d\n%v", len(expected), len(testFieldsList), testFieldsList)
|
|
}
|
|
|
|
for _, name := range expected {
|
|
if f := testFieldsList.GetByName(name); f == nil {
|
|
t.Fatalf("Missing field %q", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFieldsListAdd(t *testing.T) {
|
|
f0 := &core.TextField{}
|
|
f1 := &core.TextField{Name: "test1"}
|
|
f2 := &core.TextField{Id: "f2Id", Name: "test2"}
|
|
f3 := &core.TextField{Id: "f3Id", Name: "test3"}
|
|
testFieldsList := core.NewFieldsList(f0, f1, f2, f3)
|
|
|
|
f2New := &core.EmailField{Id: "f2Id", Name: "test2_new"}
|
|
f4 := &core.URLField{Name: "test4"}
|
|
|
|
testFieldsList.Add(f2New)
|
|
testFieldsList.Add(f4)
|
|
|
|
if len(testFieldsList) != 5 {
|
|
t.Fatalf("Expected %d, got %d\n%v", 5, len(testFieldsList), testFieldsList)
|
|
}
|
|
|
|
// check if each field has id
|
|
for _, f := range testFieldsList {
|
|
if f.GetId() == "" {
|
|
t.Fatalf("Expected field id to be set, found empty id for field %v", f)
|
|
}
|
|
}
|
|
|
|
// check if f2 field was replaced
|
|
if f := testFieldsList.GetById("f2Id"); f == nil || f.Type() != core.FieldTypeEmail {
|
|
t.Fatalf("Expected f2 field to be replaced, found %v", f)
|
|
}
|
|
|
|
// check if f4 was added
|
|
if f := testFieldsList.GetByName("test4"); f == nil || f.GetName() != "test4" {
|
|
t.Fatalf("Expected f4 field to be added, found %v", f)
|
|
}
|
|
}
|
|
|
|
func TestFieldsListAddMarshaledJSON(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
scenarios := []struct {
|
|
name string
|
|
raw []byte
|
|
expectError bool
|
|
expectedFields map[string]string
|
|
}{
|
|
{
|
|
"nil",
|
|
nil,
|
|
false,
|
|
map[string]string{"abc": core.FieldTypeNumber},
|
|
},
|
|
{
|
|
"empty array",
|
|
[]byte(`[]`),
|
|
false,
|
|
map[string]string{"abc": core.FieldTypeNumber},
|
|
},
|
|
{
|
|
"empty object",
|
|
[]byte(`{}`),
|
|
true,
|
|
map[string]string{"abc": core.FieldTypeNumber},
|
|
},
|
|
{
|
|
"array with empty object",
|
|
[]byte(`[{}]`),
|
|
true,
|
|
map[string]string{"abc": core.FieldTypeNumber},
|
|
},
|
|
{
|
|
"single object with invalid type",
|
|
[]byte(`{"type":"missing","name":"test"}`),
|
|
true,
|
|
map[string]string{"abc": core.FieldTypeNumber},
|
|
},
|
|
{
|
|
"single object with valid type",
|
|
[]byte(`{"type":"text","name":"test"}`),
|
|
false,
|
|
map[string]string{
|
|
"abc": core.FieldTypeNumber,
|
|
"test": core.FieldTypeText,
|
|
},
|
|
},
|
|
{
|
|
"array of object with valid types",
|
|
[]byte(`[{"type":"text","name":"test1"},{"type":"url","name":"test2"}]`),
|
|
false,
|
|
map[string]string{
|
|
"abc": core.FieldTypeNumber,
|
|
"test1": core.FieldTypeText,
|
|
"test2": core.FieldTypeURL,
|
|
},
|
|
},
|
|
{
|
|
"fields with duplicated ids should replace existing fields",
|
|
[]byte(`[{"type":"text","name":"test1"},{"type":"url","name":"test2"},{"type":"text","name":"abc2", "id":"abc_id"}]`),
|
|
false,
|
|
map[string]string{
|
|
"abc2": core.FieldTypeText,
|
|
"test1": core.FieldTypeText,
|
|
"test2": core.FieldTypeURL,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, s := range scenarios {
|
|
t.Run(s.name, func(t *testing.T) {
|
|
testList := core.NewFieldsList(&core.NumberField{Name: "abc", Id: "abc_id"})
|
|
err := testList.AddMarshaledJSON(s.raw)
|
|
|
|
hasErr := err != nil
|
|
if hasErr != s.expectError {
|
|
t.Fatalf("Expected hasErr %v, got %v", s.expectError, hasErr)
|
|
}
|
|
|
|
if len(s.expectedFields) != len(testList) {
|
|
t.Fatalf("Expected %d fields, got %d", len(s.expectedFields), len(testList))
|
|
}
|
|
|
|
for fieldName, typ := range s.expectedFields {
|
|
f := testList.GetByName(fieldName)
|
|
|
|
if f == nil {
|
|
t.Errorf("Missing expected field %q", fieldName)
|
|
continue
|
|
}
|
|
|
|
if f.Type() != typ {
|
|
t.Errorf("Expect field %q to has type %q, got %q", fieldName, typ, f.Type())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFieldsListStringAndValue(t *testing.T) {
|
|
t.Run("empty list", func(t *testing.T) {
|
|
testFieldsList := core.NewFieldsList()
|
|
|
|
str := testFieldsList.String()
|
|
if str != "[]" {
|
|
t.Fatalf("Expected empty slice, got\n%q", str)
|
|
}
|
|
|
|
v, err := testFieldsList.Value()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v != str {
|
|
t.Fatalf("Expected String and Value to match")
|
|
}
|
|
})
|
|
|
|
t.Run("list with fields", func(t *testing.T) {
|
|
testFieldsList := core.NewFieldsList(
|
|
&core.TextField{Id: "f1id", Name: "test1"},
|
|
&core.BoolField{Id: "f2id", Name: "test2"},
|
|
&core.URLField{Id: "f3id", Name: "test3"},
|
|
)
|
|
|
|
str := testFieldsList.String()
|
|
|
|
v, err := testFieldsList.Value()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v != str {
|
|
t.Fatalf("Expected String and Value to match")
|
|
}
|
|
|
|
expectedParts := []string{
|
|
`"type":"bool"`,
|
|
`"type":"url"`,
|
|
`"type":"text"`,
|
|
`"id":"f1id"`,
|
|
`"id":"f2id"`,
|
|
`"id":"f3id"`,
|
|
`"name":"test1"`,
|
|
`"name":"test2"`,
|
|
`"name":"test3"`,
|
|
}
|
|
|
|
for _, part := range expectedParts {
|
|
if !strings.Contains(str, part) {
|
|
t.Fatalf("Missing %q in\nn%v", part, str)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFieldsListScan(t *testing.T) {
|
|
scenarios := []struct {
|
|
name string
|
|
data any
|
|
expectError bool
|
|
expectJSON string
|
|
}{
|
|
{"nil", nil, false, "[]"},
|
|
{"empty string", "", false, "[]"},
|
|
{"empty byte", []byte{}, false, "[]"},
|
|
{"empty string array", "[]", false, "[]"},
|
|
{"invalid string", "invalid", true, "[]"},
|
|
{"non-string", 123, true, "[]"},
|
|
{"item with no field type", `[{}]`, true, "[]"},
|
|
{
|
|
"unknown field type",
|
|
`[{"id":"123","name":"test1","type":"unknown"},{"id":"456","name":"test2","type":"bool"}]`,
|
|
true,
|
|
`[]`,
|
|
},
|
|
{
|
|
"only the minimum field options",
|
|
`[{"id":"123","name":"test1","type":"text","required":true},{"id":"456","name":"test2","type":"bool"}]`,
|
|
false,
|
|
`[{"autogeneratePattern":"","hidden":false,"id":"123","max":0,"min":0,"name":"test1","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"hidden":false,"id":"456","name":"test2","presentable":false,"required":false,"system":false,"type":"bool"}]`,
|
|
},
|
|
{
|
|
"all field options",
|
|
`[{"autogeneratePattern":"","hidden":true,"id":"123","max":12,"min":0,"name":"test1","pattern":"","presentable":true,"primaryKey":false,"required":true,"system":false,"type":"text"},{"hidden":false,"id":"456","name":"test2","presentable":false,"required":false,"system":true,"type":"bool"}]`,
|
|
false,
|
|
`[{"autogeneratePattern":"","hidden":true,"id":"123","max":12,"min":0,"name":"test1","pattern":"","presentable":true,"primaryKey":false,"required":true,"system":false,"type":"text"},{"hidden":false,"id":"456","name":"test2","presentable":false,"required":false,"system":true,"type":"bool"}]`,
|
|
},
|
|
}
|
|
|
|
for _, s := range scenarios {
|
|
t.Run(s.name, func(t *testing.T) {
|
|
testFieldsList := core.FieldsList{}
|
|
|
|
err := testFieldsList.Scan(s.data)
|
|
|
|
hasErr := err != nil
|
|
if hasErr != s.expectError {
|
|
t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err)
|
|
}
|
|
|
|
str := testFieldsList.String()
|
|
if str != s.expectJSON {
|
|
t.Fatalf("Expected\n%v\ngot\n%v", s.expectJSON, str)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFieldsListJSON(t *testing.T) {
|
|
scenarios := []struct {
|
|
name string
|
|
data string
|
|
expectError bool
|
|
expectJSON string
|
|
}{
|
|
{"empty string", "", true, "[]"},
|
|
{"invalid string", "invalid", true, "[]"},
|
|
{"empty string array", "[]", false, "[]"},
|
|
{"item with no field type", `[{}]`, true, "[]"},
|
|
{
|
|
"unknown field type",
|
|
`[{"id":"123","name":"test1","type":"unknown"},{"id":"456","name":"test2","type":"bool"}]`,
|
|
true,
|
|
`[]`,
|
|
},
|
|
{
|
|
"only the minimum field options",
|
|
`[{"id":"123","name":"test1","type":"text","required":true},{"id":"456","name":"test2","type":"bool"}]`,
|
|
false,
|
|
`[{"autogeneratePattern":"","hidden":false,"id":"123","max":0,"min":0,"name":"test1","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"hidden":false,"id":"456","name":"test2","presentable":false,"required":false,"system":false,"type":"bool"}]`,
|
|
},
|
|
{
|
|
"all field options",
|
|
`[{"autogeneratePattern":"","hidden":true,"id":"123","max":12,"min":0,"name":"test1","pattern":"","presentable":true,"primaryKey":false,"required":true,"system":false,"type":"text"},{"hidden":false,"id":"456","name":"test2","presentable":false,"required":false,"system":true,"type":"bool"}]`,
|
|
false,
|
|
`[{"autogeneratePattern":"","hidden":true,"id":"123","max":12,"min":0,"name":"test1","pattern":"","presentable":true,"primaryKey":false,"required":true,"system":false,"type":"text"},{"hidden":false,"id":"456","name":"test2","presentable":false,"required":false,"system":true,"type":"bool"}]`,
|
|
},
|
|
}
|
|
|
|
for _, s := range scenarios {
|
|
t.Run(s.name, func(t *testing.T) {
|
|
testFieldsList := core.FieldsList{}
|
|
|
|
err := testFieldsList.UnmarshalJSON([]byte(s.data))
|
|
|
|
hasErr := err != nil
|
|
if hasErr != s.expectError {
|
|
t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err)
|
|
}
|
|
|
|
raw, err := testFieldsList.MarshalJSON()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
str := string(raw)
|
|
if str != s.expectJSON {
|
|
t.Fatalf("Expected\n%v\ngot\n%v", s.expectJSON, str)
|
|
}
|
|
})
|
|
}
|
|
}
|