Skip to content

Commit

Permalink
chore(php): conformance testing for edition (#16712)
Browse files Browse the repository at this point in the history
COPYBARA_INTEGRATE_REVIEW=#16712 from bshaffer:php-editions a1c41ad
PiperOrigin-RevId: 631824623
  • Loading branch information
bshaffer authored and copybara-github committed May 8, 2024
1 parent b77343a commit 01744cc
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 91 deletions.
3 changes: 2 additions & 1 deletion conformance/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -332,13 +332,14 @@ inline_sh_binary(
],
cmd = """
php -dextension=$(rootpath //php:extension) \\
-d include_path=conformance:src/google/protobuf \\
-d include_path=conformance:src/google/protobuf:editions/golden \\
$(rootpath conformance_php.php)
""",
visibility = ["//php:__subpackages__"],
deps = [
":conformance_php_proto",
"//:test_messages_proto3_php_proto",
"//editions:test_messages_proto3_editions_php_proto",
],
)

Expand Down
214 changes: 134 additions & 80 deletions conformance/conformance_php.php
Original file line number Diff line number Diff line change
@@ -1,80 +1,134 @@
<?php

require_once("Conformance/WireFormat.php");
require_once("Conformance/ConformanceResponse.php");
require_once("Conformance/ConformanceRequest.php");
require_once("Conformance/FailureSet.php");
require_once("Conformance/JspbEncodingConfig.php");
require_once("Conformance/TestCategory.php");
require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/AliasedEnum.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedMessage.php");
require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php");

require_once("GPBMetadata/Conformance.php");
require_once("GPBMetadata/TestMessagesProto3.php");

use \Conformance\TestCategory;
use \Conformance\WireFormat;

if (!ini_get("date.timezone")) {
ini_set("date.timezone", "UTC");
require_once('Conformance/WireFormat.php');
require_once('Conformance/ConformanceResponse.php');
require_once('Conformance/ConformanceRequest.php');
require_once('Conformance/FailureSet.php');
require_once('Conformance/JspbEncodingConfig.php');
require_once('Conformance/TestCategory.php');
require_once('Protobuf_test_messages/Proto3/ForeignMessage.php');
require_once('Protobuf_test_messages/Proto3/ForeignEnum.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3/AliasedEnum.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedMessage.php');
require_once('Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3/PBBool.php');
require_once('Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedMessage.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/AliasedEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3.php');
require_once('Protobuf_test_messages/Editions/Proto3/NullHypothesisProto3.php');
require_once('Protobuf_test_messages/Editions/Proto3/ForeignEnum.php');
require_once('Protobuf_test_messages/Editions/Proto3/ForeignMessage.php');
require_once('GPBMetadata/Conformance.php');
require_once('GPBMetadata/TestMessagesProto3.php');
require_once('GPBMetadata/TestMessagesProto3Editions.php');

use Conformance\ConformanceRequest;
use Conformance\ConformanceResponse;
use Conformance\TestCategory;
use Conformance\WireFormat;
use Protobuf_test_messages\Proto3\TestAllTypesProto3;
use Protobuf_test_messages\Editions\Proto3\TestAllTypesProto3 as TestAllTypesProto3Editions;

if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}

$test_count = 0;

