]> granicus.if.org Git - graphviz/commitdiff
Attempt to fix initialization of subgraph attributes on existing subgraphs…
authorStephen C North <scnorth@gmail.com>
Mon, 7 Mar 2022 23:39:41 +0000 (18:39 -0500)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 17 Mar 2022 04:14:43 +0000 (21:14 -0700)
Attempt to fix initialization of subgraph attributes on existing subgraphs when
a new root graph attribute is created.

Fix issue 2184, initialization of existing subgraph attributes when a new top
level graph attribute is created. Looks ok, but new code unviewsubgraphsattr is
executed on many of the test graphs, so this should be tested carefully.

CHANGELOG.md
lib/cgraph/attr.c
rtest/test_regression.py

index 77d7897ca54864eec2d8e1b0caa145ab76b862b3..f2510b3afe80bde5a2ce9a0d2840bdda696a086a 100644 (file)
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   release of `gvpr`. #2185
 - spurious "no hard-coded metrics" warnings on labels with empty lines #2179
 - fixed corruption of user shape characteristics during EPSF initialization
+- output formats canon, dot, and xdot are not completely faithful to input #2184
 
 ## [3.0.0] – 2022-02-26
 
index 0b190282ca06e6890cbe835460fe6e924ecc4433..1290c48356f09143b0cfecdf5897ab625b9258d5 100644 (file)
@@ -246,6 +246,32 @@ static void addattr(Agraph_t * g, Agobj_t * obj, Agsym_t * sym)
     attr->str[sym->id] = agstrdup(g, sym->defval);
 }
 
+static Agsym_t *getattr(Agraph_t * g, int kind, char *name)
+{
+    Agsym_t *rv = 0;
+    Dict_t *dict;
+    dict = agdictof(g, kind);
+    if (dict)
+       rv = agdictsym(dict, name);     /* viewpath up to root */
+    return rv;
+}
+
+static void unviewsubgraphsattr(Agraph_t *parent, char *name)
+{
+    Agraph_t *subg;
+    Agsym_t *psym, *lsym;
+    Dict_t *ldict;
+
+    psym = getattr(parent, AGRAPH, name);
+    if (!psym) return; // supposedly can't happen, see setattr()
+    for (subg = agfstsubg(parent); subg; subg = agnxtsubg(subg)) {
+       ldict = agdatadict(subg, TRUE)->dict.g;
+        lsym = aglocaldictsym(ldict, name);
+        if (lsym) continue;
+        lsym = agnewsym(agroot(subg), name, agxget(subg,psym), psym->id, AGRAPH);
+        dtinsert(ldict, lsym);
+    }
+}
 
 static Agsym_t *setattr(Agraph_t * g, int kind, char *name, const char *value) {
     Dict_t *ldict, *rdict;
@@ -262,6 +288,7 @@ static Agsym_t *setattr(Agraph_t * g, int kind, char *name, const char *value) {
     if (lsym) {                        /* update old local definition */
        if (g != root && streq(name, "layout"))
            agerr(AGWARN, "layout attribute is invalid except on the root graph\n");
+        if (kind == AGRAPH) unviewsubgraphsattr(g,name);
        agstrfree(g, lsym->defval);
        lsym->defval = agstrdup(g, value);
        rv = lsym;
@@ -302,16 +329,6 @@ static Agsym_t *setattr(Agraph_t * g, int kind, char *name, const char *value) {
     return rv;
 }
 
-static Agsym_t *getattr(Agraph_t * g, int kind, char *name)
-{
-    Agsym_t *rv = 0;
-    Dict_t *dict;
-    dict = agdictof(g, kind);
-    if (dict)
-       rv = agdictsym(dict, name);     /* viewpath up to root */
-    return rv;
-}
-
 /*
  * create or update an existing attribute and return its descriptor.
  * if the new value is NULL, this is only a search, no update.
index 63e90948c7a12f0e5440f5e6a3effdf7e94e0ec7..da2e0ec1633c3091df49b420f14c9f3d04e6978c 100644 (file)
@@ -1399,7 +1399,6 @@ def test_2179_1():
     "incorrect warning triggered"
 
 @pytest.mark.skipif(shutil.which("nop") is None, reason="nop not available")
-@pytest.mark.xfail(strict=True) # FIXME
 def test_2184_1():
   """
   nop should not reposition labelled graph nodes
@@ -1418,7 +1417,6 @@ def test_2184_1():
   assert m is not None, \
     "nop rearranged a graph in a not-semantically-preserving way"
 
-@pytest.mark.xfail(strict=True) # FIXME
 def test_2184_2():
   """
   canonicalization should not reposition labelled graph nodes