// 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_proto::conformance::{ConformanceRequest, ConformanceResponse}; use conformance_rust_overlay_hack_proto::conformance::ConformanceRequestRustOverlayHack; #[cfg(cpp_kernel)] use protobuf_cpp as kernel; #[cfg(upb_kernel)] use protobuf_upb as kernel; use kernel::Optional::{Set, Unset}; use std::io::{self, ErrorKind, Read, Write}; use test_messages_proto2::protobuf_test_messages::proto2::TestAllTypesProto2; use test_messages_proto2_editions_proto::protobuf_test_messages::editions::proto2::TestAllTypesProto2 as EditionsTestAllTypesProto2; use test_messages_proto3::protobuf_test_messages::proto3::TestAllTypesProto3; use test_messages_proto3_editions_proto::protobuf_test_messages::editions::proto3::TestAllTypesProto3 as EditionsTestAllTypesProto3; /// 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 { 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, ConformanceRequestRustOverlayHack)> { 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(); let mut req = ConformanceRequest::new(); req.deserialize(&serialized).unwrap(); // TODO: b/318373255 - Since enum accessors aren't available yet, we parse an // overlay with int32 field instead of an enum so that we can check if the // requested output is binary or not. This will be deleted once enum // accessors are supported. let mut req_overlay_hack = ConformanceRequestRustOverlayHack::new(); req_overlay_hack.deserialize(&serialized).unwrap(); Some((req, req_overlay_hack)) } fn write_response_to_stdout(resp: &ConformanceResponse) { let bytes = resp.serialize(); 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, req_overlay_hack: &ConformanceRequestRustOverlayHack, ) -> ConformanceResponse { let mut resp = ConformanceResponse::new(); let message_type = req.message_type(); // TODO: b/318373255 - Use the enum once its supported. // if req.requested_output_format() != WireFormat.PROTOBUF { if req_overlay_hack.requested_output_format() != 1 { resp.skipped_mut().set("only wire format output implemented"); return resp; } let bytes = match req.protobuf_payload_opt() { Unset(_) => { resp.skipped_mut().set("only wire format input implemented"); return resp; } Set(bytes) => bytes, }; let serialized = match message_type.as_bytes() { b"protobuf_test_messages.proto2.TestAllTypesProto2" => { let mut proto = TestAllTypesProto2::new(); if let Err(_) = proto.deserialize(bytes) { resp.parse_error_mut().set("failed to parse bytes"); return resp; } proto.serialize() } b"protobuf_test_messages.proto3.TestAllTypesProto3" => { let mut proto = TestAllTypesProto3::new(); if let Err(_) = proto.deserialize(bytes) { resp.parse_error_mut().set("failed to parse bytes"); return resp; } proto.serialize() } b"protobuf_test_messages.editions.proto2.TestAllTypesProto2" => { let mut proto = EditionsTestAllTypesProto2::new(); if let Err(_) = proto.deserialize(bytes) { resp.parse_error_mut().set("failed to parse bytes"); return resp; } proto.serialize() } b"protobuf_test_messages.editions.proto3.TestAllTypesProto3" => { let mut proto = EditionsTestAllTypesProto3::new(); if let Err(_) = proto.deserialize(bytes) { resp.parse_error_mut().set("failed to parse bytes"); return resp; } proto.serialize() } _ => panic!("unexpected msg type {message_type}"), }; resp.protobuf_payload_mut().set(serialized); return resp; } fn main() { let mut total_runs = 0; while let Some((req, req_overlay_hack)) = read_request_from_stdin() { let resp = do_test(&req, &req_overlay_hack); write_response_to_stdout(&resp); total_runs += 1; } eprintln!("conformance_rust: received EOF from test runner after {total_runs} tests"); }