use bat_adapters::manifest::ManifestDriverRegistry; use bat_core::repositories::cas_repository::CasRepository; use bat_core::repositories::resource_repository::{ResourceQuery, ResourceRepository}; use bat_infrastructure::{ BundleSource, FileSystemCasRepository, InMemoryResourceRepository, ResourceImportService, }; use serde_json::json; use tempfile::TempDir; fn push_c_string(data: &mut Vec, value: &str) { data.extend_from_slice(value.as_bytes()); data.push(0); } fn push_u16(data: &mut Vec, value: u16) { data.extend_from_slice(&value.to_be_bytes()); } fn push_u32(data: &mut Vec, value: u32) { data.extend_from_slice(&value.to_be_bytes()); } fn push_i32(data: &mut Vec, value: i32) { data.extend_from_slice(&value.to_be_bytes()); } fn push_u64(data: &mut Vec, value: u64) { data.extend_from_slice(&value.to_be_bytes()); } fn align(data: &mut Vec, alignment: usize) { let remainder = data.len() % alignment; if remainder != 0 { data.resize(data.len() + alignment - remainder, 0); } } fn synthetic_minimal_unityfs_bundle() -> Vec { let mut blocks_info = Vec::new(); blocks_info.extend_from_slice(&[0; 16]); push_i32(&mut blocks_info, 1); push_u32(&mut blocks_info, 4); push_u32(&mut blocks_info, 4); push_u16(&mut blocks_info, 0); push_i32(&mut blocks_info, 1); push_u64(&mut blocks_info, 0); push_u64(&mut blocks_info, 4); push_u32(&mut blocks_info, 0); push_c_string(&mut blocks_info, "SYNTHETIC-GOLDEN-CAB"); let mut data = Vec::new(); push_c_string(&mut data, "UnityFS"); push_u32(&mut data, 8); push_c_string(&mut data, "5.x.x"); push_c_string(&mut data, "2021.3.56f2"); push_u64(&mut data, 0); push_u32(&mut data, blocks_info.len() as u32); push_u32(&mut data, blocks_info.len() as u32); push_u32(&mut data, 0); align(&mut data, 16); data.extend_from_slice(&blocks_info); data.extend_from_slice(b"data"); let total_size = data.len() as u64; let total_size_offset = b"UnityFS\0".len() + 4 + b"5.x.x\0".len() + b"2021.3.56f2\0".len(); data[total_size_offset..total_size_offset + 8].copy_from_slice(&total_size.to_be_bytes()); data } #[tokio::test] async fn imports_synthetic_addressables_catalog_bundle_against_golden() { let catalog = include_bytes!("fixtures/synthetic_phase2/catalog.json"); let manifest = ManifestDriverRegistry::with_defaults() .parse(catalog) .await .unwrap(); let temp_dir = TempDir::new().unwrap(); let cas = FileSystemCasRepository::new(temp_dir.path().join("cas")); let resources = InMemoryResourceRepository::new(); let service = ResourceImportService::new(&cas, &resources); let report = service .import_manifest_bundles( &manifest, &[BundleSource::new( "minimal.bundle", synthetic_minimal_unityfs_bundle(), )], ) .await .unwrap(); assert_eq!(report.imported.len(), 1); assert!(cas.exists(&report.imported[0].object_id).await); let indexed = resources.list(ResourceQuery::all()).await.unwrap(); let actual = json!({ "imported": report.imported.iter().map(|imported| { json!({ "bytes": imported.bytes, "source_path": imported.source_path, "unityfs": { "block_count": imported.unityfs.block_count, "directories": imported.unityfs.directories, "directory_count": imported.unityfs.directory_count, "unity_version": imported.unityfs.unity_version, } }) }).collect::>(), "resource_count": indexed.len(), "skipped": report.skipped, }); let expected: serde_json::Value = serde_json::from_str(include_str!("golden/synthetic_phase2_import.json")).unwrap(); assert_eq!(actual, expected); assert_eq!(indexed[0].entry.hash, report.imported[0].object_id); }