diff --git a/tests/error_tests.rs b/tests/error_tests.rs new file mode 100644 index 0000000..1fe62c9 --- /dev/null +++ b/tests/error_tests.rs @@ -0,0 +1,30 @@ +use naive_json_parser::*; + +#[test] +fn sanity_check() { + let res = JSON::parse(r#"-q"#); + assert_eq!( + res, + Err(ParseError::ExpectedDigit(String::from( + "Expected a digit, received 'q' after numeric '-'" + ))) + ); +} + +#[test] +fn bad_object_trailing_comma() { + let res = JSON::parse("{,}"); + assert_eq!( + res, + Err(ParseError::ExpectedObjectKey(String::from( + "Expected an object key. Does the object have a trailing comma?" + ))) + ); +} + +#[test] +fn bad_json() { + let res = JSON::parse(r#"5eq"#); + assert!(res.is_err()); + println!("{:#?}", res); +} diff --git a/tests/happy_paths.rs b/tests/happy_paths.rs new file mode 100644 index 0000000..51c8a74 --- /dev/null +++ b/tests/happy_paths.rs @@ -0,0 +1,170 @@ +use naive_json_parser::JSONValue::{Array, False, Null, Number, Object, True}; +use naive_json_parser::*; +use std::collections::HashMap; +use std::f64::consts::PI; + +#[test] +fn sanity_check() { + let res = JSON::parse(r#""foo""#); + assert_eq!(res, Ok(JSONValue::String(String::from("foo")))); + + let json = format!("{}", PI); + let res = JSON::parse(&json); + assert_eq!(res, Ok(JSONValue::Number(PI))); +} + +#[test] +fn can_parse_array_of_keywords() { + let result = JSON::parse("[true,false,null]"); + + assert_eq!(result, Ok(Array(vec![True, False, Null]))); +} + +#[test] +fn parse_json_types() { + // Boolean / Null + let res = JSON::parse("true"); + assert_eq!(res, Ok(True)); + let res = JSON::parse("false"); + assert_eq!(res, Ok(False)); + let res = JSON::parse("null"); + assert_eq!(res, Ok(Null)); + + // Number + let res = JSON::parse("9.38083151965"); + assert_eq!(res, Ok(Number(9.38083151965)), "Failed to parse number"); + + // String + let res = JSON::parse(r#""/^$/""#); + assert_eq!(res, Ok(JSONValue::from("/^$/")), "Failed to parse string"); + + // Number array + let res = JSON::parse("[1, 2, 3]"); + assert_eq!( + res, + Ok(Array(vec![Number(1f64), Number(2f64), Number(3f64)])) + ); + + // Object array + let result = JSON::parse("[{}]"); + assert_eq!(result, Ok(JSONValue::Array(vec![Object(HashMap::new())]))); +} + +#[test] +fn parse_nested_object() { + let res = JSON::parse(r#"{"a": {"b": []}}"#); + let mut outermap: JSONMap = HashMap::new(); + let mut innermap: JSONMap = HashMap::new(); + + innermap.insert(String::from("b"), Array(vec![])); + outermap.insert(String::from("a"), Object(innermap)); + + let expected = Ok(Object(outermap)); + + assert_eq!(res, expected); +} + +#[test] +fn parse_object_with_number_values() { + let result = JSON::parse(r#"[{ "a": 9.38083151965, "b": 4e3 }]"#); + let mut map: JSONMap = HashMap::new(); + map.insert(String::from("a"), Number(9.38083151965f64)); + map.insert(String::from("b"), Number(4e3f64)); + + let expected = Ok(Array(vec![Object(map)])); + + assert_eq!( + result, expected, + "Failed on just number values: {:#?}", + result + ); +} + +#[test] +fn parse_weird_character_array() { + let result = + JSON::parse(r#"["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"]"#); + let expected = Ok(Array(vec![ + JSONValue::from("\""), + JSONValue::from("\\"), + JSONValue::from("/"), + JSONValue::from("\u{8}"), + JSONValue::from("\x0C"), + JSONValue::from("\n"), + JSONValue::from("\r"), + JSONValue::from("\t"), + JSONValue::from("\u{1}"), + JSONValue::from("\u{face}"), + ])); + + assert_eq!(result, expected); +} + +#[test] +fn parse_full_json_example() { + let result = JSON::parse( + r#"[{ + "a": 9.38083151965, + "b": 4e3, + "c": [1, 2, 3], + "d": "foo", + "e": { + "f": { + "g": { + "h": null + } + } + }, + "i": ["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"] +}]"#, + ); + + let mut map: JSONMap = HashMap::new(); + let mut emap: JSONMap = HashMap::new(); + let mut fmap: JSONMap = HashMap::new(); + let mut gmap: JSONMap = HashMap::new(); + + gmap.insert(String::from("h"), Null); + fmap.insert(String::from("g"), Object(gmap)); + emap.insert(String::from("f"), Object(fmap)); + + map.insert(String::from("a"), Number(9.38083151965f64)); + map.insert(String::from("b"), Number(4e3f64)); + map.insert( + String::from("c"), + Array(vec![Number(1f64), Number(2f64), Number(3f64)]), + ); + map.insert(String::from("d"), JSONValue::from("foo")); + map.insert(String::from("e"), Object(emap)); + + map.insert( + String::from("i"), + Array(vec![ + JSONValue::from("\""), + JSONValue::from("\\"), + JSONValue::from("/"), + JSONValue::from("\u{8}"), + JSONValue::from("\x0C"), + JSONValue::from("\n"), + JSONValue::from("\r"), + JSONValue::from("\t"), + JSONValue::from("\u{1}"), + JSONValue::from("\u{face}"), + ]), + ); + + assert!(result.is_ok(), format!("{:#?}", result)); + + let outer_array: Vec = result.unwrap().unwrap(); + let result_map: JSONMap = outer_array[0].clone().unwrap(); + + for (k, v) in &map { + assert_eq!( + result_map.get(k).unwrap(), + v, + "HashMap Entry Differs: {:#?}, {:#?}", + result_map.get(k).unwrap(), + v + ); + } +}