mod feeder;
mod prettyprinter;
#[cfg(feature = "tokio")]
mod tokio;
use std::fs;
use actson::feeder::PushJsonFeeder;
use actson::options::JsonParserOptionsBuilder;
use actson::parser::ParserError;
use actson::{JsonEvent, JsonParser};
use prettyprinter::PrettyPrinter;
use serde_json::Value;
fn parse(json: &str) -> String {
let feeder = PushJsonFeeder::new();
parse_with_parser(json, &mut JsonParser::new(feeder))
}
fn parse_with_parser(json: &str, parser: &mut JsonParser<PushJsonFeeder>) -> String {
let buf = json.as_bytes();
let mut prettyprinter = PrettyPrinter::new();
let mut i: usize = 0;
while let Some(e) = parser.next_event().unwrap() {
if e == JsonEvent::NeedMoreInput {
i += parser.feeder.push_bytes(&buf[i..]);
if i == json.len() {
parser.feeder.done();
}
}
prettyprinter.on_event(e, parser).unwrap();
}
prettyprinter.get_result().to_string()
}
fn parse_fail(json: &[u8]) -> ParserError {
let feeder = PushJsonFeeder::new();
parse_fail_with_parser(json, &mut JsonParser::new(feeder))
}
fn parse_fail_with_parser(json: &[u8], parser: &mut JsonParser<PushJsonFeeder>) -> ParserError {
let mut i: usize = 0;
loop {
let e = match parser.next_event() {
Err(err) => return err,
Ok(Some(ne)) => ne,
Ok(None) => panic!("End of file before error happened"),
};
if e == JsonEvent::NeedMoreInput {
i += parser.feeder.push_bytes(&json[i..]);
if i == json.len() {
parser.feeder.done();
}
}
}
}
fn parse_checking_consumed_bytes(json: &str, events_bytes: &[(Option<JsonEvent>, usize)]) {
let buf = json.as_bytes();
let mut parser = JsonParser::new(PushJsonFeeder::new());
for &(event, bytes) in events_bytes {
let parsed_bytes = parser.parsed_bytes();
let next_event = parse_until_next_event(&buf[parsed_bytes..], &mut parser);
let parsed_bytes = parser.parsed_bytes();
assert_eq!(next_event, event);
assert_eq!(parsed_bytes, bytes);
}
}
fn parse_until_next_event(
json: &[u8],
parser: &mut JsonParser<PushJsonFeeder>,
) -> Option<JsonEvent> {
let mut i: usize = 0;
loop {
let event = parser.next_event().unwrap();
match event {
Some(JsonEvent::NeedMoreInput) => {
i += parser.feeder.push_bytes(&json[i..]);
if i == json.len() {
parser.feeder.done();
}
}
Some(_) => return event,
None => return None,
}
}
}
fn assert_json_eq(expected: &str, actual: &str) {
let em: Value = serde_json::from_str(expected).unwrap();
let am: Value = serde_json::from_str(actual).unwrap();
assert_eq!(em, am);
}
#[test]
fn test_pass() {
for i in 1..=3 {
let json = fs::read_to_string(format!("tests/fixtures/pass{i}.txt")).unwrap();
assert_json_eq(&json, &parse(&json));
}
}
#[test]
fn test_pass_with_reset() {
let mut parser = JsonParser::new(PushJsonFeeder::new());
for i in 1..=3 {
let json = fs::read_to_string(format!("tests/fixtures/pass{i}.txt")).unwrap();
assert_json_eq(&json, &parse_with_parser(&json, &mut parser));
parser.reset_fully();
}
}
#[test]
fn test_escape_in_key() {
let json = r#"{"foo\u0000bar": 42}"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn test_utf16_in_array() {
let json = r#"["\uD801\udc37"]"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn test_fail() {
for i in 2..=34 {
let mut parser = JsonParser::new_with_options(
PushJsonFeeder::new(),
JsonParserOptionsBuilder::default()
.with_max_depth(16)
.build(),
);
let json = fs::read_to_string(format!("tests/fixtures/fail{i}.txt")).unwrap();
parse_fail_with_parser(json.as_bytes(), &mut parser);
}
}
#[test]
fn test_fail_with_reset() {
let mut parser = JsonParser::new_with_options(
PushJsonFeeder::new(),
JsonParserOptionsBuilder::default()
.with_max_depth(16)
.build(),
);
for i in 2..=34 {
let json = fs::read_to_string(format!("tests/fixtures/fail{i}.txt")).unwrap();
parse_fail_with_parser(json.as_bytes(), &mut parser);
parser.reset_fully();
}
}
#[test]
fn empty_object() {
let json = r#"{}"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn simple_object() {
let json = r#"{"name": "Elvis"}"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn empty_array() {
let json = r#"[]"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn simple_array() {
let json = r#"["Elvis", "Max"]"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn mixed_array() {
let json = r#"["Elvis", 132, "Max", 80.67]"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn utf8() {
let json = "{\"name\": \"Bj\u{0153}rn\"}";
assert_json_eq(json, &parse(json));
}
#[test]
fn too_many_next_event() {
let json = "{}";
let feeder = PushJsonFeeder::new();
let mut parser = JsonParser::new(feeder);
assert_json_eq(json, &parse_with_parser(json, &mut parser));
assert!(matches!(parser.next_event(), Err(ParserError::NoMoreInput)));
}
#[test]
fn illegal_character() {
let json = "{\"key\":\x02}";
assert!(matches!(
parse_fail(json.as_bytes()),
ParserError::IllegalInput(0x02)
));
}
#[test]
fn escaped_json_string_is_escaped() {
let json = r#""{\"test\": \n\"value\"}""#;
let mut json_parser = JsonParser::new(PushJsonFeeder::new());
json_parser.feeder.push_bytes(json.as_bytes());
let event = json_parser.next_event().unwrap();
assert_eq!(event, Some(JsonEvent::ValueString));
assert_eq!(
json_parser.current_str().unwrap(),
r#"{"test":
"value"}"#
);
}
#[test]
fn all_escape_characters() {
let json = r#""\"\\\/\b\f\n\r\t""#;
let mut json_parser = JsonParser::new(PushJsonFeeder::new());
json_parser.feeder.push_bytes(json.as_bytes());
let event = json_parser.next_event().unwrap();
assert_eq!(event, Some(JsonEvent::ValueString));
assert_eq!(json_parser.current_str().unwrap(), "\"\\/\u{8}\u{c}\n\r\t");
}
#[test]
fn syntax_error() {
let json = "{key}";
assert!(matches!(
parse_fail(json.as_bytes()),
ParserError::SyntaxError
));
}
#[test]
fn number_and_end_of_object() {
let json = r#"{"n":2}"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn fraction() {
let json = r#"{"n":2.1}"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn illegal_number() {
let json = r#"{"n":-2.}"#;
assert!(matches!(
parse_fail(json.as_bytes()),
ParserError::SyntaxError
));
}
#[test]
fn zero_with_exp() {
let json = r#"{"n":0e1}"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn top_level_empty_string() {
let json = r#""""#;
assert_json_eq(json, &parse(json));
}
#[test]
fn top_level_false() {
let json = r#"false"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn top_level_int() {
let json = r#"42"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn top_level_long() {
let json = r#"42123123123"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn number_and_eof() {
let json = r#"{"i":42"#;
assert!(matches!(
parse_fail(json.as_bytes()),
ParserError::NoMoreInput
));
}
#[test]
fn top_level_zero() {
let json = r#"0"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn number_of_processed_bytes() {
let json = r#"{"name": "Elvis"}"#;
let events_bytes = [
(Some(JsonEvent::StartObject), 1),
(Some(JsonEvent::FieldName), 7),
(Some(JsonEvent::ValueString), 16),
(Some(JsonEvent::EndObject), 17),
(None, 17),
];
parse_checking_consumed_bytes(json, &events_bytes);
let json = r#"["Elvis", 132, "Max", 80.67]"#;
let events_bytes = [
(Some(JsonEvent::StartArray), 1),
(Some(JsonEvent::ValueString), 8),
(Some(JsonEvent::ValueInt), 14),
(Some(JsonEvent::ValueString), 20),
(Some(JsonEvent::ValueFloat), 28),
(Some(JsonEvent::EndArray), 28),
(None, 28),
];
parse_checking_consumed_bytes(json, &events_bytes);
let json = "{\"name\": \"Bj\u{0153}rn\"}";
let events_bytes = [
(Some(JsonEvent::StartObject), 1),
(Some(JsonEvent::FieldName), 7),
(Some(JsonEvent::ValueString), 17),
(Some(JsonEvent::EndObject), 18),
(None, 18),
];
parse_checking_consumed_bytes(json, &events_bytes);
}
#[test]
fn test_suite_pass() {
let files = fs::read_dir("tests/json_test_suite/test_parsing").unwrap();
for f in files {
let f = f.unwrap();
let name = f.file_name();
if name.to_str().unwrap().starts_with('y') {
let json = fs::read_to_string(f.path()).unwrap();
if name == "y_number_minus_zero.json" || name == "y_number_negative_zero.json" {
assert_eq!("[\n 0\n]", &parse(&json));
} else {
assert_json_eq(&json, &parse(&json));
}
}
}
}
#[test]
fn test_string_1_2_3_bytes() {
let json = r#"["\u0060\u012a\u12AB"]"#;
assert_json_eq(json, &parse(json));
}
#[test]
fn test_suite_fail() {
let files = fs::read_dir("tests/json_test_suite/test_parsing").unwrap();
for f in files {
let f = f.unwrap();
let name = f.file_name();
if name.to_str().unwrap().starts_with('n') {
let json = fs::read(f.path()).unwrap();
parse_fail(&json); }
}
}
#[test]
fn streaming_numbers() {
let options = JsonParserOptionsBuilder::default()
.with_streaming(true)
.build();
let json = r#"1 2 3 4 5"#;
let feeder = PushJsonFeeder::new();
let r = parse_with_parser(json, &mut JsonParser::new_with_options(feeder, options));
assert_eq!("12345", r);
}
#[test]
fn streaming_strings() {
let options = JsonParserOptionsBuilder::default()
.with_streaming(true)
.build();
let json = r#""1""2" "3""4" "5""#;
let feeder = PushJsonFeeder::new();
let r = parse_with_parser(json, &mut JsonParser::new_with_options(feeder, options));
assert_eq!(r#""1""2""3""4""5""#, r);
}
#[test]
fn streaming_arrays() {
let options = JsonParserOptionsBuilder::default()
.with_streaming(true)
.build();
let json = r#"[1][2][3][4][5]"#;
let feeder = PushJsonFeeder::new();
let r = parse_with_parser(json, &mut JsonParser::new_with_options(feeder, options));
assert_eq!("[\n 1\n][\n 2\n][\n 3\n][\n 4\n][\n 5\n]", r);
}
#[test]
fn streaming_objects() {
let options = JsonParserOptionsBuilder::default()
.with_streaming(true)
.build();
let json = r#"{"a":1}{"b":2}{"c":3}{"d":4}{"e":5}"#;
let feeder = PushJsonFeeder::new();
let r = parse_with_parser(json, &mut JsonParser::new_with_options(feeder, options));
assert_eq!(
r#"{
"a": 1
}{
"b": 2
}{
"c": 3
}{
"d": 4
}{
"e": 5
}"#,
r
);
}
#[test]
fn streaming_complex() {
let options = JsonParserOptionsBuilder::default()
.with_streaming(true)
.build();
let json = r#"1.0 2"3"{"a":4}5
6e-5["b"]["c"] 7{"d":"e"}true8falsenull"#;
let feeder = PushJsonFeeder::new();
let r = parse_with_parser(json, &mut JsonParser::new_with_options(feeder, options));
assert_eq!(
r#"1.02"3"{
"a": 4
}50.00006[
"b"
][
"c"
]7{
"d": "e"
}true8falsenull"#,
r
);
}