]> granicus.if.org Git - graphviz/commitdiff
tests: add new test_svg_analyzer test skeleton
authorMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Thu, 21 Jul 2022 11:16:41 +0000 (13:16 +0200)
committerMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Tue, 16 Aug 2022 10:21:45 +0000 (12:21 +0200)
Upcoming commits will add functionality to the SVG analyzer and extend
this test.

tests/CMakeLists.txt
tests/test_svg_analyzer.cpp [new file with mode: 0644]
tests/test_utilities.cpp [new file with mode: 0644]
tests/test_utilities.h [new file with mode: 0644]

index 2ac89859c532f3149f1933db9a9e611dc0f1d18c..0a1b956c7c291f073a04396f682d59ed17860fa5 100644 (file)
@@ -12,6 +12,7 @@ enable_testing()
 # separate test can be as small as possible
 add_library(test_common SHARED
             catch2_main.cpp
+            test_utilities.cpp
             svgpp_context.cpp
             svgpp_context.h
             svgpp_document_traverser.cpp
@@ -77,3 +78,4 @@ CREATE_TEST(neatopack)
 CREATE_TEST(simple)
 CREATE_TEST(subgraph_layout)
 CREATE_TEST(subgraphs)
+CREATE_TEST(svg_analyzer)
diff --git a/tests/test_svg_analyzer.cpp b/tests/test_svg_analyzer.cpp
new file mode 100644 (file)
index 0000000..33e5f72
--- /dev/null
@@ -0,0 +1,106 @@
+#include <catch2/catch.hpp>
+#include <fmt/format.h>
+
+#include "svg_analyzer.h"
+#include <cgraph++/AGraph.h>
+#include <gvc++/GVContext.h>
+#include <gvc++/GVLayout.h>
+#include <gvc++/GVRenderData.h>
+
+#include "test_utilities.h"
+
+TEST_CASE(
+    "SvgAnalyzer",
+    "The SvgAnalyzer parses an SVG produced by Graphviz to an internal data "
+    "structure and supports retrieval of information about that graph") {
+
+  const auto shape_char_ptr = GENERATE(from_range(all_node_shapes));
+  const std::string shape{shape_char_ptr};
+  INFO(fmt::format("Shape: {}", shape));
+
+  auto dot = fmt::format("digraph g1 {{node [shape={}]; a -> b}}", shape);
+
+  auto g = CGraph::AGraph{dot};
+
+  const auto demand_loading = false;
+  auto gvc = GVC::GVContext(lt_preloaded_symbols, demand_loading);
+
+  const auto layout = GVC::GVLayout(std::move(gvc), std::move(g), "dot");
+
+  const auto result = layout.render("svg");
+  const std::string original_svg{result.string_view()};
+  SVGAnalyzer svgAnalyzer{result.c_str()};
+
+  const std::size_t expected_num_graphs = 1;
+  const std::size_t expected_num_nodes = 2;
+  const std::size_t expected_num_edges = 1;
+
+  {
+    const std::size_t expected_num_svgs = expected_num_graphs;
+    const std::size_t expected_num_groups =
+        expected_num_graphs + expected_num_nodes + expected_num_edges;
+    const std::size_t expected_num_circles = 0;
+    const std::size_t expected_num_ellipses = [&]() {
+      if (shape == "doublecircle") {
+        return expected_num_nodes * 2;
+      } else if (contains_ellipse_shape(shape)) {
+        return expected_num_nodes;
+      } else {
+        return 0UL;
+      }
+    }();
+    const std::size_t expected_num_lines = 0;
+    const std::size_t expected_num_paths =
+        expected_num_edges + (shape == "cylinder" ? expected_num_nodes * 2 : 0);
+    const std::size_t expected_num_polygons =
+        expected_num_graphs + expected_num_edges + [&]() {
+          if (shape == "noverhang") {
+            return expected_num_nodes * 4;
+          } else if (shape == "tripleoctagon") {
+            return expected_num_nodes * 3;
+          } else if (shape == "doubleoctagon" || shape == "fivepoverhang" ||
+                     shape == "threepoverhang" || shape == "assembly") {
+            return expected_num_nodes * 2;
+          } else if (contains_polygon_shape(shape)) {
+            return expected_num_nodes;
+          } else {
+            return 0UL;
+          }
+        }();
+    const std::size_t expected_num_polylines = [&]() {
+      if (shape == "Mdiamond" || shape == "Msquare") {
+        return expected_num_nodes * 4;
+      } else if (shape == "box3d" || shape == "signature" ||
+                 shape == "insulator" || shape == "ribosite" ||
+                 shape == "rnastab") {
+        return expected_num_nodes * 3;
+      } else if (shape == "Mcircle" || shape == "note" ||
+                 shape == "component" || shape == "restrictionsite" ||
+                 shape == "noverhang" || shape == "assembly" ||
+                 shape == "proteasesite" || shape == "proteinstab") {
+        return expected_num_nodes * 2;
+      } else if (shape == "underline" || shape == "tab" ||
+                 shape == "promoter" || shape == "terminator" ||
+                 shape == "utr" || shape == "primersite" ||
+                 shape == "fivepoverhang" || shape == "threepoverhang") {
+        return expected_num_nodes;
+      } else {
+        return 0UL;
+      }
+    }();
+    const std::size_t expected_num_rects = 0;
+    const std::size_t expected_num_titles =
+        expected_num_graphs + expected_num_nodes + expected_num_edges;
+
+    CHECK(svgAnalyzer.num_svgs() == expected_num_svgs);
+    CHECK(svgAnalyzer.num_groups() == expected_num_groups);
+    CHECK(svgAnalyzer.num_circles() == expected_num_circles);
+    CHECK(svgAnalyzer.num_ellipses() == expected_num_ellipses);
+    CHECK(svgAnalyzer.num_lines() == expected_num_lines);
+    CHECK(svgAnalyzer.num_paths() == expected_num_paths);
+    CHECK(svgAnalyzer.num_polygons() == expected_num_polygons);
+    CHECK(svgAnalyzer.num_polylines() == expected_num_polylines);
+    CHECK(svgAnalyzer.num_rects() == expected_num_rects);
+    CHECK(svgAnalyzer.num_titles() == expected_num_titles);
+  }
+}
diff --git a/tests/test_utilities.cpp b/tests/test_utilities.cpp
new file mode 100644 (file)
index 0000000..a155f46
--- /dev/null
@@ -0,0 +1,155 @@
+#include <string_view>
+#include <unordered_set>
+
+#include "test_utilities.h"
+
+const std::unordered_set<std::string_view> node_shapes_consisting_of_ellipse = {
+    "ellipse",      //
+    "oval",         //
+    "circle",       //
+    "doublecircle", //
+    "point",        //
+};
+
+const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_ellipse_and_polyline = {
+        "Mcircle", //
+};
+
+const std::unordered_set<std::string_view> node_shapes_consisting_of_path = {
+    "cylinder", //
+};
+
+const std::unordered_set<std::string_view> node_shapes_consisting_of_polygon = {
+    "box",           //
+    "polygon",       //
+    "egg",           //
+    "triangle",      //
+    "diamond",       //
+    "trapezium",     //
+    "parallelogram", //
+    "house",         //
+    "pentagon",      //
+    "hexagon",       //
+    "septagon",      //
+    "octagon",       //
+    "doubleoctagon", //
+    "tripleoctagon", //
+    "invtriangle",   //
+    "invtrapezium",  //
+    "invhouse",      //
+    "rect",          //
+    "rectangle",     //
+    "square",        //
+    "star",          //
+    "cds",           //
+    "rpromoter",     //
+    "rarrow",        //
+    "larrow",        //
+    "lpromoter",     //
+    "folder",        //
+};
+
+const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_polygon_and_polyline = {
+        "Mdiamond",        //
+        "Msquare",         //
+        "underline",       //
+        "note",            //
+        "tab",             //
+        "box3d",           //
+        "component",       //
+        "promoter",        //
+        "terminator",      //
+        "utr",             //
+        "primersite",      //
+        "restrictionsite", //
+        "fivepoverhang",   //
+        "threepoverhang",  //
+        "noverhang",       //
+        "assembly",        //
+        "signature",       //
+        "insulator",       //
+        "ribosite",        //
+        "rnastab",         //
+        "proteasesite",    //
+        "proteinstab",     //
+};
+
+const std::unordered_set<std::string_view> node_shapes_without_svg_shape = {
+    "plaintext", //
+    "plain",     //
+    "none",      //
+};
+
+const std::unordered_set<std::string_view> all_node_shapes = {
+    "box",             //
+    "polygon",         //
+    "ellipse",         //
+    "oval",            //
+    "circle",          //
+    "point",           //
+    "egg",             //
+    "triangle",        //
+    "plaintext",       //
+    "plain",           //
+    "diamond",         //
+    "trapezium",       //
+    "parallelogram",   //
+    "house",           //
+    "pentagon",        //
+    "hexagon",         //
+    "septagon",        //
+    "octagon",         //
+    "doublecircle",    //
+    "doubleoctagon",   //
+    "tripleoctagon",   //
+    "invtriangle",     //
+    "invtrapezium",    //
+    "invhouse",        //
+    "Mdiamond",        //
+    "Msquare",         //
+    "Mcircle",         //
+    "rect",            //
+    "rectangle",       //
+    "square",          //
+    "star",            //
+    "none",            //
+    "underline",       //
+    "cylinder",        //
+    "note",            //
+    "tab",             //
+    "folder",          //
+    "box3d",           //
+    "component",       //
+    "promoter",        //
+    "cds",             //
+    "terminator",      //
+    "utr",             //
+    "primersite",      //
+    "restrictionsite", //
+    "fivepoverhang",   //
+    "threepoverhang",  //
+    "noverhang",       //
+    "assembly",        //
+    "signature",       //
+    "insulator",       //
+    "ribosite",        //
+    "rnastab",         //
+    "proteasesite",    //
+    "proteinstab",     //
+    "rpromoter",       //
+    "rarrow",          //
+    "larrow",          //
+    "lpromoter"        //
+};
+
+bool contains_polygon_shape(std::string_view shape) {
+  return node_shapes_consisting_of_polygon.contains(shape) ||
+         node_shapes_consisting_of_polygon_and_polyline.contains(shape);
+}
+
+bool contains_ellipse_shape(std::string_view shape) {
+  return node_shapes_consisting_of_ellipse.contains(shape) ||
+         node_shapes_consisting_of_ellipse_and_polyline.contains(shape);
+}
diff --git a/tests/test_utilities.h b/tests/test_utilities.h
new file mode 100644 (file)
index 0000000..7cbd0de
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <string_view>
+#include <unordered_set>
+
+/// node shapes
+
+extern const std::unordered_set<std::string_view> all_node_shapes;
+extern const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_ellipse;
+extern const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_ellipse_and_polyline;
+extern const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_path;
+extern const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_polygon;
+extern const std::unordered_set<std::string_view>
+    node_shapes_consisting_of_polygon_and_polyline;
+extern const std::unordered_set<std::string_view> node_shapes_without_svg_shape;
+
+bool contains_ellipse_shape(std::string_view shape);
+bool contains_polygon_shape(std::string_view shape);