weakjson 0.0.7

Library for parsing bad JSON
Documentation
use rustc_serialize::json::Json;

use rustc_serialize::json::Json::*;

use rustc_serialize::json::ErrorCode::*;
use rustc_serialize::json::ParserError::*;

use std::collections::BTreeMap;
use std::f64;

fn mk_object(items: &[(String, Json)]) -> Json {
    let mut d = BTreeMap::new();

    for item in items.iter() {
        match *item {
            (ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); },
        }
    };

    Object(d)
}

#[test]
fn test_single_quote_string() {
    assert_eq!(super::from_str("'"), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
    assert_eq!(super::from_str("'lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));

    assert_eq!(super::from_str("''"), Ok(String("".to_string())));
    assert_eq!(super::from_str("'foo'"), Ok(String("foo".to_string())));
    assert_eq!(super::from_str("'foo\\'bar'"), Ok(String("foo'bar".to_string())));
    assert_eq!(super::from_str("'foo\"bar'"), Ok(String("foo\"bar".to_string())));
}

#[test]
fn test_ignore_invalid_escaping() {
    assert_eq!(super::from_str("\"foo\\abar\""), Ok(String("fooabar".to_string())));
}

#[test]
fn test_multiline_string() {
    assert_eq!(super::from_str("\"\n\""), Ok(String("\n".to_string())));
    assert_eq!(super::from_str("\"\n\n\""), Ok(String("\n\n".to_string())));
    assert_eq!(super::from_str("\"foo\nbar\""), Ok(String("foo\nbar".to_string())));
    assert_eq!(super::from_str("\"foo\\\nbar\""), Ok(String("foo\nbar".to_string())));
}

#[test]
fn test_number_with_plus_sign() {
    assert_eq!(super::from_str("+3"), Ok(U64(3)));
    assert_eq!(super::from_str("+3.1"), Ok(F64(3.1)));
    assert_eq!(super::from_str("+0.4"), Ok(F64(0.4)));
    assert_eq!(super::from_str("+0.4e5"), Ok(F64(0.4e5)));
    assert_eq!(super::from_str("+0.4e+15"), Ok(F64(0.4e15)));
    assert_eq!(super::from_str("+0.4e-01"), Ok(F64(0.4e-01)));
}

#[test]
fn test_trailing_zeros() {
    assert_eq!(super::from_str("00"), Ok(U64(0)));
    assert_eq!(super::from_str("01"), Ok(U64(1)));
    assert_eq!(super::from_str("-01"), Ok(I64(-1)));

    assert_eq!(super::from_str("0.0"), Ok(F64(0.0)));
    assert_eq!(super::from_str("0.4e05"), Ok(F64(0.4e5)));
    assert_eq!(super::from_str("0.4e+015"), Ok(F64(0.4e15)));
    assert_eq!(super::from_str("0.4e-1"), Ok(F64(0.4e-01)));
}

#[test]
fn test_infinity_and_nan() {
    match super::from_str("NaN") {
        Ok(F64(x)) => assert!(x != x, "Unable to parse NaN"),
        _ => panic!("Unable to parse NaN")
    }
    match super::from_str("+NaN") {
        Ok(F64(x)) => assert!(x != x, "Unable to parse +NaN"),
        _ => panic!("Unable to parse +NaN")
    }
    match super::from_str("-NaN") {
        Ok(F64(x)) => assert!(x != x, "Unable to parse -NaN"),
        _ => panic!("Unable to parse -NaN")
    }

    assert_eq!(super::from_str("Infinity"), Ok(F64(f64::INFINITY)));
    assert_eq!(super::from_str("+Infinity"), Ok(F64(f64::INFINITY)));
    assert_eq!(super::from_str("-Infinity"), Ok(F64(f64::NEG_INFINITY)));
}

#[test]
fn test_leading_and_trailing_decimal_point() {
    assert_eq!(super::from_str("3."), Ok(F64(3.0)));
    assert_eq!(super::from_str(".1"), Ok(F64(0.1)));
    assert_eq!(super::from_str("+.1"), Ok(F64(0.1)));
    assert_eq!(super::from_str("-.1"), Ok(F64(-0.1)));

    assert_eq!(super::from_str("0."), Ok(F64(0.0)));
    assert_eq!(super::from_str(".0"), Ok(F64(0.0)));
    assert_eq!(super::from_str("+0."), Ok(F64(0.0)));
    assert_eq!(super::from_str("-.0"), Ok(F64(0.0)));

    assert_eq!(super::from_str("3.e5"), Ok(F64(3.0e5)));
    assert_eq!(super::from_str(".1e5"), Ok(F64(0.1e5)));

    assert_eq!(super::from_str(".e5"), Err(SyntaxError(InvalidNumber, 1, 2)));
    assert_eq!(super::from_str("e5"), Err(SyntaxError(InvalidSyntax, 1, 1)));
}

#[test]
fn test_hexadecimal() {
    assert_eq!(super::from_str("0xff"), Ok(U64(255)));
    assert_eq!(super::from_str("0xFF"), Ok(U64(255)));
    assert_eq!(super::from_str("0Xff"), Ok(U64(255)));
    assert_eq!(super::from_str("-0Xff"), Ok(I64(-255)));

    assert_eq!(super::from_str("0x"), Err(SyntaxError(InvalidNumber, 1, 3)));
    assert_eq!(super::from_str("0x.0"), Err(SyntaxError(InvalidNumber, 1, 3)));
    assert_eq!(super::from_str("0xf.0"), Err(SyntaxError(TrailingCharacters, 1, 4)));
}

#[test]
fn test_comments() {
    assert_eq!(super::from_str("0 // comment"), Ok(U64(0)));
    assert_eq!(super::from_str("0 // comment\n"), Ok(U64(0)));
    assert_eq!(super::from_str("// comment\n0"), Ok(U64(0)));
    assert_eq!(super::from_str(" // comment\n0"), Ok(U64(0)));
    assert_eq!(super::from_str("// comment\n 0"), Ok(U64(0)));

    assert_eq!(super::from_str("0 /* comment */"), Ok(U64(0)));
    assert_eq!(super::from_str("0 // comment\n"), Ok(U64(0)));
    assert_eq!(super::from_str("/* comment */ 0"), Ok(U64(0)));
    assert_eq!(super::from_str("/**/0"), Ok(U64(0)));

    assert_eq!(super::from_str("/* // */0"), Ok(U64(0)));

    assert_eq!(super::from_str("/**/[/**/3/**/,/**/1/**/]/**/"),
               Ok(Array(vec![U64(3), U64(1)])));

    assert_eq!(super::from_str("/**/{/**/\"a\"/**/:/**/3/**/}/**/").unwrap(),
               mk_object(&[("a".to_string(), U64(3))]));

    assert_eq!(super::from_str("//c\n[//c\n3//c\n,//c\n1//c\n]//c\n"),
               Ok(Array(vec![U64(3), U64(1)])));

    assert_eq!(super::from_str("//c\n{//c\n\"a\"//c\n://c\n3//c\n}//c\n").unwrap(),
               mk_object(&[("a".to_string(), U64(3))]));

    assert_eq!(super::from_str("0/*"), Err(SyntaxError(InvalidSyntax, 1, 4)));
    assert_eq!(super::from_str("/*/0"), Err(SyntaxError(InvalidSyntax, 1, 5)));
}

#[test]
fn test_trailing_comma_in_array() {
    assert_eq!(super::from_str("[1,]"), Ok(Array(vec![U64(1)])));
    assert_eq!(super::from_str("[1, 2,]"), Ok(Array(vec![U64(1), U64(2)])));

    assert_eq!(super::from_str("[,]"), Err(SyntaxError(InvalidSyntax, 1, 2)));
    assert_eq!(super::from_str("[,1]"), Err(SyntaxError(InvalidSyntax, 1, 2)));
    assert_eq!(super::from_str("[,,]"), Err(SyntaxError(InvalidSyntax, 1, 2)));
    assert_eq!(super::from_str("[1,,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
    assert_eq!(super::from_str("[1,,2]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
}

#[test]
fn test_trailing_comma_in_object() {
    assert_eq!(super::from_str("{\"a\": 1,}").unwrap(),
               mk_object(&[("a".to_string(), U64(1))]));
    assert_eq!(super::from_str("{\"a\":1, \"b\":2,}").unwrap(),
               mk_object(&[("a".to_string(), U64(1)), ("b".to_string(), U64(2))]));

    assert_eq!(super::from_str("{,}"), Err(SyntaxError(InvalidSyntax, 1, 2)));
    assert_eq!(super::from_str("{,\"a\": 1}"), Err(SyntaxError(InvalidSyntax, 1, 2)));
    assert_eq!(super::from_str("{,,}"), Err(SyntaxError(InvalidSyntax, 1, 2)));
    assert_eq!(super::from_str("{\"a\": 1,,}"), Err(SyntaxError(InvalidSyntax, 1, 9)));
    assert_eq!(super::from_str("{\"a\": 1,, \"a\": 2}"), Err(SyntaxError(InvalidSyntax, 1, 9)));
}

#[test]
fn test_unquoted_keys_in_object() {
    assert_eq!(super::from_str("{a: 1}").unwrap(), mk_object(&[("a".to_string(), U64(1))]));
    assert_eq!(super::from_str("{$a: 1}").unwrap(), mk_object(&[("$a".to_string(), U64(1))]));
    assert_eq!(super::from_str("{_1: 1}").unwrap(), mk_object(&[("_1".to_string(), U64(1))]));

    assert_eq!(super::from_str("{ф: 1}"), Err(SyntaxError(InvalidSyntax, 1, 2)));
}

#[test]
fn test_numeric_keys_in_object() {
    assert_eq!(super::from_str("{1: 1}").unwrap(), mk_object(&[("1".to_string(), U64(1))]));
    assert_eq!(super::from_str("{01: 1}").unwrap(), mk_object(&[("1".to_string(), U64(1))]));
    assert_eq!(super::from_str("{123: 1}").unwrap(), mk_object(&[("123".to_string(), U64(1))]));

    assert_eq!(super::from_str("{0a: 1}"), Err(SyntaxError(ExpectedColon, 1, 3)));
    assert_eq!(super::from_str("{0.2: 1}"), Err(SyntaxError(ExpectedColon, 1, 3)));
    assert_eq!(super::from_str("{-3: 1}"), Err(SyntaxError(InvalidSyntax, 1, 2)));
}