github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/tests/models/attributes_test.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2016-2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package models
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"testing"
    25  
    26  	"github.com/e154/smart-home/common/encryptor"
    27  
    28  	"github.com/e154/smart-home/common"
    29  	m "github.com/e154/smart-home/models"
    30  	. "github.com/smartystreets/goconvey/convey"
    31  )
    32  
    33  func TestAttributes(t *testing.T) {
    34  
    35  	const data = `
    36  {
    37    "s": "string",
    38    "d": "e0a342c056b7da409ef11c872e361ace3e72c3849abe51da834fa250b833f40ebe078f0cecef23544338c9",
    39    "p": [42.86754085166162, 74.57289978531306],
    40    "i": 123,
    41    "f": 456.123,
    42    "b": true,
    43    "m": {
    44      "s2": "string",
    45      "i2": 123,
    46      "f2": 456.123,
    47      "b2": true,
    48      "m2": {
    49        "s3": "string",
    50        "i3": 123,
    51        "f3": 456.123,
    52        "b3": true
    53      }
    54    }
    55  }`
    56  	const sourceAttrs = `
    57  {
    58    "ozone": {
    59      "name": "ozone",
    60      "type": "float"
    61    },
    62    "position": {
    63      "name": "position",
    64      "type": "point"
    65    },
    66    "datetime": {
    67      "name": "datetime",
    68      "type": "time"
    69    },
    70    "humidity": {
    71      "name": "humidity",
    72      "type": "float"
    73    },
    74    "attribution": {
    75      "name": "attribution",
    76      "type": "string"
    77    },
    78    "forecast_day1": {
    79      "name": "forecast_day1",
    80      "type": "map",
    81      "value": {
    82        "ozone": {
    83          "name": "ozone",
    84          "type": "float"
    85        },
    86        "datetime": {
    87          "name": "datetime",
    88          "type": "time"
    89        },
    90        "humidity": {
    91          "name": "humidity",
    92          "type": "float"
    93        },
    94        "pressure": {
    95          "name": "pressure",
    96          "type": "float"
    97        },
    98        "visibility": {
    99          "name": "visibility",
   100          "type": "float"
   101        },
   102        "wind_speed": {
   103          "name": "wind_speed",
   104          "type": "float"
   105        },
   106        "temperature": {
   107          "name": "temperature",
   108          "type": "float"
   109        },
   110        "wind_bearing": {
   111          "name": "wind_bearing",
   112          "type": "float"
   113        },
   114        "max_temperature": {
   115          "name": "max_temperature",
   116          "type": "float"
   117        },
   118        "min_temperature": {
   119          "name": "min_temperature",
   120          "type": "float"
   121        }
   122      }
   123    }
   124  }`
   125  	const sourceAttrsValue = `{
   126    "ozone": null,
   127    "position": [42.86754085166162, 74.57289978531306],
   128    "datetime": "2021-04-21T23:20:07.829185+07:00",
   129    "humidity": 78.4,
   130    "attribution": "Weather forecast from met.no, delivered by the Norwegian Meteorological Institute.",
   131    "forecast_day1": {
   132      "ozone": null,
   133      "datetime": "2021-04-22T00:00:00+07:00",
   134      "humidity": 78.4,
   135      "pressure": 1037.8,
   136      "visibility": null,
   137      "wind_speed": 9.72,
   138      "temperature": null,
   139      "wind_bearing": 27.3,
   140      "max_temperature": 5.8,
   141      "min_temperature": -4.2
   142    },
   143    "max_temperature": 5.4,
   144    "min_temperature": -4.2
   145  }`
   146  
   147  	t.Run("deserialize", func(t *testing.T) {
   148  		Convey("deserialize", t, func(ctx C) {
   149  
   150  			obj := map[string]interface{}{}
   151  			err := json.Unmarshal([]byte(data), &obj)
   152  			So(err, ShouldBeNil)
   153  
   154  			var attrs = NetAttr()
   155  			changed, err := attrs.Deserialize(obj)
   156  			So(err, ShouldBeNil)
   157  			So(changed, ShouldEqual, true)
   158  
   159  			data, err := encryptor.Encrypt("foo")
   160  			So(err, ShouldBeNil)
   161  			fmt.Println(data)
   162  
   163  			So(attrs["s"].Value, ShouldEqual, "string")
   164  			So(attrs["s"].String(), ShouldEqual, "string")
   165  			So(attrs["d"].Value, ShouldEqual, "e0a342c056b7da409ef11c872e361ace3e72c3849abe51da834fa250b833f40ebe078f0cecef23544338c9")
   166  			So(attrs["d"].Decrypt(), ShouldEqual, "foo")
   167  			So(attrs["p"].Value, ShouldResemble, []interface{}{42.86754085166162, 74.57289978531306})
   168  			So(attrs["p"].Point().Lat, ShouldEqual, 74.57289978531306)
   169  			So(attrs["p"].Point().Lon, ShouldEqual, 42.86754085166162)
   170  			So(attrs["i"].Value, ShouldEqual, 123)
   171  			So(attrs["i"].Int64(), ShouldEqual, 123)
   172  			So(attrs["f"].Value, ShouldEqual, 456.123)
   173  			So(attrs["f"].Float64(), ShouldEqual, 456.123)
   174  			So(attrs["b"].Value, ShouldEqual, true)
   175  			So(attrs["b"].Bool(), ShouldEqual, true)
   176  			m1 := attrs["m"].Map()
   177  			So(m1, ShouldNotBeNil)
   178  			So(m1["s2"].Value, ShouldEqual, "string")
   179  			So(m1["s2"].String(), ShouldEqual, "string")
   180  			So(m1["i2"].Value, ShouldEqual, 123)
   181  			So(m1["i2"].Int64(), ShouldEqual, 123)
   182  			So(m1["f2"].Value, ShouldEqual, 456.123)
   183  			So(m1["f2"].Float64(), ShouldEqual, 456.123)
   184  			So(m1["b2"].Value, ShouldEqual, true)
   185  			So(m1["b2"].Bool(), ShouldEqual, true)
   186  			m2 := m1["m2"].Map()
   187  			So(m2["s3"].Value, ShouldEqual, "string")
   188  			So(m2["s3"].String(), ShouldEqual, "string")
   189  			So(m2["i3"].Value, ShouldEqual, 123)
   190  			So(m2["i3"].Int64(), ShouldEqual, 123)
   191  			So(m2["f3"].Value, ShouldEqual, 456.123)
   192  			So(m2["f3"].Float64(), ShouldEqual, 456.123)
   193  			So(m2["b3"].Value, ShouldEqual, true)
   194  			So(m2["b3"].Bool(), ShouldEqual, true)
   195  		})
   196  	})
   197  
   198  	t.Run("deserialize from string", func(t *testing.T) {
   199  		Convey("deserialize from string", t, func(ctx C) {
   200  
   201  			attrVal := make(m.AttributeValue)
   202  			err := json.Unmarshal([]byte(sourceAttrsValue), &attrVal)
   203  			So(err, ShouldBeNil)
   204  
   205  			var attrs = make(m.Attributes)
   206  			err = json.Unmarshal([]byte(sourceAttrs), &attrs)
   207  			So(err, ShouldBeNil)
   208  
   209  			changed, err := attrs.Deserialize(attrVal)
   210  			So(err, ShouldBeNil)
   211  			So(changed, ShouldEqual, true)
   212  
   213  			So(attrs["attribution"].Value, ShouldEqual, "Weather forecast from met.no, delivered by the Norwegian Meteorological Institute.")
   214  			So(attrs["ozone"].Value, ShouldBeEmpty)
   215  			So(attrs["position"].Value, ShouldNotBeEmpty)
   216  			So(attrs["position"].Value, ShouldResemble, []interface{}{42.86754085166162, 74.57289978531306})
   217  			So(attrs["datetime"].Value, ShouldEqual, "2021-04-21T23:20:07.829185+07:00")
   218  			So(attrs["humidity"].Value, ShouldEqual, 78.4)
   219  			m := attrs["forecast_day1"].Map()
   220  			So(m["datetime"].Value, ShouldEqual, "2021-04-22T00:00:00+07:00")
   221  			So(m["humidity"].Value, ShouldEqual, 78.4)
   222  			So(m["max_temperature"].Value, ShouldEqual, 5.8)
   223  			So(m["min_temperature"].Value, ShouldEqual, -4.2)
   224  			So(m["pressure"].Value, ShouldEqual, 1037.8)
   225  			So(m["wind_bearing"].Value, ShouldEqual, 27.3)
   226  			So(m["wind_speed"].Value, ShouldEqual, 9.72)
   227  		})
   228  	})
   229  
   230  	t.Run("serialize", func(t *testing.T) {
   231  		Convey("serialize", t, func(ctx C) {
   232  
   233  			obj := map[string]interface{}{}
   234  			err := json.Unmarshal([]byte(data), &obj)
   235  			So(err, ShouldBeNil)
   236  
   237  			var attrs = NetAttr()
   238  			changed, err := attrs.Deserialize(obj)
   239  			So(err, ShouldBeNil)
   240  			So(changed, ShouldEqual, true)
   241  
   242  			s := attrs.Serialize()
   243  			So(s["s"], ShouldEqual, "string")
   244  			So(s["p"], ShouldResemble, []interface{}{42.86754085166162, 74.57289978531306})
   245  			So(s["i"], ShouldEqual, 123)
   246  			So(s["f"], ShouldEqual, 456.123)
   247  			So(s["b"], ShouldEqual, true)
   248  			m1, ok := s["m"].(m.AttributeValue)
   249  			So(ok, ShouldEqual, true)
   250  			So(m1["s2"], ShouldEqual, "string")
   251  			So(m1["i2"], ShouldEqual, 123)
   252  			So(m1["f2"], ShouldEqual, 456.123)
   253  			So(m1["b2"], ShouldEqual, true)
   254  			So(m1["m2"], ShouldNotBeNil)
   255  			m2, ok := m1["m2"].(m.AttributeValue)
   256  			So(ok, ShouldEqual, true)
   257  			So(m2["s3"], ShouldEqual, "string")
   258  			So(m2["i3"], ShouldEqual, 123)
   259  			So(m2["f3"], ShouldEqual, 456.123)
   260  			So(m2["b3"], ShouldEqual, true)
   261  		})
   262  	})
   263  
   264  	t.Run("signature", func(t *testing.T) {
   265  		Convey("signature", t, func(ctx C) {
   266  
   267  			obj := map[string]interface{}{}
   268  			err := json.Unmarshal([]byte(data), &obj)
   269  			So(err, ShouldBeNil)
   270  
   271  			var attrs = NetAttr()
   272  			changed, err := attrs.Deserialize(obj)
   273  			So(err, ShouldBeNil)
   274  			So(changed, ShouldEqual, true)
   275  
   276  			s := attrs.Signature()
   277  			So(s["s"].Name, ShouldEqual, "s")
   278  			So(s["s"].Value, ShouldBeNil)
   279  			So(s["s"].Type, ShouldEqual, common.AttributeString)
   280  			So(s["p"].Name, ShouldEqual, "p")
   281  			So(s["p"].Value, ShouldBeNil)
   282  			So(s["p"].Type, ShouldEqual, common.AttributePoint)
   283  			So(s["i"].Name, ShouldEqual, "i")
   284  			So(s["i"].Value, ShouldBeNil)
   285  			So(s["i"].Type, ShouldEqual, common.AttributeInt)
   286  			So(s["f"].Name, ShouldEqual, "f")
   287  			So(s["f"].Value, ShouldBeNil)
   288  			So(s["f"].Type, ShouldEqual, common.AttributeFloat)
   289  			So(s["b"].Name, ShouldEqual, "b")
   290  			So(s["b"].Value, ShouldBeNil)
   291  			So(s["b"].Type, ShouldEqual, common.AttributeBool)
   292  			So(s["m"].Name, ShouldEqual, "m")
   293  			So(s["m"].Value, ShouldNotBeNil)
   294  			So(s["m"].Type, ShouldEqual, common.AttributeMap)
   295  
   296  			m1 := s["m"].Map()
   297  			So(m1["s2"].Name, ShouldEqual, "s2")
   298  			So(m1["s2"].Value, ShouldBeNil)
   299  			So(m1["s2"].Type, ShouldEqual, common.AttributeString)
   300  			So(m1["i2"].Name, ShouldEqual, "i2")
   301  			So(m1["i2"].Value, ShouldBeNil)
   302  			So(m1["i2"].Type, ShouldEqual, common.AttributeInt)
   303  			So(m1["f2"].Name, ShouldEqual, "f2")
   304  			So(m1["f2"].Value, ShouldBeNil)
   305  			So(m1["f2"].Type, ShouldEqual, common.AttributeFloat)
   306  			So(m1["b2"].Name, ShouldEqual, "b2")
   307  			So(m1["b2"].Value, ShouldBeNil)
   308  			So(m1["b2"].Type, ShouldEqual, common.AttributeBool)
   309  			So(m1["m2"].Name, ShouldEqual, "m2")
   310  			So(m1["m2"].Value, ShouldNotBeNil)
   311  			So(m1["m2"].Type, ShouldEqual, common.AttributeMap)
   312  
   313  			m2 := m1["m2"].Map()
   314  			So(m2["s3"].Name, ShouldEqual, "s3")
   315  			So(m2["s3"].Value, ShouldBeNil)
   316  			So(m2["s3"].Type, ShouldEqual, common.AttributeString)
   317  			So(m2["i3"].Name, ShouldEqual, "i3")
   318  			So(m2["i3"].Value, ShouldBeNil)
   319  			So(m2["i3"].Type, ShouldEqual, common.AttributeInt)
   320  			So(m2["f3"].Name, ShouldEqual, "f3")
   321  			So(m2["f3"].Value, ShouldBeNil)
   322  			So(m2["f3"].Type, ShouldEqual, common.AttributeFloat)
   323  			So(m2["b3"].Name, ShouldEqual, "b3")
   324  			So(m2["b3"].Value, ShouldBeNil)
   325  			So(m2["b3"].Type, ShouldEqual, common.AttributeBool)
   326  		})
   327  	})
   328  
   329  	t.Run("copy", func(t *testing.T) {
   330  		Convey("copy", t, func(ctx C) {
   331  
   332  			obj := map[string]interface{}{}
   333  			err := json.Unmarshal([]byte(data), &obj)
   334  			So(err, ShouldBeNil)
   335  
   336  			var attrs = NetAttr()
   337  			changed, err := attrs.Deserialize(obj)
   338  			So(err, ShouldBeNil)
   339  			So(changed, ShouldEqual, true)
   340  
   341  			cpy := attrs.Copy()
   342  
   343  			So(cpy["s"].Value, ShouldEqual, "string")
   344  			So(cpy["s"].String(), ShouldEqual, "string")
   345  			So(cpy["p"].Value, ShouldResemble, []interface{}{42.86754085166162, 74.57289978531306})
   346  			So(cpy["p"].Point(), ShouldResemble, m.Point{Lon: 42.86754085166162, Lat: 74.57289978531306})
   347  			So(cpy["i"].Value, ShouldEqual, 123)
   348  			So(cpy["i"].Int64(), ShouldEqual, 123)
   349  			So(cpy["f"].Value, ShouldEqual, 456.123)
   350  			So(cpy["f"].Float64(), ShouldEqual, 456.123)
   351  			So(cpy["b"].Value, ShouldEqual, true)
   352  			So(cpy["b"].Bool(), ShouldEqual, true)
   353  			m1 := attrs["m"].Map()
   354  			So(m1, ShouldNotBeNil)
   355  			So(m1["s2"].Value, ShouldEqual, "string")
   356  			So(m1["s2"].String(), ShouldEqual, "string")
   357  			So(m1["i2"].Value, ShouldEqual, 123)
   358  			So(m1["i2"].Int64(), ShouldEqual, 123)
   359  			So(m1["f2"].Value, ShouldEqual, 456.123)
   360  			So(m1["f2"].Float64(), ShouldEqual, 456.123)
   361  			So(m1["b2"].Value, ShouldEqual, true)
   362  			So(m1["b2"].Bool(), ShouldEqual, true)
   363  			m2 := m1["m2"].Map()
   364  			So(m2["s3"].Value, ShouldEqual, "string")
   365  			So(m2["s3"].String(), ShouldEqual, "string")
   366  			So(m2["i3"].Value, ShouldEqual, 123)
   367  			So(m2["i3"].Int64(), ShouldEqual, 123)
   368  			So(m2["f3"].Value, ShouldEqual, 456.123)
   369  			So(m2["f3"].Float64(), ShouldEqual, 456.123)
   370  			So(m2["b3"].Value, ShouldEqual, true)
   371  			So(m2["b3"].Bool(), ShouldEqual, true)
   372  		})
   373  	})
   374  
   375  	t.Run("serialize+copy", func(t *testing.T) {
   376  		Convey("serialize + copy", t, func(ctx C) {
   377  
   378  			obj := map[string]interface{}{}
   379  			err := json.Unmarshal([]byte(data), &obj)
   380  			So(err, ShouldBeNil)
   381  
   382  			var attrs = NetAttr()
   383  			changed, err := attrs.Deserialize(obj)
   384  			So(err, ShouldBeNil)
   385  			So(changed, ShouldEqual, true)
   386  
   387  			attrs.Serialize()
   388  
   389  			cpy := attrs.Copy()
   390  
   391  			So(cpy["s"].Value, ShouldEqual, "string")
   392  			So(cpy["s"].String(), ShouldEqual, "string")
   393  			So(cpy["p"].Value, ShouldResemble, []interface{}{42.86754085166162, 74.57289978531306})
   394  			So(cpy["p"].Point(), ShouldResemble, m.Point{Lon: 42.86754085166162, Lat: 74.57289978531306})
   395  			So(cpy["i"].Value, ShouldEqual, 123)
   396  			So(cpy["i"].Int64(), ShouldEqual, 123)
   397  			So(cpy["f"].Value, ShouldEqual, 456.123)
   398  			So(cpy["f"].Float64(), ShouldEqual, 456.123)
   399  			So(cpy["b"].Value, ShouldEqual, true)
   400  			So(cpy["b"].Bool(), ShouldEqual, true)
   401  			m1 := attrs["m"].Map()
   402  			So(m1, ShouldNotBeNil)
   403  			So(m1["s2"].Value, ShouldEqual, "string")
   404  			So(m1["s2"].String(), ShouldEqual, "string")
   405  			So(m1["i2"].Value, ShouldEqual, 123)
   406  			So(m1["i2"].Int64(), ShouldEqual, 123)
   407  			So(m1["f2"].Value, ShouldEqual, 456.123)
   408  			So(m1["f2"].Float64(), ShouldEqual, 456.123)
   409  			So(m1["b2"].Value, ShouldEqual, true)
   410  			So(m1["b2"].Bool(), ShouldEqual, true)
   411  			m2 := m1["m2"].Map()
   412  			So(m2["s3"].Value, ShouldEqual, "string")
   413  			So(m2["s3"].String(), ShouldEqual, "string")
   414  			So(m2["i3"].Value, ShouldEqual, 123)
   415  			So(m2["i3"].Int64(), ShouldEqual, 123)
   416  			So(m2["f3"].Value, ShouldEqual, 456.123)
   417  			So(m2["f3"].Float64(), ShouldEqual, 456.123)
   418  			So(m2["b3"].Value, ShouldEqual, true)
   419  			So(m2["b3"].Bool(), ShouldEqual, true)
   420  		})
   421  	})
   422  
   423  	t.Run("signature+copy", func(t *testing.T) {
   424  		Convey("signature + copy", t, func(ctx C) {
   425  
   426  			obj := map[string]interface{}{}
   427  			err := json.Unmarshal([]byte(data), &obj)
   428  			So(err, ShouldBeNil)
   429  
   430  			var attrs = NetAttr()
   431  			changed, err := attrs.Deserialize(obj)
   432  			So(err, ShouldBeNil)
   433  			So(changed, ShouldEqual, true)
   434  
   435  			attrs.Signature()
   436  
   437  			cpy := attrs.Copy()
   438  
   439  			So(cpy["s"].Value, ShouldEqual, "string")
   440  			So(cpy["s"].String(), ShouldEqual, "string")
   441  			So(cpy["p"].Value, ShouldResemble, []interface{}{42.86754085166162, 74.57289978531306})
   442  			So(cpy["p"].Point(), ShouldResemble, m.Point{Lon: 42.86754085166162, Lat: 74.57289978531306})
   443  			So(cpy["i"].Value, ShouldEqual, 123)
   444  			So(cpy["i"].Int64(), ShouldEqual, 123)
   445  			So(cpy["f"].Value, ShouldEqual, 456.123)
   446  			So(cpy["f"].Float64(), ShouldEqual, 456.123)
   447  			So(cpy["b"].Value, ShouldEqual, true)
   448  			So(cpy["b"].Bool(), ShouldEqual, true)
   449  			m1 := attrs["m"].Map()
   450  			So(m1, ShouldNotBeNil)
   451  			So(m1["s2"].Value, ShouldEqual, "string")
   452  			So(m1["s2"].String(), ShouldEqual, "string")
   453  			So(m1["i2"].Value, ShouldEqual, 123)
   454  			So(m1["i2"].Int64(), ShouldEqual, 123)
   455  			So(m1["f2"].Value, ShouldEqual, 456.123)
   456  			So(m1["f2"].Float64(), ShouldEqual, 456.123)
   457  			So(m1["b2"].Value, ShouldEqual, true)
   458  			So(m1["b2"].Bool(), ShouldEqual, true)
   459  			m2 := m1["m2"].Map()
   460  			So(m2["s3"].Value, ShouldEqual, "string")
   461  			So(m2["s3"].String(), ShouldEqual, "string")
   462  			So(m2["i3"].Value, ShouldEqual, 123)
   463  			So(m2["i3"].Int64(), ShouldEqual, 123)
   464  			So(m2["f3"].Value, ShouldEqual, 456.123)
   465  			So(m2["f3"].Float64(), ShouldEqual, 456.123)
   466  			So(m2["b3"].Value, ShouldEqual, true)
   467  			So(m2["b3"].Bool(), ShouldEqual, true)
   468  		})
   469  	})
   470  }