Skip to content

Commit 3f946df

Browse files
committed
Implement conformance test binary
1 parent f725928 commit 3f946df

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ members = [
1313
"protobuf-examples/issue-614",
1414
"protobuf-parse",
1515
"protobuf-support",
16+
"test-crates/conformance",
1617
"test-crates/perftest/bytes",
1718
"test-crates/perftest/misc",
1819
"test-crates/perftest/vs-cxx",

test-crates/conformance/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "conformance"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
anyhow = "1.0.68"
8+
protobuf = { path = "../../protobuf" }
9+
protobuf-json-mapping = { version = "4.0.0-alpha.0", path = "../../protobuf-json-mapping" }
10+
11+
[build-dependencies]
12+
protobuf-codegen = { path = "../../protobuf-codegen" }

test-crates/conformance/build.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
protobuf_codegen::Codegen::new()
3+
.includes(["../../google-protobuf-all-protos/protobuf/protobuf-git/conformance", "../../google-protobuf-all-protos/protobuf/protobuf-git/src/google/protobuf"])
4+
.inputs(["../../google-protobuf-all-protos/protobuf/protobuf-git/conformance/conformance.proto", "../../google-protobuf-all-protos/protobuf/protobuf-git/src/google/protobuf/test_messages_proto2.proto", "../../google-protobuf-all-protos/protobuf/protobuf-git/src/google/protobuf/test_messages_proto3.proto"])
5+
.cargo_out_dir("protos")
6+
.run_from_script();
7+
}

test-crates/conformance/src/main.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use std::io::{self, Read, Write};
2+
3+
use anyhow::{anyhow, bail, Context, Error, Result};
4+
5+
mod protos {
6+
include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));
7+
}
8+
9+
use protobuf::Message;
10+
use protos::conformance::{
11+
conformance_request::Payload, ConformanceRequest, ConformanceResponse, WireFormat,
12+
};
13+
14+
fn main() {
15+
loop {
16+
match serve_conformance_request() {
17+
Ok(false) => {}
18+
Ok(true) => break,
19+
Err(e) => {
20+
eprintln!("{:#}", e);
21+
std::process::exit(1)
22+
}
23+
}
24+
}
25+
}
26+
27+
fn serve_conformance_request() -> Result<bool> {
28+
let mut stdin = io::stdin().lock();
29+
let mut len = [0; 4];
30+
match stdin.read_exact(&mut len) {
31+
Ok(()) => {}
32+
Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => {
33+
return Ok(true);
34+
}
35+
Err(e) => return Err(Error::new(e).context("reading request length")),
36+
}
37+
let len = u32::from_le_bytes(len);
38+
let mut buf = vec![0; len as usize];
39+
stdin.read_exact(&mut buf).context("reading request")?;
40+
41+
let request = ConformanceRequest::parse_from_bytes(&buf).context("parsing request")?;
42+
43+
let response = run_test(&request).context("running test")?;
44+
45+
let response = response.write_to_bytes().context("serializing response")?;
46+
io::stdout()
47+
.write_all(&response)
48+
.context("writing response")?;
49+
50+
Ok(false)
51+
}
52+
53+
fn run_test(request: &ConformanceRequest) -> Result<ConformanceResponse> {
54+
let files = [
55+
protos::test_messages_proto3::file_descriptor(),
56+
protos::test_messages_proto2::file_descriptor(),
57+
];
58+
let descriptor = files
59+
.into_iter()
60+
.flat_map(|file| file.message_by_full_name(&request.message_type))
61+
.next()
62+
.ok_or_else(|| anyhow!("couldn't find message type {}", request.message_type))?;
63+
64+
let Some(ref payload) = request.payload else { bail!("missing or unsupported payload"); };
65+
66+
let mut test_message = descriptor.new_instance();
67+
let mut response = ConformanceResponse::new();
68+
match *payload {
69+
Payload::ProtobufPayload(ref payload) => {
70+
if let Err(e) = test_message.merge_from_bytes_dyn(payload) {
71+
response.set_parse_error(e.to_string());
72+
}
73+
}
74+
Payload::JsonPayload(ref payload) => {
75+
if let Err(e) = protobuf_json_mapping::merge_from_str(&mut *test_message, payload) {
76+
response.set_parse_error(e.to_string());
77+
}
78+
}
79+
Payload::JspbPayload(_) => {
80+
response.set_skipped("JSPB input not supported".into());
81+
}
82+
Payload::TextPayload(ref payload) => {
83+
if let Err(e) = protobuf::text_format::merge_from_str(&mut *test_message, payload) {
84+
response.set_parse_error(e.to_string());
85+
}
86+
}
87+
}
88+
89+
let requested_output_format = request
90+
.requested_output_format
91+
.enum_value()
92+
.map_err(|i| anyhow!("unknown wire format {}", i))?;
93+
match requested_output_format {
94+
WireFormat::UNSPECIFIED => bail!("unspecified output format"),
95+
WireFormat::PROTOBUF => response.set_protobuf_payload(
96+
test_message
97+
.write_to_bytes_dyn()
98+
.context("serializing test message")?,
99+
),
100+
WireFormat::JSON => {
101+
response.set_json_payload(
102+
protobuf_json_mapping::print_to_string(&*test_message)
103+
.context("serializing test message as JSON")?,
104+
);
105+
}
106+
WireFormat::JSPB => response.set_skipped("JSPB output not supported".into()),
107+
WireFormat::TEXT_FORMAT => {
108+
response.set_text_payload(protobuf::text_format::print_to_string(&*test_message))
109+
}
110+
}
111+
112+
Ok(response)
113+
}

0 commit comments

Comments
 (0)