Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions management/content_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,32 @@ type ContentTypeInput struct {
}

type ContentTypeOptions struct {
Title string `json:"title"`
Publishable bool `json:"bool"`
IsPage bool `json:"is_page"`
Singleton bool `json:"singleton"`
SubTitle []string `json:"sub_title"`
UrlPattern string `json:"url_pattern"`
UrlPrefix string `json:"url_prefix"`
Title string `json:"title"`
Publishable bool `json:"bool"`
IsPage bool `json:"is_page"`
Singleton bool `json:"singleton"`
SubTitle []string `json:"sub_title"`
UrlPattern FlexString `json:"url_pattern"`
UrlPrefix FlexString `json:"url_prefix"`
}

// FlexString unmarshals a JSON value that is either a string or a boolean.
// The Contentstack API returns false (boolean) for string fields that are unset,
// rather than omitting them or returning an empty string.
type FlexString string

func (f *FlexString) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
*f = FlexString(s)
return nil
}
var b bool
if err := json.Unmarshal(data, &b); err == nil {
*f = ""
return nil
}
return fmt.Errorf("FlexString: cannot unmarshal %s into string or bool", data)
}

func (si *StackInstance) ContentTypeCreate(ctx context.Context, input ContentTypeInput) (*ContentType, error) {
Expand Down
124 changes: 124 additions & 0 deletions management/content_type_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package management

import (
"encoding/json"
"testing"
)

func TestFlexString_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
input string
want FlexString
wantErr bool
}{
{
name: "string value",
input: `"/:title"`,
want: "/:title",
},
{
name: "empty string",
input: `""`,
want: "",
},
{
name: "boolean false treated as empty string",
input: `false`,
want: "",
},
{
name: "boolean true treated as empty string",
input: `true`,
want: "",
},
{
name: "number is invalid",
input: `42`,
wantErr: true,
},
{
// JSON null unmarshals into bool as false in Go, so null is treated
// as empty string rather than an error.
name: "null treated as empty string",
input: `null`,
want: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var f FlexString
err := json.Unmarshal([]byte(tt.input), &f)
if (err != nil) != tt.wantErr {
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && f != tt.want {
t.Errorf("UnmarshalJSON() = %q, want %q", f, tt.want)
}
})
}
}

func TestContentTypeOptions_UnmarshalJSON(t *testing.T) {
t.Run("url_pattern and url_prefix as strings", func(t *testing.T) {
input := `{
"title": "My Type",
"is_page": true,
"singleton": false,
"url_pattern": "/:title",
"url_prefix": "/"
}`
var opts ContentTypeOptions
if err := json.Unmarshal([]byte(input), &opts); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if opts.UrlPattern != "/:title" {
t.Errorf("UrlPattern = %q, want %q", opts.UrlPattern, "/:title")
}
if opts.UrlPrefix != "/" {
t.Errorf("UrlPrefix = %q, want %q", opts.UrlPrefix, "/")
}
})

t.Run("url_pattern and url_prefix as boolean false (unset)", func(t *testing.T) {
input := `{
"title": "My Type",
"is_page": false,
"singleton": false,
"url_pattern": false,
"url_prefix": false
}`
var opts ContentTypeOptions
if err := json.Unmarshal([]byte(input), &opts); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if opts.UrlPattern != "" {
t.Errorf("UrlPattern = %q, want empty string", opts.UrlPattern)
}
if opts.UrlPrefix != "" {
t.Errorf("UrlPrefix = %q, want empty string", opts.UrlPrefix)
}
})

t.Run("singleton content type without url fields", func(t *testing.T) {
input := `{
"title": "Header",
"is_page": false,
"singleton": true,
"url_pattern": false,
"url_prefix": false
}`
var opts ContentTypeOptions
if err := json.Unmarshal([]byte(input), &opts); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !opts.Singleton {
t.Error("Singleton = false, want true")
}
if opts.UrlPattern != "" {
t.Errorf("UrlPattern = %q, want empty string", opts.UrlPattern)
}
})
}