gonum.org/v1/gonum@v0.14.0/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  	"gonum.org/v1/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: `2:7: error: expected one of "{", "}", graphx, ";", "--", "->", node, edge, "[", "=", subgraph, ":", or id; got: unknown/invalid token "~"`,
   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 %#q, got %#q", g.path, g.want, got)
   141  			continue
   142  		}
   143  	}
   144  }