use jaded::{Content, ConversionError, JavaError, ObjectData, Parser, PrimitiveType::*, Value::*};
use std::fs::File;
use std::io::Read;
const STREAM_ERROR: &str = "Couldn't read from stream";
fn load_stream(name: &str) -> Parser<File> {
let full_file = &format!("res/{name}.obj");
let source = File::open(full_file).unwrap_or_else(|_| panic!("File '{}' missing", full_file));
Parser::new(source).expect("Parser failed")
}
fn read_content(name: &str) -> Content {
load_stream(name).read().expect(STREAM_ERROR)
}
macro_rules! assume {
($stream:ident.$( $method:ident($($args:tt)?) ).+ ) => {
$stream$(.$method($($args)?).expect(
concat!(".", stringify!($method), "(", stringify!($($args)?), ") returned None")
))+
};
}
#[test]
fn externalized() {
let content = read_content("extern");
let obj = assume!(content.value().object_data());
assert_eq!(1, obj.annotation_count());
let mut anno = obj.get_annotation(0).unwrap();
assert_eq!(17, anno.read_i32().unwrap());
}
#[test]
fn proxy() {
let content = read_content("proxy");
let obj = assume!(content.value().object_data());
assert_eq!("java.lang.reflect.Proxy", obj.class_name());
assert_eq!(1, obj.field_count());
let proxied = get_field(obj, "h");
let proxied_obj = assume!(proxied.object_data());
assert_eq!(1, proxied_obj.field_count());
assert_eq!(0, proxied_obj.annotation_count());
assert_eq!(&Null, get_field(proxied_obj, "foo"));
assert_eq!("com.example.MeaningOfLife", proxied_obj.class_name());
}
#[test]
fn custom_write() {
let content = read_content("custom_write");
let obj = assume!(content.value().object_data());
assert_eq!("com.example.Custom", obj.class_name());
let mut anno = obj.get_annotation(0).unwrap();
assert_eq!(2, anno.read_i32().unwrap());
println!("read int");
assert_eq!("helloWorld", assume!(anno.read_object().string()));
println!("read string");
assert_eq!(2, anno.read_i32().unwrap());
println!("read int");
}
#[test]
fn sample_record() {
let content = read_content("sample_record");
let obj = assume!(content.value().object_data());
assert_eq!("com.example.SampleRecord", obj.class_name());
assert_eq!(42, obj.get_field_as("i").unwrap());
assert_eq!("helloWorld", assume!(obj.get_field("s").string()));
}
#[test]
fn loop_reference() {
let content = read_content("loop_reference");
let data = assume!(content.value().object_data());
assert_eq!(&Loop(0), get_field(data, "loop"));
}
#[test]
fn arraylist() {
let content = read_content("arraylist");
let list = assume!(content.value());
let data = assume!(list.object_data());
assert_eq!("java.util.ArrayList", data.class_name());
assert_eq!(1, data.field_count());
assert_eq!(3, data.get_field_as("size").unwrap());
let mut arraylist_anno = data.get_annotation(0).unwrap();
assert_eq!(3, arraylist_anno.read_i32().unwrap());
let child = "com.example.Child";
let c1 = arraylist_anno.read_object().unwrap();
assert_eq!(child, c1.object_data().unwrap().class_name());
let c2 = arraylist_anno.read_object().unwrap();
assert_eq!(child, c2.object_data().unwrap().class_name());
let c3 = arraylist_anno.read_object().unwrap();
assert_eq!(child, c3.object_data().unwrap().class_name());
assert_ne!(c1, c2);
assert_eq!(c2, c3);
}
#[test]
fn extended_pojo() {
let content = read_content("extended_pojo");
let obj = assume!(content.value().object_data());
assert_eq!("com.example.Child", obj.class_name());
assert_eq!(0, obj.annotation_count());
assert_eq!(6, obj.field_count());
assert_eq!(1, obj.get_field_as("i").unwrap());
assert_eq!(
&Enum("com.example.Direction".to_string(), "EAST".to_string()),
get_field(obj, "d")
);
assert_eq!("helloWorld", &obj.get_field_as::<String>("bar").unwrap());
assert_eq!(
&PrimitiveArray(vec![Double(1.2), Double(2.3), Double(3.4), Double(4.5)]),
get_field(obj, "arr")
);
assert_eq!("bar", &obj.get_field_as::<String>("foo").unwrap());
let other = get_field(obj, "other").object_data().unwrap();
assert_eq!("com.example.Other", other.class_name());
assert_eq!("def", other.get_field_as::<String>("abc").unwrap());
assert_eq!(0, other.annotation_count());
}
#[test]
fn pojo() {
let content = read_content("pojo");
let pojo = assume!(content.value());
let obj = assume!(pojo.object_data());
assert_eq!(obj.class_name(), "com.example.Parent");
assert_eq!(obj.annotation_count(), 0);
assert_eq!(obj.field_count(), 2);
assert_eq!(13, obj.get_field_as("i").unwrap());
assert_eq!("bar", obj.get_field_as::<String>("foo").unwrap());
}
#[test]
fn strings() {
let mut p = load_stream("strings");
assert_eq!(assume!(p.read().value().string()), "helloWorld");
assert_eq!(assume!(p.read().value().string()), "hello");
assert_eq!(assume!(p.read().value().string()), "world");
assert_eq!(assume!(p.read().value().string()), "helloWorld");
let mut p = load_stream("string_long");
let long = p.read().expect(STREAM_ERROR);
let long_string = assume!(long.value().string());
assert!(long_string.len() > u16::MAX.into());
assert!(long_string.starts_with("Lorem ipsum"));
assert!(long_string.ends_with("magna aliqua"));
}
#[test]
fn auto_box_string() {
let mut p = load_stream("strings");
assert_eq!(Box::new("helloWorld".to_string()), p.read_as().unwrap());
}
#[test]
fn reset() {
let mut p = load_stream("reset");
let s1 = p.read().expect(STREAM_ERROR);
let s2 = p.read().expect(STREAM_ERROR);
let s3 = p.read().expect(STREAM_ERROR);
let s4 = p.read().expect(STREAM_ERROR);
assert_eq!(assume!(s1.value().string()), "helloWorld");
assert_eq!(assume!(s2.value().string()), "helloWorld");
assert_eq!(assume!(s3.value().string()), "foobar");
assert_eq!(assume!(s4.value().string()), "foobar");
}
#[test]
fn null_reference() {
assert!(read_content("null").value().unwrap().is_null())
}
#[test]
fn null_as_string() {
let mut p = load_stream("null");
match p.read_as::<String>() {
Err(JavaError::ConvertError(ConversionError::NullPointerException)) => (),
Err(e) => panic!("Expected NPE but got: {}", e),
Ok(s) => panic!("Expected NPE but read {}", s),
}
}
#[test]
fn null_as_optional_string() {
let mut p = load_stream("null");
match p.read_as::<Option<String>>() {
Ok(None) => (),
Ok(Some(s)) => panic!("Expected None but read {}", s),
Err(e) => panic!("Expected None but got: {}", e),
}
}
#[test]
fn enum_constant() {
match read_content("enum").value().unwrap() {
Enum(cls, cons) => assert_eq!(
("com.example.Direction", "EAST"),
(cls.as_str(), cons.as_str())
),
_ => panic!("Expected enum constant"),
}
}
#[test]
fn class() {
assert_eq!(
&Class("com.example.Parent".to_string()),
read_content("class_only").value().unwrap()
);
}
#[test]
fn block_data() {
let content = read_content("block");
let short = content.data().unwrap();
assert_eq!(
short,
vec![
0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 84, 0, 10, 104, 101, 108, 108, 111, 87, 111, 114, 108, 100
]
);
let content = read_content("block_long");
let long = content.data().unwrap();
assert_eq!(long, [0; 256]);
}
#[test]
fn nested_array() {
let content = read_content("array_nested");
let arrays = content.value().unwrap();
assert_eq!(
&Array(vec![
PrimitiveArray(vec![Boolean(true), Boolean(false)]),
PrimitiveArray(vec![Boolean(false), Boolean(true)]),
]),
arrays
);
}
#[test]
fn primitive_arrays() {
let mut parser = load_stream("array_primitive");
assert_eq!(
parser.read().expect(STREAM_ERROR).value().unwrap(),
&PrimitiveArray(vec![Double(1.2), Double(2.3), Double(3.4), Double(4.5)])
);
assert_eq!(
parser.read().expect(STREAM_ERROR).value().unwrap(),
&PrimitiveArray(vec![
Boolean(true),
Boolean(true),
Boolean(false),
Boolean(true)
])
);
}
#[test]
fn primitive_arrays_as_vec() {
let mut parser = load_stream("array_primitive");
assert_eq!(
vec![1.2, 2.3, 3.4, 4.5],
parser.read_as::<Vec<f64>>().unwrap()
);
assert_eq!(
vec![true, true, false, true],
parser.read_as::<Vec<bool>>().unwrap()
);
}
#[test]
fn primitives_from_value() {
let mut parser = load_stream("primitives");
assert!(parser.read_as::<bool>().unwrap());
assert_eq!('A', parser.read_as().unwrap());
assert_eq!(-42i16, parser.read_as().unwrap());
assert_eq!(-23, parser.read_as().unwrap());
assert_eq!(-84i64, parser.read_as().unwrap());
assert_eq!(1.23f32, parser.read_as().unwrap());
assert_eq!(4.56, parser.read_as().unwrap());
assert_eq!(76u8, parser.read_as().unwrap());
assert!(parser.read_as::<f32>().unwrap().is_nan());
assert!(parser.read_as::<f64>().unwrap().is_nan());
assert!(parser.read_as::<f64>().unwrap().is_infinite());
}
#[test]
fn primitives_as_objects() {
let mut parser = load_stream("primitives");
assert_eq!(extract_primitive(&mut parser, "Boolean"), Boolean(true));
assert_eq!(extract_primitive(&mut parser, "Character"), Char('A'));
assert_eq!(extract_primitive(&mut parser, "Short"), Short(-42));
assert_eq!(extract_primitive(&mut parser, "Integer"), Int(-23));
assert_eq!(extract_primitive(&mut parser, "Long"), Long(-84));
assert_eq!(extract_primitive(&mut parser, "Float"), Float(1.23));
assert_eq!(extract_primitive(&mut parser, "Double"), Double(4.56));
assert_eq!(extract_primitive(&mut parser, "Byte"), Byte(76));
match extract_primitive(&mut parser, "Float") {
Float(f) => assert!(f.is_nan()),
_ => panic!("expected NaN"),
}
match extract_primitive(&mut parser, "Double") {
Double(f) => assert!(f.is_nan()),
_ => panic!("expected NaN"),
}
match extract_primitive(&mut parser, "Double") {
Double(f) => assert!(f.is_infinite() && f.is_sign_positive()),
_ => panic!("expected NaN"),
}
}
fn extract_primitive<T: Read>(parser: &mut Parser<T>, class: &str) -> jaded::PrimitiveType {
match parser.read().expect("Couldn't read from stream").value() {
Some(Object(obj)) => {
assert_eq!(format!("java.lang.{class}"), obj.class_name());
assert_eq!(0, obj.annotation_count());
*obj.get_field("value").unwrap().primitive().unwrap()
}
_ => panic!("Expected instance of java.lang.{}", class),
}
}
fn get_field<'a>(obj: &'a ObjectData, field: &str) -> &'a jaded::Value {
obj.get_field(field).unwrap()
}