eventson 0.1.0

An event based JSON parser with competitive performance
Documentation
use std::io::Cursor;

use eventson::error::{Error, InvalidInput};
use eventson::{Event, Parser};

const JSON_CHECKER_DIR: &str = "data/jsonchecker";

json_checker_test!(fail01_EXCLUDE, InvalidInput::WrongTokenForContext);
json_checker_test!(fail02, InvalidInput::UnexpectedEof);
json_checker_test!(fail03, InvalidInput::InvalidTokenStart(b'u'));
json_checker_test!(fail04, InvalidInput::WrongTokenForContext);
json_checker_test!(fail05, InvalidInput::WrongTokenForContext);
json_checker_test!(fail06, InvalidInput::WrongTokenForContext);
json_checker_test!(fail07, InvalidInput::WrongTokenForContext);
json_checker_test!(fail08, InvalidInput::WrongTokenForContext);
json_checker_test!(fail09, InvalidInput::WrongTokenForContext);
json_checker_test!(fail10, InvalidInput::WrongTokenForContext);
json_checker_test!(fail11, InvalidInput::InvalidTokenStart(b'+'));
json_checker_test!(fail12, InvalidInput::InvalidTokenStart(b'a'));

// TODO: Decide if we want to make the inner error a part of the API.
json_checker_test!(
    fail13,
    InvalidInput::InvalidNumber(Some(lexical::Error::InvalidLeadingZeros(0)))
);
json_checker_test!(fail14, InvalidInput::InvalidNumber(None));
json_checker_test!(fail15, InvalidInput::InvalidEscape(b'x'));
json_checker_test!(fail16, InvalidInput::InvalidTokenStart(b'\\'));
json_checker_test!(fail17, InvalidInput::InvalidEscape(b'0'));
// This is not a real test case, which is probably why it has "EXCLUDE" on it,
// but I'm not sure what the intent ever was here.
// json_checker_test!(fail18_EXCLUDE, InvalidInput::InvalidEscape(b'0'));
json_checker_test!(fail19, InvalidInput::WrongTokenForContext);
json_checker_test!(fail20, InvalidInput::WrongTokenForContext);
json_checker_test!(fail21, InvalidInput::WrongTokenForContext);
json_checker_test!(fail22, InvalidInput::WrongTokenForContext);
json_checker_test!(fail23, InvalidInput::InvalidLiteral);
json_checker_test!(fail24, InvalidInput::InvalidTokenStart(b'\''));
json_checker_test!(fail25, InvalidInput::ControlCharacterInString(b'\t'));
json_checker_test!(fail26, InvalidInput::InvalidEscape(b' '));
json_checker_test!(fail27, InvalidInput::ControlCharacterInString(b'\n'));
json_checker_test!(fail28, InvalidInput::InvalidEscape(b'\n'));
json_checker_test!(
    fail29,
    InvalidInput::InvalidNumber(Some(lexical::Error::EmptyExponent(2)))
);
json_checker_test!(
    fail30,
    InvalidInput::InvalidNumber(Some(lexical::Error::EmptyExponent(3)))
);
json_checker_test!(
    fail31,
    InvalidInput::InvalidNumber(Some(lexical::Error::EmptyExponent(3)))
);
json_checker_test!(fail32, InvalidInput::UnexpectedEof);
json_checker_test!(fail33, InvalidInput::WrongTokenForContext);

#[macro_export]
macro_rules! json_checker_test {
    ($name:ident, $input:expr) => {
        #[test]
        #[allow(non_snake_case)]
        fn $name() {
            run_json_checker_test(stringify!($name), $input);
        }
    };
}

fn run_json_checker_test(file: &str, expected: InvalidInput) {
    let file = format!("{}/{}.json", JSON_CHECKER_DIR, file);
    let content = std::fs::read_to_string(file).expect("Failed to read file");
    let mut parser = Parser::new(Cursor::new(content), 1028, 128);
    loop {
        match parser.next() {
            Ok(event) => {
                if event == Event::Eof {
                    panic!("Expected error {:?}, but got EOF", expected);
                }
            }
            Err(e) => match e {
                Error::InvalidInput { input, .. } => {
                    if input == expected {
                        break;
                    } else {
                        panic!("Expected {:?}, got {:?}", expected, input);
                    }
                }
                _ => {
                    panic!("Unexpected error: {:?}", e);
                }
            },
        }
    }
}