xref: /aosp_15_r20/external/cronet/third_party/protobuf/php/tests/PhpImplementationTest.php (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1<?php
2
3require_once('test_base.php');
4require_once('test_util.php');
5
6use Foo\TestEnum;
7use Foo\TestMessage;
8use Foo\TestMessage\Sub;
9use Foo\TestPackedMessage;
10use Google\Protobuf\Internal\CodedInputStream;
11use Google\Protobuf\Internal\FileDescriptorSet;
12use Google\Protobuf\Internal\GPBLabel;
13use Google\Protobuf\Internal\GPBType;
14use Google\Protobuf\Internal\GPBWire;
15use Google\Protobuf\Internal\CodedOutputStream;
16
17/**
18 * Please note, this test is only intended to be run without the protobuf C
19 * extension.
20 */
21class PhpImplementationTest extends TestBase
22{
23    /**
24     * Avoid calling setUp, which has void return type (not avalialbe in php7.0).
25     * @before
26     */
27    public function skipTestsForExtension()
28    {
29        if (extension_loaded('protobuf')) {
30            $this->markTestSkipped();
31        }
32    }
33
34    public function testReadInt32()
35    {
36        $value = null;
37
38        // Positive number.
39        $input = new CodedInputStream(hex2bin("01"));
40        GPBWire::readInt32($input, $value);
41        $this->assertSame(1, $value);
42
43        // Negative number.
44        $input = new CodedInputStream(hex2bin("ffffffff0f"));
45        GPBWire::readInt32($input, $value);
46        $this->assertSame(-1, $value);
47
48        // Discard overflow bits.
49        $input = new CodedInputStream(hex2bin("ffffffff7f"));
50        GPBWire::readInt32($input, $value);
51        $this->assertSame(-1, $value);
52    }
53
54    public function testReadUint32()
55    {
56        $value = null;
57
58        // Positive number.
59        $input = new CodedInputStream(hex2bin("01"));
60        GPBWire::readUint32($input, $value);
61        $this->assertSame(1, $value);
62
63        // Max uint32.
64        $input = new CodedInputStream(hex2bin("ffffffff0f"));
65        GPBWire::readUint32($input, $value);
66        $this->assertSame(-1, $value);
67
68        // Discard overflow bits.
69        $input = new CodedInputStream(hex2bin("ffffffff7f"));
70        GPBWire::readUint32($input, $value);
71        $this->assertSame(-1, $value);
72    }
73
74    public function testReadInt64()
75    {
76        $value = null;
77
78        // Positive number.
79        $input = new CodedInputStream(hex2bin("01"));
80        GPBWire::readInt64($input, $value);
81        $this->assertEquals(1, $value);
82
83        // Negative number.
84        $input = new CodedInputStream(hex2bin("ffffffffffffffffff01"));
85        GPBWire::readInt64($input, $value);
86        $this->assertEquals(-1, $value);
87
88        // Discard overflow bits.
89        $input = new CodedInputStream(hex2bin("ffffffffffffffffff0f"));
90        GPBWire::readInt64($input, $value);
91        $this->assertEquals(-1, $value);
92    }
93
94    public function testReadUint64()
95    {
96        $value = null;
97
98        // Positive number.
99        $input = new CodedInputStream(hex2bin("01"));
100        GPBWire::readUint64($input, $value);
101        $this->assertEquals(1, $value);
102
103        // Negative number.
104        $input = new CodedInputStream(hex2bin("FFFFFFFFFFFFFFFFFF01"));
105        GPBWire::readUint64($input, $value);
106        $this->assertEquals(-1, $value);
107
108        // Discard overflow bits.
109        $input = new CodedInputStream(hex2bin("FFFFFFFFFFFFFFFFFF0F"));
110        GPBWire::readUint64($input, $value);
111        $this->assertEquals(-1, $value);
112    }
113
114    public function testReadSint32()
115    {
116        $value = null;
117
118        $input = new CodedInputStream(hex2bin("00"));
119        GPBWire::readSint32($input, $value);
120        $this->assertSame(0, $value);
121
122        $input = new CodedInputStream(hex2bin("01"));
123        GPBWire::readSint32($input, $value);
124        $this->assertSame(-1, $value);
125
126        $input = new CodedInputStream(hex2bin("02"));
127        GPBWire::readSint32($input, $value);
128        $this->assertSame(1, $value);
129    }
130
131    public function testReadSint64()
132    {
133        $value = null;
134
135        $input = new CodedInputStream(hex2bin("00"));
136        GPBWire::readSint64($input, $value);
137        $this->assertEquals(0, $value);
138
139        $input = new CodedInputStream(hex2bin("01"));
140        GPBWire::readSint64($input, $value);
141        $this->assertEquals(-1, $value);
142
143        $input = new CodedInputStream(hex2bin("02"));
144        GPBWire::readSint64($input, $value);
145        $this->assertEquals(1, $value);
146    }
147
148    public function testReadFixed32()
149    {
150        $value = null;
151        $input = new CodedInputStream(hex2bin("12345678"));
152        GPBWire::readFixed32($input, $value);
153        $this->assertSame(0x78563412, $value);
154    }
155
156    public function testReadFixed64()
157    {
158        $value = null;
159        $input = new CodedInputStream(hex2bin("1234567812345678"));
160        GPBWire::readFixed64($input, $value);
161        if (PHP_INT_SIZE == 4) {
162            $this->assertSame("8671175386481439762", $value);
163        } else {
164            $this->assertSame(0x7856341278563412, $value);
165        }
166    }
167
168    public function testReadSfixed32()
169    {
170        $value = null;
171        $input = new CodedInputStream(hex2bin("12345678"));
172        GPBWire::readSfixed32($input, $value);
173        $this->assertSame(0x78563412, $value);
174    }
175
176    public function testReadFloat()
177    {
178        $value = null;
179        $input = new CodedInputStream(hex2bin("0000803F"));
180        GPBWire::readFloat($input, $value);
181        $this->assertSame(1.0, $value);
182    }
183
184    public function testReadBool()
185    {
186        $value = null;
187
188        $input = new CodedInputStream(hex2bin("00"));
189        GPBWire::readBool($input, $value);
190        $this->assertSame(false, $value);
191
192        $input = new CodedInputStream(hex2bin("01"));
193        GPBWire::readBool($input, $value);
194        $this->assertSame(true, $value);
195    }
196
197    public function testReadDouble()
198    {
199        $value = null;
200        $input = new CodedInputStream(hex2bin("000000000000F03F"));
201        GPBWire::readDouble($input, $value);
202        $this->assertSame(1.0, $value);
203    }
204
205    public function testReadSfixed64()
206    {
207        $value = null;
208        $input = new CodedInputStream(hex2bin("1234567812345678"));
209        GPBWire::readSfixed64($input, $value);
210        if (PHP_INT_SIZE == 4) {
211            $this->assertSame("8671175386481439762", $value);
212        } else {
213            $this->assertSame(0x7856341278563412, $value);
214        }
215    }
216
217    public function testZigZagEncodeDecode()
218    {
219        $this->assertSame(0, GPBWire::zigZagEncode32(0));
220        $this->assertSame(1, GPBWire::zigZagEncode32(-1));
221        $this->assertSame(2, GPBWire::zigZagEncode32(1));
222        $this->assertSame(3, GPBWire::zigZagEncode32(-2));
223        $this->assertSame(0x7FFFFFFE, GPBWire::zigZagEncode32(0x3FFFFFFF));
224        $this->assertSame(0x7FFFFFFF, GPBWire::zigZagEncode32(0xC0000000));
225        $this->assertSame(0x7FFFFFFF, GPBWire::zigZagEncode32(-1073741824));
226
227        $this->assertSame(0,  GPBWire::zigZagDecode32(0));
228        $this->assertSame(-1, GPBWire::zigZagDecode32(1));
229        $this->assertSame(1,  GPBWire::zigZagDecode32(2));
230        $this->assertSame(-2, GPBWire::zigZagDecode32(3));
231        $this->assertSame(0x3FFFFFFF,  GPBWire::zigZagDecode32(0x7FFFFFFE));
232        $this->assertSame(-1073741824, GPBWire::zigZagDecode32(0x7FFFFFFF));
233        $this->assertSame(0x7FFFFFFF,  GPBWire::zigZagDecode32(0xFFFFFFFE));
234        $this->assertSame((int)-2147483648,GPBWire::zigZagDecode32(0xFFFFFFFF));
235
236        if (PHP_INT_SIZE == 4) {
237            $this->assertSame(-2, GPBWire::zigZagEncode32(0x7FFFFFFF));
238            $this->assertSame(-1, GPBWire::zigZagEncode32(0x80000000));
239            $this->assertSame('0', GPBWire::zigZagEncode64(0));
240            $this->assertSame('1', GPBWire::zigZagEncode64(-1));
241            $this->assertSame('2', GPBWire::zigZagEncode64(1));
242            $this->assertSame('3', GPBWire::zigZagEncode64(-2));
243            $this->assertSame(
244                '2147483646',  // 0x7FFFFFE
245                GPBWire::zigZagEncode64(0x3FFFFFFF));
246            $this->assertSame(
247                '2147483647',  // 0x7FFFFFF
248                GPBWire::zigZagEncode64(-1073741824));  // 0xFFFFFFFFC0000000
249            $this->assertSame(
250                '4294967294',                           // 0xFFFFFFFE
251                GPBWire::zigZagEncode64(2147483647));   // 0x7FFFFFFF
252            $this->assertSame(
253                '4294967295',                           // 0xFFFFFFFF
254                GPBWire::zigZagEncode64(-2147483648));  // 0xFFFFFFFF80000000
255            $this->assertSame(
256                '18446744073709551614',  // 0xFFFFFFFFFFFFFFFE
257                                         // 0x7FFFFFFFFFFFFFFF
258                GPBWire::zigZagEncode64("9223372036854775807"));
259            $this->assertSame(
260                '18446744073709551615',  // 0xFFFFFFFFFFFFFFFF
261                                         // 0x8000000000000000
262                GPBWire::zigZagEncode64("-9223372036854775808"));
263
264            $this->assertSame('0', GPBWire::zigZagDecode64(0));
265            $this->assertSame('-1', GPBWire::zigZagDecode64(1));
266            $this->assertSame('1', GPBWire::zigZagDecode64(2));
267            $this->assertSame('-2', GPBWire::zigZagDecode64(3));
268        } else {
269            $this->assertSame(4294967294, GPBWire::zigZagEncode32(0x7FFFFFFF));
270            $this->assertSame(4294967295, GPBWire::zigZagEncode32(0x80000000));
271            $this->assertSame(0, GPBWire::zigZagEncode64(0));
272            $this->assertSame(1, GPBWire::zigZagEncode64(-1));
273            $this->assertSame(2, GPBWire::zigZagEncode64(1));
274            $this->assertSame(3, GPBWire::zigZagEncode64(-2));
275            $this->assertSame(0x7FFFFFFE, GPBWire::zigZagEncode64(0x3FFFFFFF));
276            $this->assertSame(
277                0x7FFFFFFF,
278                GPBWire::zigZagEncode64(0xFFFFFFFFC0000000));
279            $this->assertSame(
280                0xFFFFFFFE,
281                GPBWire::zigZagEncode64(0x7FFFFFFF));
282            $this->assertSame(
283                0xFFFFFFFF,
284                GPBWire::zigZagEncode64(0xFFFFFFFF80000000));
285            $this->assertSame(
286                -2,  // 0xFFFFFFFFFFFFFFFE
287                GPBWire::zigZagEncode64(0x7FFFFFFFFFFFFFFF));
288            $this->assertSame(
289                -1,  // 0xFFFFFFFFFFFFFFFF
290                GPBWire::zigZagEncode64(0x8000000000000000));
291
292            $this->assertSame(0, GPBWire::zigZagDecode64(0));
293            $this->assertSame(-1, GPBWire::zigZagDecode64(1));
294            $this->assertSame(1, GPBWire::zigZagDecode64(2));
295            $this->assertSame(-2, GPBWire::zigZagDecode64(3));
296        }
297
298        // Round trip
299        $this->assertSame(0, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(0)));
300        $this->assertSame(1, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(1)));
301        $this->assertSame(-1, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(-1)));
302        $this->assertSame(14927,
303                      GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(14927)));
304        $this->assertSame(-3612,
305                      GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(-3612)));
306    }
307
308    public function testDecode()
309    {
310        $m = new TestMessage();
311        $m->mergeFromString(TestUtil::getGoldenTestMessage());
312        TestUtil::assertTestMessage($m);
313
314        $this->assertTrue(true);
315    }
316
317    public function testDescriptorDecode()
318    {
319        $file_desc_set = new FileDescriptorSet();
320        $file_desc_set->mergeFromString(hex2bin(
321            "0a3b0a12746573745f696e636c7564652e70726f746f120362617222180a" .
322            "0b54657374496e636c75646512090a0161180120012805620670726f746f33"));
323
324        $this->assertSame(1, sizeof($file_desc_set->getFile()));
325
326        $file_desc = $file_desc_set->getFile()[0];
327        $this->assertSame("test_include.proto", $file_desc->getName());
328        $this->assertSame("bar", $file_desc->getPackage());
329        $this->assertSame(0, sizeof($file_desc->getDependency()));
330        $this->assertSame(1, sizeof($file_desc->getMessageType()));
331        $this->assertSame(0, sizeof($file_desc->getEnumType()));
332        $this->assertSame("proto3", $file_desc->getSyntax());
333
334        $desc = $file_desc->getMessageType()[0];
335        $this->assertSame("TestInclude", $desc->getName());
336        $this->assertSame(1, sizeof($desc->getField()));
337        $this->assertSame(0, sizeof($desc->getNestedType()));
338        $this->assertSame(0, sizeof($desc->getEnumType()));
339        $this->assertSame(0, sizeof($desc->getOneofDecl()));
340
341        $field = $desc->getField()[0];
342        $this->assertSame("a", $field->getName());
343        $this->assertSame(1, $field->getNumber());
344        $this->assertSame(GPBLabel::OPTIONAL, $field->getLabel());
345        $this->assertSame(GPBType::INT32, $field->getType());
346    }
347
348    public function testReadVarint64()
349    {
350        $var = 0;
351
352        // Empty buffer.
353        $input = new CodedInputStream(hex2bin(''));
354        $this->assertFalse($input->readVarint64($var));
355
356        // The largest varint is 10 bytes long.
357        $input = new CodedInputStream(hex2bin('8080808080808080808001'));
358        $this->assertFalse($input->readVarint64($var));
359
360        // Corrupted varint.
361        $input = new CodedInputStream(hex2bin('808080'));
362        $this->assertFalse($input->readVarint64($var));
363
364        // Normal case.
365        $input = new CodedInputStream(hex2bin('808001'));
366        $this->assertTrue($input->readVarint64($var));
367        if (PHP_INT_SIZE == 4) {
368            $this->assertSame('16384', $var);
369        } else {
370            $this->assertSame(16384, $var);
371        }
372        $this->assertFalse($input->readVarint64($var));
373
374        // Read two varint.
375        $input = new CodedInputStream(hex2bin('808001808002'));
376        $this->assertTrue($input->readVarint64($var));
377        if (PHP_INT_SIZE == 4) {
378            $this->assertSame('16384', $var);
379        } else {
380            $this->assertSame(16384, $var);
381        }
382        $this->assertTrue($input->readVarint64($var));
383        if (PHP_INT_SIZE == 4) {
384            $this->assertSame('32768', $var);
385        } else {
386            $this->assertSame(32768, $var);
387        }
388        $this->assertFalse($input->readVarint64($var));
389
390        // Read 64 testing
391        $testVals = array(
392            '10'                 => '0a000000000000000000',
393            '100'                => '64000000000000000000',
394            '800'                => 'a0060000000000000000',
395            '6400'               => '80320000000000000000',
396            '70400'              => '80a60400000000000000',
397            '774400'             => '80a22f00000000000000',
398            '9292800'            => '8098b704000000000000',
399            '74342400'           => '80c0b923000000000000',
400            '743424000'          => '8080bfe2020000000000',
401            '8177664000'         => '8080b5bb1e0000000000',
402            '65421312000'        => '8080a8dbf30100000000',
403            '785055744000'       => '8080e0c7ec1600000000',
404            '9420668928000'      => '808080dd969202000000',
405            '103627358208000'    => '808080fff9c717000000',
406            '1139900940288000'   => '808080f5bd9783020000',
407            '13678811283456000'  => '808080fce699a6180000',
408            '109430490267648000' => '808080e0b7ceb1c20100',
409            '984874412408832000' => '808080e0f5c1bed50d00',
410        );
411
412        foreach ($testVals as $original => $encoded) {
413            $input = new CodedInputStream(hex2bin($encoded));
414            $this->assertTrue($input->readVarint64($var));
415            $this->assertEquals($original, $var);
416        }
417    }
418
419    public function testReadVarint32()
420    {
421        $var = 0;
422
423        // Empty buffer.
424        $input = new CodedInputStream(hex2bin(''));
425        $this->assertFalse($input->readVarint32($var));
426
427        // The largest varint is 10 bytes long.
428        $input = new CodedInputStream(hex2bin('8080808080808080808001'));
429        $this->assertFalse($input->readVarint32($var));
430
431        // Corrupted varint.
432        $input = new CodedInputStream(hex2bin('808080'));
433        $this->assertFalse($input->readVarint32($var));
434
435        // Normal case.
436        $input = new CodedInputStream(hex2bin('808001'));
437        $this->assertTrue($input->readVarint32($var));
438        $this->assertSame(16384, $var);
439        $this->assertFalse($input->readVarint32($var));
440
441        // Read two varint.
442        $input = new CodedInputStream(hex2bin('808001808002'));
443        $this->assertTrue($input->readVarint32($var));
444        $this->assertSame(16384, $var);
445        $this->assertTrue($input->readVarint32($var));
446        $this->assertSame(32768, $var);
447        $this->assertFalse($input->readVarint32($var));
448
449        // Read a 64-bit integer. High-order bits should be discarded.
450        $input = new CodedInputStream(hex2bin('808081808001'));
451        $this->assertTrue($input->readVarint32($var));
452        $this->assertSame(16384, $var);
453        $this->assertFalse($input->readVarint32($var));
454    }
455
456    public function testReadTag()
457    {
458        $input = new CodedInputStream(hex2bin('808001'));
459        $tag = $input->readTag();
460        $this->assertSame(16384, $tag);
461        $tag = $input->readTag();
462        $this->assertSame(0, $tag);
463    }
464
465    public function testPushPopLimit()
466    {
467        $input = new CodedInputStream(hex2bin('808001'));
468        $old_limit = $input->pushLimit(0);
469        $tag = $input->readTag();
470        $this->assertSame(0, $tag);
471        $input->popLimit($old_limit);
472        $tag = $input->readTag();
473        $this->assertSame(16384, $tag);
474    }
475
476    public function testReadRaw()
477    {
478        $input = new CodedInputStream(hex2bin('808001'));
479        $buffer = null;
480
481        $this->assertTrue($input->readRaw(3, $buffer));
482        $this->assertSame(hex2bin('808001'), $buffer);
483
484        $this->assertFalse($input->readRaw(1, $buffer));
485    }
486
487    public function testWriteVarint32()
488    {
489        $output = new CodedOutputStream(3);
490        $output->writeVarint32(16384, true);
491        $this->assertSame(hex2bin('808001'), $output->getData());
492
493        // Negative numbers are padded to be compatible with int64.
494        $output = new CodedOutputStream(10);
495        $output->writeVarint32(-43, false);
496        $this->assertSame(hex2bin('D5FFFFFFFFFFFFFFFF01'), $output->getData());
497    }
498
499    public function testWriteVarint64()
500    {
501        $output = new CodedOutputStream(10);
502        $output->writeVarint64(-43);
503        $this->assertSame(hex2bin('D5FFFFFFFFFFFFFFFF01'), $output->getData());
504    }
505
506    public function testWriteLittleEndian32()
507    {
508        $output = new CodedOutputStream(4);
509        $output->writeLittleEndian32(46);
510        $this->assertSame(hex2bin('2E000000'), $output->getData());
511    }
512
513    public function testWriteLittleEndian64()
514    {
515        $output = new CodedOutputStream(8);
516        $output->writeLittleEndian64(47);
517        $this->assertSame(hex2bin('2F00000000000000'), $output->getData());
518    }
519
520    public function testByteSize()
521    {
522        $m = new TestMessage();
523        TestUtil::setTestMessage($m);
524        $this->assertSame(504, $m->byteSize());
525    }
526
527    public function testPackedByteSize()
528    {
529        $m = new TestPackedMessage();
530        TestUtil::setTestPackedMessage($m);
531        $this->assertSame(166, $m->byteSize());
532    }
533
534    public function testArrayConstructorJsonCaseThrowsException()
535    {
536        $this->expectException(UnexpectedValueException::class);
537        $this->expectExceptionMessage(
538            'Invalid message property: optionalInt32');
539
540        $m = new TestMessage([
541            'optionalInt32' => -42,
542        ]);
543    }
544
545    public function testArraysForMessagesThrowsException()
546    {
547        $this->expectException(Exception::class);
548        $this->expectExceptionMessage(
549            'Expect Foo\TestMessage\Sub.');
550
551        $m = new TestMessage([
552            'optional_message' => [
553                'a' => 33
554            ]
555        ]);
556    }
557
558    public function testArrayConstructorWithNullValues()
559    {
560        $requestData = [
561            'optional_bool' => null,
562            'optional_string' => null,
563            'optional_bytes' => null,
564            'optional_message' => null,
565        ];
566
567        $m = new TestMessage($requestData);
568
569        $this->assertSame(false, $m->getOptionalBool());
570        $this->assertSame('', $m->getOptionalString());
571        $this->assertSame('', $m->getOptionalBytes());
572        $this->assertSame(null, $m->getOptionalMessage());
573    }
574
575    /**
576     * @dataProvider provideArrayConstructorWithNullValuesThrowsException
577     */
578    public function testArrayConstructorWithNullValuesThrowsException($requestData)
579    {
580        $this->expectException(Exception::class);
581
582        $m = new TestMessage($requestData);
583    }
584
585    public function provideArrayConstructorWithNullValuesThrowsException()
586    {
587        return [
588            [['optional_int32' => null]],
589            [['optional_int64' => null]],
590            [['optional_uint32' => null]],
591            [['optional_uint64' => null]],
592            [['optional_sint32' => null]],
593            [['optional_sint64' => null]],
594            [['optional_fixed32' => null]],
595            [['optional_fixed64' => null]],
596            [['optional_sfixed32' => null]],
597            [['optional_sfixed64' => null]],
598            [['optional_float' => null]],
599            [['optional_double' => null]],
600            [['optional_enum' => null]],
601            [['repeated_int32' => null]],
602            [['map_int32_int32' => null]],
603        ];
604    }
605}
606