summaryrefslogtreecommitdiff
path: root/rsvg/tests/src/geometries.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rsvg/tests/src/geometries.rs')
-rw-r--r--rsvg/tests/src/geometries.rs135
1 files changed, 135 insertions, 0 deletions
diff --git a/rsvg/tests/src/geometries.rs b/rsvg/tests/src/geometries.rs
new file mode 100644
index 00000000..c62f1eeb
--- /dev/null
+++ b/rsvg/tests/src/geometries.rs
@@ -0,0 +1,135 @@
+//! Tests for the data files from https://github.com/horizon-eda/horizon/
+//!
+//! Horizon is an app Electronic Design Automation. It has SVG templates with specially
+//! named elements; the app extracts their geometries and renders GUI widgets instead of
+//! those elements. So, it is critical that the geometries get computed accurately.
+//!
+//! Horizon's build system pre-computes the geometries of the SVG templates' elements, and
+//! stores them in JSON files. You can see the SVGs and the .subs JSON files in the
+//! tests/fixtures/horizon in the librsvg source tree.
+//!
+//! This test file has machinery to load the SVG templates, and the JSON files with the
+//! expected geometries. The tests check that librsvg computes the same geometries every
+//! time.
+
+use anyhow::{Context, Result};
+use rsvg::{CairoRenderer, LengthUnit, Loader, Rect};
+use serde::Deserialize;
+use std::collections::BTreeMap;
+use std::fs;
+use std::path::Path;
+
+// Copy of cairo::Rectangle
+//
+// Somehow I can't make serde's "remote" work here, in combination with the BTreeMap below...
+#[derive(Copy, Clone, Deserialize, Debug, PartialEq)]
+struct Rectangle {
+ x: f64,
+ y: f64,
+ width: f64,
+ height: f64,
+}
+
+impl From<Rectangle> for Rect {
+ fn from(r: Rectangle) -> Rect {
+ Rect {
+ x0: r.x,
+ y0: r.y,
+ x1: r.x + r.width,
+ y1: r.y + r.height,
+ }
+ }
+}
+
+#[derive(Deserialize)]
+struct Geometries(BTreeMap<String, Rectangle>);
+
+fn read_geometries(path: &Path) -> Result<Geometries> {
+ let contents = fs::read_to_string(path).context(format!("could not read {:?}", path))?;
+ Ok(serde_json::from_str(&contents).context(format!("could not parse JSON from {:?}", path))?)
+}
+
+// We create a struct with the id and geometry so that
+// assert_eq!() in the tests will print out the element name for failures.
+#[derive(Debug, PartialEq)]
+struct Element {
+ id: String,
+ geom: Rect,
+}
+
+macro_rules! assert_rectangles_approx_eq {
+ ($id:expr, $expected:expr, $computed:expr) => {
+ if !$expected.approx_eq(&$computed) {
+ eprintln!(
+ "assertion failed: rectangles are not approximately equal for id={}",
+ $id
+ );
+ eprintln!(" expected: {:?}", $expected);
+ eprintln!(" computed: {:?}", $computed);
+ panic!();
+ }
+ };
+}
+
+fn test(svg_filename: &str) {
+ let mut geometries_filename = String::from(svg_filename);
+ geometries_filename.push_str(".subs");
+
+ let geometries =
+ read_geometries(Path::new(&geometries_filename)).expect("reading geometries JSON");
+
+ let handle = Loader::new()
+ .read_path(svg_filename)
+ .expect("reading geometries SVG");
+ let renderer = CairoRenderer::new(&handle);
+ let dimensions = renderer.intrinsic_dimensions();
+ let (svg_width, svg_height) = renderer
+ .intrinsic_size_in_pixels()
+ .expect("intrinsic size in pixels");
+
+ assert!(matches!(dimensions.width.unit, LengthUnit::Px));
+ assert!(matches!(dimensions.height.unit, LengthUnit::Px));
+ assert_eq!(dimensions.width.length, svg_width);
+ assert_eq!(dimensions.height.length, svg_height);
+
+ for (id, expected) in geometries.0.iter() {
+ println!("id: {}", id);
+ let expected = Element {
+ id: String::from(id),
+ geom: Rect::from(*expected),
+ };
+
+ let viewport = cairo::Rectangle::new(0.0, 0.0, svg_width, svg_height);
+
+ let (geometry, _) = renderer
+ .geometry_for_layer(Some(id), &viewport)
+ .expect(&format!("getting geometry for {}", id));
+
+ let computed = Element {
+ id: String::from(id),
+ geom: geometry.into(),
+ };
+
+ assert_rectangles_approx_eq!(id, expected.geom, computed.geom);
+ }
+}
+
+#[test]
+fn dual() {
+ test("tests/fixtures/geometries/dual.svg");
+}
+
+#[test]
+fn grid() {
+ test("tests/fixtures/geometries/grid.svg");
+}
+
+#[test]
+fn quad() {
+ test("tests/fixtures/geometries/quad.svg");
+}
+
+#[test]
+fn single() {
+ test("tests/fixtures/geometries/single.svg");
+}