]> granicus.if.org Git - graphviz/commitdiff
Keep the edge order in json output
authorGraph <graphgalaxyapp@gmail.com>
Wed, 3 Feb 2021 16:17:35 +0000 (00:17 +0800)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Sun, 14 Feb 2021 01:58:40 +0000 (17:58 -0800)
CHANGELOG.md
plugin/core/gvrender_core_json.c
rtest/test_misc.py

index 0dfb7920b672ef8d3d43d3328ea8b5c3d4554add..d8fe2a61f9416ba751d4e156f9002676181f4157 100644 (file)
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Changed
+- The edges in JSON output are ordered now !1728
+
 ### Fixed
 - typos in gpcanvas.c #1927
 
index 8c22dddfd7e31b18c0e836c6768d2edcf172a602..e53c4c23907c02bee3ef88a020d7e74d189f6bd1 100644 (file)
@@ -33,6 +33,8 @@
 #include <gvc/gvio.h>
 #include <gvc/gvcint.h>
 
+#include <common/memory.h>
+
 typedef enum {
        FORMAT_JSON,
        FORMAT_JSON0,
@@ -460,6 +462,22 @@ static int write_subgs(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
     return 1;
 }
 
+static int agseqasc(Agedge_t **lhs, Agedge_t **rhs)
+{
+    Agedge_t *e1 = *lhs;
+    Agedge_t *e2 = *rhs;
+
+    if (AGSEQ(e1) < AGSEQ(e2)) {
+        return -1;
+    }
+    else if (AGSEQ(e1) > AGSEQ(e2)) {
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
 static void write_edge(Agedge_t * e, GVJ_t * job, int top, state_t* sp)
 {
     if (top) {
@@ -484,39 +502,49 @@ static void write_edge(Agedge_t * e, GVJ_t * job, int top, state_t* sp)
 
 static int write_edges(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
 {
-    Agnode_t* np;
-    Agedge_t* ep;
+    size_t count = 0;
     int not_first = 0;
 
-    np = agfstnode(g);
-    if (!np) return 0;
-    ep = NULL;
-    /* find a first edge */
-    for (; np; np = agnxtnode(g,np)) {
-       for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) {
-           if (ep) break;
-       }
-       if (ep) break;
+    for (Agnode_t *np = agfstnode(g); np; np = agnxtnode(g, np)) {
+        for (Agedge_t *ep = agfstout(g, np); ep; ep = agnxtout(g, ep)) {
+            ++count;
+        }
     }
-    if (!ep) return 0;
+
+    if (count == 0) {
+        return 0;
+    }
+
+    Agedge_t **edges = gcalloc(count, sizeof(Agedge_t *));
+
+    size_t i = 0;
+    for (Agnode_t *np = agfstnode(g); np; np = agnxtnode(g, np)) {
+        for (Agedge_t *ep = agfstout(g, np); ep; ep = agnxtout(g, ep)) {
+            edges[i] = ep;
+            ++i;
+        }
+    }
+
+    qsort(edges, count, sizeof(Agedge_t *), (qsort_cmpf)agseqasc);
 
     gvputs(job, ",\n");
     indent(job, sp->Level++);
     gvputs(job, "\"edges\": [\n");
     if (!top)
         indent(job, sp->Level);
-    for (; np; np = agnxtnode(g,np)) {
-       for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) {
-           if (not_first) 
-                if (top)
-                   gvputs(job, ",\n");
-                else
-                   gvputs(job, ",");
-           else
-               not_first = 1;
-           write_edge(ep, job, top, sp);
-       }
+    for (size_t j = 0; j < count; ++j) {
+        if (not_first)
+            if (top)
+                gvputs(job, ",\n");
+            else
+                gvputs(job, ",");
+        else
+            not_first = 1;
+        write_edge(edges[j], job, top, sp);
     }
+
+    free(edges);
+
     sp->Level--;
     gvputs(job, "\n");
     indent(job, sp->Level);
index d0e52704de187a05be37fa1923c193cc06dedcd3..8ce48fddd90f69efb74bf1f9aeb3d7bb76ac9814 100644 (file)
@@ -1,5 +1,4 @@
 import json
-import pytest
 import subprocess
 
 def test_json_node_order():
@@ -35,7 +34,6 @@ def test_json_node_order():
     # the nodes should appear in the order in which they were seen in the input
     assert nodes == ['1', '2', '4', '5', '7', '6', '3', '8']
 
-@pytest.mark.xfail(strict=True)
 def test_json_edge_order():
     '''
     test that edges appear in JSON output in the same order as they were input