diff --git a/CHANGELOG.md b/CHANGELOG.md index 9932d2c..6fe7349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.7] - 2024-02-29 + +### Added + +- Adds support for serialization and deserialization untyped nodes. + ## [1.0.6] - 2024-02-12 ### Changed diff --git a/go.mod b/go.mod index 364e3d1..e82f28c 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.18 require ( github.com/google/uuid v1.6.0 - github.com/microsoft/kiota-abstractions-go v1.5.6 - github.com/stretchr/testify v1.8.4 + github.com/microsoft/kiota-abstractions-go v1.6.0 + github.com/stretchr/testify v1.9.0 ) require ( @@ -15,9 +15,9 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/std-uritemplate/std-uritemplate/go v0.0.50 // indirect - go.opentelemetry.io/otel v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/otel/trace v1.22.0 // indirect + github.com/std-uritemplate/std-uritemplate/go v0.0.55 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 5ca9295..439ed54 100644 --- a/go.sum +++ b/go.sum @@ -14,20 +14,20 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/microsoft/kiota-abstractions-go v1.5.6 h1:3hd1sACWB2B9grv8KG1T8g/gGQ4A8kTLv91OUxHSxkE= -github.com/microsoft/kiota-abstractions-go v1.5.6/go.mod h1:2WX7Oh8V9SAdZ80OGeE53rcbdys54Pd38rAeDUghrpM= +github.com/microsoft/kiota-abstractions-go v1.6.0 h1:qbGBNMU0/o5myKbikCBXJFohVCFrrpx2cO15Rta2WyA= +github.com/microsoft/kiota-abstractions-go v1.6.0/go.mod h1:7YH20ZbRWXGfHSSvdHkdztzgCB9mRdtFx13+hrYIEpo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/std-uritemplate/std-uritemplate/go v0.0.50 h1:LAE6WYRmLlDXPtEzr152BnD/MHxGCKmcp5D2Pw0NvmU= -github.com/std-uritemplate/std-uritemplate/go v0.0.50/go.mod h1:CLZ1543WRCuUQQjK0BvPM4QrG2toY8xNZUm8Vbt7vTc= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +github.com/std-uritemplate/std-uritemplate/go v0.0.55 h1:muSH037g97K7U2f94G9LUuE8tZlJsoSSrPsO9V281WY= +github.com/std-uritemplate/std-uritemplate/go v0.0.55/go.mod h1:rG/bqh/ThY4xE5de7Rap3vaDkYUT76B0GPJ0loYeTTc= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/untyped_test_entity.go b/internal/untyped_test_entity.go new file mode 100644 index 0000000..2fcfc34 --- /dev/null +++ b/internal/untyped_test_entity.go @@ -0,0 +1,176 @@ +package internal + +import ( + absser "github.com/microsoft/kiota-abstractions-go/serialization" +) + +type UntypedTestEntity struct { + additionalData map[string]interface{} + id *string + title *string + location absser.UntypedNodeable + keywords absser.UntypedNodeable + detail absser.UntypedNodeable +} + +type TestUntypedTestEntityable interface { + absser.Parsable + absser.AdditionalDataHolder + GetId() *string + SetId(value *string) + GetTitle() *string + SetTitle(value *string) + GetLocation() absser.UntypedNodeable + SetLocation(value absser.UntypedNodeable) + GetKeywords() absser.UntypedNodeable + SetKeywords(value absser.UntypedNodeable) + GetDetail() absser.UntypedNodeable + SetDetail(value absser.UntypedNodeable) +} + +func NewUntypedTestEntity() *UntypedTestEntity { + return &UntypedTestEntity{ + additionalData: make(map[string]interface{}), + } +} + +func UntypedTestEntityDiscriminator(parseNode absser.ParseNode) (absser.Parsable, error) { + return NewUntypedTestEntity(), nil +} + +func (e *UntypedTestEntity) GetAdditionalData() map[string]interface{} { + return e.additionalData +} +func (e *UntypedTestEntity) SetAdditionalData(value map[string]interface{}) { + e.additionalData = value +} + +func (e *UntypedTestEntity) GetId() *string { + return e.id +} +func (e *UntypedTestEntity) SetId(value *string) { + e.id = value +} + +func (e *UntypedTestEntity) GetTitle() *string { + return e.title +} +func (e *UntypedTestEntity) SetTitle(value *string) { + e.title = value +} + +func (e *UntypedTestEntity) GetLocation() absser.UntypedNodeable { + return e.location +} +func (e *UntypedTestEntity) SetLocation(value absser.UntypedNodeable) { + e.location = value +} + +func (e *UntypedTestEntity) GetKeywords() absser.UntypedNodeable { + return e.keywords +} +func (e *UntypedTestEntity) SetKeywords(value absser.UntypedNodeable) { + e.keywords = value +} + +func (e *UntypedTestEntity) GetDetail() absser.UntypedNodeable { + return e.detail +} +func (e *UntypedTestEntity) SetDetail(value absser.UntypedNodeable) { + e.detail = value +} + +func (e *UntypedTestEntity) GetFieldDeserializers() map[string]func(absser.ParseNode) error { + res := make(map[string]func(absser.ParseNode) error) + res["id"] = func(n absser.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + e.SetId(val) + } + return nil + } + res["title"] = func(n absser.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + e.SetTitle(val) + } + return nil + } + res["location"] = func(n absser.ParseNode) error { + val, err := n.GetObjectValue(absser.CreateUntypedNodeFromDiscriminatorValue) + if err != nil { + return err + } + if val != nil { + e.SetLocation(val.(absser.UntypedNodeable)) + } + return nil + } + res["keywords"] = func(n absser.ParseNode) error { + val, err := n.GetObjectValue(absser.CreateUntypedNodeFromDiscriminatorValue) + if err != nil { + return err + } + if val != nil { + e.SetKeywords(val.(absser.UntypedNodeable)) + } + return nil + } + res["detail"] = func(n absser.ParseNode) error { + val, err := n.GetObjectValue(absser.CreateUntypedNodeFromDiscriminatorValue) + if err != nil { + return err + } + if val != nil { + e.SetDetail(val.(absser.UntypedNodeable)) + } + return nil + } + return res +} + +func (m *UntypedTestEntity) Serialize(writer absser.SerializationWriter) error { + { + err := writer.WriteStringValue("id", m.GetId()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("title", m.GetTitle()) + if err != nil { + return err + } + } + { + err := writer.WriteObjectValue("location", m.GetLocation()) + if err != nil { + return err + } + } + { + err := writer.WriteObjectValue("keywords", m.GetKeywords()) + if err != nil { + return err + } + } + { + err := writer.WriteObjectValue("detail", m.GetDetail()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} diff --git a/json_parse_node.go b/json_parse_node.go index fbab902..18396de 100644 --- a/json_parse_node.go +++ b/json_parse_node.go @@ -8,10 +8,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/google/uuid" "io" "time" + "github.com/google/uuid" + abstractions "github.com/microsoft/kiota-abstractions-go" absser "github.com/microsoft/kiota-abstractions-go/serialization" ) @@ -187,6 +188,62 @@ func (n *JsonParseNode) GetObjectValue(ctor absser.ParsableFactory) (absser.Pars if err != nil { return nil, err } + + _, isUntypedNode := result.(absser.UntypedNodeable) + if isUntypedNode { + switch value := n.value.(type) { + case *bool: + return absser.NewUntypedBoolean(*value), nil + case *string: + return absser.NewUntypedString(*value), nil + case *float32: + return absser.NewUntypedFloat(*value), nil + case *float64: + return absser.NewUntypedDouble(*value), nil + case *int32: + return absser.NewUntypedInteger(*value), nil + case *int64: + return absser.NewUntypedLong(*value), nil + case nil: + return absser.NewUntypedNull(), nil + case map[string]*JsonParseNode: + properties := make(map[string]absser.UntypedNodeable) + for key, value := range value { + parsable, err := value.GetObjectValue(absser.CreateUntypedNodeFromDiscriminatorValue) + if err != nil { + return nil, errors.New("cannot parse object value") + } + if parsable == nil { + parsable = absser.NewUntypedNull() + } + property, ok := parsable.(absser.UntypedNodeable) + if ok { + properties[key] = property + } + } + return absser.NewUntypedObject(properties), nil + case []*JsonParseNode: + collection := make([]absser.UntypedNodeable, len(value)) + for index, node := range value { + parsable, err := node.GetObjectValue(absser.CreateUntypedNodeFromDiscriminatorValue) + if err != nil { + return nil, errors.New("cannot parse object value") + } + if parsable == nil { + parsable = absser.NewUntypedNull() + } + property, ok := parsable.(absser.UntypedNodeable) + if ok { + collection[index] = property + } + + } + return absser.NewUntypedArray(collection), nil + default: + return absser.NewUntypedNode(value), nil + } + } + abstractions.InvokeParsableAction(n.GetOnBeforeAssignFieldValues(), result) properties, ok := n.value.(map[string]*JsonParseNode) fields := result.GetFieldDeserializers() diff --git a/json_parse_node_test.go b/json_parse_node_test.go index 84cd018..952f2f2 100644 --- a/json_parse_node_test.go +++ b/json_parse_node_test.go @@ -222,6 +222,95 @@ func TestThrowErrorOfPrimitiveType(t *testing.T) { assert.Equal(t, "targetType wrong.UUID is not supported", err.Error()) } +func TestUntypedJsonObject(t *testing.T) { + sourceJson := []byte(TestUntypedJson) + parseNode, err := NewJsonParseNode(sourceJson) + if err != nil { + t.Errorf("Error creating parse node: %s", err.Error()) + } + if parseNode == nil { + t.Errorf("Expected parse node to be non-nil") + } + + parsable, err := parseNode.GetObjectValue(internal.UntypedTestEntityDiscriminator) + testEntity := parsable.(*internal.UntypedTestEntity) + assert.Nil(t, err) + assert.NotNil(t, testEntity) + + assert.Equal(t, "5", *testEntity.GetId()) + assert.Equal(t, "Project 101", *testEntity.GetTitle()) + assert.NotNil(t, testEntity.GetLocation()) + assert.NotNil(t, testEntity.GetKeywords()) + assert.Nil(t, testEntity.GetDetail()) + + location := testEntity.GetLocation().(*absser.UntypedObject) + assert.NotNil(t, location) + locationProperties := location.GetValue() + assert.NotNil(t, locationProperties) + + untypedDisplayName := locationProperties["displayName"].(*absser.UntypedString) + assert.Equal(t, "Microsoft Building 92", *untypedDisplayName.GetValue()) + + untypedAddress := locationProperties["address"].(*absser.UntypedObject) + assert.NotNil(t, untypedAddress) + + untypedCount := locationProperties["floorCount"].(*absser.UntypedDouble) + assert.Equal(t, float64(50), *untypedCount.GetValue()) + + untypedBool := locationProperties["hasReception"].(*absser.UntypedBoolean) + assert.Equal(t, true, *untypedBool.GetValue()) + + untypedNull := locationProperties["contact"].(*absser.UntypedNull) + assert.Equal(t, nil, untypedNull.GetValue()) + + untypedArray := testEntity.GetKeywords().(*absser.UntypedArray) + assert.NotNil(t, untypedArray) + assert.Equal(t, 2, len(untypedArray.GetValue())) + + additionalData := testEntity.GetAdditionalData() + assert.NotNil(t, additionalData) +} + +const TestUntypedJson = "{\r\n" + + " \"@odata.context\": \"https://graph.microsoft.com/v1.0/$metadata#sites('contoso.sharepoint.com')/lists('fa631c4d-ac9f-4884-a7f5-13c659d177e3')/items('1')/fields/$entity\",\r\n" + + " \"id\": \"5\",\r\n" + + " \"title\": \"Project 101\",\r\n" + + " \"location\": {\r\n" + + " \"address\": {\r\n" + + " \"city\": \"Redmond\",\r\n" + + " \"postalCode\": \"98052\",\r\n" + + " \"state\": \"Washington\",\r\n" + + " \"street\": \"NE 36th St\"\r\n" + + " },\r\n" + + " \"coordinates\": {\r\n" + + " \"latitude\": 47.641942,\r\n" + + " \"longitude\": -122.127222\r\n" + + " },\r\n" + + " \"displayName\": \"Microsoft Building 92\",\r\n" + + " \"floorCount\": 50,\r\n" + + " \"hasReception\": true,\r\n" + + " \"contact\": null\r\n" + + " },\r\n" + + " \"keywords\": [\r\n" + + " {\r\n" + + " \"created\": \"2023-07-26T10:41:26Z\",\r\n" + + " \"label\": \"Keyword1\",\r\n" + + " \"termGuid\": \"10e9cc83-b5a4-4c8d-8dab-4ada1252dd70\",\r\n" + + " \"wssId\": 6442450942\r\n" + + " },\r\n" + + " {\r\n" + + " \"created\": \"2023-07-26T10:51:26Z\",\r\n" + + " \"label\": \"Keyword2\",\r\n" + + " \"termGuid\": \"2cae6c6a-9bb8-4a78-afff-81b88e735fef\",\r\n" + + " \"wssId\": 6442450943\r\n" + + " }\r\n" + + " ],\r\n" + + " \"detail\": null,\r\n" + + " \"extra\": {\r\n" + + " \"createdDateTime\":\"2024-01-15T00:00:00\\u002B00:00\"\r\n" + + " }\r\n" + + "}" + const FunctionalTestSource = "{" + "\"@odata.context\": \"https://graph.microsoft.com/v1.0/$metadata#users('vincent%40biret365.onmicrosoft.com')/messages\"," + "\"@odata.nextLink\": \"https://graph.microsoft.com/v1.0/users/vincent@biret365.onmicrosoft.com/messages?$skip=10\"," + diff --git a/json_serialization_writer.go b/json_serialization_writer.go index 2da8a7f..f136c08 100644 --- a/json_serialization_writer.go +++ b/json_serialization_writer.go @@ -279,6 +279,72 @@ func (w *JsonSerializationWriter) WriteByteArrayValue(key string, value []byte) func (w *JsonSerializationWriter) WriteObjectValue(key string, item absser.Parsable, additionalValuesToMerge ...absser.Parsable) error { additionalValuesLen := len(additionalValuesToMerge) if item != nil || additionalValuesLen > 0 { + untypedNode, isUntypedNode := item.(absser.UntypedNodeable) + if isUntypedNode { + switch value := untypedNode.(type) { + case *absser.UntypedBoolean: + w.WriteBoolValue(key, value.GetValue()) + return nil + case *absser.UntypedFloat: + w.WriteFloat32Value(key, value.GetValue()) + return nil + case *absser.UntypedDouble: + w.WriteFloat64Value(key, value.GetValue()) + return nil + case *absser.UntypedInteger: + w.WriteInt32Value(key, value.GetValue()) + return nil + case *absser.UntypedLong: + w.WriteInt64Value(key, value.GetValue()) + return nil + case *absser.UntypedNull: + w.WriteNullValue(key) + return nil + case *absser.UntypedString: + w.WriteStringValue(key, value.GetValue()) + return nil + case *absser.UntypedObject: + if key != "" { + w.writePropertyName(key) + } + properties := value.GetValue() + if properties != nil { + w.writeObjectStart() + for objectKey, val := range properties { + err := w.WriteObjectValue(objectKey, val) + if err != nil { + return err + } + } + w.writeObjectEnd() + if key != "" { + w.writePropertySeparator() + } + } + return nil + case *absser.UntypedArray: + if key != "" { + w.writePropertyName(key) + } + values := value.GetValue() + if values != nil { + w.writeArrayStart() + for _, val := range values { + err := w.WriteObjectValue("", val) + if err != nil { + return err + } + w.writePropertySeparator() + } + w.writeArrayEnd() + } + if key != "" { + w.writePropertySeparator() + } + return nil + } + } + if key != "" { w.writePropertyName(key) } @@ -822,6 +888,8 @@ func (w *JsonSerializationWriter) WriteAdditionalData(value map[string]interface err = w.WriteDateOnlyValue(key, value) case absser.DateOnly: err = w.WriteDateOnlyValue(key, &value) + case absser.UntypedNodeable: + err = w.WriteObjectValue(key, value) default: err = w.WriteAnyValue(key, &value) } diff --git a/json_serialization_writer_test.go b/json_serialization_writer_test.go index 57aa683..250fb1e 100644 --- a/json_serialization_writer_test.go +++ b/json_serialization_writer_test.go @@ -316,16 +316,12 @@ func TestShortEscapeSequencesInString(t *testing.T) { expected: []byte(`"\\"`), }, { - input: 0x08, // backspace character - // Until go1.22 is released this will be the more generic \u0008 escape - // code. - expected: []byte(`"\u0008"`), + input: 0x08, // backspace character + expected: []byte(`"\b"`), }, { - input: 0x0c, // form feed character - // Until go1.22 is released this will be the more generic \u000c escape - // code. - expected: []byte(`"\u000c"`), + input: 0x0c, // form feed character + expected: []byte(`"\f"`), }, { input: 0x0a, // line feed character @@ -579,6 +575,79 @@ func TestJsonSerializationWriter(t *testing.T) { assert.Equal(t, 1, countStart) } +func TestWriteUntypedJson(t *testing.T) { + serializer := NewJsonSerializationWriter() + untypedTestEntity := internal.NewUntypedTestEntity() + id := "1" + untypedTestEntity.SetId(&id) + title := "Title" + untypedTestEntity.SetTitle(&title) + + locationProperties := make(map[string]absser.UntypedNodeable) + + addressProperties := make(map[string]absser.UntypedNodeable) + addressProperties["city"] = absser.NewUntypedString("Redmond") + addressProperties["postalCode"] = absser.NewUntypedString("98052") + addressProperties["state"] = absser.NewUntypedString("Washington") + addressProperties["street"] = absser.NewUntypedString("NE 36th St") + + locationProperties["address"] = absser.NewUntypedObject(addressProperties) + + coordinatesProperties := make(map[string]absser.UntypedNodeable) + coordinatesProperties["latitude"] = absser.NewUntypedDouble(47.641942) + coordinatesProperties["longitude"] = absser.NewUntypedDouble(-122.127222) + + locationProperties["coordinates"] = absser.NewUntypedObject(coordinatesProperties) + + locationProperties["displayName"] = absser.NewUntypedString("Microsoft Building 92") + locationProperties["floorCount"] = absser.NewUntypedInteger(int32(50)) + locationProperties["hasReception"] = absser.NewUntypedBoolean(true) + locationProperties["contact"] = absser.NewUntypedNull() + location := absser.NewUntypedObject(locationProperties) + untypedTestEntity.SetLocation(location) + + keywords := make([]absser.UntypedNodeable, 2) + firstKeywordProperties := make(map[string]absser.UntypedNodeable) + firstKeywordProperties["created"] = absser.NewUntypedString("2023-07-26T10:41:26Z") + firstKeywordProperties["label"] = absser.NewUntypedString("Keyword1") + firstKeywordProperties["termGuid"] = absser.NewUntypedString("10e9cc83-b5a4-4c8d-8dab-4ada1252dd70") + firstKeywordProperties["wssId"] = absser.NewUntypedLong(int64(6442450941)) + keywords[0] = absser.NewUntypedObject(firstKeywordProperties) + + secondKeywordProperties := make(map[string]absser.UntypedNodeable) + secondKeywordProperties["created"] = absser.NewUntypedString("2023-07-26T10:51:26Z") + secondKeywordProperties["label"] = absser.NewUntypedString("Keyword2") + secondKeywordProperties["termGuid"] = absser.NewUntypedString("2cae6c6a-9bb8-4a78-afff-81b88e735fef") + secondKeywordProperties["wssId"] = absser.NewUntypedLong(int64(6442450942)) + keywords[1] = absser.NewUntypedObject(secondKeywordProperties) + + untypedKeywordsArray := absser.NewUntypedArray(keywords) + untypedTestEntity.SetKeywords(untypedKeywordsArray) + + extraProperties := make(map[string]absser.UntypedNodeable) + extraProperties["createdDateTime"] = absser.NewUntypedString("2024-01-15T00:00:00+00:00") + extra := absser.NewUntypedObject(extraProperties) + additionalData := make(map[string]interface{}) + additionalData["extra"] = extra + untypedTestEntity.SetAdditionalData(additionalData) + + err := serializer.WriteObjectValue("", untypedTestEntity) + assert.NoError(t, err) + result, err := serializer.GetSerializedContent() + assert.NoError(t, err) + resultString := string(result[:]) + assert.Contains(t, resultString, "\"id\":\"1\",") + assert.Contains(t, resultString, "\"title\":\"Title\",") + assert.Contains(t, resultString, "\"extra\":{\"createdDateTime\":\"2024-01-15T00:00:00+00:00\"}}") + assert.Contains(t, resultString, "\"hasReception\":true") + assert.Contains(t, resultString, "\"keywords\":[") + assert.Contains(t, resultString, "\"wssId\":6442450942") + assert.Contains(t, resultString, "\"hasReception\":true") + assert.Contains(t, resultString, "\"floorCount\":50") + assert.Contains(t, resultString, "\"termGuid\":\"10e9cc83-b5a4-4c8d-8dab-4ada1252dd70\"") + +} + type TestStruct struct { Key string `json:"key"` }