use domain::entities::{ Asset, AssetMetadata, AssetStack, AssetType, DerivativeAsset, DerivativeProfile, DetectionMethod, DuplicateGroup, DuplicateStatus, GenerationStatus, MetadataSource, SourceReference, StackMemberRole, StackType, }; use domain::errors::DomainError; use domain::value_objects::{Checksum, MetadataValue, StructuredData, SystemId}; // --- Asset --- fn make_asset() -> Asset { let src = SourceReference { volume_id: SystemId::new(), relative_path: "photos/img.jpg".to_string(), checksum: Checksum::new("a".repeat(64)).unwrap(), }; Asset::new(src, AssetType::Image, "image/jpeg", 1024, SystemId::new()) } #[test] fn new_asset_is_unprocessed() { let a = make_asset(); assert!(!a.is_processed); } #[test] fn mark_processed() { let mut a = make_asset(); a.mark_processed(); assert!(a.is_processed); } // --- AssetMetadata --- #[test] fn metadata_source_ordering() { assert!(MetadataSource::ExifExtracted < MetadataSource::AiGenerated); assert!(MetadataSource::AiGenerated < MetadataSource::UserEdited); } #[test] fn create_metadata_layer() { let mut data = StructuredData::new(); data.insert("camera", MetadataValue::String("Canon".to_string())); let meta = AssetMetadata::new(SystemId::new(), MetadataSource::ExifExtracted, data); assert_eq!(meta.metadata_source, MetadataSource::ExifExtracted); assert_eq!(meta.data.get_string("camera"), Some("Canon")); } // --- AssetStack --- #[test] fn new_stack_contains_primary() { let primary = SystemId::new(); let stack = AssetStack::new(StackType::LivePhoto, primary.clone(), SystemId::new()); assert_eq!(stack.members.len(), 1); assert_eq!(stack.members[0].asset_id, primary); assert_eq!(stack.members[0].role, StackMemberRole::PrimaryDisplay); assert_eq!(stack.members[0].sort_order, 0); } #[test] fn add_motion_clip() { let mut stack = AssetStack::new(StackType::LivePhoto, SystemId::new(), SystemId::new()); let clip_id = SystemId::new(); stack .add_member(clip_id.clone(), StackMemberRole::MotionClip) .unwrap(); assert_eq!(stack.members.len(), 2); assert_eq!(stack.members[1].asset_id, clip_id); assert_eq!(stack.members[1].sort_order, 1); } #[test] fn cannot_add_duplicate_to_stack() { let primary = SystemId::new(); let mut stack = AssetStack::new(StackType::LivePhoto, primary.clone(), SystemId::new()); let result = stack.add_member(primary, StackMemberRole::HighResSource); assert!(matches!(result, Err(DomainError::Conflict(_)))); } // --- DerivativeAsset --- #[test] fn derivative_lifecycle() { let mut d = DerivativeAsset::new_pending( SystemId::new(), DerivativeProfile::ThumbnailSquare, "/thumbs/abc.webp", ); assert_eq!(d.generation_status, GenerationStatus::Pending); assert_eq!(d.file_size, 0); assert_eq!(d.dimensions, (0, 0)); d.mark_ready("image/webp", 4096, (256, 256)); assert_eq!(d.generation_status, GenerationStatus::Ready); assert_eq!(d.mime_type, "image/webp"); assert_eq!(d.file_size, 4096); assert_eq!(d.dimensions, (256, 256)); } // --- Duplicate --- #[test] fn exact_duplicate_group() { let g = DuplicateGroup::new_exact(SystemId::new(), SystemId::new()); assert_eq!(g.detection_method, DetectionMethod::ExactHash); assert_eq!(g.status, DuplicateStatus::Unresolved); assert_eq!(g.candidates.len(), 2); assert_eq!(g.candidates[0].similarity_score, 1.0); assert_eq!(g.candidates[1].similarity_score, 1.0); } #[test] fn resolve_group() { let mut g = DuplicateGroup::new_exact(SystemId::new(), SystemId::new()); g.resolve(); assert_eq!(g.status, DuplicateStatus::Resolved); }