From ccd3edac2c8d976a2bc29db9c712ab30d2b45ea6 Mon Sep 17 00:00:00 2001 From: fbuedding <100070891+fbuedding@users.noreply.github.com> Date: Sat, 30 Mar 2024 11:59:15 +0100 Subject: [PATCH] Added custom marshaller for StaticAttribute, so that it handles json and int which are in a string. This is due iot-agent-node-lib not parsing strings --- iota-types.go | 72 +++++++++++++++++++++++++++ iota-types_test.go | 120 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) diff --git a/iota-types.go b/iota-types.go index 7e4a77b..8208f7a 100644 --- a/iota-types.go +++ b/iota-types.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "strings" "time" @@ -181,6 +182,77 @@ func (d *Device) MarshalJSON() ([]byte, error) { } } +func (sa *StaticAttribute) MarshalJSON() ([]byte, error) { + type Alias StaticAttribute + switch v := sa.Value.(type) { + // Logic for checken if it is indead a string + // first we check if its valid json + // then we check if its a number + // then we just assume its a string + case string: + valid := json.Valid([]byte(v)) + if valid { + var tmp any + err := json.Unmarshal([]byte(v), &tmp) + if err != nil { + return nil, fmt.Errorf("Unexpected error while marshalling static attribute value: %v json", v) + } + + return json.Marshal(&struct { + Value any `json:"value" form:"value"` + *Alias + }{ + Value: tmp, + Alias: (*Alias)(sa), + }) + } + f, err := strconv.ParseFloat(v, 64) + if err == nil { + return json.Marshal(&struct { + Value float64 `json:"value" form:"value"` + *Alias + }{ + Value: f, + Alias: (*Alias)(sa), + }) + } + i, err := strconv.ParseInt(v, 10, 64) + if err == nil { + return json.Marshal(&struct { + Value int64 `json:"value" form:"value"` + *Alias + }{ + Value: i, + Alias: (*Alias)(sa), + }) + } + b, err := strconv.ParseBool(v) + if err == nil { + return json.Marshal(&struct { + Value bool `json:"value" form:"value"` + *Alias + }{ + Value: b, + Alias: (*Alias)(sa), + }) + } + return json.Marshal(&struct { + Value string `json:"value" form:"value"` + *Alias + }{ + Value: v, + Alias: (*Alias)(sa), + }) + } + // Any other case just default marshalling + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(sa), + }) + +} + type MissingFields struct { Fields vector.StringVector Message string diff --git a/iota-types_test.go b/iota-types_test.go index 4f103b4..f01fc6f 100644 --- a/iota-types_test.go +++ b/iota-types_test.go @@ -250,3 +250,123 @@ func TestDevice_MarshalJSON(t *testing.T) { }) } } + +func TestStaticAttribute_MarshalJSON(t *testing.T) { + type fields struct { + ObjectID string + Name string + Type string + Value any + Metadata map[string]Metadata + } + tests := []struct { + name string + fields fields + want []byte + wantErr bool + }{ + { + name: "Test object", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: `{"test":1}`, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"value":{"test":1},"name":"","type":""}`), + wantErr: false, + }, + { + name: "Test array", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: `[1,2,3,4]`, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"value":[1,2,3,4],"name":"","type":""}`), + wantErr: false, + }, + { + name: "Test float", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: `1.23543`, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"value":1.23543,"name":"","type":""}`), + wantErr: false, + }, + { + name: "Test int", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: `1`, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"value":1,"name":"","type":""}`), + wantErr: false, + }, + { + name: "Test bool", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: `True`, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"value":true,"name":"","type":""}`), + wantErr: false, + }, + { + name: "Test string", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: `string`, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"value":"string","name":"","type":""}`), + wantErr: false, + }, + { + name: "Test int as input", + fields: fields{ + ObjectID: "", + Name: "", + Type: "", + Value: 1, + Metadata: map[string]Metadata{}, + }, + want: []byte(`{"name":"","type":"","value":1}`), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sa := &StaticAttribute{ + ObjectID: tt.fields.ObjectID, + Name: tt.fields.Name, + Type: tt.fields.Type, + Value: tt.fields.Value, + Metadata: tt.fields.Metadata, + } + got, err := sa.MarshalJSON() + if (err != nil) != tt.wantErr { + t.Errorf("StaticAttribute.MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("StaticAttribute.MarshalJSON() = %v, want %v", string(got), string(tt.want)) + } + }) + } +}