use crate::json_util::object_to_string;
use crate::json_util::object_from_string;
use crate::json_util::array_to_string;
use crate::json_util::array_from_string;
use crate::json_util::ParseError;
use crate::json_util::unescape;
#[cfg(test)]
mod tests {
use super::*;
use crate::data::*;
use crate::dataarray::DataArray;
use crate::databytes::DataBytes; use crate::dataobject::DataObject;
fn d_string(s: &str) -> Data {
Data::DString(s.to_string())
}
#[test]
fn test_object_to_string_simple() {
crate::init(); let mut obj = DataObject::new();
obj.set_property("name", d_string("test"));
obj.set_property("value", Data::DInt(123));
obj.set_property("active", Data::DBoolean(true));
obj.set_property("nothing", Data::DNull);
obj.set_property("price", Data::DFloat(99.99));
let json_string = object_to_string(obj.clone());
assert!(json_string.starts_with('{') && json_string.ends_with('}'));
assert!(json_string.contains("\"name\":\"test\""));
assert!(json_string.contains("\"value\":123"));
assert!(json_string.contains("\"active\":true"));
assert!(json_string.contains("\"nothing\":null"));
assert!(json_string.contains("\"price\":99.99"));
}
#[test]
fn test_object_to_string_nested() {
crate::init(); let mut inner_obj = DataObject::new();
inner_obj.set_property("inner_key", d_string("inner_value"));
let mut obj = DataObject::new();
obj.set_property("outer_key", d_string("outer_value"));
obj.set_property("nested", Data::DObject(inner_obj.data_ref));
let json_string = object_to_string(obj.clone()); assert!(json_string.contains("\"outer_key\":\"outer_value\""));
assert!(json_string.contains("\"nested\":{\"inner_key\":\"inner_value\"}"));
}
#[test]
fn test_object_to_string_with_array() {
crate::init(); let mut arr = DataArray::new();
arr.push_property(Data::DInt(1));
arr.push_property(d_string("two"));
let mut obj = DataObject::new();
obj.set_property("list", Data::DArray(arr.data_ref));
let json_string = object_to_string(obj.clone()); assert_eq!(json_string, "{\"list\":[1,\"two\"]}");
}
#[test]
fn test_object_to_string_escaped() {
crate::init(); let mut obj = DataObject::new();
obj.set_property("key\"with\\quotes", d_string("value\nwith\tescapes"));
let json_string = object_to_string(obj.clone()); assert_eq!(json_string, r#"{"key\"with\\quotes":"value\nwith\tescapes"}"#);
}
#[test]
fn test_object_to_string_empty() {
crate::init(); let obj = DataObject::new();
let json_string = object_to_string(obj.clone()); assert_eq!(json_string, "{}");
}
#[test]
fn test_array_to_string_simple() {
crate::init(); let mut arr = DataArray::new();
arr.push_property(d_string("hello"));
arr.push_property(Data::DInt(42));
arr.push_property(Data::DBoolean(false));
arr.push_property(Data::DNull);
let json_string = array_to_string(arr.clone()); assert_eq!(json_string, r#"["hello",42,false,null]"#);
}
#[test]
fn test_array_to_string_nested() {
crate::init(); let mut inner_arr = DataArray::new();
inner_arr.push_property(Data::DInt(1));
let mut inner_obj = DataObject::new();
inner_obj.set_property("a", Data::DInt(2));
let mut arr = DataArray::new();
arr.push_property(Data::DArray(inner_arr.data_ref));
arr.push_property(Data::DObject(inner_obj.data_ref));
let json_string = array_to_string(arr.clone()); assert!(json_string.contains(r#"[1]"#));
assert!(json_string.contains(r#"{"a":2}"#));
assert!(json_string.starts_with('[') && json_string.ends_with(']'));
}
#[test]
fn test_array_to_string_escaped() {
crate::init(); let mut arr = DataArray::new();
arr.push_property(d_string("string with \"quotes\" and \\ backslash"));
let json_string = array_to_string(arr.clone()); assert_eq!(json_string, r#"["string with \"quotes\" and \\ backslash"]"#);
}
#[test]
fn test_array_to_string_empty() {
crate::init(); let arr = DataArray::new();
let json_string = array_to_string(arr.clone()); assert_eq!(json_string, "[]");
}
#[test]
fn test_object_from_string_simple() {
crate::init(); let json = r#" { "name" : "test", "value": 123, "active": true, "nothing": null, "price": 99.9 } "#;
let result = object_from_string(json);
assert!(result.is_ok());
let obj = result.unwrap();
assert_eq!(obj.get_property("name"), d_string("test"));
assert_eq!(obj.get_property("value"), Data::DInt(123));
assert_eq!(obj.get_property("active"), Data::DBoolean(true));
assert_eq!(obj.get_property("nothing"), Data::DNull);
assert_eq!(obj.get_property("price"), Data::DFloat(99.9));
obj.decr(); }
#[test]
fn test_object_from_string_nested() {
crate::init(); let json = r#" { "outer": "value", "nested": { "inner": 1 } } "#;
let result = object_from_string(json);
assert!(result.is_ok());
let obj = result.unwrap();
assert_eq!(obj.get_property("outer"), d_string("value"));
let nested_data = obj.get_property("nested");
assert!(nested_data.is_object());
if let Data::DObject(obj_ref) = nested_data {
let nested_obj = DataObject::get(obj_ref);
assert_eq!(nested_obj.get_property("inner"), Data::DInt(1));
} else {
panic!("Nested data is not a Data::DObject variant");
}
obj.decr(); }
#[test]
fn test_object_from_string_with_array() {
crate::init(); let json = r#" { "list": [1, "two", false, null] } "#;
let result = object_from_string(json);
assert!(result.is_ok());
let obj = result.unwrap();
let list_data = obj.get_property("list");
assert!(list_data.is_array());
if let Data::DArray(arr_ref) = list_data {
let list_arr = DataArray::get(arr_ref);
assert_eq!(list_arr.len(), 4);
assert_eq!(list_arr.get_property(0), Data::DInt(1));
assert_eq!(list_arr.get_property(1), d_string("two"));
assert_eq!(list_arr.get_property(2), Data::DBoolean(false));
assert_eq!(list_arr.get_property(3), Data::DNull);
} else {
panic!("List data is not a Data::DArray variant");
}
obj.decr();
}
#[test]
fn test_object_from_string_escaped() {
crate::init(); let json = r#" { "key\"\\" : "value\n\t\r\/" } "#;
let result = object_from_string(json);
assert!(result.is_ok());
let obj = result.unwrap();
assert_eq!(obj.get_property("key\"\\"), d_string("value\n\t\r/"));
obj.decr();
}
#[test]
fn test_object_from_string_unicode_escape() {
crate::init(); let json = r#" { "unicode": "Hello\u0020World\u2764" } "#; let result = object_from_string(json);
assert!(result.is_ok(), "Parsing failed with: {:?}", result.err());
let obj = result.unwrap();
assert_eq!(obj.get_property("unicode"), d_string("Hello World❤"));
obj.decr();
}
#[test]
fn test_object_from_string_empty() {
crate::init(); let json = r"{}";
let result = object_from_string(json);
assert!(result.is_ok());
let obj = result.unwrap();
assert_eq!(obj.clone().keys().len(), 0);
obj.decr(); }
#[test]
fn test_object_from_string_invalid_syntax() {
crate::init(); let json = r#" { "key": value_not_quoted }"#;
let result = object_from_string(json);
assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ParseError::UnexpectedCharacter('v')), "Expected UnexpectedCharacter('v'), got {:?}", err);
}
#[test]
fn test_object_from_string_missing_colon() {
crate::init(); let json = r#" { "key" "value" }"#;
let result = object_from_string(json);
assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ParseError::UnexpectedCharacter('"')), "Expected UnexpectedCharacter('\"'), got {:?}", err);
}
#[test]
fn test_object_from_string_trailing_comma() {
crate::init(); let json = r#" { "key": 1, } "#;
let result = object_from_string(json);
assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ParseError::ExpectedCharacter('"')), "Expected ExpectedCharacter('\"'), got {:?}", err);
}
#[test]
fn test_object_from_string_trailing_chars() {
crate::init(); let json = r#" { "key": 1 } extra stuff "#;
let result = object_from_string(json);
assert!(result.is_err());
assert!(matches!(result.err().unwrap(), ParseError::TrailingCharacters(_)));
}
#[test]
fn test_array_from_string_simple() {
crate::init(); let json = r#"[ 1, "two", true, null, 3.14 ]"#;
let result = array_from_string(json);
assert!(result.is_ok());
let arr = result.unwrap();
assert_eq!(arr.len(), 5);
assert_eq!(arr.get_property(0), Data::DInt(1));
assert_eq!(arr.get_property(1), d_string("two"));
assert_eq!(arr.get_property(2), Data::DBoolean(true));
assert_eq!(arr.get_property(3), Data::DNull);
assert_eq!(arr.get_property(4), Data::DFloat(3.14));
arr.decr();
}
#[test]
fn test_array_from_string_nested() {
crate::init(); let json = r#"[ [1, 2], {"a": "b"} ]"#;
let result = array_from_string(json);
assert!(result.is_ok());
let arr = result.unwrap();
let inner_arr_data = arr.get_property(0);
assert!(inner_arr_data.is_array());
if let Data::DArray(inner_arr_ref) = inner_arr_data {
let inner_arr = DataArray::get(inner_arr_ref);
assert_eq!(inner_arr.len(), 2);
assert_eq!(inner_arr.get_property(0), Data::DInt(1));
assert_eq!(inner_arr.get_property(1), Data::DInt(2)); } else {
panic!("Inner array data is not a Data::DArray variant");
}
let inner_obj_data = arr.get_property(1);
assert!(inner_obj_data.is_object());
if let Data::DObject(inner_obj_ref) = inner_obj_data {
let inner_obj = DataObject::get(inner_obj_ref);
assert_eq!(inner_obj.get_property("a"), d_string("b"));
} else {
panic!("Inner object data is not a Data::DObject variant");
}
arr.decr();
}
#[test]
fn test_array_from_string_empty() {
crate::init(); let json = r"[]";
let result = array_from_string(json);
assert!(result.is_ok());
let arr = result.unwrap();
assert_eq!(arr.len(), 0);
arr.decr();
}
#[test]
fn test_array_from_string_invalid_syntax() {
crate::init(); let json = r#"[ 1, "two" false ]"#; let result = array_from_string(json);
assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ParseError::UnexpectedCharacter('f')), "Expected UnexpectedCharacter('f'), got {:?}", err);
}
#[test]
fn test_array_from_string_trailing_comma() {
crate::init(); let json = r#"[ 1, 2, ]"#;
let result = array_from_string(json);
assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ParseError::ExpectedValue), "Expected ExpectedValue, got {:?}", err);
}
#[test]
fn test_array_from_string_trailing_chars() {
crate::init(); let json = r#"[ 1, 2 ] extra"#;
let result = array_from_string(json);
assert!(result.is_err());
assert!(matches!(result.err().unwrap(), ParseError::TrailingCharacters(_)));
}
#[test]
fn test_unescape_basic() {
assert_eq!(unescape(r#"hello world"#).unwrap(), "hello world");
assert_eq!(unescape(r#"hello\"world"#).unwrap(), "hello\"world");
assert_eq!(unescape(r#"hello\\world"#).unwrap(), "hello\\world");
assert_eq!(unescape(r#"hello\/world"#).unwrap(), "hello/world");
assert_eq!(unescape(r#"hello\nworld"#).unwrap(), "hello\nworld");
assert_eq!(unescape(r#"hello\rworld"#).unwrap(), "hello\rworld");
assert_eq!(unescape(r#"hello\tworld"#).unwrap(), "hello\tworld");
assert_eq!(unescape(r#"hello\bworld"#).unwrap(), "hello\x08world");
assert_eq!(unescape(r#"hello\fworld"#).unwrap(), "hello\x0cworld");
}
#[test]
fn test_unescape_unicode() {
assert_eq!(unescape(r#"\u0048\u0065\u006C\u006C\u006F"#).unwrap(), "Hello"); assert_eq!(unescape(r#"\u2764"#).unwrap(), "❤"); assert_eq!(unescape(r#"\uD83D\uDE00"#).unwrap(), "😀"); }
#[test]
fn test_unescape_mixed() {
let result = unescape(r#"\"\\\/\b\f\n\r\t\u0041"#);
assert!(result.is_ok(), "Unescape failed: {:?}", result.err());
assert_eq!(result.unwrap(), "\"\\/\x08\x0c\n\r\tA");
}
#[test]
fn test_unescape_invalid_escape() {
assert!(unescape(r#"\q"#).is_err());
assert!(matches!(unescape(r#"\q"#).err().unwrap(), ParseError::InvalidEscapeSequence(_)));
assert!(unescape(r#"hello\"#).is_err());
assert!(matches!(unescape(r#"hello\"#).err().unwrap(), ParseError::UnexpectedEof));
}
#[test]
fn test_unescape_invalid_unicode() {
assert!(unescape(r#"\u123"#).is_err()); assert!(matches!(unescape(r#"\u123"#).err().unwrap(), ParseError::InvalidUnicodeEscape(_)));
assert!(unescape(r#"\u123G"#).is_err()); assert!(matches!(unescape(r#"\u123G"#).err().unwrap(), ParseError::InvalidUnicodeEscape(_)));
assert!(unescape(r#"\u"#).is_err()); assert!(matches!(unescape(r#"\u"#).err().unwrap(), ParseError::InvalidUnicodeEscape(_)));
assert!(unescape(r#"\uD800"#).is_err());
assert!(matches!(unescape(r#"\uD800"#).err().unwrap(), ParseError::InvalidUnicodeEscape(_)));
assert!(unescape(r#"\uZZZZ"#).is_err()); assert!(matches!(unescape(r#"\uZZZZ"#).err().unwrap(), ParseError::InvalidUnicodeEscape(_)));
}
#[test]
fn test_unescape_prohibited_chars() {
assert!(unescape("\x01").is_err());
assert!(matches!(unescape("\x1f").err().unwrap(), ParseError::UnexpectedCharacter(_)));
assert_eq!(unescape(r#"\u0001"#).unwrap(), "\x01");
}
#[test]
#[ignore] fn test_databytes_serialization() {
crate::init(); }
}