1<?php 2 3require_once('test_util.php'); 4 5use Google\Protobuf\Internal\RepeatedField; 6use Google\Protobuf\Internal\GPBType; 7use Foo\TestMessage; 8use Foo\TestMessage\Sub; 9 10class RepeatedFieldTest extends \PHPUnit\Framework\TestCase 11{ 12 13 ######################################################### 14 # Test int32 field. 15 ######################################################### 16 17 public function testInt32() 18 { 19 $arr = new RepeatedField(GPBType::INT32); 20 21 // Test append. 22 $arr[] = MAX_INT32; 23 $this->assertSame(MAX_INT32, $arr[0]); 24 $arr[] = MIN_INT32; 25 $this->assertSame(MIN_INT32, $arr[1]); 26 27 $arr[] = 1.1; 28 $this->assertSame(1, $arr[2]); 29 $arr[] = MAX_INT32_FLOAT; 30 $this->assertSame(MAX_INT32, $arr[3]); 31 $arr[] = MAX_INT32_FLOAT; 32 $this->assertSame(MAX_INT32, $arr[4]); 33 34 $arr[] = '2'; 35 $this->assertSame(2, $arr[5]); 36 $arr[] = '3.1'; 37 $this->assertSame(3, $arr[6]); 38 $arr[] = MAX_INT32_STRING; 39 $this->assertSame(MAX_INT32, $arr[7]); 40 41 $this->assertEquals(8, count($arr)); 42 43 for ($i = 0; $i < count($arr); $i++) { 44 $arr[$i] = 0; 45 $this->assertSame(0, $arr[$i]); 46 } 47 48 // Test set. 49 $arr[0] = MAX_INT32; 50 $this->assertSame(MAX_INT32, $arr[0]); 51 $arr[1] = MIN_INT32; 52 $this->assertSame(MIN_INT32, $arr[1]); 53 54 $arr[2] = 1.1; 55 $this->assertSame(1, $arr[2]); 56 $arr[3] = MAX_INT32_FLOAT; 57 $this->assertSame(MAX_INT32, $arr[3]); 58 $arr[4] = MAX_INT32_FLOAT; 59 $this->assertSame(MAX_INT32, $arr[4]); 60 61 $arr[5] = '2'; 62 $this->assertSame(2, $arr[5]); 63 $arr[6] = '3.1'; 64 $this->assertSame(3, $arr[6]); 65 $arr[7] = MAX_INT32_STRING; 66 $this->assertSame(MAX_INT32, $arr[7]); 67 68 // Test foreach. 69 $arr = new RepeatedField(GPBType::INT32); 70 for ($i = 0; $i < 3; $i++) { 71 $arr[] = $i; 72 } 73 $i = 0; 74 foreach ($arr as $val) { 75 $this->assertSame($i++, $val); 76 } 77 $this->assertSame(3, $i); 78 } 79 80 ######################################################### 81 # Test uint32 field. 82 ######################################################### 83 84 public function testUint32() 85 { 86 $arr = new RepeatedField(GPBType::UINT32); 87 88 // Test append. 89 $arr[] = MAX_UINT32; 90 $this->assertSame(-1, $arr[0]); 91 $arr[] = -1; 92 $this->assertSame(-1, $arr[1]); 93 $arr[] = MIN_UINT32; 94 $this->assertSame(MIN_UINT32, $arr[2]); 95 96 $arr[] = 1.1; 97 $this->assertSame(1, $arr[3]); 98 $arr[] = MAX_UINT32_FLOAT; 99 $this->assertSame(-1, $arr[4]); 100 $arr[] = -1.0; 101 $this->assertSame(-1, $arr[5]); 102 $arr[] = MIN_UINT32_FLOAT; 103 $this->assertSame(MIN_UINT32, $arr[6]); 104 105 $arr[] = '2'; 106 $this->assertSame(2, $arr[7]); 107 $arr[] = '3.1'; 108 $this->assertSame(3, $arr[8]); 109 $arr[] = MAX_UINT32_STRING; 110 $this->assertSame(-1, $arr[9]); 111 $arr[] = '-1.0'; 112 $this->assertSame(-1, $arr[10]); 113 $arr[] = MIN_UINT32_STRING; 114 $this->assertSame(MIN_UINT32, $arr[11]); 115 116 $this->assertEquals(12, count($arr)); 117 118 for ($i = 0; $i < count($arr); $i++) { 119 $arr[$i] = 0; 120 $this->assertSame(0, $arr[$i]); 121 } 122 123 // Test set. 124 $arr[0] = MAX_UINT32; 125 $this->assertSame(-1, $arr[0]); 126 $arr[1] = -1; 127 $this->assertSame(-1, $arr[1]); 128 $arr[2] = MIN_UINT32; 129 $this->assertSame(MIN_UINT32, $arr[2]); 130 131 $arr[3] = 1.1; 132 $this->assertSame(1, $arr[3]); 133 $arr[4] = MAX_UINT32_FLOAT; 134 $this->assertSame(-1, $arr[4]); 135 $arr[5] = -1.0; 136 $this->assertSame(-1, $arr[5]); 137 $arr[6] = MIN_UINT32_FLOAT; 138 $this->assertSame(MIN_UINT32, $arr[6]); 139 140 $arr[7] = '2'; 141 $this->assertSame(2, $arr[7]); 142 $arr[8] = '3.1'; 143 $this->assertSame(3, $arr[8]); 144 $arr[9] = MAX_UINT32_STRING; 145 $this->assertSame(-1, $arr[9]); 146 $arr[10] = '-1.0'; 147 $this->assertSame(-1, $arr[10]); 148 $arr[11] = MIN_UINT32_STRING; 149 $this->assertSame(MIN_UINT32, $arr[11]); 150 } 151 152 ######################################################### 153 # Test int64 field. 154 ######################################################### 155 156 public function testInt64() 157 { 158 $arr = new RepeatedField(GPBType::INT64); 159 160 // Test append. 161 $arr[] = MAX_INT64; 162 $arr[] = MIN_INT64; 163 $arr[] = 1.1; 164 $arr[] = '2'; 165 $arr[] = '3.1'; 166 $arr[] = MAX_INT64_STRING; 167 $arr[] = MIN_INT64_STRING; 168 if (PHP_INT_SIZE == 4) { 169 $this->assertSame(MAX_INT64, $arr[0]); 170 $this->assertSame(MIN_INT64, $arr[1]); 171 $this->assertSame('1', $arr[2]); 172 $this->assertSame('2', $arr[3]); 173 $this->assertSame('3', $arr[4]); 174 $this->assertSame(MAX_INT64_STRING, $arr[5]); 175 $this->assertSame(MIN_INT64_STRING, $arr[6]); 176 } else { 177 $this->assertSame(MAX_INT64, $arr[0]); 178 $this->assertSame(MIN_INT64, $arr[1]); 179 $this->assertSame(1, $arr[2]); 180 $this->assertSame(2, $arr[3]); 181 $this->assertSame(3, $arr[4]); 182 $this->assertSame(MAX_INT64, $arr[5]); 183 $this->assertSame(MIN_INT64, $arr[6]); 184 } 185 186 187 $this->assertEquals(7, count($arr)); 188 189 for ($i = 0; $i < count($arr); $i++) { 190 $arr[$i] = 0; 191 if (PHP_INT_SIZE == 4) { 192 $this->assertSame('0', $arr[$i]); 193 } else { 194 $this->assertSame(0, $arr[$i]); 195 } 196 } 197 198 // Test set. 199 $arr[0] = MAX_INT64; 200 $arr[1] = MIN_INT64; 201 $arr[2] = 1.1; 202 $arr[3] = '2'; 203 $arr[4] = '3.1'; 204 $arr[5] = MAX_INT64_STRING; 205 $arr[6] = MIN_INT64_STRING; 206 207 if (PHP_INT_SIZE == 4) { 208 $this->assertSame(MAX_INT64_STRING, $arr[0]); 209 $this->assertSame(MIN_INT64_STRING, $arr[1]); 210 $this->assertSame('1', $arr[2]); 211 $this->assertSame('2', $arr[3]); 212 $this->assertSame('3', $arr[4]); 213 $this->assertSame(MAX_INT64_STRING, $arr[5]); 214 $this->assertEquals(MIN_INT64_STRING, $arr[6]); 215 } else { 216 $this->assertSame(MAX_INT64, $arr[0]); 217 $this->assertSame(MIN_INT64, $arr[1]); 218 $this->assertSame(1, $arr[2]); 219 $this->assertSame(2, $arr[3]); 220 $this->assertSame(3, $arr[4]); 221 $this->assertSame(MAX_INT64, $arr[5]); 222 $this->assertEquals(MIN_INT64, $arr[6]); 223 } 224 } 225 226 ######################################################### 227 # Test uint64 field. 228 ######################################################### 229 230 public function testUint64() 231 { 232 $arr = new RepeatedField(GPBType::UINT64); 233 234 // Test append. 235 $arr[] = MAX_UINT64; 236 $arr[] = 1.1; 237 $arr[] = '2'; 238 $arr[] = '3.1'; 239 $arr[] = MAX_UINT64_STRING; 240 241 if (PHP_INT_SIZE == 4) { 242 $this->assertSame(MAX_UINT64_STRING, $arr[0]); 243 $this->assertSame('1', $arr[1]); 244 $this->assertSame('2', $arr[2]); 245 $this->assertSame('3', $arr[3]); 246 $this->assertSame(MAX_UINT64_STRING, $arr[4]); 247 } else { 248 $this->assertSame(MAX_UINT64, $arr[0]); 249 $this->assertSame(1, $arr[1]); 250 $this->assertSame(2, $arr[2]); 251 $this->assertSame(3, $arr[3]); 252 $this->assertSame(MAX_UINT64, $arr[4]); 253 $this->assertSame(5, count($arr)); 254 } 255 256 $this->assertSame(5, count($arr)); 257 258 for ($i = 0; $i < count($arr); $i++) { 259 $arr[$i] = 0; 260 if (PHP_INT_SIZE == 4) { 261 $this->assertSame('0', $arr[$i]); 262 } else { 263 $this->assertSame(0, $arr[$i]); 264 } 265 } 266 267 // Test set. 268 $arr[0] = MAX_UINT64; 269 $arr[1] = 1.1; 270 $arr[2] = '2'; 271 $arr[3] = '3.1'; 272 $arr[4] = MAX_UINT64_STRING; 273 274 if (PHP_INT_SIZE == 4) { 275 $this->assertSame(MAX_UINT64_STRING, $arr[0]); 276 $this->assertSame('1', $arr[1]); 277 $this->assertSame('2', $arr[2]); 278 $this->assertSame('3', $arr[3]); 279 $this->assertSame(MAX_UINT64_STRING, $arr[4]); 280 } else { 281 $this->assertSame(MAX_UINT64, $arr[0]); 282 $this->assertSame(1, $arr[1]); 283 $this->assertSame(2, $arr[2]); 284 $this->assertSame(3, $arr[3]); 285 $this->assertSame(MAX_UINT64, $arr[4]); 286 } 287 } 288 289 ######################################################### 290 # Test float field. 291 ######################################################### 292 293 public function testFloat() 294 { 295 $arr = new RepeatedField(GPBType::FLOAT); 296 297 // Test append. 298 $arr[] = 1; 299 $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); 300 301 $arr[] = 1.1; 302 $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); 303 304 $arr[] = '2'; 305 $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); 306 $arr[] = '3.1'; 307 $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); 308 309 $this->assertEquals(4, count($arr)); 310 311 for ($i = 0; $i < count($arr); $i++) { 312 $arr[$i] = 0; 313 $this->assertSame(0.0, $arr[$i]); 314 } 315 316 // Test set. 317 $arr[0] = 1; 318 $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); 319 320 $arr[1] = 1.1; 321 $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); 322 323 $arr[2] = '2'; 324 $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); 325 $arr[3] = '3.1'; 326 $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); 327 } 328 329 ######################################################### 330 # Test double field. 331 ######################################################### 332 333 public function testDouble() 334 { 335 $arr = new RepeatedField(GPBType::DOUBLE); 336 337 // Test append. 338 $arr[] = 1; 339 $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); 340 341 $arr[] = 1.1; 342 $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); 343 344 $arr[] = '2'; 345 $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); 346 $arr[] = '3.1'; 347 $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); 348 349 $this->assertEquals(4, count($arr)); 350 351 for ($i = 0; $i < count($arr); $i++) { 352 $arr[$i] = 0; 353 $this->assertSame(0.0, $arr[$i]); 354 } 355 356 // Test set. 357 $arr[0] = 1; 358 $this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); 359 360 $arr[1] = 1.1; 361 $this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); 362 363 $arr[2] = '2'; 364 $this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); 365 $arr[3] = '3.1'; 366 $this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); 367 } 368 369 ######################################################### 370 # Test bool field. 371 ######################################################### 372 373 public function testBool() 374 { 375 $arr = new RepeatedField(GPBType::BOOL); 376 377 // Test append. 378 $arr[] = true; 379 $this->assertSame(true, $arr[0]); 380 381 $arr[] = -1; 382 $this->assertSame(true, $arr[1]); 383 384 $arr[] = 1.1; 385 $this->assertSame(true, $arr[2]); 386 387 $arr[] = ''; 388 $this->assertSame(false, $arr[3]); 389 390 $this->assertEquals(4, count($arr)); 391 392 for ($i = 0; $i < count($arr); $i++) { 393 $arr[$i] = 0; 394 $this->assertSame(false, $arr[$i]); 395 } 396 397 // Test set. 398 $arr[0] = true; 399 $this->assertSame(true, $arr[0]); 400 401 $arr[1] = -1; 402 $this->assertSame(true, $arr[1]); 403 404 $arr[2] = 1.1; 405 $this->assertSame(true, $arr[2]); 406 407 $arr[3] = ''; 408 $this->assertSame(false, $arr[3]); 409 } 410 411 ######################################################### 412 # Test string field. 413 ######################################################### 414 415 public function testString() 416 { 417 $arr = new RepeatedField(GPBType::STRING); 418 419 // Test append. 420 $arr[] = 'abc'; 421 $this->assertSame('abc', $arr[0]); 422 423 $arr[] = 1; 424 $this->assertSame('1', $arr[1]); 425 426 $arr[] = 1.1; 427 $this->assertSame('1.1', $arr[2]); 428 429 $arr[] = true; 430 $this->assertSame('1', $arr[3]); 431 432 $this->assertEquals(4, count($arr)); 433 434 for ($i = 0; $i < count($arr); $i++) { 435 $arr[$i] = ''; 436 $this->assertSame('', $arr[$i]); 437 } 438 439 // Test set. 440 $arr[0] = 'abc'; 441 $this->assertSame('abc', $arr[0]); 442 443 $arr[1] = 1; 444 $this->assertSame('1', $arr[1]); 445 446 $arr[2] = 1.1; 447 $this->assertSame('1.1', $arr[2]); 448 449 $arr[3] = true; 450 $this->assertSame('1', $arr[3]); 451 } 452 453 ######################################################### 454 # Test message field. 455 ######################################################### 456 457 public function testMessage() 458 { 459 $arr = new RepeatedField(GPBType::MESSAGE, Sub::class); 460 461 // Test append. 462 $sub_m = new Sub(); 463 $sub_m->setA(1); 464 $arr[] = $sub_m; 465 $this->assertSame(1, $arr[0]->getA()); 466 467 $this->assertEquals(1, count($arr)); 468 469 // Test set. 470 $sub_m = new Sub(); 471 $sub_m->setA(2); 472 $arr[0] = $sub_m; 473 $this->assertSame(2, $arr[0]->getA()); 474 475 // Test foreach. 476 $arr = new RepeatedField(GPBType::MESSAGE, Sub::class); 477 for ($i = 0; $i < 3; $i++) { 478 $arr[] = new Sub(); 479 $arr[$i]->setA($i); 480 } 481 $i = 0; 482 foreach ($arr as $val) { 483 $this->assertSame($i++, $val->getA()); 484 } 485 $this->assertSame(3, $i); 486 } 487 488 ######################################################### 489 # Test offset type 490 ######################################################### 491 492 public function testOffset() 493 { 494 $arr = new RepeatedField(GPBType::INT32); 495 $arr[] = 0; 496 497 $arr[0] = 1; 498 $this->assertSame(1, $arr[0]); 499 $this->assertSame(1, count($arr)); 500 501 $arr['0'] = 2; 502 $this->assertSame(2, $arr['0']); 503 $this->assertSame(2, $arr[0]); 504 $this->assertSame(1, count($arr)); 505 506 $arr[0.0] = 3; 507 $this->assertSame(3, $arr[0.0]); 508 $this->assertSame(1, count($arr)); 509 } 510 511 public function testInsertRemoval() 512 { 513 $arr = new RepeatedField(GPBType::INT32); 514 515 $arr[] = 0; 516 $arr[] = 1; 517 $arr[] = 2; 518 $this->assertSame(3, count($arr)); 519 520 unset($arr[2]); 521 $this->assertSame(2, count($arr)); 522 $this->assertSame(0, $arr[0]); 523 $this->assertSame(1, $arr[1]); 524 525 $arr[] = 3; 526 $this->assertSame(3, count($arr)); 527 $this->assertSame(0, $arr[0]); 528 $this->assertSame(1, $arr[1]); 529 $this->assertSame(3, $arr[2]); 530 } 531 532 ######################################################### 533 # Test reference in array 534 ######################################################### 535 536 public function testArrayElementIsReferenceInSetters() 537 { 538 // Bool elements 539 $values = [true]; 540 array_walk($values, function (&$value) {}); 541 $m = new TestMessage(); 542 $m->setRepeatedBool($values); 543 544 // Int32 elements 545 $values = [1]; 546 array_walk($values, function (&$value) {}); 547 $m = new TestMessage(); 548 $m->setRepeatedInt32($values); 549 550 // Double elements 551 $values = [1.0]; 552 array_walk($values, function (&$value) {}); 553 $m = new TestMessage(); 554 $m->setRepeatedDouble($values); 555 556 // String elements 557 $values = ['a']; 558 array_walk($values, function (&$value) {}); 559 $m = new TestMessage(); 560 $m->setRepeatedString($values); 561 562 // Message elements 563 $m = new TestMessage(); 564 $subs = [1, 2]; 565 foreach ($subs as &$sub) { 566 $sub = new Sub(['a' => $sub]); 567 } 568 $m->setRepeatedMessage($subs); 569 } 570 571 ######################################################### 572 # Test memory leak 573 ######################################################### 574 575 public function testCycleLeak() 576 { 577 gc_collect_cycles(); 578 $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); 579 $arr[] = new TestMessage; 580 $arr[0]->SetRepeatedRecursive($arr); 581 582 // Clean up memory before test. 583 gc_collect_cycles(); 584 $start = memory_get_usage(); 585 unset($arr); 586 587 // Explicitly trigger garbage collection. 588 gc_collect_cycles(); 589 590 $end = memory_get_usage(); 591 $this->assertLessThan($start, $end); 592 } 593} 594