]> gitweb.michael.orlitzky.com - libsvgtiny.git/commitdiff
test/css: add some visually-verified test cases for our new features
authorMichael Orlitzky <michael@orlitzky.com>
Thu, 16 Nov 2023 15:55:11 +0000 (10:55 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Mon, 20 Nov 2023 16:42:58 +0000 (11:42 -0500)
It's helpful to have some test cases for our CSS handling, but
unfortunately, it's not all that easy to write them. How should we
compare the actual output to the expected output?

For now we settle for a visual comparison. You can render the test
diagrams using the example program examples/svgtiny_display_x11, and
also open them in another SVG viewer. Do they look the same? Great.
The test cases should be simple enough that _subtle_ visual mismatches
are not possible.

Automating this is not an impossible problem: for example, we could
render the parsed diagram to a bitmap image using cairo and then
compare it to what we get using librsvg which is also cairo-based. But
that has downsides too (like the portability of librsvg) that we don't
want to address right now.

14 files changed:
test/css/README [new file with mode: 0644]
test/css/attributes.svg [new file with mode: 0644]
test/css/case-sensitive-elements.svg [new file with mode: 0644]
test/css/empty-pseudo-class.svg [new file with mode: 0644]
test/css/id-and-class.svg [new file with mode: 0644]
test/css/inherit.svg [new file with mode: 0644]
test/css/inline.svg [new file with mode: 0644]
test/css/lang.svg [new file with mode: 0644]
test/css/link-pseudo-class.svg [new file with mode: 0644]
test/css/node-name.svg [new file with mode: 0644]
test/css/nth-child.svg [new file with mode: 0644]
test/css/root.svg [new file with mode: 0644]
test/css/siblings-and-descendants.svg [new file with mode: 0644]
test/css/styles-at-end.svg [new file with mode: 0644]

diff --git a/test/css/README b/test/css/README
new file mode 100644 (file)
index 0000000..fd429d3
--- /dev/null
@@ -0,0 +1,11 @@
+The SVG files in this directory are used to verify that certain CSS
+constructs are processed properly. These "tests" are un-automated; you
+have to view each diagram with the example program svgtiny_display_x11
+to see if they are rendered correctly.
+
+What is "correctly?"
+
+Each test should be simple enough that the correct behavior is not to
+hard for someone familiar with CSS to deduce. Hints may be given in
+the comment at the top of the file. Or, maybe you just open the same
+file in firefox and look at them side-by-side.
diff --git a/test/css/attributes.svg b/test/css/attributes.svg
new file mode 100644 (file)
index 0000000..3e008e8
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the following select handlers via the corresponding CSS
+constructs,
+
+  node_has_attribute           : node[attr]
+  node_has_attribute_equal     : node[attr=value]
+  node_has_attribute_dashmatch : node[attr|=value]
+  node_has_attribute_includes  : node[attr~=value]
+  node_has_attribute_prefix    : node[attr^=value]
+  node_has_attribute_suffix    : node[attr$=value]
+  node_has_attribute_substring : node[attr*=value]
+
+The result should be an empty document with a 5px red border, because
+we're using each of the seven selectors above to make one of the seven
+rectangles transparent. The first rectangle however has a 5px red
+stroke that is not affected by the fill-opacity, so that stroke will
+remain visible.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    rect[stroke] {
+      fill-opacity: 0;
+    }
+    rect[fill="green"] {
+      fill-opacity: 0;
+    }
+    rect[fill|="black"] {
+      fill-opacity: 0;
+    }
+    rect[class~="yellow"] {
+      fill-opacity: 0;
+    }
+    rect[fill^="ora"] {
+      fill-opacity: 0;
+    }
+    rect[fill$="urple"] {
+      fill-opacity: 0;
+    }
+    rect[fill*="rquoi"] {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="red"
+       stroke="red"
+       stroke-width="5" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="green" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="black" />
+
+  <rect x="0"
+        y="0"
+       class="a yellow rectangle"
+        width="640"
+        height="480"
+       fill="yellow" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="orange" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="purple" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="turquoise" />
+</svg>
diff --git a/test/css/case-sensitive-elements.svg b/test/css/case-sensitive-elements.svg
new file mode 100644 (file)
index 0000000..f5c9986
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+The sole <RECT /> in this document should be ignored because element
+names are case-sensitive. This isn't really a CSS test, but it isn't
+tested anywhere else, and can obviously affect how the result looks.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <RECT x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="red"
+       style="this is completely ignored" />
+</svg>
diff --git a/test/css/empty-pseudo-class.svg b/test/css/empty-pseudo-class.svg
new file mode 100644 (file)
index 0000000..ebe3c28
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the node_is_empty select handler via the :empty pseudo-class.
+The result should be a blue document, because the second rect is
+not empty.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    :empty {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="red" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="blue">
+    <desc>I'm a rectangle.</desc>
+  </rect>
+</svg>
+
diff --git a/test/css/id-and-class.svg b/test/css/id-and-class.svg
new file mode 100644 (file)
index 0000000..be5a9d7
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the following select handlers via the corresponding CSS
+constructs,
+
+  node_has_id    : #id
+  node_has_class : .class
+
+The two rules for .rects and #rect2 should take effect with the latter
+having precedence; the rules for .Rects and #Rect2 should not because
+everything is case-sensitive.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    .rects {
+      fill-opacity: 0.25;
+    }
+    #rect2 {
+      fill-opacity: 0.75;
+    }
+    .Rects {
+      fill-opacity: 1;
+    }
+    #Rect2 {
+      fill-opacity: 1;
+    }
+  </style>
+
+  <rect class="rects"
+        x="5"
+        y="5"
+        width="390"
+        height="470"
+        fill="red" />
+
+  <rect id="rect2"
+        class="rects"
+        x="320"
+        y="0"
+        width="320"
+        height="480"
+        fill="blue" />
+
+</svg>
diff --git a/test/css/inherit.svg b/test/css/inherit.svg
new file mode 100644 (file)
index 0000000..8ab3c1f
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Make sure "inherit" works. The inline rect "inherit" should cause the
+second rect to inherit its fill-opacity from g3<-g2<-g1.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    rect {
+      fill-opacity: 0.8;
+    }
+    #g1 {
+      fill-opacity: 0.05;
+    }
+    #g2,g3 {
+      fill-opacity: inherit;
+    }
+  </style>
+
+  <rect x="5"
+        y="5"
+        width="390"
+        height="470"
+        fill="red" />
+
+  <g id="g1">
+    <g id="g2">
+      <g id="g3">
+        <rect x="320"
+              y="0"
+              width="320"
+              height="480"
+              fill="blue"
+             style="fill-opacity: inherit;" />
+      </g>
+    </g>
+  </g>
+
+</svg>
diff --git a/test/css/inline.svg b/test/css/inline.svg
new file mode 100644 (file)
index 0000000..7c84b62
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Inline styles override <style> elements. This is tested elsewhere, but
+here we do it explicitly.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    #rect2 {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <rect x="5"
+        y="5"
+        width="390"
+        height="470"
+        fill="red" />
+
+  <rect id="rect2"
+        x="320"
+        y="0"
+        width="320"
+        height="480"
+        fill="blue"
+        style="fill-opacity: 0.5;" />
+</svg>
diff --git a/test/css/lang.svg b/test/css/lang.svg
new file mode 100644 (file)
index 0000000..4ca92de
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the node_is_lang() select handler via the CSS :lang()
+pseudo-selector. The result should be a red square because
+because we select the blue lang="en" one and hide it.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    rect:lang(en) {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="red" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="blue"
+       lang="en" />
+
+</svg>
diff --git a/test/css/link-pseudo-class.svg b/test/css/link-pseudo-class.svg
new file mode 100644 (file)
index 0000000..d9b6edf
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the node_is_link select handler via the :link pseudo-class. The
+result should be a blue document, because we treat all "a" elements
+with an "href" as links, but only case-sensitively (the HREF is
+ignored).
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    :link {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <a href="#">
+    <rect x="0"
+          y="0"
+          width="640"
+          height="480"
+          fill="red" />
+  </a>
+
+  <a HREF="#">
+    <rect x="0"
+          y="0"
+          width="640"
+          height="480"
+          fill="blue" />
+  </a>
+</svg>
+
diff --git a/test/css/node-name.svg b/test/css/node-name.svg
new file mode 100644 (file)
index 0000000..5a3e282
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the node_has_name select handler; in particular the universal
+selector should work, and (unrelated) CSS should take precedence over
+inline attributes.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    * {
+      fill-opacity: 0.3;
+      stroke-opacity: 1;
+    }
+    rect {
+      stroke-opacity: 0.2;
+    }
+  </style>
+
+  <rect x="5"
+        y="5"
+        width="390"
+        height="470"
+        fill="red"
+        fill-opacity="1"
+        stroke="black"
+        stroke-width="10px"
+        stroke-opacity="1" />
+
+  <rect x="320"
+        y="0"
+        width="320"
+        height="480"
+        fill="blue"
+        fill-opacity="0" />
+
+</svg>
diff --git a/test/css/nth-child.svg b/test/css/nth-child.svg
new file mode 100644 (file)
index 0000000..137298e
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the node_is_root() select handler via the CSS :root
+pseudo-selector. The result should be an empty document,
+because the root SVG node is made fully transparent and
+its one child should inherit that.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="black" />
+
+  <style>
+    rect:first-child {
+      fill-opacity: 0;
+    }
+    rect:nth-child(3) {
+      fill-opacity: 0;
+    }
+    rect:nth-child(4) {
+      fill-opacity: 0;
+    }
+    rect:last-child {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="red" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="blue" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="green" />
+</svg>
diff --git a/test/css/root.svg b/test/css/root.svg
new file mode 100644 (file)
index 0000000..dd20d98
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the node_is_root() select handler via the CSS :root
+pseudo-selector. The result should be an empty document,
+because the root SVG node is made fully transparent and
+its one child should inherit that.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    :root {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+        fill="red" />
+</svg>
diff --git a/test/css/siblings-and-descendants.svg b/test/css/siblings-and-descendants.svg
new file mode 100644 (file)
index 0000000..272ddc4
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Test the following select handlers via the corresponding CSS
+constructs,
+
+  named_ancestor_node          : node descendant
+  named_parent_node            : node > child
+  named_sibling_node           : node + sibling
+  named_generic_sibling_node   : node ~ sibling
+
+The result should be an empty document, since we're using each of the
+four selectors above to make one of the four rectangles transparent.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <style>
+    g rect {
+      fill-opacity: 0;
+    }
+    g > rect {
+      fill-opacity: 0;
+    }
+    g + rect {
+      fill-opacity: 0;
+    }
+    g ~ rect {
+      fill-opacity: 0;
+    }
+  </style>
+
+  <g>
+    <a href="#">
+      <rect x="0"
+            y="0"
+            width="640"
+            height="480"
+            fill="red" />
+    </a>
+  </g>
+
+  <g>
+    <rect x="0"
+          y="0"
+          width="640"
+          height="480"
+         fill="green" />
+  </g>
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="black" />
+
+  <rect x="0"
+        y="0"
+        width="640"
+        height="480"
+       fill="yellow" />
+</svg>
diff --git a/test/css/styles-at-end.svg b/test/css/styles-at-end.svg
new file mode 100644 (file)
index 0000000..540bba0
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Putting the <style> element at the end of the <svg> also works.
+-->
+<svg width="640"
+     height="480"
+     viewBox="0 0 640 480"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg">
+
+  <rect x="5"
+        y="5"
+        width="390"
+        height="470"
+        fill="red" />
+
+  <rect id="rect2"
+        x="320"
+        y="0"
+        width="320"
+        height="480"
+        fill="blue" />
+
+  <style>
+    * {
+      fill-opacity: 0;
+    }
+  </style>
+</svg>