diff options
Diffstat (limited to 'vendor/exr/tests/fuzz.rs')
-rw-r--r-- | vendor/exr/tests/fuzz.rs | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/vendor/exr/tests/fuzz.rs b/vendor/exr/tests/fuzz.rs new file mode 100644 index 0000000..9bdc79d --- /dev/null +++ b/vendor/exr/tests/fuzz.rs @@ -0,0 +1,176 @@ +//! Fuzzy testing. +//! Tries to discover panics with random bytes. +//! This test is expensive and therefore marked with `#[ignore]`. To run this test, use `cargo test -- --ignored`. + +use std::panic::{catch_unwind}; +use rand::rngs::{StdRng}; +use rand::{Rng}; + +extern crate exr; +use exr::prelude::*; +use std::path::PathBuf; +use std::ffi::OsStr; +use std::fs::File; +use std::io::{Write, Cursor}; +use exr::image::read::read_first_rgba_layer_from_file; +use exr::image::pixel_vec::PixelVec; + +fn exr_files(path: &'static str, filter: bool) -> impl Iterator<Item=PathBuf> { + walkdir::WalkDir::new(path).into_iter().map(std::result::Result::unwrap) + .filter(|entry| entry.path().is_file()) + + .filter(move |entry| !filter || entry.path().extension() == Some(OsStr::new("exr"))) + .map(walkdir::DirEntry::into_path) +} + + +/// Just don't panic. +#[test] +pub fn fuzzed(){ + for ref file in exr_files("tests/images/fuzzed", false) { + let _ = read().no_deep_data().largest_resolution_level().all_channels() + .first_valid_layer().all_attributes().pedantic().from_file(file); + + let _ = read().no_deep_data().all_resolution_levels().all_channels() + .all_layers().all_attributes().pedantic().from_file(file); + } +} + +/// Require an error but no panic. +#[test] +pub fn damaged(){ + let mut passed = true; + + for ref file in exr_files("tests/images/invalid", false) { + let result = catch_unwind(move || { + let _meta_data = MetaData::read_from_file(file, false)?; + + { + let _minimal = read().no_deep_data() + .largest_resolution_level() + .rgba_channels( + |_size, _channels| (), + |_: &mut (), _position: Vec2<usize>, _pixel: (Sample, Sample, Sample, Sample)| {} + ) + .first_valid_layer().all_attributes() + .from_file(&file)?; + } + + { + let _minimal = read().no_deep_data() + .largest_resolution_level() // TODO all levels + .rgba_channels( + |_size, _channels| (), + |_: &mut (), _position: Vec2<usize>, _pixel: (Sample, Sample, Sample, Sample)| {} + ) + .all_layers().all_attributes() + .pedantic() + .from_file(&file)?; + } + + { + let _rgba = read_first_rgba_layer_from_file( + file, + PixelVec::<(Sample, Sample, Sample, Sample)>::constructor, + PixelVec::set_pixel + )?; + } + + { + let _full = read_all_data_from_file(file)?; + } + + Ok(()) + }); + + // this should not panic, only err: + passed = passed && match result { + Ok(Err(Error::Invalid(message))) => { + println!("✓ Recognized as invalid ({}): {:?}", message, file); + true + }, + + Ok(Err(Error::NotSupported(message))) => { + println!("- Unsupported ({}): {:?}", message, file); + true + }, + + Ok(Err(Error::Io(error))) => { + println!("✗ Unexpected IO Error: {:?}, {:?}", file, error); + false + }, + + Err(_) => { + println!("✗ Not recognized as invalid: {:?}", file); + false + }, + + Ok(Ok(_)) => { + let meta_data = MetaData::read_from_file(file, true); + + if let Err(error) = meta_data { + println!("✓ Recognized as invalid when pedantic ({}): {:?}", error, file); + true + } + else { + println!("✗ Oh no, there is nothing wrong with: {:#?}", file); + false + } + }, + + _ => unreachable!(), + }; + } + + assert!(passed, "A damaged file was not handled correctly"); +} + +#[test] +#[ignore] +pub fn fuzz(){ + println!("started fuzzing"); + let files: Vec<PathBuf> = exr_files("tests/images", true).collect(); + + let seed = [92,1,0,130,211,8,21,70,74,4,9,5,0,23,0,3,20,25,6,5,229,30,0,34,218,0,40,7,5,2,7,0,]; + let mut random: StdRng = rand::SeedableRng::from_seed(seed); + + let mut records = File::create("tests/images/fuzzed/list.txt").unwrap(); + records.write_all(format!("seed = {:?}", seed).as_bytes()).unwrap(); + + let start_index = 0; // default is 0. increase this integer for debugging a specific fuzz case + for fuzz_index in 0 .. 1024_u64 * 2048 * 4 { + + let file_1_name = &files[random.gen_range(0 .. files.len())]; + let mutation_point = random.gen::<f32>().powi(3); + let mutation = random.gen::<u8>(); + + if fuzz_index >= start_index { + let mut file = std::fs::read(file_1_name).unwrap(); + let index = ((mutation_point * file.len() as f32) as usize + 4) % file.len(); + file[index] = mutation; + + let file = file.as_slice(); + let result = catch_unwind(move || { + let read_all_data = read().no_deep_data() + .all_resolution_levels().all_channels().all_layers().all_attributes(); + + match read_all_data.from_buffered(Cursor::new(file)) { + Err(Error::Invalid(error)) => println!("✓ No Panic. [{}]: Invalid: {}.", fuzz_index, error), + Err(Error::NotSupported(error)) => println!("- No Panic. [{}]: Unsupported: {}.", fuzz_index, error), + _ => {}, + } + }); + + if let Err(_) = result { + records.write_all(fuzz_index.to_string().as_bytes()).unwrap(); + records.flush().unwrap(); + + let seed = seed.iter().map(|num| num.to_string()).collect::<Vec<String>>().join("-"); + let mut saved = File::create(format!("tests/images/fuzzed/fuzz_{}_{}.exr", fuzz_index, seed)).unwrap(); + saved.write_all(file).unwrap(); + + println!("✗ PANIC! [{}]", fuzz_index); + } + } + } +} |