github.com/gopherd/gonum@v0.0.4/graph/formats/dot/internal/parser/parser_test.go (about) 1 // This file is dual licensed under CC0 and The Gonum License. 2 // 3 // Copyright ©2017 The Gonum Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 // 7 // Copyright ©2017 Robin Eklind. 8 // This file is made available under a Creative Commons CC0 1.0 9 // Universal Public Domain Dedication. 10 11 package parser_test 12 13 import ( 14 "archive/zip" 15 "bytes" 16 "os" 17 "testing" 18 19 "github.com/gopherd/gonum/graph/formats/dot" 20 ) 21 22 func TestParseFile(t *testing.T) { 23 golden := []struct { 24 in string 25 out string 26 }{ 27 {in: "../testdata/empty.dot"}, 28 {in: "../testdata/graph.dot"}, 29 {in: "../testdata/digraph.dot"}, 30 {in: "../testdata/strict.dot"}, 31 {in: "../testdata/multi.dot"}, 32 {in: "../testdata/named_graph.dot"}, 33 {in: "../testdata/node_stmt.dot"}, 34 {in: "../testdata/edge_stmt.dot"}, 35 {in: "../testdata/attr_stmt.dot"}, 36 {in: "../testdata/attr.dot"}, 37 { 38 in: "../testdata/subgraph.dot", 39 out: "../testdata/subgraph.golden", 40 }, 41 { 42 in: "../testdata/semi.dot", 43 out: "../testdata/semi.golden", 44 }, 45 { 46 in: "../testdata/empty_attr.dot", 47 out: "../testdata/empty_attr.golden", 48 }, 49 { 50 in: "../testdata/attr_lists.dot", 51 out: "../testdata/attr_lists.golden", 52 }, 53 { 54 in: "../testdata/attr_sep.dot", 55 out: "../testdata/attr_sep.golden", 56 }, 57 {in: "../testdata/subgraph_vertex.dot"}, 58 {in: "../testdata/port.dot"}, 59 {in: "../testdata/quoted_id.dot"}, 60 { 61 in: "../testdata/backslash_newline_id.dot", 62 out: "../testdata/backslash_newline_id.golden", 63 }, 64 } 65 for _, g := range golden { 66 file, err := dot.ParseFile(g.in) 67 if err != nil { 68 t.Errorf("%q: unable to parse file; %v", g.in, err) 69 continue 70 } 71 // If no output path is specified, the input is already golden. 72 out := g.in 73 if len(g.out) > 0 { 74 out = g.out 75 } 76 buf, err := os.ReadFile(out) 77 if err != nil { 78 t.Errorf("%q: unable to read file; %v", g.in, err) 79 continue 80 } 81 got := file.String() 82 // Remove trailing newline. 83 want := string(bytes.TrimSpace(buf)) 84 if got != want { 85 t.Errorf("%q: graph mismatch; expected `%s`, got `%s`", g.in, want, got) 86 } 87 } 88 } 89 90 func TestParseFuzz(t *testing.T) { 91 r, err := zip.OpenReader("../../fuzz/corpus.zip") 92 if err != nil { 93 if os.IsNotExist(err) { 94 t.Skip("no corpus") 95 } 96 t.Fatalf("failed to open corpus: %v", err) 97 } 98 defer r.Close() 99 100 for _, f := range r.File { 101 rc, err := f.Open() 102 if err != nil { 103 t.Fatalf("failed to open %q: %v", f.Name, err) 104 } 105 func() { 106 defer func() { 107 p := recover() 108 if p != nil { 109 t.Errorf("unexpected panic parsing %q: %v", f.Name, p) 110 } 111 }() 112 113 _, err = dot.Parse(rc) 114 if err != nil { 115 t.Errorf("unexpected error parsing %q: %v", f.Name, err) 116 } 117 }() 118 rc.Close() 119 } 120 } 121 122 func TestParseError(t *testing.T) { 123 golden := []struct { 124 path string 125 want string 126 }{ 127 { 128 path: "../testdata/error.dot", 129 want: `Error in S30: INVALID(0,~), Pos(offset=13, line=2, column=7), expected one of: { } graphx ; -- -> node edge [ = subgraph : id `, 130 }, 131 } 132 for _, g := range golden { 133 _, err := dot.ParseFile(g.path) 134 if err == nil { 135 t.Errorf("%q: expected error, got nil", g.path) 136 continue 137 } 138 got := err.Error() 139 if got != g.want { 140 t.Errorf("%q: error mismatch; expected `%v`, got `%v`", g.path, g.want, got) 141 continue 142 } 143 } 144 }