summaryrefslogtreecommitdiff
path: root/src/test.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test.rs')
-rw-r--r--src/test.rs104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/test.rs b/src/test.rs
new file mode 100644
index 0000000..df9f7d0
--- /dev/null
+++ b/src/test.rs
@@ -0,0 +1,104 @@
+use crate::{decode_png, decode_png_header, ColorType, Error};
+use std::{fs, sync::Mutex};
+
+#[derive(Debug)]
+enum Flaw {
+ ErrorFromValidPNG,
+ NoErrorFromInvalidPNG,
+ DecodedMismatch,
+ ConvertedMismatch,
+}
+
+impl core::fmt::Display for Flaw {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ match self {
+ Self::ErrorFromValidPNG => write!(f, "decoding valid PNG gives error"),
+ Self::NoErrorFromInvalidPNG => write!(f, "decoding invalid PNG gives no error"),
+ Self::DecodedMismatch => write!(f, "image incorrectly decoded"),
+ Self::ConvertedMismatch => write!(f, "image incorrectly converted"),
+ }
+ }
+}
+
+const LARGE_BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
+fn test_bytes(bytes: &[u8]) -> Result<(), Flaw> {
+ let decoder = png::Decoder::new(bytes);
+ let mut is_valid = true;
+ if let Ok(mut reader) = decoder.read_info() {
+ let mut png_buf = vec![0; reader.output_buffer_size()];
+ if let Ok(png_header) = reader.next_frame(&mut png_buf) {
+ let png_bytes = &png_buf[..png_header.buffer_size()];
+
+ let tiny_header = match decode_png_header(bytes) {
+ Ok(h) => h,
+ Err(Error::UnsupportedInterlace) => return Ok(()),
+ Err(_) => return Err(Flaw::ErrorFromValidPNG),
+ };
+ let mut tiny_buf = vec![0; tiny_header.required_bytes_rgba8bpc()];
+ let mut image =
+ decode_png(bytes, &mut tiny_buf).map_err(|_| Flaw::ErrorFromValidPNG)?;
+ let tiny_bytes = image.pixels();
+ if png_bytes != tiny_bytes {
+ return Err(Flaw::DecodedMismatch);
+ }
+ let (_, mut data) = png_decoder::decode(bytes).unwrap();
+ if matches!(image.color_type(), ColorType::Gray | ColorType::Rgb) {
+ // pretend there's no tRNS chunk.
+ // there shouldnt be one who the fucks stupid idea was that.
+ for i in 0..data.len() / 4 {
+ data[4 * i + 3] = 255;
+ }
+ }
+ image.convert_to_rgba8bpc().unwrap();
+ if data != image.pixels() {
+ return Err(Flaw::ConvertedMismatch);
+ }
+ } else {
+ is_valid = false;
+ }
+ } else {
+ is_valid = false;
+ }
+
+ if !is_valid && decode_png(bytes, &mut LARGE_BUF.lock().unwrap()).is_ok() {
+ return Err(Flaw::NoErrorFromInvalidPNG);
+ }
+ Ok(())
+}
+
+fn test_images_in_dir(dir: &str) {
+ for entry in fs::read_dir(dir).unwrap() {
+ let entry = entry.unwrap();
+ let r#type = entry.file_type().unwrap();
+ let path = entry.path().to_str().unwrap().to_string();
+ if r#type.is_file() {
+ if let Err(flaw) = test_bytes(&std::fs::read(&path).unwrap()) {
+ panic!("flaw for file {path}: {flaw}");
+ }
+ } else if r#type.is_dir() {
+ test_images_in_dir(&path);
+ }
+ println!("{path} ... \x1b[32mok\x1b[0m");
+ }
+}
+
+#[test]
+fn test_images() {
+ *LARGE_BUF.lock().unwrap() = vec![0; 10 << 20];
+
+ test_images_in_dir("test");
+}
+
+#[test]
+fn test_bad_png() {
+ let mut data = &b"hello"[..];
+ let err = decode_png_header(&mut data).unwrap_err();
+ assert!(matches!(err, Error::NotPng));
+}
+#[test]
+fn test_buffer_too_small() {
+ let png = &include_bytes!("../test/ouroboros.png")[..];
+ let mut buffer = [0; 128];
+ let err = decode_png(png, &mut buffer[..]).unwrap_err();
+ assert!(matches!(err, Error::BufferTooSmall));
+}