use serde_json::Value as JsonValue;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum FormatConvertError {
#[error("json→toml serialize: {0}")]
Serialize(String),
#[error("json→toml deserialize: {0}")]
Deserialize(String),
#[error("toml parse: {0}")]
TomlParse(String),
}
pub fn json_to_toml(json_value: &JsonValue) -> Result<toml::Value, FormatConvertError> {
let json_str = serde_json::to_string(json_value)
.map_err(|e| FormatConvertError::Serialize(e.to_string()))?;
let toml_value: toml::Value = serde_json::from_str(&json_str)
.map_err(|e| FormatConvertError::Deserialize(e.to_string()))?;
Ok(toml_value)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_json_to_toml_simple_object() {
let json = json!({"key": "value", "count": 42});
let toml_val = json_to_toml(&json).expect("conversion must succeed");
assert_eq!(toml_val["key"].as_str(), Some("value"));
assert_eq!(toml_val["count"].as_integer(), Some(42));
}
#[test]
fn test_json_to_toml_empty_object() {
let json = json!({});
let result = json_to_toml(&json);
assert!(result.is_ok(), "empty object must convert successfully");
let toml_val = result.unwrap();
assert!(toml_val.as_table().map(|t| t.is_empty()).unwrap_or(false));
}
#[test]
fn test_json_to_toml_nested_object() {
let json = json!({"outer": {"inner": true}});
let toml_val = json_to_toml(&json).expect("nested object must convert");
let outer = toml_val.get("outer").expect("outer key must exist");
assert_eq!(outer["inner"].as_bool(), Some(true));
}
#[test]
fn test_json_to_toml_null_value_is_boundary() {
let json = json!(null);
let _ = json_to_toml(&json); }
#[test]
fn test_json_to_toml_string_with_unicode() {
let json = json!({"emoji": "🦀", "text": "日本語"});
let toml_val = json_to_toml(&json).expect("unicode must convert");
assert_eq!(toml_val["emoji"].as_str(), Some("🦀"));
assert_eq!(toml_val["text"].as_str(), Some("日本語"));
}
#[test]
fn test_format_convert_error_serialize_display() {
let err = FormatConvertError::Serialize("bad input".to_string());
assert!(err.to_string().contains("serialize"));
assert!(err.to_string().contains("bad input"));
}
#[test]
fn test_format_convert_error_deserialize_display() {
let err = FormatConvertError::Deserialize("unexpected char".to_string());
assert!(err.to_string().contains("deserialize"));
assert!(err.to_string().contains("unexpected char"));
}
#[test]
fn test_format_convert_error_toml_parse_display() {
let err = FormatConvertError::TomlParse("invalid toml".to_string());
assert!(err.to_string().contains("toml parse"));
assert!(err.to_string().contains("invalid toml"));
}
#[test]
fn test_format_convert_error_is_std_error() {
let err = FormatConvertError::Serialize("x".to_string());
let _: &dyn std::error::Error = &err;
}
}