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 }