Commit a3ca1fa4 authored by Joshua Haberman's avatar Joshua Haberman

Merge pull request #588 from haberman/conformance-json

Added support for JSON and valid input to conformance tests.
parents fe500440 b0500b37
...@@ -54,7 +54,7 @@ class ConformanceJava { ...@@ -54,7 +54,7 @@ class ConformanceJava {
break; break;
} }
case JSON_PAYLOAD: { case JSON_PAYLOAD: {
return Conformance.ConformanceResponse.newBuilder().setRuntimeError("JSON not yet supported.").build(); return Conformance.ConformanceResponse.newBuilder().setSkipped("JSON not yet supported.").build();
} }
case PAYLOAD_NOT_SET: { case PAYLOAD_NOT_SET: {
throw new RuntimeException("Request didn't have payload."); throw new RuntimeException("Request didn't have payload.");
...@@ -65,7 +65,7 @@ class ConformanceJava { ...@@ -65,7 +65,7 @@ class ConformanceJava {
} }
} }
switch (request.getRequestedOutput()) { switch (request.getRequestedOutputFormat()) {
case UNSPECIFIED: case UNSPECIFIED:
throw new RuntimeException("Unspecified output format."); throw new RuntimeException("Unspecified output format.");
...@@ -73,7 +73,7 @@ class ConformanceJava { ...@@ -73,7 +73,7 @@ class ConformanceJava {
return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build(); return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build();
case JSON: case JSON:
return Conformance.ConformanceResponse.newBuilder().setRuntimeError("JSON not yet supported.").build(); return Conformance.ConformanceResponse.newBuilder().setSkipped("JSON not yet supported.").build();
default: { default: {
throw new RuntimeException("Unexpected request output."); throw new RuntimeException("Unexpected request output.");
......
...@@ -51,6 +51,12 @@ option java_package = "com.google.protobuf.conformance"; ...@@ -51,6 +51,12 @@ option java_package = "com.google.protobuf.conformance";
// - running as a sub-process may be more tricky in unusual environments like // - running as a sub-process may be more tricky in unusual environments like
// iOS apps, where fork/stdin/stdout are not available. // iOS apps, where fork/stdin/stdout are not available.
enum WireFormat {
UNSPECIFIED = 0;
PROTOBUF = 1;
JSON = 2;
}
// Represents a single test case's input. The testee should: // Represents a single test case's input. The testee should:
// //
// 1. parse this proto (which should always succeed) // 1. parse this proto (which should always succeed)
...@@ -64,14 +70,8 @@ message ConformanceRequest { ...@@ -64,14 +70,8 @@ message ConformanceRequest {
string json_payload = 2; string json_payload = 2;
} }
enum RequestedOutput {
UNSPECIFIED = 0;
PROTOBUF = 1;
JSON = 2;
}
// Which format should the testee serialize its message to? // Which format should the testee serialize its message to?
RequestedOutput requested_output = 3; WireFormat requested_output_format = 3;
} }
// Represents a single test case's output. // Represents a single test case's output.
...@@ -96,6 +96,10 @@ message ConformanceResponse { ...@@ -96,6 +96,10 @@ message ConformanceResponse {
// If the input was successfully parsed and the requested output was JSON, // If the input was successfully parsed and the requested output was JSON,
// serialize to JSON and set it in this field. // serialize to JSON and set it in this field.
string json_payload = 4; string json_payload = 4;
// For when the testee skipped the test, likely because a certain feature
// wasn't supported, like JSON input/output.
string skipped = 5;
} }
} }
......
...@@ -33,14 +33,33 @@ ...@@ -33,14 +33,33 @@
#include <unistd.h> #include <unistd.h>
#include "conformance.pb.h" #include "conformance.pb.h"
#include <google/protobuf/util/json_util.h>
#include <google/protobuf/util/type_resolver_util.h>
using std::string;
using conformance::ConformanceRequest; using conformance::ConformanceRequest;
using conformance::ConformanceResponse; using conformance::ConformanceResponse;
using conformance::TestAllTypes; using conformance::TestAllTypes;
using google::protobuf::Descriptor;
using google::protobuf::DescriptorPool;
using google::protobuf::internal::scoped_ptr;
using google::protobuf::util::BinaryToJsonString;
using google::protobuf::util::JsonToBinaryString;
using google::protobuf::util::NewTypeResolverForDescriptorPool;
using google::protobuf::util::Status;
using google::protobuf::util::TypeResolver;
using std::string;
static const char kTypeUrlPrefix[] = "type.googleapis.com";
static string GetTypeUrl(const Descriptor* message) {
return string(kTypeUrlPrefix) + "/" + message->full_name();
}
int test_count = 0; int test_count = 0;
bool verbose = false; bool verbose = false;
TypeResolver* type_resolver;
string* type_url;
bool CheckedRead(int fd, void *buf, size_t len) { bool CheckedRead(int fd, void *buf, size_t len) {
size_t ofs = 0; size_t ofs = 0;
...@@ -79,28 +98,44 @@ void DoTest(const ConformanceRequest& request, ConformanceResponse* response) { ...@@ -79,28 +98,44 @@ void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
} }
break; break;
case ConformanceRequest::kJsonPayload: case ConformanceRequest::kJsonPayload: {
response->set_runtime_error("JSON input is not yet supported."); string proto_binary;
Status status = JsonToBinaryString(type_resolver, *type_url,
request.json_payload(), &proto_binary);
if (!status.ok()) {
response->set_parse_error(string("Parse error: ") +
status.error_message().as_string());
return;
}
GOOGLE_CHECK(test_message.ParseFromString(proto_binary));
break; break;
}
case ConformanceRequest::PAYLOAD_NOT_SET: case ConformanceRequest::PAYLOAD_NOT_SET:
GOOGLE_LOG(FATAL) << "Request didn't have payload."; GOOGLE_LOG(FATAL) << "Request didn't have payload.";
break; break;
} }
switch (request.requested_output()) { switch (request.requested_output_format()) {
case ConformanceRequest::UNSPECIFIED: case conformance::UNSPECIFIED:
GOOGLE_LOG(FATAL) << "Unspecified output format"; GOOGLE_LOG(FATAL) << "Unspecified output format";
break; break;
case ConformanceRequest::PROTOBUF: case conformance::PROTOBUF:
test_message.SerializeToString(response->mutable_protobuf_payload()); GOOGLE_CHECK(
test_message.SerializeToString(response->mutable_protobuf_payload()));
break; break;
case ConformanceRequest::JSON: case conformance::JSON: {
response->set_runtime_error("JSON output is not yet supported."); string proto_binary;
GOOGLE_CHECK(test_message.SerializeToString(&proto_binary));
Status status = BinaryToJsonString(type_resolver, *type_url, proto_binary,
response->mutable_json_payload());
GOOGLE_CHECK(status.ok());
break; break;
} }
}
} }
bool DoTestIo() { bool DoTestIo() {
...@@ -146,6 +181,9 @@ bool DoTestIo() { ...@@ -146,6 +181,9 @@ bool DoTestIo() {
} }
int main() { int main() {
type_resolver = NewTypeResolverForDescriptorPool(
kTypeUrlPrefix, DescriptorPool::generated_pool());
type_url = new string(GetTypeUrl(TestAllTypes::descriptor()));
while (1) { while (1) {
if (!DoTestIo()) { if (!DoTestIo()) {
fprintf(stderr, "conformance-cpp: received EOF from test runner " fprintf(stderr, "conformance-cpp: received EOF from test runner "
......
This diff is collapsed.
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#define CONFORMANCE_CONFORMANCE_TEST_H #define CONFORMANCE_CONFORMANCE_TEST_H
#include <string> #include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/wire_format_lite.h> #include <google/protobuf/wire_format_lite.h>
namespace conformance { namespace conformance {
...@@ -98,10 +100,22 @@ class ConformanceTestSuite { ...@@ -98,10 +100,22 @@ class ConformanceTestSuite {
private: private:
void ReportSuccess(const std::string& test_name); void ReportSuccess(const std::string& test_name);
void ReportFailure(const std::string& test_name, const char* fmt, ...); void ReportFailure(const string& test_name,
const conformance::ConformanceRequest& request,
const conformance::ConformanceResponse& response,
const char* fmt, ...);
void ReportSkip(const string& test_name,
const conformance::ConformanceRequest& request,
const conformance::ConformanceResponse& response);
void RunTest(const std::string& test_name, void RunTest(const std::string& test_name,
const conformance::ConformanceRequest& request, const conformance::ConformanceRequest& request,
conformance::ConformanceResponse* response); conformance::ConformanceResponse* response);
void RunValidInputTest(const string& test_name, const string& input,
conformance::WireFormat input_format,
const string& equivalent_text_format,
conformance::WireFormat requested_output);
void RunValidJsonTest(const string& test_name, const string& input_json,
const string& equivalent_text_format);
void ExpectParseFailureForProto(const std::string& proto, void ExpectParseFailureForProto(const std::string& proto,
const std::string& test_name); const std::string& test_name);
void ExpectHardParseFailureForProto(const std::string& proto, void ExpectHardParseFailureForProto(const std::string& proto,
...@@ -110,7 +124,7 @@ class ConformanceTestSuite { ...@@ -110,7 +124,7 @@ class ConformanceTestSuite {
bool CheckSetEmpty(const set<string>& set_to_check, const char* msg); bool CheckSetEmpty(const set<string>& set_to_check, const char* msg);
ConformanceTestRunner* runner_; ConformanceTestRunner* runner_;
int successes_; int successes_;
int failures_; int expected_failures_;
bool verbose_; bool verbose_;
std::string output_; std::string output_;
...@@ -127,6 +141,13 @@ class ConformanceTestSuite { ...@@ -127,6 +141,13 @@ class ConformanceTestSuite {
// The set of tests that succeeded, but weren't expected to. // The set of tests that succeeded, but weren't expected to.
std::set<std::string> unexpected_succeeding_tests_; std::set<std::string> unexpected_succeeding_tests_;
// The set of tests that the testee opted out of;
std::set<std::string> skipped_;
google::protobuf::internal::scoped_ptr<google::protobuf::util::TypeResolver>
type_resolver_;
std::string type_url_;
}; };
} // namespace protobuf } // namespace protobuf
......
...@@ -7,15 +7,15 @@ ...@@ -7,15 +7,15 @@
# TODO(haberman): insert links to corresponding bugs tracking the issue. # TODO(haberman): insert links to corresponding bugs tracking the issue.
# Should we use GitHub issues or the Google-internal bug tracker? # Should we use GitHub issues or the Google-internal bug tracker?
PrematureEofBeforeKnownRepeatedValue.MESSAGE ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
PrematureEofInPackedField.BOOL ProtobufInput.PrematureEofInPackedField.BOOL
PrematureEofInPackedField.ENUM ProtobufInput.PrematureEofInPackedField.ENUM
PrematureEofInPackedField.INT32 ProtobufInput.PrematureEofInPackedField.INT32
PrematureEofInPackedField.INT64 ProtobufInput.PrematureEofInPackedField.INT64
PrematureEofInPackedField.SINT32 ProtobufInput.PrematureEofInPackedField.SINT32
PrematureEofInPackedField.SINT64 ProtobufInput.PrematureEofInPackedField.SINT64
PrematureEofInPackedField.UINT32 ProtobufInput.PrematureEofInPackedField.UINT32
PrematureEofInPackedField.UINT64 ProtobufInput.PrematureEofInPackedField.UINT64
PrematureEofInsideKnownRepeatedValue.MESSAGE ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment