1<?php 2 3require_once('test_base.php'); 4require_once('test_util.php'); 5 6use Google\Protobuf\Internal\RepeatedField; 7use Google\Protobuf\Internal\GPBType; 8use Foo\EmptyAnySerialization; 9use Foo\TestInt32Value; 10use Foo\TestStringValue; 11use Foo\TestAny; 12use Foo\TestEnum; 13use Foo\TestLargeFieldNumber; 14use Foo\TestMessage; 15use Foo\TestMessage\Sub; 16use Foo\TestPackedMessage; 17use Foo\TestRandomFieldOrder; 18use Foo\TestUnpackedMessage; 19use Google\Protobuf\Any; 20use Google\Protobuf\DoubleValue; 21use Google\Protobuf\FieldMask; 22use Google\Protobuf\FloatValue; 23use Google\Protobuf\Int32Value; 24use Google\Protobuf\UInt32Value; 25use Google\Protobuf\Int64Value; 26use Google\Protobuf\UInt64Value; 27use Google\Protobuf\BoolValue; 28use Google\Protobuf\StringValue; 29use Google\Protobuf\BytesValue; 30use Google\Protobuf\Value; 31use Google\Protobuf\ListValue; 32use Google\Protobuf\Struct; 33use Google\Protobuf\GPBEmpty; 34 35class DebugInfoTest extends TestBase 36{ 37 public function setUp(): void 38 { 39 if (extension_loaded('protobuf')) { 40 $this->markTestSkipped('__debugInfo is not supported for the protobuf extension'); 41 } 42 } 43 44 public function testVarDumpOutput() 45 { 46 $m = new DoubleValue(); 47 $m->setValue(1.5); 48 var_dump($m); 49 $regex = <<<EOL 50object(Google\Protobuf\DoubleValue)#%s (1) { 51 ["value"]=> 52 float(1.5) 53} 54EOL; 55 $this->expectOutputRegex('/' . sprintf(preg_quote($regex), '\d+') . '/'); 56 } 57 58 public function testTopLevelDoubleValue() 59 { 60 $m = new DoubleValue(); 61 $m->setValue(1.5); 62 $this->assertSame(['value' => 1.5], $m->__debugInfo()); 63 } 64 65 public function testTopLevelFloatValue() 66 { 67 $m = new FloatValue(); 68 $m->setValue(1.5); 69 $this->assertSame(['value' => 1.5], $m->__debugInfo()); 70 } 71 72 public function testTopLevelInt32Value() 73 { 74 $m = new Int32Value(); 75 $m->setValue(1); 76 $this->assertSame(['value' => 1], $m->__debugInfo()); 77 } 78 79 public function testTopLevelUInt32Value() 80 { 81 $m = new UInt32Value(); 82 $m->setValue(1); 83 $this->assertSame(['value' => 1], $m->__debugInfo()); 84 } 85 86 public function testTopLevelInt64Value() 87 { 88 $m = new Int64Value(); 89 $m->setValue(1); 90 $this->assertSame(['value' => '1'], $m->__debugInfo()); 91 } 92 93 public function testTopLevelUInt64Value() 94 { 95 $m = new UInt64Value(); 96 $m->setValue(1); 97 $this->assertSame(['value' => '1'], $m->__debugInfo()); 98 } 99 100 public function testTopLevelStringValue() 101 { 102 $m = new StringValue(); 103 $m->setValue("a"); 104 $this->assertSame(['value' => 'a'], $m->__debugInfo()); 105 } 106 107 public function testTopLevelBoolValue() 108 { 109 $m = new BoolValue(); 110 $m->setValue(true); 111 $this->assertSame(['value' => true], $m->__debugInfo()); 112 } 113 114 public function testTopLevelBytesValue() 115 { 116 $m = new BytesValue(); 117 $m->setValue("a"); 118 $this->assertSame(['value' => 'YQ=='], $m->__debugInfo()); 119 } 120 121 public function testTopLevelLongBytesValue() 122 { 123 $m = new BytesValue(); 124 $data = $this->generateRandomString(12007); 125 $m->setValue($data); 126 $expected = base64_encode($data); 127 $this->assertSame(['value' => $expected], $m->__debugInfo()); 128 } 129 130 public function testJsonEncodeNullSubMessage() 131 { 132 $from = new TestMessage(); 133 $from->setOptionalMessage(null); 134 $data = $from->__debugInfo(); 135 $this->assertEquals([], $data); 136 } 137 138 public function testDuration() 139 { 140 $m = new Google\Protobuf\Duration(); 141 $m->setSeconds(1234); 142 $m->setNanos(999999999); 143 $this->assertEquals([ 144 'seconds' => 1234, 145 'nanos' => 999999999, 146 ], $m->__debugInfo()); 147 } 148 149 public function testTimestamp() 150 { 151 $m = new Google\Protobuf\Timestamp(); 152 $m->setSeconds(946684800); 153 $m->setNanos(123456789); 154 $this->assertEquals([ 155 'seconds' => 946684800, 156 'nanos' => 123456789, 157 ], $m->__debugInfo()); 158 } 159 160 public function testTopLevelValue() 161 { 162 $m = new Value(); 163 $m->setStringValue("a"); 164 $this->assertSame(['stringValue' => 'a'], $m->__debugInfo()); 165 166 $m = new Value(); 167 $m->setNumberValue(1.5); 168 $this->assertSame(['numberValue' => 1.5], $m->__debugInfo()); 169 170 $m = new Value(); 171 $m->setBoolValue(true); 172 $this->assertSame(['boolValue' => true], $m->__debugInfo()); 173 174 $m = new Value(); 175 $m->setNullValue(\Google\Protobuf\NullValue::NULL_VALUE); 176 $this->assertSame(['nullValue' => 0], $m->__debugInfo()); 177 178 $m = new Value(); 179 $struct = new Struct(); 180 $map = $struct->getFields(); 181 $sub = new Value(); 182 $sub->setNumberValue(1.5); 183 $map["a"] = $sub; 184 $m->setStructValue($struct); 185 $this->assertSame(['structValue' => ['a' => 1.5]], $m->__debugInfo()); 186 187 $m = new Value(); 188 $list = new ListValue(); 189 $arr = $list->getValues(); 190 $sub = new Value(); 191 $sub->setNumberValue(1.5); 192 $arr[] = $sub; 193 $m->setListValue($list); 194 $this->assertSame(['listValue' => [1.5]], $m->__debugInfo()); 195 } 196 197 public function testTopLevelListValue() 198 { 199 $m = new ListValue(); 200 $arr = $m->getValues(); 201 $sub = new Value(); 202 $sub->setNumberValue(1.5); 203 $arr[] = $sub; 204 $this->assertSame([1.5], $m->__debugInfo()); 205 } 206 207 public function testEmptyListValue() 208 { 209 $m = new Struct(); 210 $m->setFields(['test' => (new Value())->setListValue(new ListValue())]); 211 $this->assertSame(['test' => []], $m->__debugInfo()); 212 } 213 214 public function testTopLevelStruct() 215 { 216 $m = new Struct(); 217 $map = $m->getFields(); 218 $sub = new Value(); 219 $sub->setNumberValue(1.5); 220 $map["a"] = $sub; 221 $this->assertSame(['a' => 1.5], $m->__debugInfo()); 222 } 223 224 public function testEmptyStruct() 225 { 226 $m = new Struct(); 227 $m->setFields(['test' => (new Value())->setStructValue(new Struct())]); 228 $this->assertSame(['test' => []], $m->__debugInfo()); 229 } 230 231 public function testEmptyValue() 232 { 233 $m = new Value(); 234 $this->assertSame([], $m->__debugInfo()); 235 } 236 237 public function testTopLevelAny() 238 { 239 // Test a normal message. 240 $packed = new TestMessage(); 241 $packed->setOptionalInt32(123); 242 $packed->setOptionalString("abc"); 243 244 $m = new Any(); 245 $m->pack($packed); 246 $expected = [ 247 '@type' => 'type.googleapis.com/foo.TestMessage', 248 'optionalInt32' => 123, 249 'optionalString' => 'abc', 250 ]; 251 $result = $m->__debugInfo(); 252 $this->assertSame($expected, $result); 253 254 // Test a well known message. 255 $packed = new Int32Value(); 256 $packed->setValue(123); 257 258 $m = new Any(); 259 $m->pack($packed); 260 $this->assertSame([ 261 '@type' => 'type.googleapis.com/google.protobuf.Int32Value', 262 'value' => 123 263 ], $m->__debugInfo()); 264 265 // Test an Any message. 266 $outer = new Any(); 267 $outer->pack($m); 268 $this->assertSame([ 269 '@type' => 'type.googleapis.com/google.protobuf.Any', 270 'value' => [ 271 '@type' => 'type.googleapis.com/google.protobuf.Int32Value', 272 'value' => 123 273 ], 274 ], $outer->__debugInfo()); 275 276 // Test a Timestamp message. 277 $packed = new Google\Protobuf\Timestamp(); 278 $packed->setSeconds(946684800); 279 $packed->setNanos(123456789); 280 $m = new Any(); 281 $m->pack($packed); 282 $this->assertSame([ 283 '@type' => 'type.googleapis.com/google.protobuf.Timestamp', 284 'value' => '2000-01-01T00:00:00.123456789Z', 285 ], $m->__debugInfo()); 286 } 287 288 public function testAnyWithDefaultWrapperMessagePacked() 289 { 290 $any = new Any(); 291 $any->pack(new TestInt32Value([ 292 'field' => new Int32Value(['value' => 0]), 293 ])); 294 $this->assertSame( 295 ['@type' => 'type.googleapis.com/foo.TestInt32Value', 'field' => 0], 296 $any->__debugInfo() 297 ); 298 } 299 300 public function testTopLevelFieldMask() 301 { 302 $m = new FieldMask(); 303 $m->setPaths(["foo.bar_baz", "qux"]); 304 $this->assertSame(['paths' => ['foo.bar_baz', 'qux']], $m->__debugInfo()); 305 } 306 307 public function testEmptyAnySerialization() 308 { 309 $m = new EmptyAnySerialization(); 310 311 $any = new Any(); 312 $any->pack($m); 313 314 $data = $any->__debugInfo(); 315 $this->assertEquals(['@type' => 'type.googleapis.com/foo.EmptyAnySerialization'], $data); 316 } 317 318 public function testRepeatedStringValue() 319 { 320 $m = new TestStringValue(); 321 $r = [new StringValue(['value' => 'a'])]; 322 $m->setRepeatedField($r); 323 $this->assertSame(['repeatedField' => ['a']], $m->__debugInfo()); 324 } 325 326 public function testMapStringValue() 327 { 328 $m = new TestStringValue(); 329 $m->mergeFromJsonString("{\"map_field\":{\"1\": \"a\"}}"); 330 $this->assertSame(['mapField' => [1 => 'a']], $m->__debugInfo()); 331 } 332 333 public function testNestedAny() 334 { 335 // Make sure packed message has been created at least once. 336 $m = new TestAny(); 337 $m->mergeFromJsonString( 338 "{\"any\":{\"optionalInt32\": 1, " . 339 "\"@type\":\"type.googleapis.com/foo.TestMessage\", " . 340 "\"optionalInt64\": 2}}"); 341 $this->assertSame([ 342 'any' => [ 343 '@type' => 'type.googleapis.com/foo.TestMessage', 344 'optionalInt32' => 1, 345 'optionalInt64' => '2', 346 ] 347 ], $m->__debugInfo()); 348 } 349 350 public function testEnum() 351 { 352 $m = new TestMessage(); 353 $m->setOneofEnum(TestEnum::ZERO); 354 $this->assertSame(['oneofEnum' => 'ZERO'], $m->__debugInfo()); 355 } 356 357 public function testTopLevelRepeatedField() 358 { 359 $r1 = new RepeatedField(GPBType::class); 360 $r1[] = 'a'; 361 $this->assertSame(['a'], $r1->__debugInfo()); 362 363 $r2 = new RepeatedField(TestMessage::class); 364 $r2[] = new TestMessage(['optional_int32' => -42]); 365 $r2[] = new TestMessage(['optional_int64' => 43]); 366 $this->assertSame([ 367 ['optionalInt32' => -42], 368 ['optionalInt64' => '43'], 369 ], $r2->__debugInfo()); 370 371 $r3 = new RepeatedField(RepeatedField::class); 372 $r3[] = $r1; 373 $r3[] = $r2; 374 375 $this->assertSame([ 376 ['a'], 377 [ 378 ['optionalInt32' => -42], 379 ['optionalInt64' => '43'], 380 ], 381 ], $r3->__debugInfo()); 382 } 383 384 public function testEverything() 385 { 386 $m = new TestMessage([ 387 'optional_int32' => -42, 388 'optional_int64' => -43, 389 'optional_uint32' => 42, 390 'optional_uint64' => 43, 391 'optional_sint32' => -44, 392 'optional_sint64' => -45, 393 'optional_fixed32' => 46, 394 'optional_fixed64' => 47, 395 'optional_sfixed32' => -46, 396 'optional_sfixed64' => -47, 397 'optional_float' => 1.5, 398 'optional_double' => 1.6, 399 'optional_bool' => true, 400 'optional_string' => 'a', 401 'optional_bytes' => 'bbbb', 402 'optional_enum' => TestEnum::ONE, 403 'optional_message' => new Sub([ 404 'a' => 33 405 ]), 406 'repeated_int32' => [-42, -52], 407 'repeated_int64' => [-43, -53], 408 'repeated_uint32' => [42, 52], 409 'repeated_uint64' => [43, 53], 410 'repeated_sint32' => [-44, -54], 411 'repeated_sint64' => [-45, -55], 412 'repeated_fixed32' => [46, 56], 413 'repeated_fixed64' => [47, 57], 414 'repeated_sfixed32' => [-46, -56], 415 'repeated_sfixed64' => [-47, -57], 416 'repeated_float' => [1.5, 2.5], 417 'repeated_double' => [1.6, 2.6], 418 'repeated_bool' => [true, false], 419 'repeated_string' => ['a', 'c'], 420 'repeated_bytes' => ['bbbb', 'dddd'], 421 'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE], 422 'repeated_message' => [new Sub(['a' => 34]), 423 new Sub(['a' => 35])], 424 'map_int32_int32' => [-62 => -62], 425 'map_int64_int64' => [-63 => -63], 426 'map_uint32_uint32' => [62 => 62], 427 'map_uint64_uint64' => [63 => 63], 428 'map_sint32_sint32' => [-64 => -64], 429 'map_sint64_sint64' => [-65 => -65], 430 'map_fixed32_fixed32' => [66 => 66], 431 'map_fixed64_fixed64' => [67 => 67], 432 'map_sfixed32_sfixed32' => [-68 => -68], 433 'map_sfixed64_sfixed64' => [-69 => -69], 434 'map_int32_float' => [1 => 3.5], 435 'map_int32_double' => [1 => 3.6], 436 'map_bool_bool' => [true => true], 437 'map_string_string' => ['e' => 'e'], 438 'map_int32_bytes' => [1 => 'ffff'], 439 'map_int32_enum' => [1 => TestEnum::ONE], 440 'map_int32_message' => [1 => new Sub(['a' => 36])], 441 ]); 442 443 $this->assertSame([ 444 'optionalInt32' => -42, 445 'optionalInt64' => '-43', 446 'optionalUint32' => 42, 447 'optionalUint64' => '43', 448 'optionalSint32' => -44, 449 'optionalSint64' => '-45', 450 'optionalFixed32' => 46, 451 'optionalFixed64' => '47', 452 'optionalSfixed32' => -46, 453 'optionalSfixed64' => '-47', 454 'optionalFloat' => 1.5, 455 'optionalDouble' => 1.6, 456 'optionalBool' => true, 457 'optionalString' => 'a', 458 'optionalBytes' => 'YmJiYg==', 459 'optionalEnum' => 'ONE', 460 'optionalMessage' => [ 461 'a' => 33, 462 ], 463 'repeatedInt32' => [ 464 -42, 465 -52, 466 ], 467 'repeatedInt64' => [ 468 '-43', 469 '-53', 470 ], 471 'repeatedUint32' => [ 472 42, 473 52, 474 ], 475 'repeatedUint64' => [ 476 '43', 477 '53', 478 ], 479 'repeatedSint32' => [ 480 -44, 481 -54, 482 ], 483 'repeatedSint64' => [ 484 '-45', 485 '-55', 486 ], 487 'repeatedFixed32' => [ 488 46, 489 56, 490 ], 491 'repeatedFixed64' => [ 492 '47', 493 '57', 494 ], 495 'repeatedSfixed32' => [ 496 -46, 497 -56, 498 ], 499 'repeatedSfixed64' => [ 500 '-47', 501 '-57', 502 ], 503 'repeatedFloat' => [ 504 1.5, 505 2.5, 506 ], 507 'repeatedDouble' => [ 508 1.6, 509 2.6, 510 ], 511 'repeatedBool' => [ 512 true, 513 false, 514 ], 515 'repeatedString' => [ 516 'a', 517 'c', 518 ], 519 'repeatedBytes' => [ 520 'YmJiYg==', 521 'ZGRkZA==', 522 ], 523 'repeatedEnum' => [ 524 'ZERO', 525 'ONE', 526 ], 527 'repeatedMessage' => [ 528 [ 529 'a' => 34, 530 ], 531 [ 532 'a' => 35, 533 ], 534 ], 535 'mapInt32Int32' => [ 536 -62 => -62, 537 ], 538 'mapInt64Int64' => [ 539 -63 => '-63', 540 ], 541 'mapUint32Uint32' => [ 542 62 => 62, 543 ], 544 'mapUint64Uint64' => [ 545 63 => '63', 546 ], 547 'mapSint32Sint32' => [ 548 -64 => -64, 549 ], 550 'mapSint64Sint64' => [ 551 -65 => '-65', 552 ], 553 'mapFixed32Fixed32' => [ 554 66 => 66, 555 ], 556 'mapFixed64Fixed64' => [ 557 67 => '67', 558 ], 559 'mapSfixed32Sfixed32' => [ 560 -68 => -68, 561 ], 562 'mapSfixed64Sfixed64' => [ 563 -69 => '-69', 564 ], 565 'mapInt32Float' => [ 566 1 => 3.5, 567 ], 568 'mapInt32Double' => [ 569 1 => 3.6, 570 ], 571 'mapBoolBool' => [ 572 'true' => true, 573 ], 574 'mapStringString' => [ 575 'e' => 'e', 576 ], 577 'mapInt32Bytes' => [ 578 1 => 'ZmZmZg==', 579 ], 580 'mapInt32Enum' => [ 581 1 => 'ONE', 582 ], 583 'mapInt32Message' => [ 584 1 => ['a' => 36], 585 ], 586 ], $m->__debugInfo()); 587 } 588 589 private function generateRandomString($length = 10) 590 { 591 $randomString = str_repeat("+", $length); 592 for ($i = 0; $i < $length; $i++) { 593 $randomString[$i] = chr(rand(0, 255)); 594 } 595 return $randomString; 596 } 597} 598