gonum.org/v1/gonum@v0.14.0/graph/formats/cytoscapejs/cytoscapejs_test.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cytoscapejs 6 7 import ( 8 "encoding/json" 9 "os" 10 "path/filepath" 11 "reflect" 12 "testing" 13 ) 14 15 var cytoscapejsElementsTests = []struct { 16 path string 17 wantNodes int 18 wantEdges int 19 wantGraph []Element 20 wantAttributes []string 21 }{ 22 { 23 path: "edge-type.json", 24 wantNodes: 10, 25 wantEdges: 10, 26 wantGraph: []Element{ 27 {Data: ElemData{ID: "n01", Attributes: map[string]interface{}{"type": "bezier"}}}, 28 {Data: ElemData{ID: "n02"}}, 29 {Data: ElemData{ID: "e01", Source: "n01", Target: "n02"}, Classes: "bezier"}, 30 {Data: ElemData{ID: "e02", Source: "n01", Target: "n02"}, Classes: "bezier"}, 31 {Data: ElemData{ID: "e03", Source: "n02", Target: "n01"}, Classes: "bezier"}, 32 {Data: ElemData{ID: "n03", Attributes: map[string]interface{}{"type": "unbundled-bezier"}}}, 33 {Data: ElemData{ID: "n04"}}, 34 {Data: ElemData{ID: "e04", Source: "n03", Target: "n04"}, Classes: "unbundled-bezier"}, 35 {Data: ElemData{ID: "n05", Attributes: map[string]interface{}{"type": "unbundled-bezier(multiple)"}}}, 36 {Data: ElemData{ID: "n06"}}, 37 {Data: ElemData{ID: "e05", Source: "n05", Target: "n06", Parent: ""}, Classes: "multi-unbundled-bezier"}, 38 {Data: ElemData{ID: "n07", Attributes: map[string]interface{}{"type": "haystack"}}}, 39 {Data: ElemData{ID: "n08"}}, 40 {Data: ElemData{ID: "e06", Source: "n08", Target: "n07"}, Classes: "haystack"}, 41 {Data: ElemData{ID: "e07", Source: "n08", Target: "n07"}, Classes: "haystack"}, 42 {Data: ElemData{ID: "e08", Source: "n08", Target: "n07"}, Classes: "haystack"}, 43 {Data: ElemData{ID: "e09", Source: "n08", Target: "n07"}, Classes: "haystack"}, 44 {Data: ElemData{ID: "n09", Attributes: map[string]interface{}{"type": "segments"}}}, 45 {Data: ElemData{ID: "n10"}}, 46 {Data: ElemData{ID: "e10", Source: "n09", Target: "n10"}, Classes: "segments"}, 47 }, 48 }, 49 } 50 51 func TestUnmarshalElements(t *testing.T) { 52 for _, test := range cytoscapejsElementsTests { 53 data, err := os.ReadFile(filepath.Join("testdata", test.path)) 54 if err != nil { 55 t.Errorf("failed to read %q: %v", test.path, err) 56 continue 57 } 58 var got []Element 59 err = json.Unmarshal(data, &got) 60 if err != nil { 61 t.Errorf("failed to unmarshal %q: %v", test.path, err) 62 continue 63 } 64 var gotNodes, gotEdges int 65 for _, e := range got { 66 typ, err := e.Type() 67 if err != nil { 68 t.Errorf("unexpected error finding element type for %+v: %v", e, err) 69 } 70 switch typ { 71 case NodeElement: 72 gotNodes++ 73 case EdgeElement: 74 gotEdges++ 75 } 76 } 77 78 if gotNodes != test.wantNodes { 79 t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, gotNodes, test.wantNodes) 80 } 81 if gotEdges != test.wantEdges { 82 t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, gotEdges, test.wantEdges) 83 } 84 if test.wantGraph != nil && !reflect.DeepEqual(got, test.wantGraph) { 85 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, test.wantGraph) 86 } 87 } 88 } 89 90 func TestMarshalElements(t *testing.T) { 91 for _, test := range cytoscapejsElementsTests { 92 data, err := os.ReadFile(filepath.Join("testdata", test.path)) 93 if err != nil { 94 t.Errorf("failed to read %q: %v", test.path, err) 95 continue 96 } 97 var want []Element 98 err = json.Unmarshal(data, &want) 99 if err != nil { 100 t.Errorf("failed to unmarshal %q: %v", test.path, err) 101 continue 102 } 103 marshaled, err := json.Marshal(want) 104 if err != nil { 105 t.Errorf("failed to unmarshal %q: %v", test.path, err) 106 continue 107 } 108 var got []Element 109 err = json.Unmarshal(marshaled, &got) 110 if err != nil { 111 t.Errorf("failed to unmarshal %q: %v", test.path, err) 112 continue 113 } 114 if !reflect.DeepEqual(got, want) { 115 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want) 116 } 117 } 118 } 119 120 var cytoscapejsNodeEdgeTests = []struct { 121 path string 122 wantNodes int 123 wantEdges int 124 wantGraph *Elements 125 firstNode Node 126 firstEdge Edge 127 wantNodeAttributes map[string]bool 128 wantEdgeAttributes map[string]bool 129 }{ 130 { 131 path: "cola-compound.json", 132 wantNodes: 9, 133 wantEdges: 7, 134 wantGraph: &Elements{ 135 Nodes: []Node{ 136 {Data: NodeData{ID: "compound-1", Parent: ""}}, 137 {Data: NodeData{ID: "compound-2", Parent: ""}}, 138 {Data: NodeData{ID: "compound-3", Parent: ""}}, 139 {Data: NodeData{ID: "b", Parent: "compound-1"}}, 140 {Data: NodeData{ID: "c", Parent: "compound-1"}}, 141 {Data: NodeData{ID: "a", Parent: "compound-2"}}, 142 {Data: NodeData{ID: "d", Parent: "compound-3"}}, 143 {Data: NodeData{ID: "e", Parent: "compound-3"}}, 144 {Data: NodeData{ID: "f", Parent: ""}}, 145 }, 146 Edges: []Edge{ 147 {Data: EdgeData{ID: "ab", Source: "a", Target: "b"}}, 148 {Data: EdgeData{ID: "bc", Source: "b", Target: "c"}}, 149 {Data: EdgeData{ID: "ac", Source: "a", Target: "c"}}, 150 {Data: EdgeData{ID: "cd", Source: "c", Target: "d"}}, 151 {Data: EdgeData{ID: "de", Source: "d", Target: "e"}}, 152 {Data: EdgeData{ID: "df", Source: "d", Target: "f"}}, 153 {Data: EdgeData{ID: "af", Source: "a", Target: "f"}}, 154 }, 155 }, 156 }, 157 { 158 path: "tokyo-railways.json", 159 wantNodes: 943, 160 wantEdges: 860, 161 firstNode: Node{ 162 Data: NodeData{ 163 ID: "8220", 164 Attributes: map[string]interface{}{ 165 "station_name": "京成高砂", 166 "close_ymd": "", 167 "lon": 139.866875, 168 "post": "", 169 "e_status": 0.0, 170 "SUID": 8220.0, 171 "station_g_cd": 2300110.0, 172 "add": "東京都葛飾区高砂五丁目28-1", 173 "line_cd": 99340.0, 174 "selected": false, 175 "open_ymd": "", 176 "name": "9934001", 177 "pref_name": "東京都", 178 "shared_name": "9934001", 179 "lat": 35.750932, 180 "x": 1398668.75, 181 "y": -357509.32, 182 }, 183 }, 184 Position: &Position{ 185 X: 1398668.75, 186 Y: -357509.32, 187 }, 188 }, 189 firstEdge: Edge{ 190 Data: EdgeData{ 191 ID: "18417", 192 Source: "8220", 193 Target: "8221", 194 Attributes: map[string]interface{}{ 195 "line_name_k": "ホクソウテツドウホクソウセン", 196 "is_bullet": false, 197 "lon": 140.03784499075186, 198 "company_name_k": "ホクソウテツドウ", 199 "zoom": 11.0, 200 "SUID": 18417.0, 201 "company_type": 0.0, 202 "company_name_h": "北総鉄道株式会社", 203 "interaction": "99340", 204 "shared_interaction": "99340", 205 "company_url": "http://www.hokuso-railway.co.jp/", 206 "line_name": "北総鉄道北総線", 207 "selected": false, 208 "company_name": "北総鉄道", 209 "company_cd": 152.0, 210 "name": "9934001 (99340) 9934002", 211 "rr_cd": 99.0, 212 "company_name_r": "北総鉄道", 213 "e_status_x": 0.0, 214 "shared_name": "9934001 (99340) 9934002", 215 "lat": 35.78346285846615, 216 "e_status_y": 0.0, 217 "line_name_h": "北総鉄道北総線", 218 }, 219 }, 220 }, 221 wantNodeAttributes: map[string]bool{ 222 "station_name": true, 223 "close_ymd": true, 224 "lon": true, 225 "post": true, 226 "e_status": true, 227 "SUID": true, 228 "station_g_cd": true, 229 "add": true, 230 "line_cd": true, 231 "selected": true, 232 "open_ymd": true, 233 "name": true, 234 "pref_name": true, 235 "shared_name": true, 236 "lat": true, 237 "x": true, 238 "y": true, 239 }, 240 wantEdgeAttributes: map[string]bool{ 241 "line_name_k": true, 242 "is_bullet": true, 243 "lon": true, 244 "company_name_k": true, 245 "zoom": true, 246 "SUID": true, 247 "company_type": true, 248 "company_name_h": true, 249 "interaction": true, 250 "shared_interaction": true, 251 "company_url": true, 252 "line_name": true, 253 "selected": true, 254 "company_name": true, 255 "company_cd": true, 256 "name": true, 257 "rr_cd": true, 258 "company_name_r": true, 259 "e_status_x": true, 260 "shared_name": true, 261 "lat": true, 262 "e_status_y": true, 263 "line_name_h": true, 264 }, 265 }, 266 } 267 268 func TestUnmarshalNodeEdge(t *testing.T) { 269 for _, test := range cytoscapejsNodeEdgeTests { 270 data, err := os.ReadFile(filepath.Join("testdata", test.path)) 271 if err != nil { 272 t.Errorf("failed to read %q: %v", test.path, err) 273 continue 274 } 275 var got Elements 276 err = json.Unmarshal(data, &got) 277 if err != nil { 278 t.Errorf("failed to unmarshal %q: %v", test.path, err) 279 continue 280 } 281 282 if len(got.Nodes) != test.wantNodes { 283 t.Errorf("unexpected result for order of %q: got:%d want:%d", test.path, len(got.Nodes), test.wantNodes) 284 } 285 if len(got.Edges) != test.wantEdges { 286 t.Errorf("unexpected result for size of %q: got:%d want:%d", test.path, len(got.Edges), test.wantEdges) 287 } 288 if test.wantGraph != nil { 289 if !reflect.DeepEqual(&got, test.wantGraph) { 290 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got.Nodes, test.wantGraph.Nodes) 291 } 292 } else { 293 if !reflect.DeepEqual(got.Nodes[0], test.firstNode) { 294 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got.Nodes[0], test.firstNode) 295 } 296 if !reflect.DeepEqual(got.Edges[0], test.firstEdge) { 297 t.Errorf("unexpected result for %q:\ngot:\n%v\nwant:\n%#v", test.path, got.Edges[0].Data.Source, test.firstEdge.Data.Source) 298 } 299 } 300 if test.wantNodeAttributes != nil { 301 var paths []string 302 for _, n := range got.Nodes { 303 paths = attrPaths(paths, "", n.Data.Attributes) 304 } 305 gotAttrs := make(map[string]bool) 306 for _, p := range paths { 307 gotAttrs[p] = true 308 } 309 if !reflect.DeepEqual(gotAttrs, test.wantNodeAttributes) { 310 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantNodeAttributes) 311 } 312 } 313 if test.wantEdgeAttributes != nil { 314 var paths []string 315 for _, e := range got.Edges { 316 paths = attrPaths(paths, "", e.Data.Attributes) 317 } 318 gotAttrs := make(map[string]bool) 319 for _, p := range paths { 320 gotAttrs[p] = true 321 } 322 if !reflect.DeepEqual(gotAttrs, test.wantEdgeAttributes) { 323 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, gotAttrs, test.wantEdgeAttributes) 324 } 325 } 326 } 327 } 328 329 func TestMarshalNodeEdge(t *testing.T) { 330 for _, test := range cytoscapejsNodeEdgeTests { 331 data, err := os.ReadFile(filepath.Join("testdata", test.path)) 332 if err != nil { 333 t.Errorf("failed to read %q: %v", test.path, err) 334 continue 335 } 336 var want Elements 337 err = json.Unmarshal(data, &want) 338 if err != nil { 339 t.Errorf("failed to unmarshal %q: %v", test.path, err) 340 continue 341 } 342 marshaled, err := json.Marshal(want) 343 if err != nil { 344 t.Errorf("failed to unmarshal %q: %v", test.path, err) 345 continue 346 } 347 var got Elements 348 err = json.Unmarshal(marshaled, &got) 349 if err != nil { 350 t.Errorf("failed to unmarshal %q: %v", test.path, err) 351 continue 352 } 353 if !reflect.DeepEqual(got, want) { 354 t.Errorf("unexpected result for %q:\ngot:\n%#v\nwant:\n%#v", test.path, got, want) 355 } 356 } 357 } 358 359 func attrPaths(dst []string, prefix string, m map[string]interface{}) []string { 360 for k, v := range m { 361 path := prefix 362 if path != "" { 363 path += "." 364 } 365 if v, ok := v.(map[string]interface{}); ok { 366 dst = attrPaths(dst, path+k, v) 367 } 368 dst = append(dst, path+k) 369 } 370 return dst 371 }