blob: eb9b39981afc2f7d84f9a729ec521c40880afaec [file] [log] [blame]
// 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 cytoscapejs
import (
"encoding/json"
"io/ioutil"
"path/filepath"
"reflect"
"testing"
)
var cytoscapejsElementsTests = []struct {
path string
wantNodes int
wantEdges int
wantGraph []Element
wantAttributes []string
}{
{
path: "edge-type.json",
wantNodes: 10,
wantEdges: 10,
wantGraph: []Element{
{Data: ElemData{ID: "n01", Attributes: map[string]interface{}{"type": "bezier"}}},
{Data: ElemData{ID: "n02"}},
{Data: ElemData{ID: "e01", Source: "n01", Target: "n02"}, Classes: "bezier"},
{Data: ElemData{ID: "e02", Source: "n01", Target: "n02"}, Classes: "bezier"},
{Data: ElemData{ID: "e03", Source: "n02", Target: "n01"}, Classes: "bezier"},
{Data: ElemData{ID: "n03", Attributes: map[string]interface{}{"type": "unbundled-bezier"}}},
{Data: ElemData{ID: "n04"}},
{Data: ElemData{ID: "e04", Source: "n03", Target: "n04"}, Classes: "unbundled-bezier"},
{Data: ElemData{ID: "n05", Attributes: map[string]interface{}{"type": "unbundled-bezier(multiple)"}}},
{Data: ElemData{ID: "n06"}},
{Data: ElemData{ID: "e05", Source: "n05", Target: "n06", Parent: ""}, Classes: "multi-unbundled-bezier"},
{Data: ElemData{ID: "n07", Attributes: map[string]interface{}{"type": "haystack"}}},
{Data: ElemData{ID: "n08"}},
{Data: ElemData{ID: "e06", Source: "n08", Target: "n07"}, Classes: "haystack"},
{Data: ElemData{ID: "e07", Source: "n08", Target: "n07"}, Classes: "haystack"},
{Data: ElemData{ID: "e08", Source: "n08", Target: "n07"}, Classes: "haystack"},
{Data: ElemData{ID: "e09", Source: "n08", Target: "n07"}, Classes: "haystack"},
{Data: ElemData{ID: "n09", Attributes: map[string]interface{}{"type": "segments"}}},
{Data: ElemData{ID: "n10"}},
{Data: ElemData{ID: "e10", Source: "n09", Target: "n10"}, Classes: "segments"},
},
},
}
func TestUnmarshalElements(t *testing.T) {
for _, test := range cytoscapejsElementsTests {
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 []Element
err = json.Unmarshal(data, &got)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
var gotNodes, gotEdges int
for _, e := range got {
typ, err := e.Type()
if err != nil {
t.Errorf("unexpected error finding element type for %+v: %v", e, err)
}
switch typ {
case NodeElement:
gotNodes++
case EdgeElement:
gotEdges++
}
}
if gotNodes != test.wantNodes {
t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, gotNodes, test.wantNodes)
}
if gotEdges != test.wantEdges {
t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, gotEdges, test.wantEdges)
}
if test.wantGraph != nil && !reflect.DeepEqual(got, test.wantGraph) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, test.wantGraph)
}
}
}
func TestMarshalElements(t *testing.T) {
for _, test := range cytoscapejsElementsTests {
data, err := ioutil.ReadFile(filepath.Join("testdata", test.path))
if err != nil {
t.Errorf("failed to read %q: %v", test.path, err)
continue
}
var want []Element
err = json.Unmarshal(data, &want)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
marshaled, err := json.Marshal(want)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
var got []Element
err = json.Unmarshal(marshaled, &got)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
if !reflect.DeepEqual(got, want) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want)
}
}
}
var cytoscapejsNodeEdgeTests = []struct {
path string
wantNodes int
wantEdges int
wantGraph *Elements
firstNode Node
firstEdge Edge
wantNodeAttributes map[string]bool
wantEdgeAttributes map[string]bool
}{
{
path: "cola-compound.json",
wantNodes: 9,
wantEdges: 7,
wantGraph: &Elements{
Nodes: []Node{
{Data: NodeData{ID: "compound-1", Parent: ""}},
{Data: NodeData{ID: "compound-2", Parent: ""}},
{Data: NodeData{ID: "compound-3", Parent: ""}},
{Data: NodeData{ID: "b", Parent: "compound-1"}},
{Data: NodeData{ID: "c", Parent: "compound-1"}},
{Data: NodeData{ID: "a", Parent: "compound-2"}},
{Data: NodeData{ID: "d", Parent: "compound-3"}},
{Data: NodeData{ID: "e", Parent: "compound-3"}},
{Data: NodeData{ID: "f", Parent: ""}},
},
Edges: []Edge{
{Data: EdgeData{ID: "ab", Source: "a", Target: "b"}},
{Data: EdgeData{ID: "bc", Source: "b", Target: "c"}},
{Data: EdgeData{ID: "ac", Source: "a", Target: "c"}},
{Data: EdgeData{ID: "cd", Source: "c", Target: "d"}},
{Data: EdgeData{ID: "de", Source: "d", Target: "e"}},
{Data: EdgeData{ID: "df", Source: "d", Target: "f"}},
{Data: EdgeData{ID: "af", Source: "a", Target: "f"}},
},
},
},
{
path: "tokyo-railways.json",
wantNodes: 943,
wantEdges: 860,
firstNode: Node{
Data: NodeData{
ID: "8220",
Attributes: map[string]interface{}{
"station_name": "京成高砂",
"close_ymd": "",
"lon": 139.866875,
"post": "",
"e_status": 0.0,
"SUID": 8220.0,
"station_g_cd": 2300110.0,
"add": "東京都葛飾区高砂五丁目28-1",
"line_cd": 99340.0,
"selected": false,
"open_ymd": "",
"name": "9934001",
"pref_name": "東京都",
"shared_name": "9934001",
"lat": 35.750932,
"x": 1398668.75,
"y": -357509.32,
},
},
Position: &Position{
X: 1398668.75,
Y: -357509.32,
},
},
firstEdge: Edge{
Data: EdgeData{
ID: "18417",
Source: "8220",
Target: "8221",
Attributes: map[string]interface{}{
"line_name_k": "ホクソウテツドウホクソウセン",
"is_bullet": false,
"lon": 140.03784499075186,
"company_name_k": "ホクソウテツドウ",
"zoom": 11.0,
"SUID": 18417.0,
"company_type": 0.0,
"company_name_h": "北総鉄道株式会社",
"interaction": "99340",
"shared_interaction": "99340",
"company_url": "http://www.hokuso-railway.co.jp/",
"line_name": "北総鉄道北総線",
"selected": false,
"company_name": "北総鉄道",
"company_cd": 152.0,
"name": "9934001 (99340) 9934002",
"rr_cd": 99.0,
"company_name_r": "北総鉄道",
"e_status_x": 0.0,
"shared_name": "9934001 (99340) 9934002",
"lat": 35.78346285846615,
"e_status_y": 0.0,
"line_name_h": "北総鉄道北総線",
},
},
},
wantNodeAttributes: map[string]bool{
"station_name": true,
"close_ymd": true,
"lon": true,
"post": true,
"e_status": true,
"SUID": true,
"station_g_cd": true,
"add": true,
"line_cd": true,
"selected": true,
"open_ymd": true,
"name": true,
"pref_name": true,
"shared_name": true,
"lat": true,
"x": true,
"y": true,
},
wantEdgeAttributes: map[string]bool{
"line_name_k": true,
"is_bullet": true,
"lon": true,
"company_name_k": true,
"zoom": true,
"SUID": true,
"company_type": true,
"company_name_h": true,
"interaction": true,
"shared_interaction": true,
"company_url": true,
"line_name": true,
"selected": true,
"company_name": true,
"company_cd": true,
"name": true,
"rr_cd": true,
"company_name_r": true,
"e_status_x": true,
"shared_name": true,
"lat": true,
"e_status_y": true,
"line_name_h": true,
},
},
}
func TestUnmarshalNodeEdge(t *testing.T) {
for _, test := range cytoscapejsNodeEdgeTests {
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 Elements
err = json.Unmarshal(data, &got)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
if len(got.Nodes) != test.wantNodes {
t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, len(got.Nodes), test.wantNodes)
}
if len(got.Edges) != test.wantEdges {
t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, len(got.Edges), test.wantEdges)
}
if test.wantGraph != nil {
if !reflect.DeepEqual(&got, test.wantGraph) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got.Nodes, test.wantGraph.Nodes)
}
} else {
if !reflect.DeepEqual(got.Nodes[0], test.firstNode) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got.Nodes[0], test.firstNode)
}
if !reflect.DeepEqual(got.Edges[0], test.firstEdge) {
t.Errorf("unexpected result for %q:\ngot:\n%v\nwant:\n%#v", test.path, got.Edges[0].Data.Source, test.firstEdge.Data.Source)
}
}
if test.wantNodeAttributes != nil {
var paths []string
for _, n := range got.Nodes {
paths = attrPaths(paths, "", n.Data.Attributes)
}
gotAttrs := make(map[string]bool)
for _, p := range paths {
gotAttrs[p] = true
}
if !reflect.DeepEqual(gotAttrs, test.wantNodeAttributes) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantNodeAttributes)
}
}
if test.wantEdgeAttributes != nil {
var paths []string
for _, e := range got.Edges {
paths = attrPaths(paths, "", e.Data.Attributes)
}
gotAttrs := make(map[string]bool)
for _, p := range paths {
gotAttrs[p] = true
}
if !reflect.DeepEqual(gotAttrs, test.wantEdgeAttributes) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantEdgeAttributes)
}
}
}
}
func TestMarshalNodeEdge(t *testing.T) {
for _, test := range cytoscapejsNodeEdgeTests {
data, err := ioutil.ReadFile(filepath.Join("testdata", test.path))
if err != nil {
t.Errorf("failed to read %q: %v", test.path, err)
continue
}
var want Elements
err = json.Unmarshal(data, &want)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
marshaled, err := json.Marshal(want)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
var got Elements
err = json.Unmarshal(marshaled, &got)
if err != nil {
t.Errorf("failed to unmarshal %q: %v", test.path, err)
continue
}
if !reflect.DeepEqual(got, want) {
t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want)
}
}
}
func attrPaths(dst []string, prefix string, m map[string]interface{}) []string {
for k, v := range m {
path := prefix
if path != "" {
path += "."
}
if v, ok := v.(map[string]interface{}); ok {
dst = attrPaths(dst, path+k, v)
}
dst = append(dst, path+k)
}
return dst
}