Skip to content

Commit

Permalink
Merge pull request #939 from weichou1229/issue-4964
Browse files Browse the repository at this point in the history
fix: fix inconsistent reading DTO JSON marshal and unmarshal
  • Loading branch information
cloudxxx8 authored Oct 24, 2024
2 parents 64c5aa1 + c399d60 commit a4b6201
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 27 deletions.
80 changes: 53 additions & 27 deletions dtos/reading.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ type NullReading struct {
isNull bool // indicate the reading value should be null in the JSON payload
}

func (b BaseReading) IsNull() bool {
return b.isNull
}

func newBaseReading(profileName string, deviceName string, resourceName string, valueType string) BaseReading {
return BaseReading{
Id: uuid.NewString(),
Expand Down Expand Up @@ -548,26 +552,42 @@ func (b BaseReading) marshal(marshal func(any) ([]byte, error)) ([]byte, error)
ObjectValue: nil,
})
}
return marshal(&struct {
reading `json:",inline"`
BinaryReading `json:",inline" validate:"-"`
SimpleReading `json:",inline" validate:"-"`
ObjectReading `json:",inline" validate:"-"`
}{
reading: reading{
Id: b.Id,
Origin: b.Origin,
DeviceName: b.DeviceName,
ResourceName: b.ResourceName,
ProfileName: b.ProfileName,
ValueType: b.ValueType,
Units: b.Units,
Tags: b.Tags,
},
BinaryReading: b.BinaryReading,
SimpleReading: b.SimpleReading,
ObjectReading: b.ObjectReading,
})
r := reading{
Id: b.Id,
Origin: b.Origin,
DeviceName: b.DeviceName,
ResourceName: b.ResourceName,
ProfileName: b.ProfileName,
ValueType: b.ValueType,
Units: b.Units,
Tags: b.Tags,
}
switch b.ValueType {
case common.ValueTypeObject, common.ValueTypeObjectArray:
return marshal(&struct {
reading `json:",inline"`
ObjectReading `json:",inline" validate:"-"`
}{
reading: r,
ObjectReading: b.ObjectReading,
})
case common.ValueTypeBinary:
return marshal(&struct {
reading `json:",inline"`
BinaryReading `json:",inline" validate:"-"`
}{
reading: r,
BinaryReading: b.BinaryReading,
})
default:
return marshal(&struct {
reading `json:",inline"`
SimpleReading `json:",inline" validate:"-"`
}{
reading: r,
SimpleReading: b.SimpleReading,
})
}
}

func (b *BaseReading) UnmarshalJSON(data []byte) error {
Expand Down Expand Up @@ -610,13 +630,19 @@ func (b *BaseReading) Unmarshal(data []byte, unmarshal func([]byte, any) error)
}
b.ObjectReading = aux.ObjectReading

if (aux.ValueType == common.ValueTypeObject || aux.ValueType == common.ValueTypeObjectArray) &&
aux.ObjectValue == nil {
b.isNull = true
} else if aux.ValueType == common.ValueTypeBinary && aux.BinaryValue == nil {
b.isNull = true
} else if aux.Value == nil {
b.isNull = true
switch aux.ValueType {
case common.ValueTypeObject, common.ValueTypeObjectArray:
if aux.ObjectValue == nil {
b.isNull = true
}
case common.ValueTypeBinary:
if aux.BinaryValue == nil {
b.isNull = true
}
default:
if aux.Value == nil {
b.isNull = true
}
}
return nil
}
132 changes: 132 additions & 0 deletions dtos/reading_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package dtos

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -606,3 +607,134 @@ func TestUnmarshalObjectValueError(t *testing.T) {
})
}
}

func TestMarshalObjectReading(t *testing.T) {
tests := []struct {
name string
valueType string
value any
}{
{"Object", common.ValueTypeObject,
map[string]interface{}{
"Attr1": "yyz",
"Attr2": float64(-45),
"Attr3": []any{float64(255), float64(1), float64(0)},
},
},
{"Object Array", common.ValueTypeObjectArray,
[]any{map[string]any{
"Attr1": "yyz",
"Attr2": float64(-45),
"Attr3": []any{float64(255), float64(1), float64(0)},
}},
},
{
"Nil Object value", common.ValueTypeObjectArray, nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reading := newBaseReading(TestDeviceProfileName, TestDeviceName, TestDeviceResourceName, tt.valueType)
if tt.value == nil {
reading.NullReading = NullReading{
isNull: true,
}
} else {
reading.ObjectReading = ObjectReading{
ObjectValue: tt.value,
}
}
data, err := json.Marshal(reading)
require.NoError(t, err)

var res BaseReading
err = json.Unmarshal(data, &res)
require.NoError(t, err)

assert.Equal(t, reading, res)
})
}
}

