//! Writer and parser test. #![cfg(feature = "writer")] use std::{cell::RefCell, io::Cursor, iter, rc::Rc}; use fbxcel::{ low::{v7400::AttributeValue, FbxVersion}, pull_parser::{any::AnyParser, v7400::attribute::loaders::DirectLoader}, write_v7400_binary, writer::v7400::binary::{FbxFooter, Writer}, }; use self::v7400::writer::{ expect_fbx_end, expect_node_end, expect_node_start, CUSTOM_UNKNOWN1, MAGIC, UNKNOWN3, }; mod v7400; /// Compares expected binary and binary generated with events. #[test] fn empty_write_v7400() -> Result<(), Box> { let mut dest = Vec::new(); let cursor = Cursor::new(&mut dest); let writer = Writer::new(cursor, FbxVersion::V7_4)?; let footer = FbxFooter { unknown1: Some(&CUSTOM_UNKNOWN1), padding_len: Default::default(), unknown2: None, unknown3: None, }; writer.finalize_and_flush(&footer)?; let expected = { let raw_ver = 7400u32; let mut vec = Vec::new(); // Header. { // Magic. vec.extend(MAGIC); // Version. vec.extend(raw_ver.to_le_bytes()); } // No nodes. { // End of implicit root. { vec.extend(iter::repeat(0).take(4 * 3 + 1)); } } // Footer. { // Footer: unknown1. vec.extend(CUSTOM_UNKNOWN1); // Footer: padding. { let len = vec.len().wrapping_neg() % 16; assert_eq!((vec.len() + len) % 16, 0); vec.extend(iter::repeat(0).take(len)); } // Footer: unknown2. vec.extend([0; 4]); // Footer: FBX version. vec.extend(raw_ver.to_le_bytes()); // Footer: 120 zeroes. vec.extend(iter::repeat(0).take(120)); // Footer: unknown3. vec.extend(UNKNOWN3); } vec }; assert_eq!(dest.len() % 16, 0); assert_eq!(dest, expected); let mut parser = match AnyParser::from_seekable_reader(Cursor::new(dest))? { AnyParser::V7400(parser) => parser, _ => panic!("Generated data should be parsable with v7400 parser"), }; let warnings = Rc::new(RefCell::new(Vec::new())); parser.set_warning_handler({ let warnings = warnings.clone(); move |warning, _pos| { warnings.borrow_mut().push(warning); Ok(()) } }); assert_eq!(parser.fbx_version(), FbxVersion::V7_4); { let footer_res = expect_fbx_end(&mut parser)?; let footer = footer_res?; assert_eq!(footer.unknown1, CUSTOM_UNKNOWN1); assert_eq!(footer.unknown2, [0u8; 4]); assert_eq!(footer.unknown3, UNKNOWN3); } assert_eq!(warnings.borrow().len(), 0); Ok(()) } /// Compares expected binary and binary generated with events. #[test] fn tree_write_v7500() -> Result<(), Box> { let mut dest = Vec::new(); let cursor = Cursor::new(&mut dest); let mut writer = Writer::new(cursor, FbxVersion::V7_5)?; write_v7400_binary!( writer=writer, tree={ Node0: { Node0_0: {}, Node0_1: {}, }, Node1: [true] { Node1_0: (vec![42i32.into(), 1.234f64.into()]) {} Node1_1: [&[1u8, 2, 4, 8, 16][..], "Hello, world"] {} }, }, )?; writer.finalize_and_flush(&Default::default())?; let mut parser = match AnyParser::from_seekable_reader(Cursor::new(dest))? { AnyParser::V7400(parser) => parser, _ => panic!("Generated data should be parsable with v7400 parser"), }; let warnings = Rc::new(RefCell::new(Vec::new())); parser.set_warning_handler({ let warnings = warnings.clone(); move |warning, _pos| { warnings.borrow_mut().push(warning); Ok(()) } }); assert_eq!(parser.fbx_version(), FbxVersion::V7_5); { let attrs = expect_node_start(&mut parser, "Node0")?; assert_eq!(attrs.total_count(), 0); } { let attrs = expect_node_start(&mut parser, "Node0_0")?; assert_eq!(attrs.total_count(), 0); } expect_node_end(&mut parser)?; { let attrs = expect_node_start(&mut parser, "Node0_1")?; assert_eq!(attrs.total_count(), 0); } expect_node_end(&mut parser)?; expect_node_end(&mut parser)?; { let attrs = expect_node_start(&mut parser, "Node1")?; assert_eq!(attrs.total_count(), 1); } { let attrs = expect_node_start(&mut parser, "Node1_0")?; assert_eq!(attrs.total_count(), 2); } expect_node_end(&mut parser)?; { let attrs = expect_node_start(&mut parser, "Node1_1")?; assert_eq!(attrs.total_count(), 2); } expect_node_end(&mut parser)?; expect_node_end(&mut parser)?; { let footer_res = expect_fbx_end(&mut parser)?; assert!(footer_res.is_ok()); } assert_eq!(warnings.borrow().len(), 0); Ok(()) } #[test] fn macro_v7400_idempotence() -> Result<(), Box> { let version = FbxVersion::V7_4; let mut writer = Writer::new(std::io::Cursor::new(Vec::new()), version)?; write_v7400_binary!( writer=writer, tree={ Node0: { Node0_0: {}, Node0_1: {}, }, Node1: [true] { Node1_0: (vec![42i32.into(), 1.234f64.into()]) {} Node1_1: [&[1u8, 2, 4, 8, 16][..], "Hello, world"] {} }, }, )?; let bin = writer.finalize_and_flush(&Default::default())?.into_inner(); let mut parser = match AnyParser::from_seekable_reader(Cursor::new(bin))? { AnyParser::V7400(parser) => parser, _ => panic!("Generated data should be parsable with v7400 parser"), }; let warnings = Rc::new(RefCell::new(Vec::new())); parser.set_warning_handler({ let warnings = warnings.clone(); move |warning, _pos| { warnings.borrow_mut().push(warning); Ok(()) } }); assert_eq!(parser.fbx_version(), version); { let attrs = expect_node_start(&mut parser, "Node0")?; assert_eq!(attrs.total_count(), 0); } { let attrs = expect_node_start(&mut parser, "Node0_0")?; assert_eq!(attrs.total_count(), 0); } expect_node_end(&mut parser)?; { let attrs = expect_node_start(&mut parser, "Node0_1")?; assert_eq!(attrs.total_count(), 0); } expect_node_end(&mut parser)?; expect_node_end(&mut parser)?; { let mut attrs = expect_node_start(&mut parser, "Node1")?; assert_eq!( attrs.load_next(DirectLoader)?, Some(AttributeValue::from(true)) ); assert_eq!(attrs.total_count(), 1); } { let mut attrs = expect_node_start(&mut parser, "Node1_0")?; assert_eq!( attrs.load_next(DirectLoader)?, Some(AttributeValue::from(42i32)) ); assert!(attrs .load_next(DirectLoader)? .map_or(false, |attr| attr.strict_eq(&1.234f64.into()))); assert_eq!(attrs.total_count(), 2); } expect_node_end(&mut parser)?; { let mut attrs = expect_node_start(&mut parser, "Node1_1")?; assert_eq!( attrs.load_next(DirectLoader)?, Some(AttributeValue::from(vec![1u8, 2, 4, 8, 16])) ); assert_eq!( attrs.load_next(DirectLoader)?, Some(AttributeValue::from("Hello, world")) ); assert_eq!(attrs.total_count(), 2); } expect_node_end(&mut parser)?; expect_node_end(&mut parser)?; { let footer_res = expect_fbx_end(&mut parser)?; assert!(footer_res.is_ok()); } assert_eq!(warnings.borrow().len(), 0); Ok(()) }