]> granicus.if.org Git - graphviz/commitdiff
fix erroneous commas in JSON output of graphs with only clusters
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 29 Sep 2022 01:26:34 +0000 (18:26 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 29 Sep 2022 15:36:31 +0000 (08:36 -0700)
When a graph or subgraph contained exclusively subnodes that were clusters (that
is, it contained a non-zero number of subnodes, but all of them were clusters),
the output of `-Tjson` would contain an extra comma. This malformed JSON could
not be ingested by most downstream parsers.

This appears to have been a mistake in f82c51fc9644047e9ce80d860fea562e98d3311c
that introduced cluster skipping in the loop that emits nodes in JSON. It did
not account for the earlier part of the containing function that was intended to
early-exit if the loop would have a 0 iteration count.

As noted in the discussion of #2282, a couple of the maintainers believe this
manual JSON writing code is inherently fragile and likely contains more latent
bugs. But we do not have maintainer consensus on migrating to an established
JSON-writing library. This fix attempts to surgically address the current known
bug. But I cannot guarantee it does not introduce others.

Gitlab: fixes #2282

CHANGELOG.md
plugin/core/gvrender_core_json.c
tests/test_regression.py

index f878b926709707578829dc86e73af02199065e4e..3b2406fde49cc25c0d54bc9946f471eea0167641 100644 (file)
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   a regression in 2.49.2 See #2279 for details.
 - Graphviz no longer fails to load private Ghostscript symbols ("Could not load
   `libgvplugin_gs.so.6`) #2280
+- trailing commas issue with fdp layout #2282
 
 ## [6.0.1] – 2022-09-11
 
index 41d1a5ccd09d33b8461f553678967e9f6a9ebc5c..c2b74353d0f06b10f554033bb699429cb3a6eca8 100644 (file)
@@ -531,10 +531,17 @@ static void write_node(Agnode_t *n, GVJ_t *job, bool top, state_t *sp) {
 }
 
 static int write_nodes(Agraph_t *g, GVJ_t *job, bool top, bool has_subgs, state_t *sp) {
-    Agnode_t* n;
 
-    n = agfstnode(g);
-    if (!n) {
+    // is every subcomponent of this graph a cluster?
+    bool only_clusters = true;
+    for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       if (!IS_CLUST_NODE(n)) {
+           only_clusters = false;
+           break;
+       }
+    }
+
+    if (only_clusters) {
        if (has_subgs && top) {
            sp->Level--;
            gvputs(job, "\n");
@@ -556,7 +563,7 @@ static int write_nodes(Agraph_t *g, GVJ_t *job, bool top, bool has_subgs, state_
        indent(job, sp->Level);
     }
     const char *separator = "";
-    for (; n; n = agnxtnode(g, n)) {
+    for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
        if (IS_CLUST_NODE(n)) continue;
        gvputs(job, separator);
        write_node (n, job, top, sp);
index 1c32fd2f3059fd3ca0e10b5ad9f9512b142eb694..75e817c01bd3f5467f0fd4254d194ff0d9898f4f 100644 (file)
@@ -1988,7 +1988,6 @@ def test_2272():
   # run the test
   run_c(c_src, link=["cgraph", "gvc"])
 
-@pytest.mark.xfail(strict=True)
 def test_2282():
   """
   using the `fdp` layout with JSON output should result in valid JSON