// 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"
"os"
"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: `
`,
},
{
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: `
Gephi.org
A Web network
true
`,
},
{
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: `
Gephi.org
A hierarchy file
`,
},
{
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: `
Gephi.org
A hierarchy file
`,
},
{
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: `
`,
},
{
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: `
`,
},
}
func TestUnmarshal(t *testing.T) {
for _, test := range gexfExampleTests {
data, err := os.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)
}
}
}