use cbor::{Config, GenericDecoder};
use cbor::value::{Int, Key, Text, Value};
use rustc_serialize::base64::FromBase64;
use json::{Json, Decoder, FromJson, DecodeResult};
use json::decoder::ReadIter;
use std::{f32, f64, i8, i16, i32, i64, u64};
use std::fs::File;
use util;
#[derive(Debug, Clone)]
struct TestVector {
cbor: String,
hex: String,
roundtrip: bool,
decoded: Option<Json>,
diagnostic: Option<Json>
}
impl FromJson for TestVector {
fn decode<I: Iterator<Item=char>>(d: &mut Decoder<I>) -> DecodeResult<TestVector> {
object! {
let decoder = d;
TestVector {
cbor: req. "cbor" => d.string(),
hex: req. "hex" => d.string(),
roundtrip: req. "roundtrip" => d.bool(),
decoded: opt. "decoded" => d.from_json(),
diagnostic: opt. "diagnostic" => d.from_json()
}
}
}
}
#[test]
fn int_min_max() {
util::identity(|mut e| e.i8(i8::MAX), |mut d| d.i8().unwrap() == i8::MAX);
util::identity(|mut e| e.i8(i8::MIN), |mut d| d.i8().unwrap() == i8::MIN);
util::identity(|mut e| e.i16(i16::MAX), |mut d| d.i16().unwrap() == i16::MAX);
util::identity(|mut e| e.i16(i16::MIN), |mut d| d.i16().unwrap() == i16::MIN);
util::identity(|mut e| e.i32(i32::MAX), |mut d| d.i32().unwrap() == i32::MAX);
util::identity(|mut e| e.i32(i32::MIN), |mut d| d.i32().unwrap() == i32::MIN);
util::identity(|mut e| e.i64(i64::MAX), |mut d| d.i64().unwrap() == i64::MAX);
util::identity(|mut e| e.i64(i64::MIN), |mut d| d.i64().unwrap() == i64::MIN);
util::identity(|mut e| e.int(Int::Neg(u64::MAX)), |mut d| d.int().unwrap() == Int::Neg(u64::MAX));
util::identity(|mut e| e.int(Int::Pos(u64::MAX)), |mut d| d.int().unwrap().u64() == Some(u64::MAX));
assert_eq!(Some(i64::MIN), Int::Neg(i64::MAX as u64).i64());
assert_eq!(Some(i64::MAX), Int::Pos(i64::MAX as u64).i64());
assert_eq!(Some(u64::MIN), Int::Pos(u64::MIN).u64());
assert_eq!(Some(u64::MAX), Int::Pos(u64::MAX).u64())
}
#[test]
fn test_all() {
let iter = ReadIter::new(File::open("tests/appendix_a.json").unwrap());
let test_vectors: Vec<TestVector> = Decoder::default(iter).from_json().unwrap();
for v in test_vectors {
let raw = v.cbor.from_base64().unwrap();
let mut dec = GenericDecoder::new(Config::default(), &raw[..]);
let val = dec.value().unwrap();
if let Some(x) = v.decoded {
if !eq(&x, &val) {
panic!("{}: {:?} <> {:?}", v.hex, x, val)
}
continue
}
if let Some(Json::String(ref x)) = v.diagnostic {
if !diag(&x, &val) {
panic!("{}: {:?} <> {:?}", v.hex, x, val)
}
}
}
}
fn eq(a: &Json, b: &Value) -> bool {
match (a, b) {
(&Json::Null, &Value::Null) => true,
(&Json::Bool(x), &Value::Bool(y)) => x == y,
(&Json::String(ref x), &Value::Text(Text::Text(ref y))) => x == y,
(&Json::String(ref x), &Value::Text(Text::Chunks(ref y))) => {
let mut s = String::new();
for c in y {
s.push_str(c)
}
x == &s
}
(&Json::Number(x), y) =>
util::as_f64(y)
.map(|i| (x - i).abs() < f64::EPSILON)
.unwrap_or(false),
(&Json::Array(ref x), &Value::Array(ref y)) =>
x.iter().zip(y.iter()).all(|(xi, yi)| eq(xi, yi)),
(&Json::Object(ref x), &Value::Map(ref y)) => {
for (k, v) in x {
if let Some(w) = y.get(&Key::Text(Text::Text(k.clone()))) {
if !eq(v, w) {
return false
}
} else {
return false
}
}
true
}
_ => false
}
}
fn diag(a: &str, b: &Value) -> bool {
match (a, b) {
("Infinity", &Value::F32(x)) => x == f32::INFINITY,
("Infinity", &Value::F64(x)) => x == f64::INFINITY,
("-Infinity", &Value::F32(x)) => x == -f32::INFINITY,
("-Infinity", &Value::F64(x)) => x == -f64::INFINITY,
("NaN", &Value::F32(x)) => x.is_nan(),
("NaN", &Value::F64(x)) => x.is_nan(),
("undefined", &Value::Undefined) => true,
_ => true }
}