krabka_protocol/
arbitrary_impls.rs1#![cfg(feature = "arbitrary")]
2
3use arbitrary::{Arbitrary, Unstructured};
4
5use crate::{
6 UnknownTaggedFields,
7 owned::{
8 api_versions_request::ApiVersionsRequest,
9 api_versions_response::{ApiVersion, ApiVersionsResponse},
10 },
11};
12
13fn ascii(u: &mut Unstructured, min: usize, max: usize) -> arbitrary::Result<String> {
14 let len = u.int_in_range(min..=max)?;
15 let mut s = String::with_capacity(len);
16 for _ in 0..len {
17 let c: u8 = u.int_in_range(0x20..=0x7E)?;
18 s.push(c as char);
19 }
20 Ok(s)
21}
22
23impl<'a> Arbitrary<'a> for ApiVersionsRequest {
24 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
25 Ok(Self {
26 client_software_name: ascii(u, 0, 32)?,
27 client_software_version: ascii(u, 0, 32)?,
28 cluster_id: u
29 .arbitrary::<bool>()?
30 .then(|| ascii(u, 0, 32))
31 .transpose()?,
32 node_id: u.arbitrary()?,
33 unknown_tagged_fields: UnknownTaggedFields::default(),
34 })
35 }
36}
37
38impl<'a> Arbitrary<'a> for ApiVersion {
39 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
40 Ok(Self {
41 api_key: u.arbitrary()?,
42 min_version: u.arbitrary()?,
43 max_version: u.arbitrary()?,
44 unknown_tagged_fields: UnknownTaggedFields::default(),
45 })
46 }
47}
48
49impl<'a> Arbitrary<'a> for ApiVersionsResponse {
50 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
51 let n = u.int_in_range(0..=8usize)?;
52 let mut api_keys = Vec::with_capacity(n);
53 for _ in 0..n {
54 api_keys.push(ApiVersion::arbitrary(u)?);
55 }
56 Ok(Self {
57 error_code: u.arbitrary()?,
58 api_keys,
59 throttle_time_ms: u.arbitrary()?,
60 supported_features: Vec::new(),
61 finalized_features_epoch: 0,
62 finalized_features: Vec::new(),
63 zk_migration_ready: false,
64 unknown_tagged_fields: UnknownTaggedFields::default(),
65 })
66 }
67}
68
69#[cfg(test)]
70mod tests {
71
72 use super::*;
73
74 #[test]
75 fn ascii_uses_input_and_stays_printable() {
76 let mut found = None;
77 for seed in 0u8..=u8::MAX {
78 let data = [seed, seed.wrapping_mul(37), seed.wrapping_add(91), 0x7E];
79 let mut u = Unstructured::new(&data);
80 if let Ok(s) = ascii(&mut u, 1, 8)
81 && !s.is_empty()
82 && s != "xyzzy"
83 {
84 found = Some(s);
85 break;
86 }
87 }
88
89 let s = found.expect("expected at least one generated string");
90 assert2::assert!(s.bytes().all(|b| (0x20..=0x7E).contains(&b)));
91 }
92
93 #[test]
94 fn arbitrary_api_versions_request_can_be_non_default() {
95 let mut found = false;
96 for seed in 0u8..=u8::MAX {
97 let data = [seed, seed.wrapping_add(1), seed.wrapping_add(2), 0x55, 0xAA];
98 let mut u = Unstructured::new(&data);
99 if let Ok(req) = ApiVersionsRequest::arbitrary(&mut u)
100 && req != ApiVersionsRequest::default()
101 {
102 assert2::assert!(req.client_software_name.bytes().all(|b| b.is_ascii()));
103 assert2::assert!(req.client_software_version.bytes().all(|b| b.is_ascii()));
104 found = true;
105 break;
106 }
107 }
108
109 assert2::assert!(found);
110 }
111
112 #[test]
113 fn arbitrary_api_version_can_be_non_default() {
114 let mut found = false;
115 for seed in 0u8..=u8::MAX {
116 let data = [
117 seed,
118 seed.wrapping_mul(3),
119 seed.wrapping_add(5),
120 seed.wrapping_add(8),
121 seed.wrapping_add(13),
122 seed.wrapping_add(21),
123 ];
124 let mut u = Unstructured::new(&data);
125 if let Ok(version) = ApiVersion::arbitrary(&mut u)
126 && version != ApiVersion::default()
127 {
128 found = true;
129 break;
130 }
131 }
132
133 assert2::assert!(found);
134 }
135
136 #[test]
137 fn arbitrary_api_versions_response_can_be_non_default() {
138 let mut found = false;
139 for seed in 0u8..=u8::MAX {
140 let data = [
141 seed,
142 seed.wrapping_add(1),
143 seed.wrapping_add(2),
144 seed.wrapping_add(3),
145 seed.wrapping_add(4),
146 seed.wrapping_add(5),
147 seed.wrapping_add(6),
148 seed.wrapping_add(7),
149 seed.wrapping_add(8),
150 ];
151 let mut u = Unstructured::new(&data);
152 if let Ok(resp) = ApiVersionsResponse::arbitrary(&mut u)
153 && resp != ApiVersionsResponse::default()
154 {
155 found = true;
156 break;
157 }
158 }
159
160 assert2::assert!(found);
161 }
162}