[librsvg: 1/2] (#767): Add test for generating links in PDF output




commit 9eccd1c1b6e44d500a39b45889bb3964093e3b50
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Jul 14 21:30:45 2021 -0500

    (#767): Add test for generating links in PDF output
    
    This is really basic for now; the code just tests for the presence of
    an Annotation with the correct URL, but not for the annotation being
    really associated to a page.
    
    Fixes https://gitlab.gnome.org/GNOME/librsvg/-/issues/767
    
    Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/571>

 tests/fixtures/cmdline/a-link.svg |  6 +++++
 tests/src/cmdline/rsvg_convert.rs | 12 +++++++++
 tests/src/predicates/pdf.rs       | 52 ++++++++++++++++++++++++++++++++++++---
 3 files changed, 67 insertions(+), 3 deletions(-)
---
diff --git a/tests/fixtures/cmdline/a-link.svg b/tests/fixtures/cmdline/a-link.svg
new file mode 100644
index 00000000..1ae8ace5
--- /dev/null
+++ b/tests/fixtures/cmdline/a-link.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg";>
+  <a href="https://example.com";>
+    <rect x="100" y="100" width="200" height="200" fill="lime"/>
+  </a>
+</svg>
diff --git a/tests/src/cmdline/rsvg_convert.rs b/tests/src/cmdline/rsvg_convert.rs
index f23b3f02..7794bb37 100644
--- a/tests/src/cmdline/rsvg_convert.rs
+++ b/tests/src/cmdline/rsvg_convert.rs
@@ -289,6 +289,18 @@ fn multiple_input_files_create_multi_page_pdf_output() {
         .stdout(file::is_pdf().with_page_count(3));
 }
 
+#[cfg(system_deps_have_cairo_pdf)]
+#[test]
+fn pdf_has_link() {
+    let input = Path::new("tests/fixtures/cmdline/a-link.svg");
+    RsvgConvert::new()
+        .arg("--format=pdf")
+        .arg(input)
+        .assert()
+        .success()
+        .stdout(file::is_pdf().with_link("https://example.com";));
+}
+
 #[cfg(system_deps_have_cairo_pdf)]
 #[test]
 fn env_source_data_epoch_controls_pdf_creation_date() {
diff --git a/tests/src/predicates/pdf.rs b/tests/src/predicates/pdf.rs
index 5c51514b..14ba46f7 100644
--- a/tests/src/predicates/pdf.rs
+++ b/tests/src/predicates/pdf.rs
@@ -1,7 +1,5 @@
-extern crate chrono;
-extern crate lopdf;
-
 use chrono::{DateTime, Utc};
+use lopdf::{self, Dictionary, Object};
 use predicates::prelude::*;
 use predicates::reflection::{Case, Child, PredicateReflection, Product};
 use std::cmp;
@@ -40,6 +38,13 @@ impl PdfPredicate {
             d: Detail::CreationDate(when),
         }
     }
+
+    pub fn with_link(self: Self, link: &str) -> DetailPredicate<Self> {
+        DetailPredicate::<Self> {
+            p: self,
+            d: Detail::Link(link.to_string()),
+        }
+    }
 }
 
 impl Predicate<[u8]> for PdfPredicate {
@@ -75,6 +80,7 @@ enum Detail {
     PageCount(usize),
     PageSize(Dimensions),
     CreationDate(DateTime<Utc>),
+    Link(String),
 }
 
 /// A PDF page's dimensions from its `MediaBox`.
@@ -144,6 +150,7 @@ impl DetailPredicate<PdfPredicate> {
             Detail::PageCount(n) => doc.get_page_count() == *n,
             Detail::PageSize(d) => doc.get_page_size().map_or(false, |dim| dim == *d),
             Detail::CreationDate(d) => doc.get_creation_date().map_or(false, |date| date == *d),
+            Detail::Link(link) => document_has_link(doc, &link),
         }
     }
 
@@ -173,6 +180,10 @@ impl DetailPredicate<PdfPredicate> {
                 "actual creation date",
                 format!("{:?}", doc.get_creation_date()),
             ),
+            Detail::Link(_) => Product::new(
+                "actual link contents",
+                "FIXME: who knows, but it's not what we expected".to_string(),
+            ),
         }
     }
 }
@@ -261,6 +272,41 @@ impl fmt::Display for DetailPredicate<PdfPredicate> {
             Detail::PageCount(n) => write!(f, "is a PDF with {} page(s)", n),
             Detail::PageSize(d) => write!(f, "is a PDF sized {}", d),
             Detail::CreationDate(d) => write!(f, "is a PDF created {:?}", d),
+            Detail::Link(l) => write!(f, "is a PDF with a link to {}", l),
         }
     }
 }
+
+// We do a super simple test that a PDF actually contains an Annotation object
+// with a particular link.  We don't test that this annotation is actually linked
+// from a page; that would be nicer.
+fn document_has_link(document: &lopdf::Document, link_text: &str) -> bool {
+    document
+        .objects
+        .iter()
+        .map(|(_obj_id, object)| object)
+        .any(|obj| object_is_annotation_with_link(obj, link_text))
+}
+
+fn object_is_annotation_with_link(object: &Object, link_text: &str) -> bool {
+    object
+        .as_dict()
+        .map(|dict| dict_is_annotation(dict) && dict_has_a_with_link(dict, link_text))
+        .unwrap_or(false)
+}
+
+fn dict_is_annotation(dict: &Dictionary) -> bool {
+    dict.get(b"Type")
+        .and_then(|type_val| type_val.as_name_str())
+        .map(|name| name == "Annot")
+        .unwrap_or(false)
+}
+
+fn dict_has_a_with_link(dict: &Dictionary, link_text: &str) -> bool {
+    dict.get(b"A")
+        .and_then(|obj| obj.as_dict())
+        .and_then(|dict| dict.get(b"URI"))
+        .and_then(|obj| obj.as_str())
+        .map(|string| string == link_text.as_bytes())
+        .unwrap_or(false)
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]