From 74eb9a0a304a3261f3c83e100f51081986ac8ba6 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Sat, 11 Feb 2017 16:36:17 -0800 Subject: Add clear method to PHP message (#2700) --- php/ext/google/protobuf/message.c | 19 +++++ php/ext/google/protobuf/protobuf.h | 1 + php/ext/google/protobuf/storage.c | 21 ++++- php/src/Google/Protobuf/Internal/Message.php | 111 ++++++++++++++++++++++++++- php/tests/encode_decode_test.php | 3 +- php/tests/generated_class_test.php | 26 +++++-- php/tests/php_implementation_test.php | 2 +- php/tests/test_base.php | 95 +++++++++++++++++++++++ php/tests/test_util.php | 7 ++ tests.sh | 4 +- 10 files changed, 277 insertions(+), 12 deletions(-) diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index e8b8ae81..46da9024 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -38,6 +38,7 @@ static zend_class_entry* message_type; zend_object_handlers* message_handlers; static zend_function_entry message_methods[] = { + PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC) PHP_ME(Message, encode, NULL, ZEND_ACC_PUBLIC) PHP_ME(Message, decode, NULL, ZEND_ACC_PUBLIC) PHP_ME(Message, jsonEncode, NULL, ZEND_ACC_PUBLIC) @@ -241,6 +242,24 @@ PHP_METHOD(Message, __construct) { } } +PHP_METHOD(Message, clear) { + MessageHeader* msg = + (MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC); + Descriptor* desc = msg->descriptor; + zend_class_entry* ce = desc->klass; + int i; + + for (i = 0; i < msg->std.ce->default_properties_count; i++) { + zval_ptr_dtor(&msg->std.properties_table[i]); + } + efree(msg->std.properties_table); + + zend_object_std_init(&msg->std, ce TSRMLS_CC); + object_properties_init(&msg->std, ce); + layout_init(desc->layout, message_data(msg), + msg->std.properties_table TSRMLS_CC); +} + PHP_METHOD(Message, readOneof) { long index; diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 678f2682..d4737fb9 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -244,6 +244,7 @@ const char* layout_get_oneof_case(MessageLayout* layout, const void* storage, const upb_oneofdef* oneof TSRMLS_DC); void free_layout(MessageLayout* layout); +PHP_METHOD(Message, clear); PHP_METHOD(Message, readOneof); PHP_METHOD(Message, writeOneof); PHP_METHOD(Message, whichOneof); diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c index ba6ac59e..5e05b935 100644 --- a/php/ext/google/protobuf/storage.c +++ b/php/ext/google/protobuf/storage.c @@ -248,11 +248,28 @@ void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC) { CASE(DOUBLE, DOUBLE) CASE(BOOL, BOOL) CASE(INT32, LONG) - CASE(INT64, LONG) CASE(UINT32, LONG) - CASE(UINT64, LONG) CASE(ENUM, LONG) +#undef CASE + +#if SIZEOF_LONG == 4 +#define CASE(upb_type) \ + case UPB_TYPE_##upb_type: { \ + SEPARATE_ZVAL_IF_NOT_REF(cache); \ + ZVAL_STRING(*cache, "0", 1); \ + return; \ + } +#else +#define CASE(upb_type) \ + case UPB_TYPE_##upb_type: { \ + SEPARATE_ZVAL_IF_NOT_REF(cache); \ + ZVAL_LONG(*cache, 0); \ + return; \ + } +#endif +CASE(UINT64) +CASE(INT64) #undef CASE case UPB_TYPE_STRING: diff --git a/php/src/Google/Protobuf/Internal/Message.php b/php/src/Google/Protobuf/Internal/Message.php index 82b94ee4..9e162a22 100644 --- a/php/src/Google/Protobuf/Internal/Message.php +++ b/php/src/Google/Protobuf/Internal/Message.php @@ -125,7 +125,7 @@ class Message $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; $oneof_name = $oneof->getName(); $this->$oneof_name = new OneofField($oneof); - } else if ($field->getLabel() === GPBLabel::OPTIONAL && + } else if ($field->getLabel() === GPBLabel::OPTIONAL && PHP_INT_SIZE == 4) { switch ($field->getType()) { case GPBType::INT64: @@ -381,6 +381,115 @@ class Message return true; } + /** + * Clear all containing fields. + * @return null. + */ + public function clear() + { + foreach ($this->desc->getField() as $field) { + $setter = $field->getSetter(); + if ($field->isMap()) { + $message_type = $field->getMessageType(); + $key_field = $message_type->getFieldByNumber(1); + $value_field = $message_type->getFieldByNumber(2); + switch ($value_field->getType()) { + case GPBType::MESSAGE: + case GPBType::GROUP: + $map_field = new MapField( + $key_field->getType(), + $value_field->getType(), + $value_field->getMessageType()->getClass()); + $this->$setter($map_field); + break; + case GPBType::ENUM: + $map_field = new MapField( + $key_field->getType(), + $value_field->getType(), + $value_field->getEnumType()->getClass()); + $this->$setter($map_field); + break; + default: + $map_field = new MapField( + $key_field->getType(), + $value_field->getType()); + $this->$setter($map_field); + break; + } + } else if ($field->getLabel() === GPBLabel::REPEATED) { + switch ($field->getType()) { + case GPBType::MESSAGE: + case GPBType::GROUP: + $repeated_field = new RepeatedField( + $field->getType(), + $field->getMessageType()->getClass()); + $this->$setter($repeated_field); + break; + case GPBType::ENUM: + $repeated_field = new RepeatedField( + $field->getType(), + $field->getEnumType()->getClass()); + $this->$setter($repeated_field); + break; + default: + $repeated_field = new RepeatedField($field->getType()); + $this->$setter($repeated_field); + break; + } + } else if ($field->getOneofIndex() !== -1) { + $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; + $oneof_name = $oneof->getName(); + $this->$oneof_name = new OneofField($oneof); + } else if ($field->getLabel() === GPBLabel::OPTIONAL) { + switch ($field->getType()) { + case GPBType::DOUBLE : + case GPBType::FLOAT : + $this->$setter(0.0); + break; + case GPBType::INT32 : + case GPBType::FIXED32 : + case GPBType::UINT32 : + case GPBType::SFIXED32 : + case GPBType::SINT32 : + case GPBType::ENUM : + $this->$setter(0); + break; + case GPBType::BOOL : + $this->$setter(false); + break; + case GPBType::STRING : + case GPBType::BYTES : + $this->$setter(""); + break; + case GPBType::GROUP : + case GPBType::MESSAGE : + $null = null; + $this->$setter($null); + break; + } + if (PHP_INT_SIZE == 4) { + switch ($field->getType()) { + case GPBType::INT64: + case GPBType::UINT64: + case GPBType::FIXED64: + case GPBType::SFIXED64: + case GPBType::SINT64: + $this->$setter("0"); + } + } else { + switch ($field->getType()) { + case GPBType::INT64: + case GPBType::UINT64: + case GPBType::FIXED64: + case GPBType::SFIXED64: + case GPBType::SINT64: + $this->$setter(0); + } + } + } + } + } + /** * Parses a protocol buffer contained in a string. * diff --git a/php/tests/encode_decode_test.php b/php/tests/encode_decode_test.php index 7eb815ad..3218aa63 100644 --- a/php/tests/encode_decode_test.php +++ b/php/tests/encode_decode_test.php @@ -22,7 +22,8 @@ class EncodeDecodeTest extends TestBase $this->expectFields($from); $data = $from->encode(); - $this->assertSame(TestUtil::getGoldenTestMessage(), $data); + $this->assertSame(bin2hex(TestUtil::getGoldenTestMessage()), + bin2hex($data)); } public function testDecode() diff --git a/php/tests/generated_class_test.php b/php/tests/generated_class_test.php index d347e8b4..83ce1139 100644 --- a/php/tests/generated_class_test.php +++ b/php/tests/generated_class_test.php @@ -2,6 +2,7 @@ require_once('generated/NoNameSpaceEnum.php'); require_once('generated/NoNameSpaceMessage.php'); +require_once('test_base.php'); require_once('test_util.php'); use Google\Protobuf\Internal\RepeatedField; @@ -10,7 +11,7 @@ use Foo\TestEnum; use Foo\TestMessage; use Foo\TestMessage_Sub; -class GeneratedClassTest extends PHPUnit_Framework_TestCase +class GeneratedClassTest extends TestBase { ######################################################### @@ -607,15 +608,30 @@ class GeneratedClassTest extends PHPUnit_Framework_TestCase $this->assertSame("oneof_message", $m->getMyOneof()); } + ######################################################### + # Test clear method. + ######################################################### + + public function testMessageClear() + { + $m = new TestMessage(); + $this->setFields($m); + $this->expectFields($m); + $m->clear(); + $this->expectEmptyFields($m); + } + ######################################################### # Test message/enum without namespace. ######################################################### - public function testMessageWithoutNamespace() { - $m = new NoNameSpaceMessage(); + public function testMessageWithoutNamespace() + { + $m = new NoNameSpaceMessage(); } - public function testEnumWithoutNamespace() { - $m = new NoNameSpaceEnum(); + public function testEnumWithoutNamespace() + { + $m = new NoNameSpaceEnum(); } } diff --git a/php/tests/php_implementation_test.php b/php/tests/php_implementation_test.php index ac7c13dc..00125db4 100644 --- a/php/tests/php_implementation_test.php +++ b/php/tests/php_implementation_test.php @@ -496,7 +496,7 @@ class ImplementationTest extends TestBase { $m = new TestMessage(); TestUtil::setTestMessage($m); - $this->assertSame(447, $m->byteSize()); + $this->assertSame(481, $m->byteSize()); } public function testPackedByteSize() diff --git a/php/tests/test_base.php b/php/tests/test_base.php index d461f0f7..729fea3b 100644 --- a/php/tests/test_base.php +++ b/php/tests/test_base.php @@ -1,6 +1,7 @@ assertEquals('c', $m->getRepeatedString()[1]); $this->assertEquals('d', $m->getRepeatedBytes()[1]); $this->assertEquals(35, $m->getRepeatedMessage()[1]->GetA()); + + if (PHP_INT_SIZE == 4) { + $this->assertEquals('-63', $m->getMapInt64Int64()['-63']); + $this->assertEquals('63', $m->getMapUint64Uint64()['63']); + $this->assertEquals('-65', $m->getMapSint64Sint64()['-65']); + $this->assertEquals('67', $m->getMapFixed64Fixed64()['67']); + $this->assertEquals('-69', $m->getMapSfixed64Sfixed64()['-69']); + } else { + $this->assertEquals(-63, $m->getMapInt64Int64()[-63]); + $this->assertEquals(63, $m->getMapUint64Uint64()[63]); + $this->assertEquals(-65, $m->getMapSint64Sint64()[-65]); + $this->assertEquals(67, $m->getMapFixed64Fixed64()[67]); + $this->assertEquals(-69, $m->getMapSfixed64Sfixed64()[-69]); + } + $this->assertEquals(-62, $m->getMapInt32Int32()[-62]); + $this->assertEquals(62, $m->getMapUint32Uint32()[62]); + $this->assertEquals(-64, $m->getMapSint32Sint32()[-64]); + $this->assertEquals(66, $m->getMapFixed32Fixed32()[66]); + $this->assertEquals(-68, $m->getMapSfixed32Sfixed32()[-68]); + $this->assertEquals(3.5, $m->getMapInt32Float()[1]); + $this->assertEquals(3.6, $m->getMapInt32Double()[1]); + $this->assertEquals(true , $m->getMapBoolBool()[true]); + $this->assertEquals('e', $m->getMapStringString()['e']); + $this->assertEquals('f', $m->getMapInt32Bytes()[1]); + $this->assertEquals(TestEnum::ONE, $m->getMapInt32Enum()[1]); + $this->assertEquals(36, $m->getMapInt32Message()[1]->GetA()); } public function expectEmptyFields(TestMessage $m) @@ -83,7 +110,10 @@ class TestBase extends PHPUnit_Framework_TestCase $this->assertSame(false, $m->getOptionalBool()); $this->assertSame('', $m->getOptionalString()); $this->assertSame('', $m->getOptionalBytes()); + $this->assertSame(0, $m->getOptionalEnum()); $this->assertNull($m->getOptionalMessage()); + $this->assertNull($m->getOptionalIncludedMessage()); + $this->assertNull($m->getRecursive()); if (PHP_INT_SIZE == 4) { $this->assertSame("0", $m->getOptionalInt64()); $this->assertSame("0", $m->getOptionalUint64()); @@ -97,6 +127,71 @@ class TestBase extends PHPUnit_Framework_TestCase $this->assertSame(0, $m->getOptionalFixed64()); $this->assertSame(0, $m->getOptionalSfixed64()); } + + $this->assertEquals(0, count($m->getRepeatedInt32())); + $this->assertEquals(0, count($m->getRepeatedUint32())); + $this->assertEquals(0, count($m->getRepeatedInt64())); + $this->assertEquals(0, count($m->getRepeatedUint64())); + $this->assertEquals(0, count($m->getRepeatedSint32())); + $this->assertEquals(0, count($m->getRepeatedSint64())); + $this->assertEquals(0, count($m->getRepeatedFixed32())); + $this->assertEquals(0, count($m->getRepeatedFixed64())); + $this->assertEquals(0, count($m->getRepeatedSfixed32())); + $this->assertEquals(0, count($m->getRepeatedSfixed64())); + $this->assertEquals(0, count($m->getRepeatedFloat())); + $this->assertEquals(0, count($m->getRepeatedDouble())); + $this->assertEquals(0, count($m->getRepeatedBool())); + $this->assertEquals(0, count($m->getRepeatedString())); + $this->assertEquals(0, count($m->getRepeatedBytes())); + $this->assertEquals(0, count($m->getRepeatedEnum())); + $this->assertEquals(0, count($m->getRepeatedMessage())); + $this->assertEquals(0, count($m->getRepeatedRecursive())); + + $this->assertSame("", $m->getMyOneof()); + $this->assertSame(0, $m->getOneofInt32()); + $this->assertSame(0, $m->getOneofUint32()); + $this->assertSame(0, $m->getOneofSint32()); + $this->assertSame(0, $m->getOneofFixed32()); + $this->assertSame(0, $m->getOneofSfixed32()); + $this->assertSame(0.0, $m->getOneofFloat()); + $this->assertSame(0.0, $m->getOneofDouble()); + $this->assertSame(false, $m->getOneofBool()); + $this->assertSame('', $m->getOneofString()); + $this->assertSame('', $m->getOneofBytes()); + $this->assertSame(0, $m->getOneofEnum()); + $this->assertNull($m->getOptionalMessage()); + if (PHP_INT_SIZE == 4) { + $this->assertSame("0", $m->getOneofInt64()); + $this->assertSame("0", $m->getOneofUint64()); + $this->assertSame("0", $m->getOneofSint64()); + $this->assertSame("0", $m->getOneofFixed64()); + $this->assertSame("0", $m->getOneofSfixed64()); + } else { + $this->assertSame(0, $m->getOneofInt64()); + $this->assertSame(0, $m->getOneofUint64()); + $this->assertSame(0, $m->getOneofSint64()); + $this->assertSame(0, $m->getOneofFixed64()); + $this->assertSame(0, $m->getOneofSfixed64()); + } + + $this->assertEquals(0, count($m->getMapInt64Int64())); + $this->assertEquals(0, count($m->getMapUint64Uint64())); + $this->assertEquals(0, count($m->getMapSint64Sint64())); + $this->assertEquals(0, count($m->getMapFixed64Fixed64())); + $this->assertEquals(0, count($m->getMapInt32Int32())); + $this->assertEquals(0, count($m->getMapUint32Uint32())); + $this->assertEquals(0, count($m->getMapSint32Sint32())); + $this->assertEquals(0, count($m->getMapFixed32Fixed32())); + $this->assertEquals(0, count($m->getMapSfixed32Sfixed32())); + $this->assertEquals(0, count($m->getMapSfixed64Sfixed64())); + $this->assertEquals(0, count($m->getMapInt32Float())); + $this->assertEquals(0, count($m->getMapInt32Double())); + $this->assertEquals(0, count($m->getMapBoolBool())); + $this->assertEquals(0, count($m->getMapStringString())); + $this->assertEquals(0, count($m->getMapInt32Bytes())); + $this->assertEquals(0, count($m->getMapInt32Enum())); + $this->assertEquals(0, count($m->getMapInt32Message())); + $this->assertEquals(0, count($m->getMapRecursive())); } // This test is to avoid the warning of no test by php unit. diff --git a/php/tests/test_util.php b/php/tests/test_util.php index 7f2aae15..b7db5c1d 100644 --- a/php/tests/test_util.php +++ b/php/tests/test_util.php @@ -118,6 +118,8 @@ class TestUtil $m->getMapSint64Sint64()[-65] = -65; $m->getMapFixed32Fixed32()[66] = 66; $m->getMapFixed64Fixed64()[67] = 67; + $m->getMapSfixed32Sfixed32()[-68] = -68; + $m->getMapSfixed64Sfixed64()[-69] = -69; $m->getMapInt32Float()[1] = 3.5; $m->getMapInt32Double()[1] = 3.6; $m->getMapBoolBool()[true] = true; @@ -213,16 +215,19 @@ class TestUtil assert('63' === $m->getMapUint64Uint64()['63']); assert('-65' === $m->getMapSint64Sint64()['-65']); assert('67' === $m->getMapFixed64Fixed64()['67']); + assert('-69' === $m->getMapSfixed64Sfixed64()['-69']); } else { assert(-63 === $m->getMapInt64Int64()[-63]); assert(63 === $m->getMapUint64Uint64()[63]); assert(-65 === $m->getMapSint64Sint64()[-65]); assert(67 === $m->getMapFixed64Fixed64()[67]); + assert(-69 === $m->getMapSfixed64Sfixed64()[-69]); } assert(-62 === $m->getMapInt32Int32()[-62]); assert(62 === $m->getMapUint32Uint32()[62]); assert(-64 === $m->getMapSint32Sint32()[-64]); assert(66 === $m->getMapFixed32Fixed32()[66]); + assert(-68 === $m->getMapSfixed32Sfixed32()[-68]); assert(3.5 === $m->getMapInt32Float()[1]); assert(3.6 === $m->getMapInt32Double()[1]); assert(true === $m->getMapBoolBool()[true]); @@ -296,6 +301,8 @@ class TestUtil "E20406088101108101" . "EA040A0D420000001542000000" . "F20412094300000000000000114300000000000000" . + "FA040A0DBCFFFFFF15BCFFFFFF" . + "82051209BBFFFFFFFFFFFFFF11BBFFFFFFFFFFFFFF" . "8A050708011500006040" . "92050B080111CDCCCCCCCCCC0C40" . "9A050408011001" . diff --git a/tests.sh b/tests.sh index 7d2bfc54..d0d77e49 100755 --- a/tests.sh +++ b/tests.sh @@ -445,10 +445,10 @@ build_php5.5_c_32() { use_php_bc 5.5 wget https://phar.phpunit.de/phpunit-old.phar -O /usr/bin/phpunit cd php/tests && /bin/bash ./test.sh && cd ../.. - pushd conformance # TODO(teboring): Add conformance test. + # pushd conformance # make test_php_c - popd + # popd } build_php5.6() { -- cgit v1.2.3