summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDaniel Petri Rocha <daniel.petri@tum.de>2021-11-22 22:11:07 +0100
committerDaniel Petri Rocha <daniel.petri@tum.de>2021-11-22 22:46:16 +0100
commit338f88a4683bcb312d0e03d9732a7419602b6417 (patch)
tree15db127dbe30c6edb195bb109503517d976db366 /tests
parente5a4e80bb3677a69bf0f2405bac6ba62b513d1c3 (diff)
downloadlibrsvg-338f88a4683bcb312d0e03d9732a7419602b6417.tar.gz
SvgPredicate with libxml parser
Diffstat (limited to 'tests')
-rw-r--r--tests/src/cmdline/rsvg_convert.rs68
-rw-r--r--tests/src/predicates/file.rs8
-rw-r--r--tests/src/predicates/mod.rs1
-rw-r--r--tests/src/predicates/svg.rs198
4 files changed, 270 insertions, 5 deletions
diff --git a/tests/src/cmdline/rsvg_convert.rs b/tests/src/cmdline/rsvg_convert.rs
index 78c7c625..a1ad58cc 100644
--- a/tests/src/cmdline/rsvg_convert.rs
+++ b/tests/src/cmdline/rsvg_convert.rs
@@ -16,6 +16,7 @@ use predicates::str::*;
use std::path::Path;
use tempfile::Builder;
use url::Url;
+use librsvg::{Length, LengthUnit};
// What should be tested here?
// The goal is to test the code in rsvg-convert, not the entire library.
@@ -152,7 +153,72 @@ fn output_format_svg_short_option() {
.arg("svg")
.assert()
.success()
- .stdout(file::is_svg());
+ .stdout(file::is_svg().with_svg_format());
+}
+
+#[cfg(system_deps_have_cairo_svg)]
+#[test]
+fn user_specified_width_and_height() {
+ RsvgConvert::new_with_input("tests/fixtures/dimensions/521-with-viewbox.svg")
+ .arg("--format")
+ .arg("svg")
+ .arg("--width")
+ .arg("42cm")
+ .arg("--height")
+ .arg("43cm")
+ .assert()
+ .success()
+ .stdout(file::is_svg().with_size(
+ Length::new(42.0, LengthUnit::Cm),
+ Length::new(43.0, LengthUnit::Cm)
+ )
+ );
+}
+
+#[cfg(system_deps_have_cairo_svg)]
+#[test]
+fn user_specified_width_and_height_px_output() {
+ RsvgConvert::new_with_input("tests/fixtures/dimensions/521-with-viewbox.svg")
+ .arg("--format")
+ .arg("svg")
+ .arg("--width")
+ .arg("1920")
+ .arg("--height")
+ .arg("508mm")
+ .assert()
+ .success()
+ .stdout(file::is_svg().with_size(
+ Length::new(1920.0, LengthUnit::Px),
+ Length::new(1920.0, LengthUnit::Px)
+ )
+ );
+}
+
+#[cfg(system_deps_have_cairo_svg)]
+#[test]
+fn user_specified_width_and_height_a4() {
+ RsvgConvert::new_with_input("tests/fixtures/dimensions/521-with-viewbox.svg")
+ .arg("--format")
+ .arg("svg")
+ .arg("--page-width")
+ .arg("210mm")
+ .arg("--page-height")
+ .arg("297mm")
+ .arg("--left")
+ .arg("1cm")
+ .arg("--top")
+ .arg("1cm")
+ .arg("--width")
+ .arg("190mm")
+ .arg("--height")
+ .arg("277mm")
+ .assert()
+ .success()
+ .stdout(file::is_svg().with_size(
+ Length::new(210.0, LengthUnit::Mm),
+ Length::new(297.0, LengthUnit::Mm)
+ )
+ );
}
#[test]
diff --git a/tests/src/predicates/file.rs b/tests/src/predicates/file.rs
index 1a026ce1..244835e0 100644
--- a/tests/src/predicates/file.rs
+++ b/tests/src/predicates/file.rs
@@ -1,9 +1,9 @@
-use predicates::boolean::AndPredicate;
use predicates::prelude::*;
-use predicates::str::{ContainsPredicate, StartsWithPredicate};
+use predicates::str::{StartsWithPredicate};
use crate::predicates::pdf::PdfPredicate;
use crate::predicates::png::PngPredicate;
+use crate::predicates::svg::SvgPredicate;
/// Predicates to check that some output ([u8]) is of a certain file type
@@ -23,6 +23,6 @@ pub fn is_pdf() -> PdfPredicate {
PdfPredicate {}
}
-pub fn is_svg() -> AndPredicate<StartsWithPredicate, ContainsPredicate, str> {
- predicate::str::starts_with("<?xml ").and(predicate::str::contains("<svg "))
+pub fn is_svg() -> SvgPredicate {
+ SvgPredicate {}
}
diff --git a/tests/src/predicates/mod.rs b/tests/src/predicates/mod.rs
index 04e8daa5..81716b29 100644
--- a/tests/src/predicates/mod.rs
+++ b/tests/src/predicates/mod.rs
@@ -3,6 +3,7 @@ extern crate predicates;
pub mod file;
mod pdf;
mod png;
+mod svg;
use predicates::str;
diff --git a/tests/src/predicates/svg.rs b/tests/src/predicates/svg.rs
new file mode 100644
index 00000000..f9409126
--- /dev/null
+++ b/tests/src/predicates/svg.rs
@@ -0,0 +1,198 @@
+use librsvg::Length;
+use predicates::boolean::AndPredicate;
+use predicates::prelude::*;
+use predicates::reflection::{Case, Child, PredicateReflection, Product};
+use predicates::str::StartsWithPredicate;
+use predicates::str::*;
+use std::cmp;
+use std::fmt;
+use std::str;
+
+use libxml::parser::Parser;
+use libxml::xpath::Context;
+
+use librsvg::doctest_only::Both;
+use librsvg::rsvg_convert_only::ULength;
+use librsvg::Parse;
+
+/// Checks that the variable of type [u8] can be parsed as a SVG file.
+#[derive(Debug)]
+pub struct SvgPredicate {}
+
+impl SvgPredicate {
+ pub fn with_size(self: Self, width: Length, height: Length) -> DetailPredicate<Self> {
+ DetailPredicate::<Self> {
+ p: self,
+ d: Detail::Size(Dimensions {
+ w: width,
+ h: height,
+ }),
+ }
+ }
+
+ pub fn with_svg_format(
+ self: Self,
+ ) -> AndPredicate<StartsWithPredicate, ContainsPredicate, str> {
+ predicate::str::starts_with("<?xml ").and(predicate::str::contains("<svg "))
+ }
+}
+
+impl Predicate<[u8]> for SvgPredicate {
+ fn eval(&self, data: &[u8]) -> bool {
+ str::from_utf8(data).is_ok()
+ }
+
+ fn find_case<'a>(&'a self, _expected: bool, data: &[u8]) -> Option<Case<'a>> {
+ match str::from_utf8(data) {
+ Ok(_) => None,
+ Err(e) => Some(Case::new(Some(self), false).add_product(Product::new("Error", e))),
+ }
+ }
+}
+
+impl PredicateReflection for SvgPredicate {}
+
+impl fmt::Display for SvgPredicate {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "is an SVG")
+ }
+}
+
+/// Extends a SVG Predicate by a check for its size
+#[derive(Debug)]
+pub struct DetailPredicate<SvgPredicate> {
+ p: SvgPredicate,
+ d: Detail,
+}
+
+#[derive(Debug)]
+enum Detail {
+ Size(Dimensions),
+}
+
+/// SVG's dimensions
+#[derive(Debug)]
+struct Dimensions {
+ w: Length,
+ h: Length,
+}
+
+impl Dimensions {
+ pub fn width(self: &Self) -> f64 {
+ self.w.length
+ }
+
+ pub fn height(self: &Self) -> f64 {
+ self.h.length
+ }
+}
+
+impl fmt::Display for Dimensions {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{}{} x {}{}",
+ self.width(),
+ self.w.unit,
+ self.height(),
+ self.h.unit
+ )
+ }
+}
+
+impl cmp::PartialEq for Dimensions {
+ fn eq(&self, other: &Self) -> bool {
+ approx_eq!(f64, self.width(), other.width(), epsilon = 0.000_001)
+ && approx_eq!(f64, self.height(), other.height(), epsilon = 0.000_001)
+ && (self.w.unit == self.h.unit)
+ && (self.h.unit == other.h.unit)
+ && (other.h.unit == other.w.unit)
+ }
+}
+
+impl cmp::Eq for Dimensions {}
+
+trait Details {
+ fn get_size(&self) -> Option<Dimensions>;
+}
+
+impl DetailPredicate<SvgPredicate> {
+ fn eval_doc(&self, doc: &str) -> bool {
+ match &self.d {
+ Detail::Size(d) => doc.get_size() == Some(Dimensions { w: d.w, h: d.h }),
+ }
+ }
+
+ fn find_case_for_doc<'a>(&'a self, expected: bool, doc: &str) -> Option<Case<'a>> {
+ if self.eval_doc(doc) == expected {
+ let product = self.product_for_doc(doc);
+ Some(Case::new(Some(self), false).add_product(product))
+ } else {
+ None
+ }
+ }
+
+ fn product_for_doc(&self, doc: &str) -> Product {
+ match &self.d {
+ Detail::Size(_) => Product::new(
+ "actual size",
+ match doc.get_size() {
+ Some(dim) => format!("{}", dim),
+ None => "None".to_string(),
+ },
+ ),
+ }
+ }
+}
+
+impl Details for &str {
+ fn get_size(self: &Self) -> Option<Dimensions> {
+ let parser = Parser::default();
+ let doc = parser.parse_string(self).unwrap();
+ let context = Context::new(&doc).unwrap();
+
+ let width = context.evaluate("//@width").unwrap().get_nodes_as_vec()[0].get_content();
+ let height = context.evaluate("//@height").unwrap().get_nodes_as_vec()[0].get_content();
+
+ let parsed_w = ULength::<Both>::parse_str(&width).unwrap();
+ let parsed_h = ULength::<Both>::parse_str(&height).unwrap();
+
+ let dim = Dimensions {
+ w: Length::new(parsed_w.length, parsed_w.unit),
+ h: Length::new(parsed_h.length, parsed_h.unit),
+ };
+
+ return Some(dim);
+ }
+}
+
+impl Predicate<[u8]> for DetailPredicate<SvgPredicate> {
+ fn eval(&self, data: &[u8]) -> bool {
+ match str::from_utf8(data) {
+ Ok(doc) => self.eval_doc(&doc),
+ _ => false,
+ }
+ }
+
+ fn find_case<'a>(&'a self, expected: bool, data: &[u8]) -> Option<Case<'a>> {
+ match str::from_utf8(data) {
+ Ok(doc) => self.find_case_for_doc(expected, &doc),
+ Err(e) => Some(Case::new(Some(self), false).add_product(Product::new("Error", e))),
+ }
+ }
+}
+
+impl PredicateReflection for DetailPredicate<SvgPredicate> {
+ 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 DetailPredicate<SvgPredicate> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match &self.d {
+ Detail::Size(d) => write!(f, "is an SVG sized {}", d),
+ }
+ }
+}