function doTest($request)
{
$test_message = new \Protobuf_test_messages\Proto3\TestAllTypesProto3();
$response = new \Conformance\ConformanceResponse();
if ($request->getPayload() == "protobuf_payload") {
if ($request->getMessageType() == "conformance.FailureSet") {
$response->setProtobufPayload("");
return $response;
} elseif ($request->getMessageType() == "protobuf_test_messages.proto3.TestAllTypesProto3") {
try {
$test_message->mergeFromString($request->getProtobufPayload());
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
} elseif ($request->getMessageType() == "protobuf_test_messages.proto2.TestAllTypesProto2") {
$response->setSkipped("PHP doesn't support proto2");
return $response;
} else {
trigger_error("Protobuf request doesn't have specific payload type", E_USER_ERROR);
}
} elseif ($request->getPayload() == "json_payload") {
$ignore_json_unknown =
($request->getTestCategory() ==
TestCategory::JSON_IGNORE_UNKNOWN_PARSING_TEST);
try {
$test_message->mergeFromJsonString($request->getJsonPayload(),
$ignore_json_unknown);
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
} elseif ($request->getPayload() == "text_payload") {
$response->setSkipped("PHP doesn't support text format yet");
return $response;
} else {
trigger_error("Request didn't have payload.", E_USER_ERROR);
$response = new ConformanceResponse();

switch ($request->getPayload()) {
case 'protobuf_payload':
switch ($request->getMessageType()) {
case 'protobuf_test_messages.proto3.TestAllTypesProto3':
$test_message = new TestAllTypesProto3();
break;
case 'protobuf_test_messages.editions.proto3.TestAllTypesProto3':
$test_message = new TestAllTypesProto3Editions();
break;
case 'conformance.FailureSet':
$response->setProtobufPayload('');
return $response;
case 'protobuf_test_messages.proto2.TestAllTypesProto2':
case 'protobuf_test_messages.editions.proto2.TestAllTypesProto2':
$response->setSkipped('PHP doesn\'t support proto2');
return $response;
case 'protobuf_test_messages.editions.TestAllTypesEdition2023':
$response->setSkipped('PHP doesn\'t support editions-specific features yet');
return $response;
case '':
trigger_error(
'Protobuf request doesn\'t have specific payload type',
E_USER_ERROR
);
default:
trigger_error(sprintf(
'Protobuf request doesn\'t support %s message type',
$request->getMessageType(),
), E_USER_ERROR);
}

try {
$test_message->mergeFromString($request->getProtobufPayload());
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
break;

case 'json_payload':
switch ($request->getMessageType()) {
case 'protobuf_test_messages.editions.proto3.TestAllTypesProto3':
$test_message = new TestAllTypesProto3Editions();
break;
case 'protobuf_test_messages.editions.proto2.TestAllTypesProto2':
$response->setSkipped('PHP doesn\'t support proto2');
return $response;
default:
$test_message = new TestAllTypesProto3();
}

$ignore_json_unknown =
($request->getTestCategory() == TestCategory::JSON_IGNORE_UNKNOWN_PARSING_TEST);
try {
$test_message->mergeFromJsonString(
$request->getJsonPayload(),
$ignore_json_unknown
);
} catch (Exception $e) {
$response->setParseError($e->getMessage());
return $response;
}
break;

case 'text_payload':
$response->setSkipped('PHP doesn\'t support text format yet');
return $response;
default:
trigger_error('Request didn\'t have payload.', E_USER_ERROR);
}

if ($request->getRequestedOutputFormat() == WireFormat::UNSPECIFIED) {
trigger_error("Unspecified output format.", E_USER_ERROR);
} elseif ($request->getRequestedOutputFormat() == WireFormat::PROTOBUF) {
$response->setProtobufPayload($test_message->serializeToString());
} elseif ($request->getRequestedOutputFormat() == WireFormat::JSON) {
try {
$response->setJsonPayload($test_message->serializeToJsonString());
} catch (Exception $e) {
$response->setSerializeError($e->getMessage());
return $response;
}
switch ($request->getRequestedOutputFormat()) {
case WireFormat::TEXT_FORMAT:
$response->setSkipped('PHP doesn\'t support text format yet');
return $response;
case WireFormat::UNSPECIFIED:
trigger_error('Unspecified output format.', E_USER_ERROR);
case WireFormat::PROTOBUF:
$response->setProtobufPayload($test_message->serializeToString());
break;
case WireFormat::JSON:
try {
$response->setJsonPayload($test_message->serializeToJsonString());
} catch (Exception $e) {
$response->setSerializeError($e->getMessage());
return $response;
}
}

return $response;
Expand All @@ -84,25 +138,25 @@ function doTestIO()
{
$length_bytes = fread(STDIN, 4);
if (strlen($length_bytes) == 0) {
return false; # EOF
return false; # EOF
} elseif (strlen($length_bytes) != 4) {
fwrite(STDERR, "I/O error\n");
return false;
fwrite(STDERR, "I/O error\n");
return false;
}

$length = unpack("V", $length_bytes)[1];
$length = unpack('V', $length_bytes)[1];
$serialized_request = fread(STDIN, $length);
if (strlen($serialized_request) != $length) {
trigger_error("I/O error", E_USER_ERROR);
trigger_error('I/O error', E_USER_ERROR);
}

$request = new \Conformance\ConformanceRequest();
$request = new ConformanceRequest();
$request->mergeFromString($serialized_request);

$response = doTest($request);

$serialized_response = $response->serializeToString();
fwrite(STDOUT, pack("V", strlen($serialized_response)));
fwrite(STDOUT, pack('V', strlen($serialized_response)));
fwrite(STDOUT, $serialized_response);

$GLOBALS['test_count'] += 1;
Expand All @@ -111,10 +165,10 @@ function doTestIO()
}

while(true){
if (!doTestIO()) {
fprintf(STDERR,
"conformance_php: received EOF from test runner " .
"after %d tests, exiting\n", $test_count);
exit;
}
if (!doTestIO()) {
fprintf(STDERR,
'conformance_php: received EOF from test runner ' .
"after %d tests, exiting\n", $test_count);
exit;
}
}
8 changes: 0 additions & 8 deletions conformance/text_format_failure_list_php.txt
Original file line number Diff line number Diff line change
@@ -1,8 +0,0 @@
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.GroupUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.MessageUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Print.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Print.TextFormatOutput
27 changes: 26 additions & 1 deletion editions/BUILD
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//:protobuf.bzl", "internal_objc_proto_library", "internal_py_proto_library")
load("//:protobuf.bzl", "internal_objc_proto_library", "internal_php_proto_library", "internal_py_proto_library")
load("//bazel:cc_proto_library.bzl", "cc_proto_library")
load("//bazel:upb_proto_library.bzl", "upb_c_proto_library", "upb_proto_reflection_library")
load(":defaults.bzl", "compile_edition_defaults", "embed_edition_defaults")
Expand Down Expand Up @@ -236,6 +236,31 @@ java_lite_proto_library(
deps = [":test_messages_proto3_editions_proto"],
)

internal_php_proto_library(
name = "test_messages_proto3_editions_php_proto",
testonly = 1,
srcs = ["golden/test_messages_proto3_editions.proto"],
outs = [
"GPBMetadata/TestMessagesProto3Editions.php",
"Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3.php",
"Protobuf_test_messages/Editions/Proto3/EnumOnlyProto3/PBBool.php",
"Protobuf_test_messages/Editions/Proto3/ForeignEnum.php",
"Protobuf_test_messages/Editions/Proto3/ForeignMessage.php",
"Protobuf_test_messages/Editions/Proto3/NullHypothesisProto3.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/AliasedEnum.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedEnum.php",
"Protobuf_test_messages/Editions/Proto3/TestAllTypesProto3/NestedMessage.php",
],
enable_editions = True,
includes = [
"golden",
"src",
],
proto_deps = ["//:well_known_protos"],
visibility = ["//conformance:__pkg__"],
)

internal_py_proto_library(
name = "test_messages_proto3_editions_py_pb2",
testonly = True,
Expand Down
2 changes: 2 additions & 0 deletions php/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ genrule(
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_php.txt",
maximum_edition = "2023",
target_compatible_with = select({
"@platforms//os:osx": ["@platforms//:incompatible"],
"//conditions:default": [],
Expand All @@ -75,6 +76,7 @@ conformance_test(
conformance_test(
name = "conformance_test_c",
failure_list = "//conformance:failure_list_php_c.txt",
maximum_edition = "2023",
target_compatible_with = select({
"@platforms//os:osx": [],
"//conditions:default": ["@platforms//:incompatible"],
Expand Down
8 changes: 8 additions & 0 deletions protobuf.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def _proto_gen_impl(ctx):
srcs = ctx.files.srcs
langs = ctx.attr.langs or []
out_type = ctx.attr.out_type
enable_editions = ctx.attr.enable_editions
deps = depset(direct = ctx.files.srcs)
source_dir = _SourceDir(ctx)
gen_dir = _GenDir(ctx).rstrip("/")
Expand Down Expand Up @@ -130,6 +131,8 @@ def _proto_gen_impl(ctx):
generated_files = []
for src in srcs:
args = []
if enable_editions:
args.append("--experimental_editions")

in_gen_dir = src.root.path == gen_dir
if in_gen_dir:
Expand Down Expand Up @@ -231,6 +234,7 @@ Args:
srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
against.
deps: a list of dependency labels; must be other proto libraries.
enable_editions: if true, sets the --experimental_editions flag.
includes: a list of include paths to .proto files.
protoc: the label of the protocol compiler to generate the sources.
plugin: the label of the protocol compiler plugin to be passed to the protocol
Expand All @@ -247,6 +251,7 @@ _proto_gen = rule(
attrs = {
"srcs": attr.label_list(allow_files = True),
"deps": attr.label_list(providers = [ProtoGenInfo]),
"enable_editions": attr.bool(),
"includes": attr.string_list(),
"protoc": attr.label(
cfg = "exec",
Expand Down Expand Up @@ -655,6 +660,7 @@ def _source_proto_library(
protoc = Label("//:protoc"),
testonly = None,
visibility = ["//visibility:public"],
enable_editions = False,
**kwargs):
"""Bazel rule to create generated protobuf code from proto source files for
languages not well supported by Bazel yet. This will output the generated
Expand Down Expand Up @@ -699,6 +705,7 @@ def _source_proto_library(
srcs = proto_deps,
protoc = protoc,
includes = includes,
enable_editions = enable_editions,
)
full_deps.append(":%s_deps_genproto" % name)

Expand All @@ -712,6 +719,7 @@ def _source_proto_library(
protoc = protoc,
testonly = testonly,
visibility = visibility,
enable_editions = enable_editions,
)

native.filegroup(
Expand Down
Loading

0 comments on commit 01744cc

Please sign in to comment.