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 { 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") } /// Read the first item from a stream fn read_content(name: &str) -> Content { load_stream(name).read().expect(STREAM_ERROR) } /// Macro to chain string of methods where each returns an Option that should be unwrapped 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::("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::("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::("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::("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::() { 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::>() { 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, // 42 as int 0, 0, 0, 0, 0, 0, 0, 84, // 84 as long 0, 10, 104, 101, 108, 108, 111, 87, 111, 114, 108, 100 ] ); // helloWorld as string (length, data) 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::>().unwrap() ); assert_eq!( vec![true, true, false, true], parser.read_as::>().unwrap() ); } #[test] fn primitives_from_value() { let mut parser = load_stream("primitives"); assert!(parser.read_as::().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::().unwrap().is_nan()); assert!(parser.read_as::().unwrap().is_nan()); assert!(parser.read_as::().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(parser: &mut Parser, 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() }