[librsvg/refactor-test-utils: 2/3] Implement PngPredicate.with_contents() using tests::reference_utils
- From: Sven Neumann <sneumann src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/refactor-test-utils: 2/3] Implement PngPredicate.with_contents() using tests::reference_utils
- Date: Tue, 26 Jan 2021 13:47:29 +0000 (UTC)
commit f8b96bd3fc694e0a109356167f0b0f9c585950fb
Author: Sven Neumann <sven svenfoo org>
Date: Tue Jan 26 13:46:36 2021 +0100
Implement PngPredicate.with_contents() using tests::reference_utils
src/surface_utils/compare_surfaces.rs | 21 +++++++++++
tests/src/predicates/png.rs | 69 ++++++++++++++++++++++-------------
tests/src/reference_utils.rs | 35 +++++++++++-------
3 files changed, 86 insertions(+), 39 deletions(-)
---
diff --git a/src/surface_utils/compare_surfaces.rs b/src/surface_utils/compare_surfaces.rs
index 47be0661..13b702e4 100644
--- a/src/surface_utils/compare_surfaces.rs
+++ b/src/surface_utils/compare_surfaces.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
use super::{
iterators::Pixels,
shared_surface::{SharedImageSurface, SurfaceType},
@@ -17,6 +19,25 @@ pub struct Diff {
pub surface: SharedImageSurface,
}
+impl fmt::Display for BufferDiff {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ BufferDiff::DifferentSizes => write!(f, "different sizes"),
+ BufferDiff::Diff(diff) => diff.fmt(f),
+ }
+ }
+}
+
+impl fmt::Display for Diff {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{} pixels are different, with a maximum difference of {}",
+ self.num_pixels_changed, self.max_diff
+ )
+ }
+}
+
#[inline]
fn emphasize(p: &Pixel) -> Pixel {
let emphasize_component = |c| {
diff --git a/tests/src/predicates/png.rs b/tests/src/predicates/png.rs
index 3e9dd898..c4375d7e 100644
--- a/tests/src/predicates/png.rs
+++ b/tests/src/predicates/png.rs
@@ -3,8 +3,14 @@ extern crate png;
use predicates::prelude::*;
use predicates::reflection::{Case, Child, PredicateReflection, Product};
use std::fmt;
+use std::io::BufReader;
use std::path::{Path, PathBuf};
+use librsvg::surface_utils::compare_surfaces::BufferDiff;
+use librsvg::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
+
+use crate::reference_utils::{surface_from_png, Compare, Deviation, Reference};
+
/// Checks that the variable of type [u8] can be parsed as a PNG file.
#[derive(Debug)]
pub struct PngPredicate {}
@@ -15,12 +21,9 @@ impl PngPredicate {
}
pub fn with_contents<P: AsRef<Path>>(self: Self, reference: P) -> ReferencePredicate<Self> {
- let mut reference_path = PathBuf::new();
- reference_path.push(reference);
- ReferencePredicate::<Self> {
- p: self,
- reference_path,
- }
+ let mut path = PathBuf::new();
+ path.push(reference);
+ ReferencePredicate::<Self> { p: self, path }
}
}
@@ -114,47 +117,63 @@ impl fmt::Display for SizePredicate<PngPredicate> {
#[derive(Debug)]
pub struct ReferencePredicate<PngPredicate> {
p: PngPredicate,
- reference_path: PathBuf,
+ path: PathBuf,
}
impl ReferencePredicate<PngPredicate> {
- fn eval_info(&self, info: &png::OutputInfo) -> bool {
- // info.width == self.w && info.height == self.h
- false
+ fn diff_acceptable(diff: &BufferDiff) -> bool {
+ match diff {
+ BufferDiff::DifferentSizes => false,
+ BufferDiff::Diff(diff) => !diff.inacceptable(),
+ }
}
- fn find_case_for_info<'a>(
+ fn diff_surface(&self, surface: &SharedImageSurface) -> Option<BufferDiff> {
+ let reference = Reference::from_png(&self.path).unwrap();
+ if let Ok(diff) = reference.compare(&surface) {
+ if !Self::diff_acceptable(&diff) {
+ return Some(diff);
+ }
+ }
+ None
+ }
+
+ fn find_case_for_surface<'a>(
&'a self,
expected: bool,
- info: &png::OutputInfo,
+ surface: &SharedImageSurface,
) -> Option<Case<'a>> {
- if self.eval_info(info) == expected {
- let product = self.product_for_info(info);
+ let diff = self.diff_surface(&surface);
+ if diff.is_some() != expected {
+ let product = self.product_for_diff(&diff.unwrap());
Some(Case::new(Some(self), false).add_product(product))
} else {
None
}
}
- fn product_for_info(&self, info: &png::OutputInfo) -> Product {
- let actual_size = format!("{} x {}", info.width, info.height);
- Product::new("actual size", actual_size)
+ fn product_for_diff(&self, diff: &BufferDiff) -> Product {
+ let difference = format!("{}", diff);
+ Product::new("images differ", difference)
}
}
impl Predicate<[u8]> for ReferencePredicate<PngPredicate> {
fn eval(&self, data: &[u8]) -> bool {
- let decoder = png::Decoder::new(data);
- match decoder.read_info() {
- Ok((info, _)) => self.eval_info(&info),
- _ => false,
+ if let Ok(surface) = surface_from_png(&mut BufReader::new(data)) {
+ let surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();
+ self.diff_surface(&surface).is_some()
+ } else {
+ false
}
}
fn find_case<'a>(&'a self, expected: bool, data: &[u8]) -> Option<Case<'a>> {
- let decoder = png::Decoder::new(data);
- match decoder.read_info() {
- Ok((info, _)) => self.find_case_for_info(expected, &info),
+ match surface_from_png(&mut BufReader::new(data)) {
+ Ok(surface) => {
+ let surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();
+ self.find_case_for_surface(expected, &surface)
+ }
Err(e) => Some(Case::new(Some(self), false).add_product(Product::new("Error", e))),
}
}
@@ -172,7 +191,7 @@ impl fmt::Display for ReferencePredicate<PngPredicate> {
write!(
f,
"is a PNG that matches the reference {}",
- self.reference_path.display()
+ self.path.display()
)
}
}
diff --git a/tests/src/reference_utils.rs b/tests/src/reference_utils.rs
index f059186c..758eb353 100644
--- a/tests/src/reference_utils.rs
+++ b/tests/src/reference_utils.rs
@@ -6,7 +6,7 @@
use std::convert::TryFrom;
use std::env;
use std::fs::{self, File};
-use std::io::BufReader;
+use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use std::sync::Once;
@@ -19,17 +19,8 @@ impl Reference {
pub fn from_png<P: AsRef<Path>>(path: P) -> Result<Self, cairo::IoError> {
let file = File::open(path).map_err(|e| cairo::IoError::Io(e))?;
let mut reader = BufReader::new(file);
- let png = cairo::ImageSurface::create_from_png(&mut reader)?;
- let argb =
- cairo::ImageSurface::create(cairo::Format::ARgb32, png.get_width(), png.get_height())?;
- {
- // convert to ARGB; the PNG may come as Rgb24
- let cr = cairo::Context::new(&argb);
- cr.set_source_surface(&png, 0.0, 0.0);
- cr.paint();
- }
-
- Self::from_surface(argb)
+ let surface = surface_from_png(&mut reader)?;
+ Self::from_surface(surface)
}
pub fn from_surface(surface: cairo::ImageSurface) -> Result<Self, cairo::IoError> {
@@ -42,7 +33,7 @@ pub trait Compare {
fn compare(self, surface: &SharedImageSurface) -> Result<BufferDiff, cairo::IoError>;
}
-impl Compare for Reference {
+impl Compare for &Reference {
fn compare(self, surface: &SharedImageSurface) -> Result<BufferDiff, cairo::IoError> {
compare_surfaces(&self.0, surface).map_err(cairo::IoError::from)
}
@@ -153,7 +144,7 @@ fn tolerable_difference() -> u8 {
unsafe { TOLERANCE }
}
-trait Deviation {
+pub trait Deviation {
fn distinguishable(&self) -> bool;
fn inacceptable(&self) -> bool;
}
@@ -167,3 +158,19 @@ impl Deviation for Diff {
self.max_diff > tolerable_difference()
}
}
+
+/// Creates a cairo::ImageSurface from a stream of PNG data.
+///
+/// The surface is converted to ARGB if needed. Use this helper function with `Reference`.
+pub fn surface_from_png<R: Read>(stream: &mut R) -> Result<cairo::ImageSurface, cairo::IoError> {
+ let png = cairo::ImageSurface::create_from_png(stream)?;
+ let argb =
+ cairo::ImageSurface::create(cairo::Format::ARgb32, png.get_width(), png.get_height())?;
+ {
+ // convert to ARGB; the PNG may come as Rgb24
+ let cr = cairo::Context::new(&argb);
+ cr.set_source_surface(&png, 0.0, 0.0);
+ cr.paint();
+ }
+ Ok(argb)
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]