From 4ee2dcb9483ad979911dccd1efa3827e0dfb995a Mon Sep 17 00:00:00 2001 From: charles Date: Sat, 2 May 2026 17:52:04 -0700 Subject: [PATCH] Add more thorough test cases --- data/test_data.pb | Bin 0 -> 195 bytes data/test_data.textproto | 39 +++++++++++++++++ data/test_types.proto | 53 +++++++++++++++++++++++ src/lib.rs | 91 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 data/test_data.pb create mode 100644 data/test_data.textproto create mode 100644 data/test_types.proto diff --git a/data/test_data.pb b/data/test_data.pb new file mode 100644 index 0000000000000000000000000000000000000000..f010831a060da6057c3e470a4b41c075247d88ea GIT binary patch literal 195 zcmd;d5qAvvt;p#h>ia|2K|)L6=f3S5Iyz-EUa%YdhXF>5V26)?-#wTx$->v+5hFvO zXyeP;F9J$}u?J-T{ZD*dC)ULM{_eXB#v*Qy)SR4rg`oVBe8nn(VE3@%BzKGS&|FJ{ zq)J!Y21dp%Mpi~9W){{-jLi9YsX(%%Jbw}+Ye_~?YU(UTK8{o&4!_jmlGGFhLkY%N ej657^Z~>!5j3OK-7=?I)GxO4OQWYTTBp3nW-A3R5 literal 0 HcmV?d00001 diff --git a/data/test_data.textproto b/data/test_data.textproto new file mode 100644 index 0000000..5dc54ba --- /dev/null +++ b/data/test_data.textproto @@ -0,0 +1,39 @@ +d_val: 3.1415926535 +f_val: 2.71828 +i32_val: 42 +i64_val: 123456789012345 +u32_val: 1000 +u64_val: 18446744073709551615 +si32_val: -42 +si64_val: -123456789012345 +fx32_val: 123456 +fx64_val: 1234567890123456789 +sfx32_val: -123456 +sfx64_val: -1234567890123456789 +b_val: true +s_val: "Hello Roto!" +bytes_val: "SGVsbG8gUm90byE=" +status: ACTIVE +repeated_i32: 1 +repeated_i32: 2 +repeated_i32: 3 +repeated_i32: 4 +repeated_i32: 5 +repeated_string: "one" +repeated_string: "two" +repeated_string: "three" +repeated_nested { + id: 101 + name: "Nested 1" + active: true +} +repeated_nested { + id: 102 + name: "Nested 2" + active: false +} +single_nested { + id: 200 + name: "Single Nested" + active: true +} diff --git a/data/test_types.proto b/data/test_types.proto new file mode 100644 index 0000000..c4b4a9a --- /dev/null +++ b/data/test_types.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package roto.test; + +// A comprehensive message containing all primitive types and complex structures +// to test the proto-to-rust codegen and runtime accessors. +message ComplexMessage { + // --- Floating Point --- + double d_val = 1; + float f_val = 2; + + // --- Integers (Variable Length) --- + int32 i32_val = 3; + int64 i64_val = 4; + uint32 u32_val = 5; + uint64 u64_val = 6; + sint32 si32_val = 7; + sint64 si64_val = 8; + + // --- Integers (Fixed Length) --- + fixed32 fx32_val = 9; + fixed64 fx64_val = 10; + sfixed32 sfx32_val = 11; + sfixed64 sfx64_val = 12; + + // --- Other Primitives --- + bool b_val = 13; + string s_val = 14; + bytes bytes_val = 15; + + // --- Enumerations --- + enum Status { + UNKNOWN = 0; + ACTIVE = 1; + INACTIVE = 2; + DELETED = 3; + } + Status status = 16; + + // --- Repeated Fields --- + // Testing packed primitives and non-packed types + repeated int32 repeated_i32 = 17; + repeated string repeated_string = 18; + repeated NestedMessage repeated_nested = 19; + + // --- Nested Messages --- + message NestedMessage { + int32 id = 1; + string name = 2; + bool active = 3; + } + NestedMessage single_nested = 20; +} diff --git a/src/lib.rs b/src/lib.rs index d7333e1..636c7c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -394,6 +394,97 @@ mod tests { let result = builder.write_string(1, "too long"); assert_eq!(result, Err(RotoError::BufferOverflow)); } + + #[test] + fn test_protoc_binary_compatibility() { + let data = include_bytes!("../data/test_data.pb"); + let acc = ProtoAccessor::new(data).unwrap(); + + // 1. Varints (Integers, Booleans, Enums) + let (val_i32, type_i32) = acc.get_value(3).expect("i32_val not found"); + assert_eq!(type_i32, WireType::Varint); + let (v, _) = read_varint(val_i32).unwrap(); + assert_eq!(v, 42); + + let (val_b, type_b) = acc.get_value(13).expect("b_val not found"); + assert_eq!(type_b, WireType::Varint); + let (v_b, _) = read_varint(val_b).unwrap(); + assert_eq!(v_b, 1); // true + + let (val_status, type_status) = acc.get_value(16).expect("status not found"); + assert_eq!(type_status, WireType::Varint); + let (v_s, _) = read_varint(val_status).unwrap(); + assert_eq!(v_s, 1); // ACTIVE + + // 2. Length Delimited (Strings, Bytes) + let (val_s, type_s) = acc.get_value(14).expect("s_val not found"); + assert_eq!(type_s, WireType::LengthDelimited); + assert_eq!(val_s, "Hello Roto!".as_bytes()); + + // 3. Fixed Width (Floats) + let (val_f, type_f) = acc.get_value(2).expect("f_val not found"); + assert_eq!(type_f, WireType::Fixed32); + let f_val = f32::from_le_bytes(val_f.try_into().expect("Expected 4 bytes for f32")); + assert!((f_val - 2.71828).abs() < 1e-5); + + // 4. Repeated Fields + // Note: primitive repeated fields are packed in proto3, so we iterate over the blob + let mut i32_vals = Vec::new(); + for item in acc.iter_repeated(17) { + let (blob, _) = item.expect("Failed to decode repeated i32"); + let mut cursor = 0; + while cursor < blob.len() { + let (v, len) = read_varint(&blob[cursor..]).unwrap(); + i32_vals.push(v); + cursor += len; + } + } + assert_eq!(i32_vals, vec![1, 2, 3, 4, 5]); + + let repeated_strings: Vec<_> = acc.iter_repeated(18) + .map(|r| { + let (val, _) = r.expect("Failed to decode repeated string"); + std::str::from_utf8(val).expect("Invalid utf8") + }) + .collect(); + assert_eq!(repeated_strings, vec!["one", "two", "three"]); + + let repeated_nested: Vec<_> = acc.iter_repeated(19) + .map(|r| { + let (val, _) = r.expect("Failed to decode repeated nested"); + let nested_acc = ProtoAccessor::new(val).unwrap(); + let (id_val, _) = nested_acc.get_value(1).expect("Nested id not found"); + let (id, _) = read_varint(id_val).unwrap(); + id + }) + .collect(); + assert_eq!(repeated_nested, vec![101, 102]); + + // 5. Single Nested Message + let (val_nested, type_nested) = acc.get_value(20).expect("single_nested not found"); + assert_eq!(type_nested, WireType::LengthDelimited); + let nested_acc = ProtoAccessor::new(val_nested).unwrap(); + let (val_id, _) = nested_acc.get_value(1).expect("Nested id not found"); + let (id, _) = read_varint(val_id).unwrap(); + assert_eq!(id, 200); + + // Validate that fields appear in the expected relative order + let field_numbers: Vec = acc.fields() + .map(|r| r.expect("Failed to decode field").0.field_number) + .collect(); + + let essential_fields = [1, 2, 3, 14, 16, 20]; + let mut last_field = 0; + let mut found_count = 0; + for &f in &field_numbers { + if essential_fields.contains(&f) { + assert!(f >= last_field, "Fields appeared out of order: {} came after {}", f, last_field); + last_field = f; + found_count += 1; + } + } + assert_eq!(found_count, essential_fields.len()); + } } pub struct ProtoBuilder<'a> {