func TestMarshalBinaryReading(t *testing.T) {
tests := []struct {
name string
value []byte
}{
{"Binary", []byte("HelloWorld")},
{"Nil Binary Value", nil},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var reading BaseReading
if tt.value == nil {
reading = NewNullReading(TestDeviceProfileName, TestDeviceName, TestDeviceResourceName, common.ValueTypeBinary)
} else {
reading = NewBinaryReading(TestDeviceProfileName, TestDeviceName, TestDeviceResourceName, tt.value, "application/json")
}
data, err := json.Marshal(reading)
require.NoError(t, err)

var res BaseReading
err = json.Unmarshal(data, &res)
require.NoError(t, err)

assert.Equal(t, reading, res)
})
}
}

func TestMarshalSimpleReading(t *testing.T) {
tests := []struct {
name string
valueType string
value any
}{
{"Simple Boolean", common.ValueTypeBool, true},
{"Simple String", common.ValueTypeString, "hello"},
{"Simple Uint8", common.ValueTypeUint8, uint8(255)},
{"Simple Uint16", common.ValueTypeUint16, uint16(65535)},
{"Simple Uint32", common.ValueTypeUint32, uint32(4294967295)},
{"Simple uint64", common.ValueTypeUint64, uint64(1234567890987654321)},
{"Simple int8", common.ValueTypeInt8, int8(123)},
{"Simple int16", common.ValueTypeInt16, int16(12345)},
{"Simple int32", common.ValueTypeInt32, int32(1234567890)},
{"Simple int64", common.ValueTypeInt64, int64(1234567890987654321)},
{"Simple Float32", common.ValueTypeFloat32, float32(123.456)},
{"Simple Float64", common.ValueTypeFloat64, float64(123456789.0987654321)},
{"Simple Boolean Array", common.ValueTypeBoolArray, []bool{true, false}},
{"Simple String Array", common.ValueTypeStringArray, []string{"hello", "world"}},
{"Simple Uint8 Array", common.ValueTypeUint8Array, []uint8{123, 21}},
{"Simple Uint16 Array", common.ValueTypeUint16Array, []uint16{12345, 4321}},
{"Simple Uint32 Array", common.ValueTypeUint32Array, []uint32{1234567890, 87654321}},
{"Simple Uint64 Array", common.ValueTypeUint64Array, []uint64{1234567890987654321, 10987654321}},
{"Simple Int8 Array", common.ValueTypeInt8Array, []int8{123, 123}},
{"Simple Int16 Array", common.ValueTypeInt16Array, []int16{12345, 12345}},
{"Simple Int32 Array", common.ValueTypeInt32Array, []int32{1234567890, 1234567890}},
{"Simple Int64 Array", common.ValueTypeInt64Array, []int64{1234567890987654321, 1234567890987654321}},
{"Simple Float32 Array", common.ValueTypeFloat32Array, []float32{123.456, -654.321}},
{"Simple Float64 Array", common.ValueTypeFloat64Array, []float64{123456789.0987654321, -987654321.123456789}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var reading BaseReading
var err error
if tt.value == nil {
reading = NewNullReading(TestDeviceProfileName, TestDeviceName, TestDeviceResourceName, tt.valueType)
} else {
reading, err = NewSimpleReading(TestDeviceProfileName, TestDeviceName, TestDeviceResourceName, tt.valueType, tt.value)
require.NoError(t, err)
}
data, err := json.Marshal(reading)
require.NoError(t, err)

var res BaseReading
err = json.Unmarshal(data, &res)
require.NoError(t, err)

assert.Equal(t, reading, res)
})
}
}

0 comments on commit a4b6201

Please sign in to comment.