#![allow(clippy::cyclomatic_complexity)]
extern crate num_bigint;
extern crate num_rational;
extern crate num_traits;
#[macro_use]
extern crate over;
mod errors;
use num_traits::ToPrimitive;
use over::obj::Obj;
use over::types::Type;
use over::value::Value;
macro_rules! test_eq {
($left:expr, $right:expr) => {{
if $left != $right {
panic!(format!(
"Left did not equal right.\nLeft: {:?}\nRight: {:?}\n",
$left, $right
));
}
}};
}
fn get_int(obj: &Obj, field: &str) -> i64 {
obj.get_int(field).unwrap().to_i64().unwrap()
}
#[test]
fn empty() {
let obj = Obj::from_file("tests/test_files/empty.over").unwrap();
test_eq!(obj.len(), 0);
}
#[test]
fn basic() {
let obj = Obj::from_file("tests/test_files/basic.over").unwrap();
test_eq!(get_int(&obj, "_a1"), 1);
test_eq!(get_int(&obj, "a2"), 2);
test_eq!(get_int(&obj, "_"), 0);
test_eq!(obj.get("b").unwrap(), "Smörgåsbord");
test_eq!(get_int(&obj, "c"), 10);
test_eq!(get_int(&obj, "d"), 20);
test_eq!(get_int(&obj, "eee"), 2);
test_eq!(get_int(&obj, "f"), 3);
test_eq!(get_int(&obj, "g_"), 4);
test_eq!(obj.get("Hello").unwrap(), "Hello");
test_eq!(obj.get("i_robot").unwrap(), "not #a comment");
test_eq!(get_int(&obj, "j"), 4);
test_eq!(obj.get("k").unwrap(), "hi");
test_eq!(obj.get("l").unwrap(), "$\\\"");
test_eq!(obj.get("m").unwrap(), "m");
test_eq!(obj.get("n").unwrap(), true);
test_eq!(obj.get("o").unwrap(), false);
test_eq!(obj.get("p").unwrap(), "Hello");
test_eq!(get_int(&obj, "q"), 0);
test_eq!(obj.get("r").unwrap(), Value::Null);
test_eq!(obj.get("s").unwrap(), '\'');
test_eq!(obj.get("t").unwrap(), '\n');
test_eq!(obj.get("u").unwrap(), ' ');
test_eq!(obj.get("v").unwrap(), '\'');
test_eq!(obj.get("w").unwrap(), '$');
test_eq!(obj.get_frac("x").unwrap(), frac!(1, 1));
test_eq!(obj.get("x").unwrap().get_frac().unwrap(), frac!(1, 1));
}
#[test]
fn example() {
let obj = Obj::from_file("tests/test_files/example.over").unwrap();
assert_eq!(obj.get("receipt").unwrap(), "Oz-Ware Purchase Invoice");
assert_eq!(obj.get("date").unwrap(), "2012-08-06");
assert_eq!(
obj.get("customer").unwrap(),
obj! {
"first_name" => "Dorothy",
"family_name" => "Gale"
}
);
assert_eq!(
obj.get("items").unwrap(),
arr![
obj! {
"part_no" => "A4786",
"descrip" => "Water Bucket (Filled)",
"price" => frac!(147,100),
"quantity" => 4
},
obj! {
"part_no" => "E1628",
"descrip" => "High Heeled \"Ruby\" Slippers",
"size" => 8,
"price" => frac!(1337,10),
"quantity" => 1
},
]
);
assert!(
obj.get("bill_to").unwrap()
== obj! {
"street" => "123 Tornado Alley\nSuite 16",
"city" => "East Centerville",
"state" => "KS",
}
|| obj.get("bill_to").unwrap()
== obj! {
"street" => "123 Tornado Alley\r\nSuite 16",
"city" => "East Centerville",
"state" => "KS",
}
);
assert_eq!(obj.get("ship_to").unwrap(), obj.get("bill_to").unwrap());
assert_eq!(
obj.get("specialDelivery").unwrap(),
"Follow the Yellow Brick Road to the Emerald City. \
Pay no attention to the man behind the curtain."
);
}
#[test]
fn obj() {
let obj = Obj::from_file("tests/test_files/obj.over").unwrap();
test_eq!(obj.get_obj("empty").unwrap().len(), 0);
test_eq!(obj.get_obj("empty2").unwrap().len(), 0);
assert!(!obj.contains("bools"));
let bools = obj! {"t" => true, "f" => false};
let outie = obj.get_obj("outie").unwrap();
test_eq!(outie.get_parent().unwrap(), bools);
test_eq!(get_int(&outie, "z"), 0);
let inner = outie.get_obj("inner").unwrap();
test_eq!(get_int(&inner, "z"), 1);
let innie = inner.get_obj("innie").unwrap();
test_eq!(get_int(&innie, "a"), 1);
test_eq!(inner.get("b").unwrap(), tup!(1, 2,));
test_eq!(get_int(&outie, "c"), 3);
test_eq!(outie.get("d").unwrap(), obj! {});
let obj_arr = obj.get_obj("obj_arr").unwrap();
test_eq!(obj_arr.get("arr").unwrap(), arr![1, 2, 3]);
test_eq!(obj.get_int("dot").unwrap(), int!(1));
test_eq!(obj.get_bool("dot_glob").unwrap(), true);
test_eq!(obj.get_int("dot_tup1").unwrap(), int!(1));
test_eq!(obj.get_int("dot_tup2").unwrap(), int!(2));
test_eq!(obj.get_int("dot_arr").unwrap(), int!(1));
test_eq!(obj.get_int("dot_op").unwrap(), int!(4));
test_eq!(obj.get_str("dot_var").unwrap(), "test");
assert_eq!(obj.iter().count(), 13);
let value = obj.values().last();
assert!(!value.unwrap().is_null());
}
#[test]
fn globals() {
let obj = Obj::from_file("tests/test_files/globals.over").unwrap();
let sub = obj.get_obj("sub").unwrap();
test_eq!(sub.get_int("a").unwrap(), int!(1));
test_eq!(get_int(&sub, "b"), 2);
test_eq!(sub.len(), 2);
test_eq!(get_int(&obj, "c"), 2);
test_eq!(obj.len(), 2);
}
#[test]
fn numbers() {
let obj = Obj::from_file("tests/test_files/numbers.over").unwrap();
test_eq!(get_int(&obj, "neg"), -4);
test_eq!(obj.get_frac("pos").unwrap(), frac!(4, 1));
test_eq!(obj.get_frac("neg_zero").unwrap(), frac!(0, 1));
test_eq!(obj.get_frac("pos_zero").unwrap(), frac!(0, 1));
test_eq!(obj.get("frac_from_dec").unwrap(), frac!(13, 10));
test_eq!(obj.get("neg_ffd").unwrap(), frac!(-13, 10));
test_eq!(obj.get("pos_ffd").unwrap(), frac!(13, 10));
test_eq!(obj.get("add_dec").unwrap(), frac!(3, 1));
test_eq!(obj.get("sub_dec").unwrap(), frac!(-3, 1));
let frac = obj.get_frac("big_frac").unwrap();
assert!(frac > frac!(91_000_000, 1));
assert!(frac < frac!(92_000_000, 1));
test_eq!(obj.get("frac1").unwrap(), frac!(1, 2));
test_eq!(obj.get("frac2").unwrap(), frac!(1, 2));
test_eq!(obj.get("frac3").unwrap(), frac!(0, 10));
test_eq!(obj.get("frac4").unwrap(), frac!(-5, 4));
test_eq!(obj.get("frac5").unwrap(), frac!(1, 1));
test_eq!(obj.get("whole_frac").unwrap(), frac!(3, 2));
test_eq!(obj.get("neg_whole_frac").unwrap(), frac!(-21, 4));
test_eq!(obj.get("dec_frac").unwrap(), frac!(1, 2));
test_eq!(obj.get("dec_frac2").unwrap(), frac!(-1, 2));
test_eq!(
obj.get("array").unwrap(),
arr![
obj.get_frac("whole_frac").unwrap(),
frac!(-1, 2),
frac!(3, 2),
frac!(1, 1),
]
);
test_eq!(
obj.get("tup").unwrap(),
tup!(
frac!(-1, 2),
obj.get_frac("whole_frac").unwrap(),
frac!(1, 1),
frac!(3, 2),
)
);
test_eq!(obj.get("var_frac").unwrap(), frac!(-1, 2));
}
#[test]
fn operations() {
let obj = Obj::from_file("tests/test_files/operations.over").unwrap();
test_eq!(obj.get("mod1").unwrap(), int!(5));
test_eq!(obj.get("mod2").unwrap(), int!(0));
test_eq!(obj.get("arr1").unwrap(), arr![3, 4]);
test_eq!(obj.get("arr2").unwrap(), arr![3, 4]);
test_eq!(obj.get("arr3").unwrap(), arr![3, 4]);
test_eq!(obj.get("arr4").unwrap(), arr![arr![1]]);
test_eq!(
obj.get("arr_complex").unwrap(),
arr![arr![arr![1, 2]], arr![arr![3]]]
);
test_eq!(obj.get("str1").unwrap(), "cat");
test_eq!(obj.get("str2").unwrap(), "cat");
test_eq!(obj.get("str3").unwrap(), "cat");
test_eq!(obj.get("str4").unwrap(), "cat");
test_eq!(
obj.get("tup_complex").unwrap(),
tup!(arr![arr![], arr![arr![], arr![1, 2, 3], arr![]]])
);
}
#[test]
fn any_type() {
let obj = Obj::from_file("tests/test_files/any_type.over").unwrap();
let arr1 = obj.get("arr1").unwrap();
let arr2 = arr![arr![arr![]], arr![arr![2]], arr![arr![]]];
test_eq!(arr1.get_type(), Type::Arr(Box::new(arr2.inner_type())));
test_eq!(arr1, arr2);
test_eq!(
obj.get("arr2").unwrap(),
arr![
tup!(arr![arr![]], arr![arr![2]]),
tup!(arr![arr![2]], arr![arr![]]),
]
);
}
#[test]
fn includes() {
let obj = Obj::from_file("tests/test_files/includes.over").unwrap();
let s = "Multi-line string\nwhich should be included verbatim\r\n\
in another file. \"Quotes\" and $$$\ndon't need to be escaped.\n";
test_eq!(obj.get("include").unwrap(), s);
test_eq!(obj.get("include2").unwrap(), obj.get("include").unwrap());
test_eq!(obj.get("include_arr").unwrap(), arr![1, 2, 3, 4, 5]);
test_eq!(
obj.get("include_tup").unwrap(),
tup!("hello", 1, 'c', frac!(3, 3))
);
let o = obj.get_obj("include_obj").unwrap();
test_eq!(
o,
obj! {
"obj2" => obj!{"test" => 1},
"obj3" => obj!{"test" => 2},
"dup" => obj!{"test" => 2},
}
);
assert!(o.ptr_eq(&obj.get_obj("include_obj2").unwrap()));
}
#[test]
fn write() {
let write_path = "tests/test_files/write.over";
macro_rules! write_helper {
($filename:expr) => {{
let obj1 = Obj::from_file($filename).unwrap();
obj1.write_to_file(write_path).unwrap();
let obj2 = Obj::from_file(write_path).unwrap();
test_eq!(obj1, obj2);
}};
}
write_helper!("tests/test_files/basic.over");
write_helper!("tests/test_files/empty.over");
write_helper!("tests/test_files/includes.over");
write_helper!("tests/test_files/obj.over");
write_helper!("tests/test_files/numbers.over");
write_helper!("tests/test_files/example.over");
write_helper!("tests/test_files/fuzz1.over");
write_helper!("tests/test_files/fuzz2.over");
write_helper!("tests/test_files/fuzz3.over");
}