1use base64::{engine::general_purpose, Engine as _};
7use prost_reflect::{
8 DescriptorPool, DynamicMessage, FieldDescriptor, Kind, MessageDescriptor, ReflectMessage, Value,
9};
10use serde_json::{self, Value as JsonValue};
11use std::string::String as StdString;
12use tracing::{debug, warn};
13
14#[derive(Debug, thiserror::Error)]
16pub enum ConversionError {
17 #[error("Field '{field}' required but missing from JSON")]
19 MissingField {
20 field: String,
22 },
23 #[error("Invalid value for field '{field}': {message}")]
25 InvalidValue {
26 field: String,
28 message: String,
30 },
31 #[error("Unknown field '{field}' in message")]
33 UnknownField {
34 field: String,
36 },
37 #[error("Type mismatch for field '{field}': expected {expected}, got {actual}")]
39 TypeMismatch {
40 field: String,
42 expected: String,
44 actual: String,
46 },
47 #[error("Failed to convert nested message: {0}")]
49 NestedError(String),
50 #[error("Protobuf reflection error: {0}")]
52 ProtobufError(String),
53}
54
55impl ConversionError {
56 }
58
59#[derive(Debug, Clone)]
61pub struct ProtobufJsonConverter {
62 pool: DescriptorPool,
67}
68
69impl ProtobufJsonConverter {
70 pub fn new(pool: DescriptorPool) -> Self {
72 Self { pool }
73 }
74
75 pub fn json_to_protobuf(
77 &self,
78 descriptor: &MessageDescriptor,
79 json: &JsonValue,
80 ) -> Result<DynamicMessage, ConversionError> {
81 debug!("Converting JSON to protobuf message: {}", descriptor.name());
82
83 let mut message = DynamicMessage::new(descriptor.clone());
84
85 let obj = json.as_object().ok_or_else(|| ConversionError::InvalidValue {
86 field: descriptor.name().to_string(),
87 message: "Expected JSON object".to_string(),
88 })?;
89
90 for (field_name, json_value) in obj {
92 self.set_field_from_json(&mut message, field_name, json_value)?;
93 }
94
95 self.set_default_values_for_missing_fields(&mut message)?;
97
98 Ok(message)
99 }
100
101 pub fn protobuf_to_json(
103 &self,
104 descriptor: &MessageDescriptor,
105 message: &DynamicMessage,
106 ) -> Result<JsonValue, ConversionError> {
107 debug!("Converting protobuf message to JSON: {}", descriptor.name());
108
109 let mut obj = serde_json::Map::new();
110
111 for field in descriptor.fields() {
112 let field_name = field.name();
113
114 if message.has_field(&field) {
115 let field_value = message.get_field(&field).into_owned();
116 let json_value = self.convert_protobuf_value_to_json(&field, field_value)?;
117 obj.insert(field_name.to_string(), json_value);
118 } else if field.supports_presence() && !field.is_list() {
119 }
124 }
125
126 Ok(JsonValue::Object(obj))
127 }
128
129 fn set_field_from_json(
131 &self,
132 message: &mut DynamicMessage,
133 field_name: &str,
134 json_value: &JsonValue,
135 ) -> Result<(), ConversionError> {
136 let field = message.descriptor().get_field_by_name(field_name).ok_or_else(|| {
137 ConversionError::UnknownField {
138 field: field_name.to_string(),
139 }
140 })?;
141
142 let protobuf_value = self.convert_json_value_to_protobuf(&field, json_value)?;
143 message.set_field(&field, protobuf_value);
144
145 Ok(())
146 }
147
148 fn convert_json_value_to_protobuf(
150 &self,
151 field: &FieldDescriptor,
152 json_value: &JsonValue,
153 ) -> Result<Value, ConversionError> {
154 use prost_reflect::Kind::*;
155
156 if field.is_list() {
158 if let JsonValue::Array(json_array) = json_value {
159 return self.convert_json_array_to_protobuf_list(field, json_array);
160 } else {
161 return Err(ConversionError::TypeMismatch {
163 field: field.name().to_string(),
164 expected: "array".to_string(),
165 actual: self.json_type_name(json_value),
166 });
167 }
168 }
169
170 match field.kind() {
171 Message(ref message_descriptor) => {
172 match json_value {
173 JsonValue::Object(_) => {
174 let nested_message =
175 self.json_to_protobuf(message_descriptor, json_value)?;
176 Ok(Value::Message(nested_message))
177 }
178 JsonValue::Null if field.supports_presence() => {
179 Ok(Value::Message(DynamicMessage::new(message_descriptor.clone())))
181 }
182 _ => Err(ConversionError::TypeMismatch {
183 field: field.name().to_string(),
184 expected: "object".to_string(),
185 actual: self.json_type_name(json_value),
186 }),
187 }
188 }
189 Enum(ref enum_descriptor) => {
190 match json_value {
191 JsonValue::String(s) => {
192 if let Some(enum_value) = enum_descriptor.get_value_by_name(s) {
194 Ok(Value::EnumNumber(enum_value.number()))
195 } else {
196 match s.parse::<i32>() {
198 Ok(num) => {
199 if enum_descriptor.get_value(num).is_some() {
200 Ok(Value::EnumNumber(num))
201 } else {
202 Err(ConversionError::InvalidValue {
203 field: field.name().to_string(),
204 message: format!("Invalid enum value: {}", num),
205 })
206 }
207 }
208 Err(_) => Err(ConversionError::InvalidValue {
209 field: field.name().to_string(),
210 message: format!("Unknown enum value: {}", s),
211 }),
212 }
213 }
214 }
215 JsonValue::Number(n) => {
216 if let Some(num) = n.as_i64() {
217 let num = num as i32;
218 if enum_descriptor.get_value(num).is_some() {
219 Ok(Value::EnumNumber(num))
220 } else {
221 Err(ConversionError::InvalidValue {
222 field: field.name().to_string(),
223 message: format!("Invalid enum number: {}", num),
224 })
225 }
226 } else {
227 Err(ConversionError::TypeMismatch {
228 field: field.name().to_string(),
229 expected: "integer".to_string(),
230 actual: "number".to_string(),
231 })
232 }
233 }
234 JsonValue::Null if field.supports_presence() => {
235 Ok(Value::EnumNumber(0)) }
237 _ => Err(ConversionError::TypeMismatch {
238 field: field.name().to_string(),
239 expected: "string or number".to_string(),
240 actual: self.json_type_name(json_value),
241 }),
242 }
243 }
244 String => match json_value {
245 JsonValue::String(s) => Ok(Value::String(s.clone())),
246 JsonValue::Null if field.supports_presence() => Ok(Value::String(StdString::new())),
247 _ => Err(ConversionError::TypeMismatch {
248 field: field.name().to_string(),
249 expected: "string".to_string(),
250 actual: self.json_type_name(json_value),
251 }),
252 },
253 Int32 | Sint32 | Sfixed32 => match json_value {
254 JsonValue::Number(n) => {
255 if let Some(i) = n.as_i64() {
256 Ok(Value::I32(i as i32))
257 } else {
258 Err(ConversionError::InvalidValue {
259 field: field.name().to_string(),
260 message: "Number out of range for int32".to_string(),
261 })
262 }
263 }
264 JsonValue::String(s) => match s.parse::<i32>() {
265 Ok(i) => Ok(Value::I32(i)),
266 Err(_) => Err(ConversionError::InvalidValue {
267 field: field.name().to_string(),
268 message: format!("Invalid int32 value: {}", s),
269 }),
270 },
271 JsonValue::Null if field.supports_presence() => Ok(Value::I32(0)),
272 _ => Err(ConversionError::TypeMismatch {
273 field: field.name().to_string(),
274 expected: "number or string".to_string(),
275 actual: self.json_type_name(json_value),
276 }),
277 },
278 Int64 | Sint64 | Sfixed64 => match json_value {
279 JsonValue::Number(n) => {
280 if let Some(i) = n.as_i64() {
281 Ok(Value::I64(i))
282 } else {
283 Err(ConversionError::InvalidValue {
284 field: field.name().to_string(),
285 message: "Number out of range for int64".to_string(),
286 })
287 }
288 }
289 JsonValue::String(s) => match s.parse::<i64>() {
290 Ok(i) => Ok(Value::I64(i)),
291 Err(_) => Err(ConversionError::InvalidValue {
292 field: field.name().to_string(),
293 message: format!("Invalid int64 value: {}", s),
294 }),
295 },
296 JsonValue::Null if field.supports_presence() => Ok(Value::I64(0)),
297 _ => Err(ConversionError::TypeMismatch {
298 field: field.name().to_string(),
299 expected: "number or string".to_string(),
300 actual: self.json_type_name(json_value),
301 }),
302 },
303 Uint32 | Fixed32 => match json_value {
304 JsonValue::Number(n) => {
305 if let Some(i) = n.as_u64() {
306 Ok(Value::U32(i as u32))
307 } else {
308 Err(ConversionError::InvalidValue {
309 field: field.name().to_string(),
310 message: "Number out of range for uint32".to_string(),
311 })
312 }
313 }
314 JsonValue::String(s) => match s.parse::<u32>() {
315 Ok(i) => Ok(Value::U32(i)),
316 Err(_) => Err(ConversionError::InvalidValue {
317 field: field.name().to_string(),
318 message: format!("Invalid uint32 value: {}", s),
319 }),
320 },
321 JsonValue::Null if field.supports_presence() => Ok(Value::U32(0)),
322 _ => Err(ConversionError::TypeMismatch {
323 field: field.name().to_string(),
324 expected: "number or string".to_string(),
325 actual: self.json_type_name(json_value),
326 }),
327 },
328 Uint64 | Fixed64 => match json_value {
329 JsonValue::Number(n) => {
330 if let Some(i) = n.as_u64() {
331 Ok(Value::U64(i))
332 } else {
333 Err(ConversionError::InvalidValue {
334 field: field.name().to_string(),
335 message: "Number out of range for uint64".to_string(),
336 })
337 }
338 }
339 JsonValue::String(s) => match s.parse::<u64>() {
340 Ok(i) => Ok(Value::U64(i)),
341 Err(_) => Err(ConversionError::InvalidValue {
342 field: field.name().to_string(),
343 message: format!("Invalid uint64 value: {}", s),
344 }),
345 },
346 JsonValue::Null if field.supports_presence() => Ok(Value::U64(0)),
347 _ => Err(ConversionError::TypeMismatch {
348 field: field.name().to_string(),
349 expected: "number or string".to_string(),
350 actual: self.json_type_name(json_value),
351 }),
352 },
353 Float => match json_value {
354 JsonValue::Number(n) => {
355 if let Some(f) = n.as_f64() {
356 Ok(Value::F32(f as f32))
357 } else {
358 Ok(Value::F32(0.0))
359 }
360 }
361 JsonValue::String(s) => match s.parse::<f32>() {
362 Ok(f) => Ok(Value::F32(f)),
363 Err(_) => Err(ConversionError::InvalidValue {
364 field: field.name().to_string(),
365 message: format!("Invalid float value: {}", s),
366 }),
367 },
368 JsonValue::Null if field.supports_presence() => Ok(Value::F32(0.0)),
369 _ => Err(ConversionError::TypeMismatch {
370 field: field.name().to_string(),
371 expected: "number or string".to_string(),
372 actual: self.json_type_name(json_value),
373 }),
374 },
375 Double => match json_value {
376 JsonValue::Number(n) => {
377 if let Some(f) = n.as_f64() {
378 Ok(Value::F64(f))
379 } else {
380 Ok(Value::F64(0.0))
381 }
382 }
383 JsonValue::String(s) => match s.parse::<f64>() {
384 Ok(f) => Ok(Value::F64(f)),
385 Err(_) => Err(ConversionError::InvalidValue {
386 field: field.name().to_string(),
387 message: format!("Invalid double value: {}", s),
388 }),
389 },
390 JsonValue::Null if field.supports_presence() => Ok(Value::F64(0.0)),
391 _ => Err(ConversionError::TypeMismatch {
392 field: field.name().to_string(),
393 expected: "number or string".to_string(),
394 actual: self.json_type_name(json_value),
395 }),
396 },
397 Bool => match json_value {
398 JsonValue::Bool(b) => Ok(Value::Bool(*b)),
399 JsonValue::String(s) => match s.to_lowercase().as_str() {
400 "true" | "1" | "yes" | "on" => Ok(Value::Bool(true)),
401 "false" | "0" | "no" | "off" | "" => Ok(Value::Bool(false)),
402 _ => Err(ConversionError::InvalidValue {
403 field: field.name().to_string(),
404 message: format!("Invalid boolean value: {}", s),
405 }),
406 },
407 JsonValue::Number(n) => {
408 if let Some(i) = n.as_i64() {
409 Ok(Value::Bool(i != 0))
410 } else {
411 Ok(Value::Bool(false))
412 }
413 }
414 JsonValue::Null if field.supports_presence() => Ok(Value::Bool(false)),
415 _ => Err(ConversionError::TypeMismatch {
416 field: field.name().to_string(),
417 expected: "boolean, number, or string".to_string(),
418 actual: self.json_type_name(json_value),
419 }),
420 },
421 Bytes => match json_value {
422 JsonValue::String(s) => match general_purpose::STANDARD.decode(s) {
423 Ok(bytes) => Ok(Value::Bytes(bytes.into())),
424 Err(_) => Err(ConversionError::InvalidValue {
425 field: field.name().to_string(),
426 message: format!("Invalid base64 string: {}", s),
427 }),
428 },
429 JsonValue::Null if field.supports_presence() => Ok(Value::Bytes(vec![].into())),
430 _ => Err(ConversionError::TypeMismatch {
431 field: field.name().to_string(),
432 expected: "base64 string".to_string(),
433 actual: self.json_type_name(json_value),
434 }),
435 },
436 }
437 }
438
439 fn convert_protobuf_value_to_json(
441 &self,
442 field: &FieldDescriptor,
443 value: Value,
444 ) -> Result<JsonValue, ConversionError> {
445 use prost_reflect::Value::*;
446
447 Ok(match value {
448 String(s) => JsonValue::String(s),
449 I32(i) => JsonValue::Number(i.into()),
450 I64(i) => JsonValue::Number(i.into()),
451 U32(u) => JsonValue::Number(u.into()),
452 U64(u) => JsonValue::Number(u.into()),
453 F32(f) => {
454 if f.is_finite() {
455 JsonValue::Number(serde_json::Number::from_f64(f as f64).unwrap_or(0.into()))
456 } else {
457 JsonValue::Number(0.into())
458 }
459 }
460 F64(f) => {
461 if f.is_finite() {
462 JsonValue::Number(serde_json::Number::from_f64(f).unwrap_or(0.into()))
463 } else {
464 JsonValue::Number(0.into())
465 }
466 }
467 Bool(b) => JsonValue::Bool(b),
468 EnumNumber(n) => {
469 if let Kind::Enum(ref enum_descriptor) = field.kind() {
470 if let Some(enum_value) = enum_descriptor.get_value(n) {
471 JsonValue::String(enum_value.name().to_string())
472 } else {
473 warn!("Unknown enum value {} for field {}", n, field.name());
475 JsonValue::String(n.to_string())
476 }
477 } else {
478 JsonValue::String(n.to_string())
479 }
480 }
481 Bytes(b) => JsonValue::String(general_purpose::STANDARD.encode(b)),
482 Message(msg) => self.protobuf_to_json(&msg.descriptor(), &msg)?,
483 List(list) => {
484 let mut json_array = Vec::new();
485 for item in list {
486 let json_item = self.convert_protobuf_value_to_json(field, item)?;
487 json_array.push(json_item);
488 }
489 JsonValue::Array(json_array)
490 }
491 Map(map) => {
492 let mut json_obj = serde_json::Map::new();
493 for (key, value) in map {
494 let json_key = match key {
495 prost_reflect::MapKey::String(s) => serde_json::Value::String(s),
496 prost_reflect::MapKey::I32(i) => serde_json::Value::Number(i.into()),
497 prost_reflect::MapKey::I64(i) => serde_json::Value::Number(i.into()),
498 prost_reflect::MapKey::Bool(b) => serde_json::Value::Bool(b),
499 prost_reflect::MapKey::U32(u) => serde_json::Value::Number(u.into()),
500 prost_reflect::MapKey::U64(u) => serde_json::Value::Number(u.into()),
501 };
502 let json_value = self.convert_protobuf_value_to_json(field, value)?;
503 let key_str = match json_key {
505 JsonValue::String(s) => s,
506 JsonValue::Number(n) => n.to_string(),
507 JsonValue::Bool(b) => b.to_string(),
508 _ => json_key.to_string(), };
510 json_obj.insert(key_str, json_value);
511 }
512 JsonValue::Object(json_obj)
513 }
514 })
515 }
516
517 fn set_default_values_for_missing_fields(
519 &self,
520 message: &mut DynamicMessage,
521 ) -> Result<(), ConversionError> {
522 let descriptor = message.descriptor();
523
524 for field in descriptor.fields() {
525 if !message.has_field(&field) {
526 if !field.is_list() && !field.supports_presence() {
528 let default_value = self.get_default_value_for_field(&field)?;
529 message.set_field(&field, default_value);
530 debug!("Set default value for field: {}", field.name());
531 }
532 }
533 }
534
535 Ok(())
536 }
537
538 fn get_default_value_for_field(
540 &self,
541 field: &FieldDescriptor,
542 ) -> Result<Value, ConversionError> {
543 use prost_reflect::Kind::*;
544
545 Ok(match field.kind() {
546 String => Value::String(StdString::new()),
547 Int32 | Sint32 | Sfixed32 => Value::I32(0),
548 Int64 | Sint64 | Sfixed64 => Value::I64(0),
549 Uint32 | Fixed32 => Value::U32(0),
550 Uint64 | Fixed64 => Value::U64(0),
551 Float => Value::F32(0.0),
552 Double => Value::F64(0.0),
553 Bool => Value::Bool(false),
554 Bytes => Value::Bytes(vec![].into()),
555 Enum(_) => Value::EnumNumber(0),
556 Message(ref message_descriptor) => {
557 Value::Message(DynamicMessage::new(message_descriptor.clone()))
558 }
559 })
560 }
561
562 fn json_type_name(&self, value: &JsonValue) -> String {
564 match value {
565 JsonValue::Null => "null".to_string(),
566 JsonValue::Bool(_) => "boolean".to_string(),
567 JsonValue::Number(_) => "number".to_string(),
568 JsonValue::String(_) => "string".to_string(),
569 JsonValue::Array(_) => "array".to_string(),
570 JsonValue::Object(_) => "object".to_string(),
571 }
572 }
573
574 fn convert_json_array_to_protobuf_list(
579 &self,
580 field: &FieldDescriptor,
581 json_array: &[JsonValue],
582 ) -> Result<Value, ConversionError> {
583 let mut list = Vec::new();
584
585 for json_item in json_array {
586 let protobuf_item = self.convert_json_value_to_protobuf(field, json_item)?;
587 list.push(protobuf_item);
588 }
589
590 Ok(Value::List(list))
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597
598 #[test]
599 fn test_json_to_protobuf_simple_types() {
600 let pool = DescriptorPool::new();
603 let converter = ProtobufJsonConverter::new(pool);
604 assert!(converter.pool.services().count() == 0);
605 }
606
607 #[test]
608 fn test_default_values() {
609 let pool = DescriptorPool::new();
610 let converter = ProtobufJsonConverter::new(pool);
611
612 assert!(converter.pool.services().count() == 0);
615 }
616
617 #[test]
618 fn test_json_type_name() {
619 let pool = DescriptorPool::new();
620 let converter = ProtobufJsonConverter::new(pool);
621
622 assert_eq!(converter.json_type_name(&JsonValue::Null), "null");
623 assert_eq!(converter.json_type_name(&JsonValue::Bool(true)), "boolean");
624 assert_eq!(converter.json_type_name(&JsonValue::Number(42.into())), "number");
625 assert_eq!(converter.json_type_name(&JsonValue::String("test".to_string())), "string");
626 assert_eq!(converter.json_type_name(&JsonValue::Array(vec![])), "array");
627 assert_eq!(converter.json_type_name(&JsonValue::Object(serde_json::Map::new())), "object");
628 }
629
630 #[test]
631 fn test_conversion_error_display() {
632 let error = ConversionError::MissingField {
633 field: "test_field".to_string(),
634 };
635 assert!(error.to_string().contains("test_field"));
636
637 let error = ConversionError::InvalidValue {
638 field: "test_field".to_string(),
639 message: "invalid value".to_string(),
640 };
641 assert!(error.to_string().contains("test_field"));
642 assert!(error.to_string().contains("invalid value"));
643
644 let error = ConversionError::UnknownField {
645 field: "unknown_field".to_string(),
646 };
647 assert!(error.to_string().contains("unknown_field"));
648
649 let error = ConversionError::TypeMismatch {
650 field: "test_field".to_string(),
651 expected: "string".to_string(),
652 actual: "number".to_string(),
653 };
654 assert!(error.to_string().contains("test_field"));
655 assert!(error.to_string().contains("string"));
656 assert!(error.to_string().contains("number"));
657
658 let error = ConversionError::NestedError("nested error".to_string());
659 assert!(error.to_string().contains("nested error"));
660
661 let error = ConversionError::ProtobufError("protobuf error".to_string());
662 assert!(error.to_string().contains("protobuf error"));
663 }
664
665 #[test]
666 fn test_converter_creation() {
667 let pool = DescriptorPool::new();
668 let converter = ProtobufJsonConverter::new(pool.clone());
669
670 assert_eq!(converter.pool.services().count(), 0);
671
672 let converter2 = ProtobufJsonConverter::new(pool);
674 assert_eq!(converter2.pool.services().count(), 0);
675 }
676
677 #[test]
678 fn test_json_value_type_detection() {
679 let pool = DescriptorPool::new();
680 let converter = ProtobufJsonConverter::new(pool);
681
682 assert_eq!(converter.json_type_name(&JsonValue::Null), "null");
684 assert_eq!(converter.json_type_name(&JsonValue::Bool(true)), "boolean");
685 assert_eq!(converter.json_type_name(&JsonValue::Bool(false)), "boolean");
686 assert_eq!(
687 converter.json_type_name(&JsonValue::Number(serde_json::Number::from(42))),
688 "number"
689 );
690 assert_eq!(
691 converter.json_type_name(&JsonValue::Number(
692 serde_json::Number::from_f64(std::f64::consts::PI).unwrap()
693 )),
694 "number"
695 );
696 assert_eq!(converter.json_type_name(&JsonValue::String("test".to_string())), "string");
697 assert_eq!(converter.json_type_name(&JsonValue::Array(vec![])), "array");
698 assert_eq!(converter.json_type_name(&JsonValue::Array(vec![JsonValue::Null])), "array");
699 assert_eq!(converter.json_type_name(&JsonValue::Object(serde_json::Map::new())), "object");
700
701 let mut obj = serde_json::Map::new();
702 obj.insert("key".to_string(), JsonValue::String("value".to_string()));
703 assert_eq!(converter.json_type_name(&JsonValue::Object(obj)), "object");
704 }
705
706 #[test]
707 fn test_boolean_conversion_variations() {
708 let pool = DescriptorPool::new();
709 let converter = ProtobufJsonConverter::new(pool);
710
711 let test_cases = vec![
713 (JsonValue::Bool(true), "true"),
714 (JsonValue::Bool(false), "false"),
715 (JsonValue::String("true".to_string()), "string true"),
716 (JsonValue::String("false".to_string()), "string false"),
717 (JsonValue::String("1".to_string()), "string 1"),
718 (JsonValue::String("0".to_string()), "string 0"),
719 (JsonValue::String("yes".to_string()), "string yes"),
720 (JsonValue::String("no".to_string()), "string no"),
721 (JsonValue::String("on".to_string()), "string on"),
722 (JsonValue::String("off".to_string()), "string off"),
723 (JsonValue::String("".to_string()), "empty string"),
724 (JsonValue::Number(serde_json::Number::from(1)), "number 1"),
725 (JsonValue::Number(serde_json::Number::from(0)), "number 0"),
726 (JsonValue::Number(serde_json::Number::from(42)), "number 42"),
727 ];
728
729 for (json_value, description) in test_cases {
730 let type_name = converter.json_type_name(&json_value);
733 assert!(!type_name.is_empty(), "Type name should not be empty for {}", description);
734 }
735 }
736
737 #[test]
738 fn test_string_conversion_edge_cases() {
739 let pool = DescriptorPool::new();
740 let converter = ProtobufJsonConverter::new(pool);
741
742 let test_strings = vec![
743 "",
744 " ",
745 "simple string",
746 "string with spaces",
747 "string-with-dashes",
748 "string_with_underscores",
749 "string123",
750 "123string",
751 "string with \"quotes\"",
752 "string with 'apostrophes'",
753 "string with /slashes/",
754 "string with \\backslashes\\",
755 "string with \ttabs\tand\nnewlines",
756 "string with unicode: 你好世界 🌍",
757 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ];
759
760 for test_string in test_strings {
761 let json_value = JsonValue::String(test_string.to_string());
762 let type_name = converter.json_type_name(&json_value);
763 assert_eq!(type_name, "string", "Failed for string: '{}'", test_string);
764 }
765 }
766
767 #[test]
768 fn test_number_conversion_variations() {
769 let pool = DescriptorPool::new();
770 let converter = ProtobufJsonConverter::new(pool);
771
772 let test_numbers = vec![
773 serde_json::Number::from(0),
774 serde_json::Number::from(1),
775 serde_json::Number::from(-1),
776 serde_json::Number::from(42),
777 serde_json::Number::from(-42),
778 serde_json::Number::from(i32::MAX),
779 serde_json::Number::from(i32::MIN),
780 serde_json::Number::from(i64::MAX),
781 serde_json::Number::from(i64::MIN),
782 serde_json::Number::from_f64(0.0).unwrap(),
783 serde_json::Number::from_f64(1.5).unwrap(),
784 serde_json::Number::from_f64(-1.5).unwrap(),
785 serde_json::Number::from_f64(std::f64::consts::PI).unwrap(),
786 serde_json::Number::from_f64(1e10).unwrap(),
787 serde_json::Number::from_f64(-1e10).unwrap(),
788 serde_json::Number::from_f64(1.23456789e-10).unwrap(),
789 ];
790
791 for number in test_numbers {
792 let json_value = JsonValue::Number(number);
793 let type_name = converter.json_type_name(&json_value);
794 assert_eq!(type_name, "number", "Failed for number: {}", json_value);
795 }
796 }
797
798 #[test]
799 fn test_array_conversion_variations() {
800 let pool = DescriptorPool::new();
801 let converter = ProtobufJsonConverter::new(pool);
802
803 let empty_array = JsonValue::Array(vec![]);
805 assert_eq!(converter.json_type_name(&empty_array), "array");
806
807 let mixed_array = JsonValue::Array(vec![
809 JsonValue::Null,
810 JsonValue::Bool(true),
811 JsonValue::Number(42.into()),
812 JsonValue::String("test".to_string()),
813 JsonValue::Object(serde_json::Map::new()),
814 ]);
815 assert_eq!(converter.json_type_name(&mixed_array), "array");
816
817 let nested_array = JsonValue::Array(vec![
819 JsonValue::Array(vec![JsonValue::Number(1.into())]),
820 JsonValue::Array(vec![JsonValue::String("nested".to_string())]),
821 ]);
822 assert_eq!(converter.json_type_name(&nested_array), "array");
823
824 let large_array = JsonValue::Array(vec![JsonValue::Number(1.into()); 1000]);
826 assert_eq!(converter.json_type_name(&large_array), "array");
827 }
828
829 #[test]
830 fn test_object_conversion_variations() {
831 let pool = DescriptorPool::new();
832 let converter = ProtobufJsonConverter::new(pool);
833
834 let empty_object = JsonValue::Object(serde_json::Map::new());
836 assert_eq!(converter.json_type_name(&empty_object), "object");
837
838 let mut obj = serde_json::Map::new();
840 obj.insert("string_key".to_string(), JsonValue::String("value".to_string()));
841 obj.insert("number_key".to_string(), JsonValue::Number(42.into()));
842 obj.insert("boolean_key".to_string(), JsonValue::Bool(true));
843 obj.insert("null_key".to_string(), JsonValue::Null);
844 obj.insert("array_key".to_string(), JsonValue::Array(vec![]));
845 obj.insert("object_key".to_string(), JsonValue::Object(serde_json::Map::new()));
846
847 let complex_object = JsonValue::Object(obj);
848 assert_eq!(converter.json_type_name(&complex_object), "object");
849
850 let mut nested_obj = serde_json::Map::new();
852 nested_obj.insert(
853 "level1".to_string(),
854 JsonValue::Object({
855 let mut level2 = serde_json::Map::new();
856 level2.insert(
857 "level2".to_string(),
858 JsonValue::Object({
859 let mut level3 = serde_json::Map::new();
860 level3.insert("level3".to_string(), JsonValue::String("deep".to_string()));
861 level3
862 }),
863 );
864 level2
865 }),
866 );
867 let nested_object = JsonValue::Object(nested_obj);
868 assert_eq!(converter.json_type_name(&nested_object), "object");
869 }
870
871 #[test]
872 fn test_base64_encoding_detection() {
873 let pool = DescriptorPool::new();
874 let converter = ProtobufJsonConverter::new(pool);
875
876 let base64_cases = vec![
878 "", "dGVzdA==", "SGVsbG8gV29ybGQ=", "YWJjMTIzIT8kKiYoKSctPUB+", "dGVzdGluZyB3aXRoIHNwYWNlcyBhbmQgc3BlY2lhbCBjaGFycw==", "aHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoP3F1ZXJ5PXZhbHVl", ];
885
886 for base64_str in base64_cases {
887 let json_value = JsonValue::String(base64_str.to_string());
888 let type_name = converter.json_type_name(&json_value);
889 assert_eq!(type_name, "string", "Failed for base64 string: '{}'", base64_str);
890 }
891
892 let invalid_base64 = vec![
894 "invalid!@#$%",
895 "not-base64",
896 "abc123!@#$%",
897 "This is not base64 encoded",
898 ];
899
900 for invalid_str in invalid_base64 {
901 let json_value = JsonValue::String(invalid_str.to_string());
902 let type_name = converter.json_type_name(&json_value);
903 assert_eq!(type_name, "string", "Failed for invalid base64: '{}'", invalid_str);
904 }
905 }
906}