| // Copyright 2023 Google LLC. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| use conformance_rust_proto::{ConformanceRequest, ConformanceResponse, WireFormat}; | |
| use protobuf::prelude::*; | |
| use protobuf::{Message, ParseError}; | |
| use std::io::{self, ErrorKind, Read, Write}; | |
| use test_messages_edition2023_rust_proto::TestAllTypesEdition2023; | |
| use test_messages_edition2026_rust_proto::TestAllTypesEdition2026; | |
| use test_messages_edition_unstable_rust_proto::TestAllTypesEditionUnstable; | |
| use test_messages_proto2_editions_rust_proto::TestAllTypesProto2 as EditionsTestAllTypesProto2; | |
| use test_messages_proto2_rust_proto::TestAllTypesProto2; | |
| use test_messages_proto3_editions_rust_proto::TestAllTypesProto3 as EditionsTestAllTypesProto3; | |
| use test_messages_proto3_rust_proto::TestAllTypesProto3; | |
| /// Returns Some(i32) if a binary read can succeed from stdin. | |
| /// Returns None if we have reached an EOF. | |
| /// Panics for any other error reading. | |
| fn read_little_endian_i32_from_stdin() -> Option<i32> { | |
| let mut buffer = [0_u8; 4]; | |
| if let Err(e) = io::stdin().read_exact(&mut buffer) { | |
| match e.kind() { | |
| ErrorKind::UnexpectedEof => None, | |
| _ => panic!("failed to read i32 from stdin"), | |
| } | |
| } else { | |
| Some(i32::from_le_bytes(buffer)) | |
| } | |
| } | |
| /// Returns Some of a conformance request read from stdin. | |
| /// Returns None if we have hit an EOF that suggests the test suite is complete. | |
| /// Panics in any other case (e.g. an EOF in a place that would imply a | |
| /// programmer error in the conformance test suite). | |
| fn read_request_from_stdin() -> Option<ConformanceRequest> { | |
| let msg_len = read_little_endian_i32_from_stdin()?; | |
| let mut serialized = vec![0_u8; msg_len as usize]; | |
| io::stdin().read_exact(&mut serialized).unwrap(); | |
| Some(ConformanceRequest::parse(&serialized).unwrap()) | |
| } | |
| fn write_response_to_stdout(resp: &ConformanceResponse) { | |
| let bytes = resp.serialize().unwrap(); | |
| let len = bytes.len() as u32; | |
| let mut handle = io::stdout(); | |
| handle.write_all(&len.to_le_bytes()).unwrap(); | |
| handle.write(&bytes).unwrap(); | |
| handle.flush().unwrap(); | |
| } | |
| fn do_test(req: &ConformanceRequest) -> ConformanceResponse { | |
| let mut resp = ConformanceResponse::new(); | |
| let message_type = req.message_type(); | |
| if req.requested_output_format() != WireFormat::Protobuf { | |
| resp.set_skipped("only wire format output implemented"); | |
| return resp; | |
| } | |
| let bytes = match req.protobuf_payload_opt() { | |
| Some(bytes) => bytes, | |
| None => { | |
| resp.set_skipped("only wire format input implemented"); | |
| return resp; | |
| } | |
| }; | |
| fn roundtrip<T: Message>(bytes: &[u8]) -> Result<Vec<u8>, ParseError> { | |
| T::parse(bytes).map(|msg| msg.serialize().unwrap()) | |
| } | |
| let serialized = match message_type.as_bytes() { | |
| b"protobuf_test_messages.proto2.TestAllTypesProto2" => { | |
| roundtrip::<TestAllTypesProto2>(bytes) | |
| } | |
| b"protobuf_test_messages.proto3.TestAllTypesProto3" => { | |
| roundtrip::<TestAllTypesProto3>(bytes) | |
| } | |
| b"protobuf_test_messages.editions.TestAllTypesEdition2023" => { | |
| roundtrip::<TestAllTypesEdition2023>(bytes) | |
| } | |
| b"protobuf_test_messages.editions.TestAllTypesEdition2026" => { | |
| roundtrip::<TestAllTypesEdition2026>(bytes) | |
| } | |
| b"protobuf_test_messages.edition_unstable.TestAllTypesEditionUnstable" => { | |
| roundtrip::<TestAllTypesEditionUnstable>(bytes) | |
| } | |
| b"protobuf_test_messages.editions.proto2.TestAllTypesProto2" => { | |
| roundtrip::<EditionsTestAllTypesProto2>(bytes) | |
| } | |
| b"protobuf_test_messages.editions.proto3.TestAllTypesProto3" => { | |
| roundtrip::<EditionsTestAllTypesProto3>(bytes) | |
| } | |
| _ => panic!("unexpected msg type {message_type}"), | |
| }; | |
| match serialized { | |
| Ok(serialized) => { | |
| resp.set_protobuf_payload(serialized); | |
| } | |
| Err(_) => { | |
| resp.set_parse_error("failed to parse bytes"); | |
| } | |
| } | |
| resp | |
| } | |
| fn main() { | |
| let mut total_runs = 0; | |
| while let Some(req) = read_request_from_stdin() { | |
| let resp = do_test(&req); | |
| write_response_to_stdout(&resp); | |
| total_runs += 1; | |
| } | |
| eprintln!("conformance_rust: received EOF from test runner after {total_runs} tests"); | |
| } |