use std::path::PathBuf;
use std::time::Duration;
use ff_format::PixelFormat;
use ff_format::channel::ChannelLayout;
use ff_format::codec::{AudioCodec, VideoCodec};
use ff_probe::open;
fn assets_dir() -> PathBuf {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
PathBuf::from(format!("{}/../../assets", manifest_dir))
}
fn test_video_path() -> PathBuf {
assets_dir().join("video/gameplay.mp4")
}
fn test_audio_path() -> PathBuf {
assets_dir().join("audio/konekonoosanpo.mp3")
}
#[test]
fn test_probe_video_file_opens_successfully() {
let path = test_video_path();
let result = open(&path);
assert!(
result.is_ok(),
"Failed to open video file: {:?}",
result.err()
);
}
#[test]
fn test_probe_video_file_has_correct_format() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(
info.format().contains("mp4") || info.format().contains("mov"),
"Expected mp4/mov format, got: {}",
info.format()
);
}
#[test]
fn test_probe_video_file_has_video_stream() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(info.has_video(), "Video file should have video stream");
assert!(
!info.video_streams().is_empty(),
"Video streams should not be empty"
);
}
#[test]
fn test_probe_video_file_video_stream_properties() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
assert!(video.width() > 0, "Video width should be positive");
assert!(video.height() > 0, "Video height should be positive");
let valid_codecs = [
VideoCodec::H264,
VideoCodec::H265,
VideoCodec::Vp9,
VideoCodec::Av1,
];
assert!(
valid_codecs.contains(&video.codec()) || video.codec() == VideoCodec::Unknown,
"Video codec should be a known codec or Unknown"
);
assert!(
!matches!(video.pixel_format(), PixelFormat::Other(_)),
"Pixel format should be a known format"
);
assert!(video.fps() > 0.0, "Frame rate should be positive");
}
#[test]
fn test_probe_video_file_has_audio_stream() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
if info.has_audio() {
let audio = info
.primary_audio()
.expect("Should have primary audio stream");
assert!(audio.sample_rate() > 0, "Sample rate should be positive");
assert!(audio.channels() > 0, "Channel count should be positive");
}
}
#[test]
fn test_probe_video_file_duration() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(
info.duration() > Duration::ZERO,
"Duration should be positive"
);
assert!(
info.duration() < Duration::from_secs(3600),
"Duration seems unreasonably long for a test file"
);
}
#[test]
fn test_probe_video_file_size() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(info.file_size() > 0, "File size should be positive");
}
#[test]
fn test_probe_video_file_path() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert_eq!(info.path(), path);
assert_eq!(info.file_name(), Some("gameplay.mp4"));
assert_eq!(info.extension(), Some("mp4"));
}
#[test]
fn test_probe_audio_file_opens_successfully() {
let path = test_audio_path();
let result = open(&path);
assert!(
result.is_ok(),
"Failed to open audio file: {:?}",
result.err()
);
}
#[test]
fn test_probe_audio_file_has_correct_format() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
assert!(
info.format().contains("mp3"),
"Expected mp3 format, got: {}",
info.format()
);
}
#[test]
fn test_probe_audio_file_has_audio_stream() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
assert!(info.has_audio(), "Audio file should have audio stream");
assert!(
!info.audio_streams().is_empty(),
"Audio streams should not be empty"
);
}
#[test]
fn test_probe_audio_file_no_video_stream() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
assert!(
!info.has_video(),
"Audio-only file should not have video stream"
);
assert!(
info.video_streams().is_empty(),
"Video streams should be empty"
);
}
#[test]
fn test_probe_audio_file_audio_stream_properties() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let audio = info
.primary_audio()
.expect("Should have primary audio stream");
assert_eq!(audio.codec(), AudioCodec::Mp3, "Audio codec should be MP3");
let common_sample_rates = [8000, 11025, 22050, 44100, 48000, 96000];
assert!(
common_sample_rates.contains(&audio.sample_rate()),
"Sample rate {} should be a common value",
audio.sample_rate()
);
assert!(
audio.channels() >= 1 && audio.channels() <= 8,
"Channel count {} should be between 1 and 8",
audio.channels()
);
let expected_layouts = match audio.channels() {
1 => vec![ChannelLayout::Mono],
2 => vec![ChannelLayout::Stereo],
_ => vec![],
};
if !expected_layouts.is_empty() {
assert!(
expected_layouts.contains(&audio.channel_layout()),
"Channel layout {:?} should match channel count {}",
audio.channel_layout(),
audio.channels()
);
}
}
#[test]
fn test_probe_audio_file_sample_format() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let audio = info
.primary_audio()
.expect("Should have primary audio stream");
let sample_format = audio.sample_format();
assert!(
sample_format.is_float() || sample_format.is_integer(),
"Sample format should be float or integer"
);
}
#[test]
fn test_probe_audio_file_duration() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
assert!(
info.duration() > Duration::ZERO,
"Duration should be positive"
);
assert!(
info.duration() < Duration::from_secs(600),
"Duration seems unreasonably long for a test file"
);
}
#[test]
fn test_probe_audio_file_path() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
assert_eq!(info.path(), path);
assert_eq!(info.file_name(), Some("konekonoosanpo.mp3"));
assert_eq!(info.extension(), Some("mp3"));
}
#[test]
fn test_probe_nonexistent_file() {
let path = assets_dir().join("nonexistent-file.mp4");
let result = open(&path);
assert!(result.is_err(), "Opening nonexistent file should fail");
}
#[test]
fn test_probe_invalid_file() {
let path = assets_dir().join("img/hello-triangle.png");
let result = open(&path);
if let Ok(info) = result {
assert!(!info.format().is_empty(), "Format should not be empty");
}
}
#[test]
fn test_probe_video_file_stream_counts() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(
info.video_stream_count() >= 1,
"Should have at least 1 video stream"
);
let total = info.video_stream_count() + info.audio_stream_count();
assert!(total >= 1, "Should have at least 1 stream");
}
#[test]
fn test_probe_audio_file_stream_counts() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
assert_eq!(
info.audio_stream_count(),
1,
"Should have exactly 1 audio stream"
);
assert_eq!(info.video_stream_count(), 0, "Should have 0 video streams");
}
#[test]
fn test_probe_video_resolution() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let resolution = info.resolution();
assert!(resolution.is_some(), "Video file should have resolution");
let (width, height) = resolution.unwrap();
assert!(width > 0 && height > 0, "Resolution should be positive");
let aspect = width as f64 / height as f64;
assert!(
aspect > 0.5 && aspect < 3.0,
"Aspect ratio {} seems unusual",
aspect
);
}
#[test]
fn test_probe_video_frame_rate() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let frame_rate = info.frame_rate();
assert!(frame_rate.is_some(), "Video file should have frame rate");
let fps_value = frame_rate.unwrap();
assert!(
fps_value > 10.0 && fps_value < 120.0,
"Frame rate {} seems unusual",
fps_value
);
}
#[test]
fn test_probe_audio_sample_rate() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let sample_rate = info.sample_rate();
assert!(sample_rate.is_some(), "Audio file should have sample rate");
let rate = sample_rate.unwrap();
assert!(
rate >= 8000 && rate <= 192000,
"Sample rate {} seems unusual",
rate
);
}
#[test]
fn test_probe_audio_channels() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let channels = info.channels();
assert!(channels.is_some(), "Audio file should have channel count");
let ch = channels.unwrap();
assert!(ch >= 1 && ch <= 8, "Channel count {} seems unusual", ch);
}
#[test]
fn test_probe_video_file_metadata_accessible() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let _metadata = info.metadata();
let _ = info.title();
let _ = info.artist();
let _ = info.album();
let _ = info.creation_time();
let _ = info.date();
let _ = info.comment();
let _ = info.encoder();
}
#[test]
fn test_probe_audio_file_metadata_accessible() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let _metadata = info.metadata();
let _ = info.title();
let _ = info.artist();
let _ = info.album();
let _ = info.date();
}
#[test]
fn test_probe_video_file_metadata_keys() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
for (key, _value) in info.metadata() {
assert!(!key.is_empty(), "Metadata key should not be empty");
}
}
#[test]
fn test_probe_audio_file_metadata_keys() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
for (key, _value) in info.metadata() {
assert!(!key.is_empty(), "Metadata key should not be empty");
}
}
#[test]
fn test_probe_video_color_space_extraction() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
let color_space = video.color_space();
let valid_spaces = [
ff_format::color::ColorSpace::Bt709,
ff_format::color::ColorSpace::Bt601,
ff_format::color::ColorSpace::Bt2020,
ff_format::color::ColorSpace::Srgb,
ff_format::color::ColorSpace::Unknown,
];
assert!(
valid_spaces.contains(&color_space),
"Color space {:?} should be a valid value",
color_space
);
}
#[test]
fn test_probe_video_color_range_extraction() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
let color_range = video.color_range();
let valid_ranges = [
ff_format::color::ColorRange::Limited,
ff_format::color::ColorRange::Full,
ff_format::color::ColorRange::Unknown,
];
assert!(
valid_ranges.contains(&color_range),
"Color range {:?} should be a valid value",
color_range
);
}
#[test]
fn test_probe_video_color_primaries_extraction() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
let color_primaries = video.color_primaries();
let valid_primaries = [
ff_format::color::ColorPrimaries::Bt709,
ff_format::color::ColorPrimaries::Bt601,
ff_format::color::ColorPrimaries::Bt2020,
ff_format::color::ColorPrimaries::Unknown,
];
assert!(
valid_primaries.contains(&color_primaries),
"Color primaries {:?} should be a valid value",
color_primaries
);
}
#[test]
fn test_probe_video_color_info_consistency() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
let color_space = video.color_space();
let color_primaries = video.color_primaries();
if color_space == ff_format::color::ColorSpace::Bt2020 {
assert!(
color_primaries == ff_format::color::ColorPrimaries::Bt2020
|| color_primaries == ff_format::color::ColorPrimaries::Unknown,
"BT.2020 color space should have BT.2020 or Unknown primaries, got {:?}",
color_primaries
);
}
}
#[test]
fn test_probe_video_hdr_detection() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
let color_space = video.color_space();
let color_primaries = video.color_primaries();
let is_hdr = color_space == ff_format::color::ColorSpace::Bt2020
|| color_primaries == ff_format::color::ColorPrimaries::Bt2020;
if is_hdr {
println!("HDR content detected in test file");
}
assert!(true, "HDR detection completed successfully");
}
#[test]
fn test_probe_video_file_bitrate() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let bitrate = info.bitrate();
assert!(
bitrate.is_some(),
"Video file should have container bitrate"
);
let bps = bitrate.unwrap();
assert!(
bps > 1_000 && bps < 100_000_000,
"Bitrate {} bps seems unreasonable (expected 1 kbps - 100 Mbps)",
bps
);
}
#[test]
fn test_probe_audio_file_bitrate() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let bitrate = info.bitrate();
assert!(
bitrate.is_some(),
"Audio file should have container bitrate"
);
let bps = bitrate.unwrap();
assert!(
bps > 8_000 && bps < 10_000_000,
"Audio bitrate {} bps seems unreasonable (expected 8 kbps - 10 Mbps)",
bps
);
}
#[test]
fn test_probe_video_stream_bitrate() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let video = info
.primary_video()
.expect("Should have primary video stream");
if let Some(bps) = video.bitrate() {
assert!(
bps > 1_000 && bps < 100_000_000,
"Video stream bitrate {} bps seems unreasonable",
bps
);
}
}
#[test]
fn test_probe_audio_stream_bitrate() {
let path = test_audio_path();
let info = open(&path).expect("Failed to open audio file");
let audio = info
.primary_audio()
.expect("Should have primary audio stream");
if let Some(bps) = audio.bitrate() {
assert!(
bps > 1_000 && bps < 10_000_000,
"Audio stream bitrate {} bps seems unreasonable",
bps
);
}
}
#[test]
fn test_probe_bitrate_consistency() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
let file_size = info.file_size();
let duration = info.duration();
let bitrate = info.bitrate();
if let Some(bps) = bitrate {
let duration_secs = duration.as_secs_f64();
if duration_secs > 0.0 {
#[allow(clippy::cast_precision_loss)]
let calculated_bps = (file_size as f64 * 8.0 / duration_secs) as u64;
let min_expected = calculated_bps * 80 / 100;
let max_expected = calculated_bps * 120 / 100;
assert!(
bps >= min_expected && bps <= max_expected,
"Bitrate {} should be close to calculated value {} (within 20%)",
bps,
calculated_bps
);
}
}
}
#[test]
fn test_probe_video_file_has_no_subtitle_streams() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(
info.subtitle_streams().is_empty(),
"Video file without subtitles should have empty subtitle_streams()"
);
}
#[test]
fn test_probe_video_file_has_subtitles_returns_false() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert!(
!info.has_subtitles(),
"has_subtitles() should return false for a video file without subtitle streams"
);
}
#[test]
fn test_probe_video_file_subtitle_stream_count_is_zero() {
let path = test_video_path();
let info = open(&path).expect("Failed to open video file");
assert_eq!(
info.subtitle_stream_count(),
0,
"subtitle_stream_count() should be 0 for a video file without subtitle streams"
);
}