github.com/MontFerret/ferret@v0.18.0/pkg/runtime/values/array_test.go (about) 1 package values_test 2 3 import ( 4 "context" 5 "encoding/json" 6 "testing" 7 8 "github.com/MontFerret/ferret/pkg/runtime/core" 9 "github.com/MontFerret/ferret/pkg/runtime/values" 10 "github.com/MontFerret/ferret/pkg/runtime/values/types" 11 12 . "github.com/smartystreets/goconvey/convey" 13 ) 14 15 func TestArray(t *testing.T) { 16 Convey("#constructor", t, func() { 17 Convey("Should create an empty array", func() { 18 arr := values.NewArray(10) 19 20 So(arr.Length(), ShouldEqual, 0) 21 }) 22 23 Convey("Should create an array, from passed values", func() { 24 arr := values.NewArrayWith( 25 values.NewInt(1), 26 values.NewInt(2), 27 values.NewInt(3), 28 ) 29 30 So(arr.Length(), ShouldEqual, 3) 31 }) 32 }) 33 34 Convey(".MarshalJSON", t, func() { 35 Convey("Should serialize empty array", func() { 36 arr := values.NewArray(10) 37 marshaled, err := arr.MarshalJSON() 38 39 So(err, ShouldBeNil) 40 41 So(string(marshaled), ShouldEqual, "[]") 42 }) 43 44 Convey("Should serialize full array", func() { 45 arr := values.NewArrayWith( 46 values.NewInt(1), 47 values.NewInt(2), 48 values.NewInt(3), 49 ) 50 marshaled, err := json.Marshal(arr) 51 52 So(err, ShouldBeNil) 53 54 So(string(marshaled), ShouldEqual, "[1,2,3]") 55 }) 56 }) 57 58 Convey(".Type", t, func() { 59 Convey("Should return type", func() { 60 arr := values.NewArray(1) 61 62 So(arr.Type().Equals(types.Array), ShouldBeTrue) 63 }) 64 }) 65 66 Convey(".Unwrap", t, func() { 67 Convey("Should return a an array of unwrapped values", func() { 68 arr := values.NewArrayWith( 69 values.ZeroInt, 70 values.ZeroInt, 71 ) 72 73 for _, val := range arr.Unwrap().([]interface{}) { 74 So(val, ShouldHaveSameTypeAs, 0) 75 } 76 }) 77 }) 78 79 Convey(".String", t, func() { 80 Convey("Should return a string representation ", func() { 81 arr := values.NewArrayWith(values.ZeroInt, values.ZeroInt) 82 83 So(arr.String(), ShouldEqual, "[0,0]") 84 }) 85 }) 86 87 Convey(".Compare", t, func() { 88 Convey("It should return 1 for all non-array and non-object values", func() { 89 arr := values.NewArrayWith(values.ZeroInt, values.ZeroInt) 90 91 So(arr.Compare(values.None), ShouldEqual, 1) 92 So(arr.Compare(values.ZeroInt), ShouldEqual, 1) 93 So(arr.Compare(values.ZeroFloat), ShouldEqual, 1) 94 So(arr.Compare(values.EmptyString), ShouldEqual, 1) 95 }) 96 97 Convey("It should return -1 for all object values", func() { 98 arr := values.NewArrayWith(values.ZeroInt, values.ZeroInt) 99 obj := values.NewObject() 100 101 So(arr.Compare(obj), ShouldEqual, -1) 102 }) 103 104 Convey("It should return 0 when both arrays are empty", func() { 105 arr1 := values.NewArray(1) 106 arr2 := values.NewArray(1) 107 108 So(arr1.Compare(arr2), ShouldEqual, 0) 109 }) 110 111 Convey("It should return 1 when other array is empty", func() { 112 arr1 := values.NewArrayWith(values.ZeroFloat) 113 arr2 := values.NewArray(1) 114 115 So(arr1.Compare(arr2), ShouldEqual, 1) 116 }) 117 118 Convey("It should return 1 when values are bigger", func() { 119 arr1 := values.NewArrayWith(values.NewInt(1)) 120 arr2 := values.NewArrayWith(values.ZeroInt) 121 122 So(arr1.Compare(arr2), ShouldEqual, 1) 123 }) 124 125 Convey("It should return 0 when arrays are equal", func() { 126 Convey("When only simple types are nested", func() { 127 arr1 := values.NewArrayWith( 128 values.NewInt(0), values.NewString("str"), 129 ) 130 arr2 := values.NewArrayWith( 131 values.NewInt(0), values.NewString("str"), 132 ) 133 134 So(arr1.Compare(arr2), ShouldEqual, 0) 135 }) 136 137 Convey("When object and array are nested at the same time", func() { 138 arr1 := values.NewArrayWith( 139 values.NewObjectWith( 140 values.NewObjectProperty("one", values.NewInt(1)), 141 ), 142 values.NewArrayWith( 143 values.NewInt(2), 144 ), 145 ) 146 arr2 := values.NewArrayWith( 147 values.NewObjectWith( 148 values.NewObjectProperty("one", values.NewInt(1)), 149 ), 150 values.NewArrayWith( 151 values.NewInt(2), 152 ), 153 ) 154 155 So(arr1.Compare(arr2), ShouldEqual, 0) 156 }) 157 158 Convey("When only objects are nested", func() { 159 arr1 := values.NewArrayWith( 160 values.NewObjectWith( 161 values.NewObjectProperty("one", values.NewInt(1)), 162 ), 163 ) 164 arr2 := values.NewArrayWith( 165 values.NewObjectWith( 166 values.NewObjectProperty("one", values.NewInt(1)), 167 ), 168 ) 169 170 So(arr1.Compare(arr2), ShouldEqual, 0) 171 }) 172 173 Convey("When only arrays are nested", func() { 174 arr1 := values.NewArrayWith( 175 values.NewArrayWith( 176 values.NewInt(2), 177 ), 178 ) 179 arr2 := values.NewArrayWith( 180 values.NewArrayWith( 181 values.NewInt(2), 182 ), 183 ) 184 185 So(arr1.Compare(arr2), ShouldEqual, 0) 186 }) 187 188 Convey("When simple and complex types at the same time", func() { 189 arr1 := values.NewArrayWith( 190 values.NewInt(0), 191 values.NewObjectWith( 192 values.NewObjectProperty("one", values.NewInt(1)), 193 ), 194 values.NewArrayWith( 195 values.NewInt(2), 196 ), 197 ) 198 arr2 := values.NewArrayWith( 199 values.NewInt(0), 200 values.NewObjectWith( 201 values.NewObjectProperty("one", values.NewInt(1)), 202 ), 203 values.NewArrayWith( 204 values.NewInt(2), 205 ), 206 ) 207 208 So(arr1.Compare(arr2), ShouldEqual, 0) 209 }) 210 211 Convey("When custom complex type", func() { 212 arr1 := values.NewArrayWith( 213 values.NewObjectWith( 214 values.NewObjectProperty( 215 "arr", values.NewArrayWith(values.NewObject()), 216 ), 217 ), 218 ) 219 arr2 := values.NewArrayWith( 220 values.NewObjectWith( 221 values.NewObjectProperty( 222 "arr", values.NewArrayWith(values.NewObject()), 223 ), 224 ), 225 ) 226 227 So(arr1.Compare(arr2), ShouldEqual, 0) 228 }) 229 }) 230 }) 231 232 Convey(".Hash", t, func() { 233 Convey("It should calculate hash of non-empty array", func() { 234 arr := values.NewArrayWith( 235 values.NewInt(1), 236 values.NewInt(2), 237 values.NewInt(3), 238 ) 239 240 h := arr.Hash() 241 242 So(h, ShouldBeGreaterThan, 0) 243 }) 244 245 Convey("It should calculate hash of empty array", func() { 246 arr := values.NewArrayWith() 247 248 h := arr.Hash() 249 250 So(h, ShouldBeGreaterThan, 0) 251 }) 252 253 Convey("Hash sum should be consistent", func() { 254 arr := values.NewArrayWith( 255 values.True, 256 values.NewInt(1), 257 values.NewFloat(1.1), 258 values.NewString("foobar"), 259 values.NewCurrentDateTime(), 260 values.NewArrayWith(values.NewInt(1), values.True), 261 values.NewObjectWith(values.NewObjectProperty("foo", values.NewString("bar"))), 262 ) 263 264 h1 := arr.Hash() 265 h2 := arr.Hash() 266 267 So(h1, ShouldEqual, h2) 268 }) 269 }) 270 271 Convey(".Length", t, func() { 272 Convey("Should return 0 when empty", func() { 273 arr := values.NewArray(1) 274 275 So(arr.Length(), ShouldEqual, 0) 276 }) 277 278 Convey("Should return greater than 0 when not empty", func() { 279 arr := values.NewArrayWith(values.ZeroInt, values.ZeroInt) 280 281 So(arr.Length(), ShouldEqual, 2) 282 }) 283 }) 284 285 Convey(".ForEach", t, func() { 286 Convey("Should iterate over elements", func() { 287 arr := values.NewArrayWith( 288 values.NewInt(1), 289 values.NewInt(2), 290 values.NewInt(3), 291 ) 292 counter := 0 293 294 arr.ForEach(func(value core.Value, idx int) bool { 295 counter++ 296 297 return true 298 }) 299 300 So(counter, ShouldEqual, arr.Length()) 301 }) 302 303 Convey("Should not iterate when empty", func() { 304 arr := values.NewArrayWith() 305 counter := 0 306 307 arr.ForEach(func(value core.Value, idx int) bool { 308 counter++ 309 310 return true 311 }) 312 313 So(counter, ShouldEqual, arr.Length()) 314 }) 315 316 Convey("Should break iteration when false returned", func() { 317 arr := values.NewArrayWith( 318 values.NewInt(1), 319 values.NewInt(2), 320 values.NewInt(3), 321 values.NewInt(4), 322 values.NewInt(5), 323 ) 324 threshold := 3 325 counter := 0 326 327 arr.ForEach(func(value core.Value, idx int) bool { 328 counter++ 329 330 return value.Compare(values.NewInt(threshold)) == -1 331 }) 332 333 So(counter, ShouldEqual, threshold) 334 }) 335 }) 336 337 Convey(".Get", t, func() { 338 Convey("Should return item by index", func() { 339 arr := values.NewArrayWith( 340 values.NewInt(1), 341 values.NewInt(2), 342 values.NewInt(3), 343 values.NewInt(4), 344 values.NewInt(5), 345 ) 346 347 el := arr.Get(1) 348 349 So(el.Compare(values.NewInt(2)), ShouldEqual, 0) 350 }) 351 352 Convey("Should return None when no items", func() { 353 arr := values.NewArrayWith() 354 355 el := arr.Get(1) 356 357 So(el.Compare(values.None), ShouldEqual, 0) 358 }) 359 }) 360 361 Convey(".Set", t, func() { 362 Convey("Should set item by index", func() { 363 arr := values.NewArrayWith(values.ZeroInt) 364 365 err := arr.Set(0, values.NewInt(1)) 366 367 So(err, ShouldBeNil) 368 So(arr.Length(), ShouldEqual, 1) 369 So(arr.Get(0).Compare(values.NewInt(1)), ShouldEqual, 0) 370 }) 371 372 Convey("Should return an error when index is out of bounds", func() { 373 arr := values.NewArray(10) 374 375 err := arr.Set(0, values.NewInt(1)) 376 377 So(err, ShouldNotBeNil) 378 So(arr.Length(), ShouldEqual, 0) 379 }) 380 }) 381 382 Convey(".Push", t, func() { 383 Convey("Should add an item", func() { 384 arr := values.NewArray(10) 385 386 src := []core.Value{ 387 values.ZeroInt, 388 values.ZeroInt, 389 values.ZeroInt, 390 values.ZeroInt, 391 values.ZeroInt, 392 } 393 394 for _, val := range src { 395 arr.Push(val) 396 } 397 398 So(arr.Length(), ShouldEqual, len(src)) 399 }) 400 }) 401 402 Convey(".Slice", t, func() { 403 Convey("Should return a slice", func() { 404 arr := values.NewArrayWith( 405 values.NewInt(0), 406 values.NewInt(1), 407 values.NewInt(2), 408 values.NewInt(3), 409 values.NewInt(4), 410 values.NewInt(5), 411 ) 412 413 s := arr.Slice(0, 1) 414 415 So(s.Length(), ShouldEqual, 1) 416 So(s.Get(0).Compare(values.ZeroInt), ShouldEqual, 0) 417 418 s2 := arr.Slice(2, arr.Length()) 419 420 So(s2.Length(), ShouldEqual, arr.Length()-2) 421 }) 422 }) 423 424 Convey(".Insert", t, func() { 425 Convey("Should insert an item in the middle of an array", func() { 426 arr := values.NewArrayWith( 427 values.NewInt(0), 428 values.NewInt(1), 429 values.NewInt(2), 430 values.NewInt(3), 431 values.NewInt(4), 432 values.NewInt(5), 433 ) 434 435 lenBefore := arr.Length() 436 437 arr.Insert(3, values.NewInt(100)) 438 439 lenAfter := arr.Length() 440 441 So(lenAfter, ShouldBeGreaterThan, lenBefore) 442 So(arr.Get(3), ShouldEqual, 100) 443 }) 444 }) 445 446 Convey(".RemoveAt", t, func() { 447 Convey("Should remove an item from the middle", func() { 448 arr := values.NewArrayWith( 449 values.NewInt(0), 450 values.NewInt(1), 451 values.NewInt(2), 452 values.NewInt(3), 453 values.NewInt(4), 454 values.NewInt(5), 455 ) 456 457 lenBefore := arr.Length() 458 459 arr.RemoveAt(3) 460 461 lenAfter := arr.Length() 462 463 So(lenAfter, ShouldBeLessThan, lenBefore) 464 So(arr.Get(3), ShouldEqual, 4) 465 }) 466 467 Convey("Should remove an item from the end", func() { 468 arr := values.NewArrayWith( 469 values.NewInt(0), 470 values.NewInt(1), 471 values.NewInt(2), 472 values.NewInt(3), 473 values.NewInt(4), 474 values.NewInt(5), 475 ) 476 477 lenBefore := arr.Length() 478 479 arr.RemoveAt(5) 480 481 lenAfter := arr.Length() 482 483 So(lenAfter, ShouldBeLessThan, lenBefore) 484 So(lenAfter, ShouldEqual, 5) 485 So(arr.Get(4), ShouldEqual, 4) 486 }) 487 488 Convey("Should remove an item from the beginning", func() { 489 arr := values.NewArrayWith( 490 values.NewInt(0), 491 values.NewInt(1), 492 values.NewInt(2), 493 values.NewInt(3), 494 values.NewInt(4), 495 values.NewInt(5), 496 ) 497 498 lenBefore := arr.Length() 499 500 arr.RemoveAt(0) 501 502 lenAfter := arr.Length() 503 504 So(lenAfter, ShouldBeLessThan, lenBefore) 505 So(arr.Get(0), ShouldEqual, 1) 506 }) 507 }) 508 509 Convey(".Clone", t, func() { 510 Convey("Cloned array should be equal to source array", func() { 511 arr := values.NewArrayWith( 512 values.NewInt(0), 513 values.NewObjectWith( 514 values.NewObjectProperty("one", values.NewInt(1)), 515 ), 516 values.NewArrayWith( 517 values.NewInt(2), 518 ), 519 ) 520 521 clone := arr.Clone().(*values.Array) 522 523 So(arr.Length(), ShouldEqual, clone.Length()) 524 So(arr.Compare(clone), ShouldEqual, 0) 525 }) 526 527 Convey("Cloned array should be independent of the source array", func() { 528 arr := values.NewArrayWith( 529 values.NewInt(0), 530 values.NewInt(1), 531 values.NewInt(2), 532 values.NewInt(3), 533 values.NewInt(4), 534 values.NewInt(5), 535 ) 536 537 clone := arr.Clone().(*values.Array) 538 539 arr.Push(values.NewInt(6)) 540 541 So(arr.Length(), ShouldNotEqual, clone.Length()) 542 So(arr.Compare(clone), ShouldNotEqual, 0) 543 }) 544 545 Convey("Cloned array must contain copies of the nested objects", func() { 546 arr := values.NewArrayWith( 547 values.NewArrayWith( 548 values.NewInt(0), 549 values.NewInt(1), 550 values.NewInt(2), 551 values.NewInt(3), 552 values.NewInt(4), 553 ), 554 ) 555 556 clone := arr.Clone().(*values.Array) 557 558 nestedInArr := arr.Get(values.NewInt(0)).(*values.Array) 559 nestedInArr.Push(values.NewInt(5)) 560 561 nestedInClone := clone.Get(values.NewInt(0)).(*values.Array) 562 563 So(nestedInArr.Compare(nestedInClone), ShouldNotEqual, 0) 564 }) 565 }) 566 567 Convey(".GetIn", t, func() { 568 569 ctx := context.Background() 570 571 Convey("Should return the same as .Get when input is correct", func() { 572 573 Convey("Should return item by key", func() { 574 key := values.NewInt(0) 575 arr := values.NewArrayWith( 576 values.NewInt(0), 577 ) 578 579 el, err := arr.GetIn(ctx, []core.Value{key}) 580 elGet := arr.Get(key) 581 582 So(err, ShouldBeNil) 583 So(el.Compare(elGet), ShouldEqual, 0) 584 }) 585 586 Convey("Should return None when no items", func() { 587 key := values.NewInt(0) 588 arr := values.NewArray(0) 589 590 el, err := arr.GetIn(ctx, []core.Value{key}) 591 elGet := arr.Get(key) 592 593 So(err, ShouldBeNil) 594 So(el.Compare(elGet), ShouldEqual, 0) 595 }) 596 }) 597 598 Convey("Should error when input is not correct", func() { 599 600 Convey("Should error when path[0] is not an int", func() { 601 arr := values.NewArray(0) 602 path := []core.Value{values.NewString("")} 603 604 el, err := arr.GetIn(ctx, path) 605 606 So(err, ShouldBeError) 607 So(el.Compare(values.None), ShouldEqual, 0) 608 }) 609 610 Convey("Should error when first received item is not a Getter and len(path) > 1", func() { 611 key := values.NewInt(0) 612 arr := values.NewArrayWith( 613 values.NewInt(1), 614 ) 615 path := []core.Value{key, key} 616 617 el, err := arr.GetIn(ctx, path) 618 619 So(err, ShouldBeError) 620 So(el.Compare(values.None), ShouldEqual, 0) 621 }) 622 }) 623 624 Convey("Should return None when len(path) == 0", func() { 625 arr := values.NewArrayWith( 626 values.NewInt(1), 627 ) 628 629 el, err := arr.GetIn(ctx, nil) 630 631 So(err, ShouldBeNil) 632 So(el.Compare(values.None), ShouldEqual, 0) 633 }) 634 635 Convey("Should call the nested Getter", func() { 636 key := values.NewInt(0) 637 arr := values.NewArrayWith( 638 values.NewObjectWith( 639 values.NewObjectProperty("foo", key), 640 ), 641 ) 642 643 el, err := arr.GetIn(ctx, []core.Value{ 644 key, // obj[0] 645 values.NewString("foo"), // obj[0].foo 646 }) 647 648 So(err, ShouldBeNil) 649 So(el.Compare(key), ShouldEqual, 0) 650 }) 651 }) 652 }