mirror of
https://github.com/gonum/gonum.git
synced 2025-10-06 15:47:01 +08:00
463 lines
12 KiB
Go
463 lines
12 KiB
Go
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gexf12
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var gexfExampleTests = []struct {
|
|
path string
|
|
unmarshaled Content
|
|
marshaled string
|
|
}{
|
|
{
|
|
path: "basic.gexf",
|
|
unmarshaled: Content{
|
|
XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"},
|
|
Meta: nil,
|
|
Graph: Graph{
|
|
Attributes: nil,
|
|
Nodes: Nodes{
|
|
Nodes: []Node{
|
|
{ID: "0", Label: "Hello"},
|
|
{ID: "1", Label: "Word"},
|
|
},
|
|
},
|
|
Edges: Edges{
|
|
Edges: []Edge{
|
|
{ID: "0", Source: "0", Target: "1"},
|
|
},
|
|
},
|
|
DefaultEdgeType: "directed",
|
|
Mode: "static",
|
|
},
|
|
Version: "1.2",
|
|
},
|
|
marshaled: `<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
|
<graph defaultedgetype="directed" mode="static">
|
|
<nodes>
|
|
<node id="0" label="Hello"></node>
|
|
<node id="1" label="Word"></node>
|
|
</nodes>
|
|
<edges>
|
|
<edge id="0" source="0" target="1"></edge>
|
|
</edges>
|
|
</graph>
|
|
</gexf>`,
|
|
},
|
|
{
|
|
path: "data.gexf",
|
|
unmarshaled: Content{
|
|
XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"},
|
|
Meta: &Meta{
|
|
Creator: "Gephi.org",
|
|
Description: "A Web network",
|
|
LastModified: time.Date(2009, 03, 20, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
Graph: Graph{
|
|
Attributes: []Attributes{{
|
|
Class: "node",
|
|
Attributes: []Attribute{
|
|
{
|
|
ID: "0",
|
|
Title: "url",
|
|
Type: "string",
|
|
},
|
|
{
|
|
ID: "1",
|
|
Title: "indegree",
|
|
Type: "float",
|
|
},
|
|
{
|
|
ID: "2",
|
|
Title: "frog",
|
|
Type: "boolean",
|
|
Default: "true",
|
|
},
|
|
},
|
|
}},
|
|
Nodes: Nodes{
|
|
Nodes: []Node{
|
|
{
|
|
ID: "0", Label: "Gephi",
|
|
AttValues: &AttValues{AttValues: []AttValue{
|
|
{For: "0", Value: "http://gephi.org"},
|
|
{For: "1", Value: "1"},
|
|
}},
|
|
},
|
|
{
|
|
ID: "1", Label: "Webatlas",
|
|
AttValues: &AttValues{AttValues: []AttValue{
|
|
{For: "0", Value: "http://webatlas.fr"},
|
|
{For: "1", Value: "2"},
|
|
}},
|
|
},
|
|
{
|
|
ID: "2", Label: "RTGI",
|
|
AttValues: &AttValues{AttValues: []AttValue{
|
|
{For: "0", Value: "http://rtgi.fr"},
|
|
{For: "1", Value: "1"},
|
|
}},
|
|
},
|
|
{
|
|
ID: "3", Label: "BarabasiLab",
|
|
AttValues: &AttValues{AttValues: []AttValue{
|
|
{For: "0", Value: "http://barabasilab.com"},
|
|
{For: "1", Value: "1"},
|
|
{For: "2", Value: "false"},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
Edges: Edges{
|
|
Edges: []Edge{
|
|
{ID: "0", Source: "0", Target: "1"},
|
|
{ID: "1", Source: "0", Target: "2"},
|
|
{ID: "2", Source: "1", Target: "0"},
|
|
{ID: "3", Source: "2", Target: "1"},
|
|
{ID: "4", Source: "0", Target: "3"},
|
|
},
|
|
},
|
|
DefaultEdgeType: "directed",
|
|
},
|
|
Version: "1.2",
|
|
},
|
|
marshaled: `<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
|
<meta lastmodifieddate="2009-03-20">
|
|
<creator>Gephi.org</creator>
|
|
<description>A Web network</description>
|
|
</meta>
|
|
<graph defaultedgetype="directed">
|
|
<attributes class="node">
|
|
<attribute id="0" title="url" type="string"></attribute>
|
|
<attribute id="1" title="indegree" type="float"></attribute>
|
|
<attribute id="2" title="frog" type="boolean">
|
|
<default>true</default>
|
|
</attribute>
|
|
</attributes>
|
|
<nodes>
|
|
<node id="0" label="Gephi">
|
|
<attvalues>
|
|
<attvalue for="0" value="http://gephi.org"></attvalue>
|
|
<attvalue for="1" value="1"></attvalue>
|
|
</attvalues>
|
|
</node>
|
|
<node id="1" label="Webatlas">
|
|
<attvalues>
|
|
<attvalue for="0" value="http://webatlas.fr"></attvalue>
|
|
<attvalue for="1" value="2"></attvalue>
|
|
</attvalues>
|
|
</node>
|
|
<node id="2" label="RTGI">
|
|
<attvalues>
|
|
<attvalue for="0" value="http://rtgi.fr"></attvalue>
|
|
<attvalue for="1" value="1"></attvalue>
|
|
</attvalues>
|
|
</node>
|
|
<node id="3" label="BarabasiLab">
|
|
<attvalues>
|
|
<attvalue for="0" value="http://barabasilab.com"></attvalue>
|
|
<attvalue for="1" value="1"></attvalue>
|
|
<attvalue for="2" value="false"></attvalue>
|
|
</attvalues>
|
|
</node>
|
|
</nodes>
|
|
<edges>
|
|
<edge id="0" source="0" target="1"></edge>
|
|
<edge id="1" source="0" target="2"></edge>
|
|
<edge id="2" source="1" target="0"></edge>
|
|
<edge id="3" source="2" target="1"></edge>
|
|
<edge id="4" source="0" target="3"></edge>
|
|
</edges>
|
|
</graph>
|
|
</gexf>`,
|
|
},
|
|
{
|
|
path: "hierarchy1.gexf",
|
|
unmarshaled: Content{
|
|
XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"},
|
|
Meta: &Meta{
|
|
Creator: "Gephi.org",
|
|
Description: "A hierarchy file",
|
|
LastModified: time.Date(2009, 10, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
Graph: Graph{
|
|
Nodes: Nodes{
|
|
Nodes: []Node{{
|
|
ID: "a",
|
|
Label: "Kevin Bacon",
|
|
Nodes: &Nodes{
|
|
Nodes: []Node{
|
|
{
|
|
ID: "b", Label: "God",
|
|
Nodes: &Nodes{
|
|
Nodes: []Node{
|
|
{ID: "c", Label: "human1"},
|
|
{ID: "d", Label: "human2"},
|
|
{ID: "i", Label: "human3"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: "e", Label: "Me",
|
|
Nodes: &Nodes{
|
|
Nodes: []Node{
|
|
{ID: "f", Label: "frog1"},
|
|
{ID: "g", Label: "frog2"},
|
|
{ID: "h", Label: "frog3"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: "j", Label: "You",
|
|
},
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
Edges: Edges{
|
|
Edges: []Edge{
|
|
{ID: "0", Source: "b", Target: "e"},
|
|
{ID: "1", Source: "c", Target: "d"},
|
|
{ID: "2", Source: "c", Target: "i"},
|
|
{ID: "3", Source: "g", Target: "b"},
|
|
{ID: "4", Source: "f", Target: "a"},
|
|
{ID: "5", Source: "f", Target: "g"},
|
|
{ID: "6", Source: "f", Target: "h"},
|
|
{ID: "7", Source: "g", Target: "h"},
|
|
{ID: "8", Source: "a", Target: "j"},
|
|
},
|
|
},
|
|
DefaultEdgeType: "directed",
|
|
Mode: "static",
|
|
},
|
|
Version: "1.2",
|
|
},
|
|
marshaled: `<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
|
<meta lastmodifieddate="2009-10-01">
|
|
<creator>Gephi.org</creator>
|
|
<description>A hierarchy file</description>
|
|
</meta>
|
|
<graph defaultedgetype="directed" mode="static">
|
|
<nodes>
|
|
<node id="a" label="Kevin Bacon">
|
|
<nodes>
|
|
<node id="b" label="God">
|
|
<nodes>
|
|
<node id="c" label="human1"></node>
|
|
<node id="d" label="human2"></node>
|
|
<node id="i" label="human3"></node>
|
|
</nodes>
|
|
</node>
|
|
<node id="e" label="Me">
|
|
<nodes>
|
|
<node id="f" label="frog1"></node>
|
|
<node id="g" label="frog2"></node>
|
|
<node id="h" label="frog3"></node>
|
|
</nodes>
|
|
</node>
|
|
<node id="j" label="You"></node>
|
|
</nodes>
|
|
</node>
|
|
</nodes>
|
|
<edges>
|
|
<edge id="0" source="b" target="e"></edge>
|
|
<edge id="1" source="c" target="d"></edge>
|
|
<edge id="2" source="c" target="i"></edge>
|
|
<edge id="3" source="g" target="b"></edge>
|
|
<edge id="4" source="f" target="a"></edge>
|
|
<edge id="5" source="f" target="g"></edge>
|
|
<edge id="6" source="f" target="h"></edge>
|
|
<edge id="7" source="g" target="h"></edge>
|
|
<edge id="8" source="a" target="j"></edge>
|
|
</edges>
|
|
</graph>
|
|
</gexf>`,
|
|
},
|
|
{
|
|
path: "hierarchy4.gexf",
|
|
unmarshaled: Content{
|
|
XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"},
|
|
Meta: &Meta{
|
|
Creator: "Gephi.org",
|
|
Keywords: "",
|
|
Description: "A hierarchy file",
|
|
LastModified: time.Date(2009, 10, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
Graph: Graph{
|
|
Nodes: Nodes{
|
|
Nodes: []Node{
|
|
{ID: "g", Label: "frog2", ParentID: "e"},
|
|
{ID: "a", Label: "Kevin Bacon"},
|
|
{ID: "c", Label: "human1", ParentID: "b"},
|
|
{ID: "b", Label: "God", ParentID: "a"},
|
|
{ID: "e", Label: "Me", ParentID: "a"},
|
|
{ID: "d", Label: "human2", ParentID: "b"},
|
|
{ID: "f", Label: "frog1", ParentID: "e"},
|
|
},
|
|
},
|
|
Edges: Edges{
|
|
Edges: []Edge{
|
|
{ID: "0", Source: "b", Target: "e"},
|
|
{ID: "1", Source: "c", Target: "d"},
|
|
{ID: "2", Source: "g", Target: "b"},
|
|
{ID: "3", Source: "f", Target: "a"},
|
|
},
|
|
},
|
|
DefaultEdgeType: "directed",
|
|
Mode: "static",
|
|
},
|
|
Version: "1.2",
|
|
},
|
|
marshaled: `<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
|
<meta lastmodifieddate="2009-10-01">
|
|
<creator>Gephi.org</creator>
|
|
<description>A hierarchy file</description>
|
|
</meta>
|
|
<graph defaultedgetype="directed" mode="static">
|
|
<nodes>
|
|
<node id="g" label="frog2" pid="e"></node>
|
|
<node id="a" label="Kevin Bacon"></node>
|
|
<node id="c" label="human1" pid="b"></node>
|
|
<node id="b" label="God" pid="a"></node>
|
|
<node id="e" label="Me" pid="a"></node>
|
|
<node id="d" label="human2" pid="b"></node>
|
|
<node id="f" label="frog1" pid="e"></node>
|
|
</nodes>
|
|
<edges>
|
|
<edge id="0" source="b" target="e"></edge>
|
|
<edge id="1" source="c" target="d"></edge>
|
|
<edge id="2" source="g" target="b"></edge>
|
|
<edge id="3" source="f" target="a"></edge>
|
|
</edges>
|
|
</graph>
|
|
</gexf>`,
|
|
},
|
|
{
|
|
path: "phylogeny.gexf",
|
|
unmarshaled: Content{
|
|
XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"},
|
|
Graph: Graph{
|
|
Nodes: Nodes{
|
|
Nodes: []Node{
|
|
{ID: "a", Label: "cheese"},
|
|
{ID: "b", Label: "cherry"},
|
|
{ID: "c", Label: "cake", Parents: &Parents{
|
|
Parents: []Parent{
|
|
{For: "a"},
|
|
{For: "b"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Edges: Edges{
|
|
Edges: nil,
|
|
Count: 0,
|
|
},
|
|
},
|
|
Version: "1.2",
|
|
},
|
|
marshaled: `<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
|
<graph>
|
|
<nodes>
|
|
<node id="a" label="cheese"></node>
|
|
<node id="b" label="cherry"></node>
|
|
<node id="c" label="cake">
|
|
<parents>
|
|
<parent for="a"></parent>
|
|
<parent for="b"></parent>
|
|
</parents>
|
|
</node>
|
|
</nodes>
|
|
<edges></edges>
|
|
</graph>
|
|
</gexf>`,
|
|
},
|
|
{
|
|
path: "viz.gexf",
|
|
unmarshaled: Content{
|
|
XMLName: xml.Name{Space: "http://www.gexf.net/1.2draft", Local: "gexf"},
|
|
Graph: Graph{
|
|
Nodes: Nodes{
|
|
Nodes: []Node{
|
|
{
|
|
ID: "a",
|
|
Label: "glossy",
|
|
Color: &Color{
|
|
R: 239,
|
|
G: 173,
|
|
B: 66,
|
|
A: 0.6,
|
|
},
|
|
Position: &Position{
|
|
X: 15.783598,
|
|
Y: 40.109245,
|
|
Z: 0,
|
|
},
|
|
Size: &Size{
|
|
Value: 2.0375757,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Edges: Edges{},
|
|
},
|
|
Version: "1.2",
|
|
},
|
|
marshaled: `<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
|
<graph>
|
|
<nodes>
|
|
<node id="a" label="glossy">
|
|
<color xmlns="http://www.gexf.net/1.2draft/viz" r="239" g="173" b="66" a="0.6"></color>
|
|
<position xmlns="http://www.gexf.net/1.2draft/viz" x="15.783598" y="40.109245" z="0"></position>
|
|
<size xmlns="http://www.gexf.net/1.2draft/viz" value="2.0375757"></size>
|
|
</node>
|
|
</nodes>
|
|
<edges></edges>
|
|
</graph>
|
|
</gexf>`,
|
|
},
|
|
}
|
|
|
|
func TestUnmarshal(t *testing.T) {
|
|
for _, test := range gexfExampleTests {
|
|
data, err := ioutil.ReadFile(filepath.Join("testdata", test.path))
|
|
if err != nil {
|
|
t.Errorf("failed to read %q: %v", test.path, err)
|
|
continue
|
|
}
|
|
var got Content
|
|
err = xml.Unmarshal(data, &got)
|
|
if err != nil {
|
|
t.Errorf("failed to unmarshal %q: %v", test.path, err)
|
|
}
|
|
if !reflect.DeepEqual(got, test.unmarshaled) {
|
|
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, test.unmarshaled)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(kortschak): Update this test when/if namespace
|
|
// prefix handling in encoding/xml is fixed.
|
|
func TestMarshal(t *testing.T) {
|
|
for _, test := range gexfExampleTests {
|
|
got, err := xml.MarshalIndent(test.unmarshaled, "", "\t")
|
|
if err != nil {
|
|
t.Errorf("failed to marshal %q: %v", test.path, err)
|
|
continue
|
|
}
|
|
if string(got) != test.marshaled {
|
|
t.Errorf("unexpected result for %q:\ngot:\n%s\nwant:\n%s", test.path, got, test.marshaled)
|
|
}
|
|
}
|
|
}
|