Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

331 lines
10 KiB

/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* This is a upb implementation of the upb conformance tests, see:
* https://github.com/google/protobuf/tree/master/conformance
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "conformance/conformance.upb.h"
#include "conformance/conformance.upbdefs.h"
#include "src/google/protobuf/test_messages_proto2.upbdefs.h"
#include "src/google/protobuf/test_messages_proto3.upbdefs.h"
#include "upb/decode.h"
#include "upb/encode.h"
#include "upb/reflection.h"
#include "upb/json_decode.h"
#include "upb/json_encode.h"
#include "upb/text_encode.h"
#include "upb/port_def.inc"
int test_count = 0;
bool verbose = false; /* Set to true to get req/resp printed on stderr. */
bool CheckedRead(int fd, void *buf, size_t len) {
size_t ofs = 0;
while (len > 0) {
ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
if (bytes_read == 0) return false;
if (bytes_read < 0) {
perror("reading from test runner");
exit(1);
}
len -= bytes_read;
ofs += bytes_read;
}
return true;
}
void CheckedWrite(int fd, const void *buf, size_t len) {
if ((size_t)write(fd, buf, len) != len) {
perror("writing to test runner");
exit(1);
}
}
typedef struct {
const conformance_ConformanceRequest *request;
conformance_ConformanceResponse *response;
upb_arena *arena;
const upb_symtab *symtab;
} ctx;
bool parse_proto(upb_msg *msg, const upb_msgdef *m, const ctx* c) {
upb_strview proto =
conformance_ConformanceRequest_protobuf_payload(c->request);
if (upb_decode(proto.data, proto.size, msg, upb_msgdef_layout(m), c->arena) ==
kUpb_DecodeStatus_Ok) {
return true;
} else {
static const char msg[] = "Parse error";
conformance_ConformanceResponse_set_parse_error(
c->response, upb_strview_make(msg, strlen(msg)));
return false;
}
}
void serialize_proto(const upb_msg *msg, const upb_msgdef *m, const ctx *c) {
size_t len;
char *data = upb_encode(msg, upb_msgdef_layout(m), c->arena, &len);
if (data) {
conformance_ConformanceResponse_set_protobuf_payload(
c->response, upb_strview_make(data, len));
} else {
static const char msg[] = "Error serializing.";
conformance_ConformanceResponse_set_serialize_error(
c->response, upb_strview_make(msg, strlen(msg)));
}
}
void serialize_text(const upb_msg *msg, const upb_msgdef *m, const ctx *c) {
size_t len;
size_t len2;
int opts = 0;
char *data;
if (!conformance_ConformanceRequest_print_unknown_fields(c->request)) {
opts |= UPB_TXTENC_SKIPUNKNOWN;
}
len = upb_text_encode(msg, m, c->symtab, opts, NULL, 0);
data = upb_arena_malloc(c->arena, len + 1);
len2 = upb_text_encode(msg, m, c->symtab, opts, data, len + 1);
UPB_ASSERT(len == len2);
conformance_ConformanceResponse_set_text_payload(
c->response, upb_strview_make(data, len));
}
bool parse_json(upb_msg *msg, const upb_msgdef *m, const ctx* c) {
upb_strview json =
conformance_ConformanceRequest_json_payload(c->request);
upb_status status;
int opts = 0;
if (conformance_ConformanceRequest_test_category(c->request) ==
conformance_JSON_IGNORE_UNKNOWN_PARSING_TEST) {
opts |= UPB_JSONDEC_IGNOREUNKNOWN;
}
upb_status_clear(&status);
if (upb_json_decode(json.data, json.size, msg, m, c->symtab, opts, c->arena,
&status)) {
return true;
} else {
const char *inerr = upb_status_errmsg(&status);
size_t len = strlen(inerr);
char *err = upb_arena_malloc(c->arena, len + 1);
memcpy(err, inerr, strlen(inerr));
err[len] = '\0';
conformance_ConformanceResponse_set_parse_error(c->response,
upb_strview_makez(err));
return false;
}
}
void serialize_json(const upb_msg *msg, const upb_msgdef *m, const ctx *c) {
size_t len;
size_t len2;
int opts = 0;
char *data;
upb_status status;
upb_status_clear(&status);
len = upb_json_encode(msg, m, c->symtab, opts, NULL, 0, &status);
if (len == (size_t)-1) {
const char *inerr = upb_status_errmsg(&status);
size_t len = strlen(inerr);
char *err = upb_arena_malloc(c->arena, len + 1);
memcpy(err, inerr, strlen(inerr));
err[len] = '\0';
conformance_ConformanceResponse_set_serialize_error(c->response,
upb_strview_makez(err));
return;
}
data = upb_arena_malloc(c->arena, len + 1);
len2 = upb_json_encode(msg, m, c->symtab, opts, data, len + 1, &status);
UPB_ASSERT(len == len2);
conformance_ConformanceResponse_set_json_payload(
c->response, upb_strview_make(data, len));
}
bool parse_input(upb_msg *msg, const upb_msgdef *m, const ctx* c) {
switch (conformance_ConformanceRequest_payload_case(c->request)) {
case conformance_ConformanceRequest_payload_protobuf_payload:
return parse_proto(msg, m, c);
case conformance_ConformanceRequest_payload_json_payload:
return parse_json(msg, m, c);
case conformance_ConformanceRequest_payload_NOT_SET:
fprintf(stderr, "conformance_upb: Request didn't have payload.\n");
return false;
default: {
static const char msg[] = "Unsupported input format.";
conformance_ConformanceResponse_set_skipped(
c->response, upb_strview_make(msg, strlen(msg)));
return false;
}
}
}
void write_output(const upb_msg *msg, const upb_msgdef *m, const ctx* c) {
switch (conformance_ConformanceRequest_requested_output_format(c->request)) {
case conformance_UNSPECIFIED:
fprintf(stderr, "conformance_upb: Unspecified output format.\n");
exit(1);
case conformance_PROTOBUF:
serialize_proto(msg, m, c);
break;
case conformance_TEXT_FORMAT:
serialize_text(msg, m, c);
break;
case conformance_JSON:
serialize_json(msg, m, c);
break;
default: {
static const char msg[] = "Unsupported output format.";
conformance_ConformanceResponse_set_skipped(
c->response, upb_strview_make(msg, strlen(msg)));
break;
}
}
}
void DoTest(const ctx* c) {
upb_msg *msg;
upb_strview name = conformance_ConformanceRequest_message_type(c->request);
const upb_msgdef *m = upb_symtab_lookupmsg2(c->symtab, name.data, name.size);
#if 0
// Handy code for limiting conformance tests to a single input payload.
// This is a hack since the conformance runner doesn't give an easy way to
// specify what test should be run.
const char skip[] = "\343>\010\301\002\344>\230?\001\230?\002\230?\003";
upb_strview skip_str = upb_strview_make(skip, sizeof(skip) - 1);
upb_strview pb_payload =
conformance_ConformanceRequest_protobuf_payload(c->request);
if (!upb_strview_eql(pb_payload, skip_str)) m = NULL;
#endif
if (!m) {
static const char msg[] = "Unknown message type.";
conformance_ConformanceResponse_set_skipped(
c->response, upb_strview_make(msg, strlen(msg)));
return;
}
msg = upb_msg_new(m, c->arena);
if (parse_input(msg, m, c)) {
write_output(msg, m, c);
}
}
void debug_print(const char *label, const upb_msg *msg, const upb_msgdef *m,
const ctx *c) {
char buf[512];
upb_text_encode(msg, m, c->symtab, UPB_TXTENC_SINGLELINE, buf, sizeof(buf));
fprintf(stderr, "%s: %s\n", label, buf);
}
bool DoTestIo(upb_symtab *symtab) {
upb_status status;
char *input;
char *output;
uint32_t input_size;
size_t output_size;
ctx c;
if (!CheckedRead(STDIN_FILENO, &input_size, sizeof(uint32_t))) {
/* EOF. */
return false;
}
c.symtab = symtab;
c.arena = upb_arena_new();
input = upb_arena_malloc(c.arena, input_size);
if (!CheckedRead(STDIN_FILENO, input, input_size)) {
fprintf(stderr, "conformance_upb: unexpected EOF on stdin.\n");
exit(1);
}
c.request = conformance_ConformanceRequest_parse(input, input_size, c.arena);
c.response = conformance_ConformanceResponse_new(c.arena);
if (c.request) {
DoTest(&c);
} else {
fprintf(stderr, "conformance_upb: parse of ConformanceRequest failed: %s\n",
upb_status_errmsg(&status));
}
output = conformance_ConformanceResponse_serialize(c.response, c.arena,
&output_size);
CheckedWrite(STDOUT_FILENO, &output_size, sizeof(uint32_t));
CheckedWrite(STDOUT_FILENO, output, output_size);
test_count++;
if (verbose) {
debug_print("Request", c.request,
conformance_ConformanceRequest_getmsgdef(symtab), &c);
debug_print("Response", c.response,
conformance_ConformanceResponse_getmsgdef(symtab), &c);
fprintf(stderr, "\n");
}
upb_arena_free(c.arena);
return true;
}
int main(void) {
upb_symtab *symtab = upb_symtab_new();
protobuf_test_messages_proto2_TestAllTypesProto2_getmsgdef(symtab);
protobuf_test_messages_proto3_TestAllTypesProto3_getmsgdef(symtab);
while (1) {
if (!DoTestIo(symtab)) {
fprintf(stderr, "conformance_upb: received EOF from test runner "
"after %d tests, exiting\n", test_count);
upb_symtab_free(symtab);
return 0;
}
}
}