[librsvg: 8/15] tests: Add tests for other output formats of rsvg-convert
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 8/15] tests: Add tests for other output formats of rsvg-convert
- Date: Thu, 13 Feb 2020 01:12:42 +0000 (UTC)
commit f07b3c935c1a19f8bca2893669f0217662a60a01
Author: Sven Neumann <sven svenfoo org>
Date: Mon Feb 10 08:23:33 2020 +0100
tests: Add tests for other output formats of rsvg-convert
tests/Makefile.am | 4 +-
tests/src/cmdline/mod.rs | 2 +-
tests/src/cmdline/png_predicate.rs | 69 ---------------
tests/src/cmdline/predicates.rs | 171 +++++++++++++++++++++++++++++++++++++
tests/src/cmdline/rsvg_convert.rs | 131 ++++++++++++++++++----------
5 files changed, 259 insertions(+), 118 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5167de3e..ccb79d10 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,8 +4,8 @@ test_sources = \
Cargo.toml \
src/main.rs \
src/cmdline/mod.rs \
- src/cmdline/rsvg_convert.rs \
- src/cmdline/png_predicate.rs
+ src/cmdline/predicates.rs \
+ src/cmdline/rsvg_convert.rs
EXTRA_DIST += \
$(test_sources) \
diff --git a/tests/src/cmdline/mod.rs b/tests/src/cmdline/mod.rs
index 1647c326..a6d65a08 100644
--- a/tests/src/cmdline/mod.rs
+++ b/tests/src/cmdline/mod.rs
@@ -1,2 +1,2 @@
-mod png_predicate;
+mod predicates;
mod rsvg_convert;
diff --git a/tests/src/cmdline/predicates.rs b/tests/src/cmdline/predicates.rs
new file mode 100644
index 00000000..5a685e23
--- /dev/null
+++ b/tests/src/cmdline/predicates.rs
@@ -0,0 +1,171 @@
+extern crate png;
+extern crate predicates;
+
+pub mod file {
+
+ use predicates::boolean::AndPredicate;
+ use predicates::prelude::*;
+ use predicates::reflection::{Case, Child, PredicateReflection, Product};
+ use predicates::str::{ContainsPredicate, StartsWithPredicate};
+
+ use std::fmt;
+
+ /// Checks that the variable of type [u8] looks like a PDF file.
+ /// Actually it only looks at the very first bytes.
+ #[derive(Debug)]
+ pub struct PdfPredicate {}
+
+ impl PdfPredicate {
+ fn not_a_pdf<'a>(&'a self, reason: &'static str) -> Option<Case<'a>> {
+ Some(Case::new(Some(self), false).add_product(Product::new("not a PDF", reason)))
+ }
+ }
+
+ impl Predicate<[u8]> for PdfPredicate {
+ fn eval(&self, data: &[u8]) -> bool {
+ match data.get(0..5) {
+ Some(head) => head == b"%PDF-",
+ None => false,
+ }
+ }
+
+ fn find_case<'a>(&'a self, _expected: bool, data: &[u8]) -> Option<Case<'a>> {
+ match data.get(0..5) {
+ Some(head) => {
+ if head == b"%PDF-" {
+ None
+ } else {
+ self.not_a_pdf("header mismatch")
+ }
+ }
+ None => self.not_a_pdf("too short"),
+ }
+ }
+ }
+
+ impl PredicateReflection for PdfPredicate {}
+
+ impl fmt::Display for PdfPredicate {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "has PDF header")
+ }
+ }
+
+ /// Checks that the variable of type [u8] can be parsed as a PNG file.
+ #[derive(Debug)]
+ pub struct PngPredicate {}
+
+ impl PngPredicate {
+ pub fn with_size(self: Self, w: u32, h: u32) -> SizePredicate<Self> {
+ SizePredicate::<Self> { p: self, w, h }
+ }
+ }
+
+ impl Predicate<[u8]> for PngPredicate {
+ fn eval(&self, data: &[u8]) -> bool {
+ let decoder = png::Decoder::new(data);
+ decoder.read_info().is_ok()
+ }
+
+ fn find_case<'a>(&'a self, _expected: bool, data: &[u8]) -> Option<Case<'a>> {
+ let decoder = png::Decoder::new(data);
+ match decoder.read_info() {
+ Ok(_) => None,
+ Err(e) => Some(Case::new(Some(self), false).add_product(Product::new("Error", e))),
+ }
+ }
+ }
+
+ impl PredicateReflection for PngPredicate {}
+
+ impl fmt::Display for PngPredicate {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "is a PNG")
+ }
+ }
+
+ /// Extends a PngPredicate by a check for a given size of the PNG file.
+ #[derive(Debug)]
+ pub struct SizePredicate<PngPredicate> {
+ p: PngPredicate,
+ w: u32,
+ h: u32,
+ }
+
+ impl SizePredicate<PngPredicate> {
+ fn eval_info(&self, info: &png::OutputInfo) -> bool {
+ info.width == self.w && info.height == self.h
+ }
+
+ fn find_case_for_info<'a>(
+ &'a self,
+ expected: bool,
+ info: &png::OutputInfo,
+ ) -> Option<Case<'a>> {
+ if self.eval_info(info) == expected {
+ let product = self.product_for_info(info);
+ 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)
+ }
+ }
+
+ impl Predicate<[u8]> for SizePredicate<PngPredicate> {
+ fn eval(&self, data: &[u8]) -> bool {
+ let decoder = png::Decoder::new(data);
+ match decoder.read_info() {
+ Ok((info, _)) => self.eval_info(&info),
+ _ => 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),
+ Err(e) => Some(Case::new(Some(self), false).add_product(Product::new("Error", e))),
+ }
+ }
+ }
+
+ impl PredicateReflection for SizePredicate<PngPredicate> {
+ fn children<'a>(&'a self) -> Box<dyn Iterator<Item = Child<'a>> + 'a> {
+ let params = vec![Child::new("predicate", &self.p)];
+ Box::new(params.into_iter())
+ }
+ }
+
+ impl fmt::Display for SizePredicate<PngPredicate> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "is a PNG with size {} x {}", self.w, self.h)
+ }
+ }
+
+ /// Predicates to check that some output ([u8]) is of a certain file type
+
+ pub fn is_png() -> PngPredicate {
+ PngPredicate {}
+ }
+
+ pub fn is_ps() -> StartsWithPredicate {
+ predicate::str::starts_with("%!PS-Adobe-3.0\n")
+ }
+
+ pub fn is_eps() -> StartsWithPredicate {
+ predicate::str::starts_with("%!PS-Adobe-3.0 EPSF-3.0\n")
+ }
+
+ pub fn is_pdf() -> PdfPredicate {
+ PdfPredicate {}
+ }
+
+ pub fn is_svg() -> AndPredicate<StartsWithPredicate, ContainsPredicate, str> {
+ predicate::str::starts_with("<?xml ").and(predicate::str::contains("<svg "))
+ }
+}
diff --git a/tests/src/cmdline/rsvg_convert.rs b/tests/src/cmdline/rsvg_convert.rs
index 87fc2a8a..1566accf 100644
--- a/tests/src/cmdline/rsvg_convert.rs
+++ b/tests/src/cmdline/rsvg_convert.rs
@@ -1,7 +1,7 @@
extern crate assert_cmd;
extern crate predicates;
-use crate::cmdline::png_predicate;
+use crate::cmdline::predicates::file;
use assert_cmd::Command;
use predicates::prelude::*;
@@ -11,17 +11,17 @@ use std::path::Path;
// The goal is to test the code in rsvg-convert, not the entire library.
//
// - all command-line options are accepted
-// - size of the output (should be sufficient to do that for PNG)
-// - command-line options that affect size (width, height, zoom, resolution)
-// - limit on output size (32767 pixels)
-// - output formats (PNG, PDF, PS, EPS, SVG), okay to ignore XML and recording
-// - multi-page output (for PDF)
+// - size of the output (should be sufficient to do that for PNG) ✔
+// - command-line options that affect size (width, height, zoom, resolution) ✔
+// - limit on output size (32767 pixels) ✔
+// - output formats (PNG, PDF, PS, EPS, SVG), okay to ignore XML and recording ✔
+// - multi-page output (for PDF) ✔
// - handling of SOURCE_DATA_EPOCH environment variable for PDF output
// - handling of background color option
// - support for optional CSS stylesheet
-// - error handling for missing SVG dimensions
+// - error handling for missing SVG dimensions ✔
// - error handling for export lookup ID
-// - error handling for invalid input
+// - error handling for invalid input ✔
struct RsvgConvert {}
@@ -55,7 +55,7 @@ fn converts_svg_from_stdin_to_png() {
RsvgConvert::new_with_input(input)
.assert()
.success()
- .stdout(png_predicate::has_size(200, 100));
+ .stdout(file::is_png());
}
#[test]
@@ -65,18 +65,7 @@ fn argument_is_input_filename() {
.arg(input)
.assert()
.success()
- .stdout(png_predicate::has_size(200, 100));
-}
-
-#[test]
-fn multiple_input_files_not_allowed_for_png_output() {
- let input = Path::new("fixtures/dimensions/521-with-viewbox.svg");
- RsvgConvert::new()
- .arg(input)
- .arg("foo.svg")
- .assert()
- .failure()
- .stderr("Multiple SVG files are only allowed for PDF and (E)PS output.\n");
+ .stdout(file::is_png());
}
#[test]
@@ -86,7 +75,7 @@ fn output_format_png() {
.arg("--format=png")
.assert()
.success()
- .stdout(png_predicate::has_size(200, 100));
+ .stdout(file::is_png());
}
#[test]
@@ -96,7 +85,7 @@ fn output_format_ps() {
.arg("--format=ps")
.assert()
.success()
- .stdout(predicate::str::starts_with("%!PS-Adobe-3.0\n"));
+ .stdout(file::is_ps());
}
#[test]
@@ -106,7 +95,7 @@ fn output_format_eps() {
.arg("--format=eps")
.assert()
.success()
- .stdout(predicate::str::starts_with("%!PS-Adobe-3.0 EPSF-3.0\n"));
+ .stdout(file::is_eps());
}
#[test]
@@ -115,20 +104,19 @@ fn output_format_pdf() {
RsvgConvert::new_with_input(input)
.arg("--format=pdf")
.assert()
- .success();
- // TODO: add a check for PDF output
+ .success()
+ .stdout(file::is_pdf());
}
#[test]
fn output_format_svg_short_option() {
let input = Path::new("fixtures/dimensions/521-with-viewbox.svg");
- let svg_output = predicate::str::starts_with("<?xml ").and(predicate::str::contains("<svg "));
RsvgConvert::new_with_input(input)
.arg("-f")
.arg("svg")
.assert()
.success()
- .stdout(svg_output);
+ .stdout(file::is_svg());
}
#[test]
@@ -160,6 +148,57 @@ fn empty_svg_yields_error() {
.stderr("The SVG stdin has no dimensions\n");
}
+#[test]
+fn multiple_input_files_not_allowed_for_png_output() {
+ let one = Path::new("fixtures/dimensions/521-with-viewbox.svg");
+ let two = Path::new("fixtures/dimensions/sub-rect-no-unit.svg");
+ RsvgConvert::new()
+ .arg(one)
+ .arg(two)
+ .assert()
+ .failure()
+ .stderr("Multiple SVG files are only allowed for PDF and (E)PS output.\n");
+}
+
+#[test]
+fn multiple_input_files_accepted_for_eps_output() {
+ let one = Path::new("fixtures/dimensions/521-with-viewbox.svg");
+ let two = Path::new("fixtures/dimensions/sub-rect-no-unit.svg");
+ RsvgConvert::new()
+ .arg("--format=eps")
+ .arg(one)
+ .arg(two)
+ .assert()
+ .success()
+ .stdout(file::is_eps());
+}
+
+#[test]
+fn multiple_input_files_accepted_for_pdf_output() {
+ let one = Path::new("fixtures/dimensions/521-with-viewbox.svg");
+ let two = Path::new("fixtures/dimensions/sub-rect-no-unit.svg");
+ RsvgConvert::new()
+ .arg("--format=pdf")
+ .arg(one)
+ .arg(two)
+ .assert()
+ .success()
+ .stdout(file::is_pdf());
+}
+
+#[test]
+fn multiple_input_files_accepted_for_ps_output() {
+ let one = Path::new("fixtures/dimensions/521-with-viewbox.svg");
+ let two = Path::new("fixtures/dimensions/sub-rect-no-unit.svg");
+ RsvgConvert::new()
+ .arg("--format=ps")
+ .arg(one)
+ .arg(two)
+ .assert()
+ .success()
+ .stdout(file::is_ps());
+}
+
#[test]
fn width_option() {
let input = Path::new("fixtures/dimensions/521-with-viewbox.svg");
@@ -167,7 +206,7 @@ fn width_option() {
.arg("--width=300")
.assert()
.success()
- .stdout(png_predicate::has_size(300, 150));
+ .stdout(file::is_png().with_size(300, 150));
}
#[test]
@@ -177,7 +216,7 @@ fn height_option() {
.arg("--height=200")
.assert()
.success()
- .stdout(png_predicate::has_size(400, 200));
+ .stdout(file::is_png().with_size(400, 200));
}
#[test]
@@ -188,7 +227,7 @@ fn width_and_height_options() {
.arg("--height=200")
.assert()
.success()
- .stdout(png_predicate::has_size(300, 200));
+ .stdout(file::is_png().with_size(300, 200));
}
#[test]
@@ -198,7 +237,7 @@ fn zoom_factor() {
.arg("--zoom=0.8")
.assert()
.success()
- .stdout(png_predicate::has_size(160, 80));
+ .stdout(file::is_png().with_size(160, 80));
}
// TODO: Is this a bug in rsvg-convert or the desired behavior ?
@@ -222,7 +261,7 @@ fn zoom_factor_and_larger_size() {
.arg("--zoom=1.5")
.assert()
.success()
- .stdout(png_predicate::has_size(300, 150));
+ .stdout(file::is_png().with_size(300, 150));
}
#[test]
@@ -234,7 +273,7 @@ fn zoom_factor_and_smaller_size() {
.arg("--zoom=3.5")
.assert()
.success()
- .stdout(png_predicate::has_size(400, 200));
+ .stdout(file::is_png().with_size(400, 200));
}
#[test]
@@ -244,7 +283,7 @@ fn x_zoom_option() {
.arg("--x-zoom=2")
.assert()
.success()
- .stdout(png_predicate::has_size(400, 100));
+ .stdout(file::is_png().with_size(400, 100));
}
#[test]
@@ -255,7 +294,7 @@ fn x_short_option() {
.arg("2.0")
.assert()
.success()
- .stdout(png_predicate::has_size(400, 100));
+ .stdout(file::is_png().with_size(400, 100));
}
#[test]
@@ -265,7 +304,7 @@ fn y_zoom_option() {
.arg("--y-zoom=2.0")
.assert()
.success()
- .stdout(png_predicate::has_size(200, 200));
+ .stdout(file::is_png().with_size(200, 200));
}
#[test]
@@ -276,7 +315,7 @@ fn y_short_option() {
.arg("2")
.assert()
.success()
- .stdout(png_predicate::has_size(200, 200));
+ .stdout(file::is_png().with_size(200, 200));
}
#[test]
@@ -298,7 +337,7 @@ fn default_resolution_is_90dpi() {
RsvgConvert::new_with_input(input)
.assert()
.success()
- .stdout(png_predicate::has_size(262, 184));
+ .stdout(file::is_png().with_size(262, 184));
}
#[test]
@@ -308,7 +347,7 @@ fn x_resolution() {
.arg("--dpi-x=300")
.assert()
.success()
- .stdout(png_predicate::has_size(874, 184));
+ .stdout(file::is_png().with_size(874, 184));
}
#[test]
@@ -319,7 +358,7 @@ fn x_resolution_short_option() {
.arg("45")
.assert()
.success()
- .stdout(png_predicate::has_size(131, 184));
+ .stdout(file::is_png().with_size(131, 184));
}
#[test]
@@ -329,7 +368,7 @@ fn y_resolution() {
.arg("--dpi-y=300")
.assert()
.success()
- .stdout(png_predicate::has_size(262, 614));
+ .stdout(file::is_png().with_size(262, 614));
}
#[test]
@@ -340,7 +379,7 @@ fn y_resolution_short_option() {
.arg("45")
.assert()
.success()
- .stdout(png_predicate::has_size(262, 92));
+ .stdout(file::is_png().with_size(262, 92));
}
#[test]
@@ -351,7 +390,7 @@ fn x_and_y_resolution() {
.arg("--dpi-y=150")
.assert()
.success()
- .stdout(png_predicate::has_size(874, 307));
+ .stdout(file::is_png().with_size(874, 307));
}
#[test]
@@ -362,7 +401,7 @@ fn default_is_used_for_zero_resolution() {
.arg("--dpi-y=0")
.assert()
.success()
- .stdout(png_predicate::has_size(262, 184));
+ .stdout(file::is_png().with_size(262, 184));
}
#[test]
@@ -373,7 +412,7 @@ fn default_is_used_for_negative_resolution() {
.arg("--dpi-y=-100")
.assert()
.success()
- .stdout(png_predicate::has_size(262, 184));
+ .stdout(file::is_png().with_size(262, 184));
}
#[test]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]