package cabana import ( "context" "errors" "reflect" "testing" "git.golem15.com/golem15/summercms/modules/pact" "gorm.io/gorm" ) // TestMergeRequestOptions pins mergeRequestOptions without a database: a // key set in fields.yaml wins over the request's answer, the other answer // keys join; each type is asked once however many fields use it; a field of // a built-in type, a type without RequestOptions and an empty answer keep // their options; an error fails open (the field keeps its fields.yaml // options); the compiled options are never changed and fields never share // a map. func TestMergeRequestOptions(t *testing.T) { calls := 0 shared := map[string]any{"sources": []any{"a", "b"}, "mode": "request"} withOptions := &compiledFieldType{owner: "acme.blog", def: pact.FormFieldType{Name: "picker", RequestOptions: func(context.Context, *gorm.DB) (map[string]any, error) { calls++ return shared, nil }}} failing := &compiledFieldType{owner: "acme.blog", def: pact.FormFieldType{Name: "broken", RequestOptions: func(context.Context, *gorm.DB) (map[string]any, error) { return nil, errors.New("database is down") }}} empty := &compiledFieldType{owner: "acme.blog", def: pact.FormFieldType{Name: "empty", RequestOptions: func(context.Context, *gorm.DB) (map[string]any, error) { return map[string]any{}, nil }}} plain := &compiledFieldType{owner: "acme.blog", def: pact.FormFieldType{Name: "plain"}} compiled := map[string]any{"mode": "yaml", "size": 3} fields := []FormField{ {Name: "one", fieldType: withOptions, TypeOptions: compiled}, {Name: "two", fieldType: withOptions}, {Name: "three", fieldType: failing, TypeOptions: map[string]any{"mode": "yaml"}}, {Name: "four", fieldType: empty, TypeOptions: map[string]any{"size": 1}}, {Name: "five", fieldType: plain, TypeOptions: map[string]any{"size": 2}}, {Name: "six", TypeOptions: nil}, } mergeRequestOptions(context.Background(), nil, fields) if calls != 1 { t.Fatalf("RequestOptions asked %d times, want once per type", calls) } if want := map[string]any{"sources": []any{"a", "b"}, "mode": "yaml", "size": 3}; !reflect.DeepEqual(fields[0].TypeOptions, want) { t.Fatalf("field one = %v, want %v (fields.yaml wins)", fields[0].TypeOptions, want) } if want := map[string]any{"sources": []any{"a", "b"}, "mode": "request"}; !reflect.DeepEqual(fields[1].TypeOptions, want) { t.Fatalf("field two = %v, want the answer", fields[1].TypeOptions) } if want := map[string]any{"mode": "yaml"}; !reflect.DeepEqual(fields[2].TypeOptions, want) { t.Fatalf("field three = %v, want its fields.yaml options after the error", fields[2].TypeOptions) } if want := map[string]any{"size": 1}; !reflect.DeepEqual(fields[3].TypeOptions, want) { t.Fatalf("field four = %v", fields[3].TypeOptions) } if want := map[string]any{"size": 2}; !reflect.DeepEqual(fields[4].TypeOptions, want) { t.Fatalf("field five = %v", fields[4].TypeOptions) } if fields[5].TypeOptions != nil { t.Fatalf("a built-in field got options %v", fields[5].TypeOptions) } if want := map[string]any{"mode": "yaml", "size": 3}; !reflect.DeepEqual(compiled, want) { t.Fatalf("the compiled options changed: %v", compiled) } // The two fields of one type hold their own maps and copies of the // answer's values. fields[1].TypeOptions["mode"] = "changed" fields[1].TypeOptions["sources"].([]any)[0] = "z" if fields[0].TypeOptions["mode"] != "yaml" || shared["mode"] != "request" || shared["sources"].([]any)[0] != "a" { t.Fatalf("fields share state: one=%v answer=%v", fields[0].TypeOptions, shared) } } // TestMergeRequestOptionsNoFields pins the empty request: nothing is asked. func TestMergeRequestOptionsNoFields(t *testing.T) { asked := false ft := &compiledFieldType{def: pact.FormFieldType{Name: "picker", RequestOptions: func(context.Context, *gorm.DB) (map[string]any, error) { asked = true return nil, nil }}} _ = ft mergeRequestOptions(context.Background(), nil, nil) mergeRequestOptions(context.Background(), nil, []FormField{}) if asked { t.Fatal("RequestOptions was asked without a field") } }