// Copyright ©2014 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 testgraphs import ( "bytes" "errors" "reflect" "strings" "testing" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" ) var _ graph.Graph = (*Grid)(nil) func join(g ...string) string { return strings.Join(g, "\n") } type node int64 func (n node) ID() int64 { return int64(n) } func TestGrid(t *testing.T) { t.Parallel() g := NewGrid(4, 4, false) got := g.String() want := join( "****", "****", "****", "****", ) if got != want { t.Fatalf("unexpected grid rendering:\ngot: %q\nwant:%q", got, want) } var ops = []struct { r, c int state bool want string }{ { r: 0, c: 1, state: true, want: join( "*.**", "****", "****", "****", ), }, { r: 0, c: 1, state: false, want: join( "****", "****", "****", "****", ), }, { r: 0, c: 1, state: true, want: join( "*.**", "****", "****", "****", ), }, { r: 0, c: 2, state: true, want: join( "*..*", "****", "****", "****", ), }, { r: 1, c: 2, state: true, want: join( "*..*", "**.*", "****", "****", ), }, { r: 2, c: 2, state: true, want: join( "*..*", "**.*", "**.*", "****", ), }, { r: 3, c: 2, state: true, want: join( "*..*", "**.*", "**.*", "**.*", ), }, } for _, test := range ops { g.Set(test.r, test.c, test.state) got := g.String() if got != test.want { t.Fatalf("unexpected grid rendering after set (%d, %d) open state to %t:\ngot: %q\nwant:%q", test.r, test.c, test.state, got, test.want) } } // Match the last state from the loop against the // explicit description of the grid. got = NewGridFrom( "*..*", "**.*", "**.*", "**.*", ).String() want = g.String() if got != want { t.Fatalf("unexpected grid rendering from NewGridFrom:\ngot: %q\nwant:%q", got, want) } var paths = []struct { path []graph.Node diagonal bool want string }{ { path: nil, diagonal: false, want: join( "*..*", "**.*", "**.*", "**.*", ), }, { path: []graph.Node{node(1), node(2), node(6), node(10), node(14)}, diagonal: false, want: join( "*So*", "**o*", "**o*", "**G*", ), }, { path: []graph.Node{node(1), node(6), node(10), node(14)}, diagonal: false, want: join( "*S.*", "**!*", "**.*", "**.*", ), }, { path: []graph.Node{node(1), node(6), node(10), node(14)}, diagonal: true, want: join( "*S.*", "**o*", "**o*", "**G*", ), }, { path: []graph.Node{node(1), node(5), node(9)}, diagonal: false, want: join( "*S.*", "*!.*", "**.*", "**.*", ), }, } for _, test := range paths { g.AllowDiagonal = test.diagonal got, err := g.Render(test.path) errored := err != nil if bytes.Contains(got, []byte{'!'}) != errored { t.Fatalf("unexpected error return: got:%v want:%v", err, errors.New("grid: not a path in graph")) } if string(got) != test.want { t.Fatalf("unexpected grid path rendering for %v:\ngot: %q\nwant:%q", test.path, got, want) } } var coords = []struct { r, c int id int64 }{ {r: 0, c: 0, id: 0}, {r: 0, c: 3, id: 3}, {r: 3, c: 0, id: 12}, {r: 3, c: 3, id: 15}, } for _, test := range coords { if id := g.NodeAt(test.r, test.c).ID(); id != test.id { t.Fatalf("unexpected ID for node at (%d, %d):\ngot: %d\nwant:%d", test.r, test.c, id, test.id) } if r, c := g.RowCol(test.id); r != test.r || c != test.c { t.Fatalf("unexpected row/col for node %d:\ngot: (%d, %d)\nwant:(%d, %d)", test.id, r, c, test.r, test.c) } } var reach = []struct { from graph.Node diagonal bool to []graph.Node }{ { from: node(0), diagonal: false, to: nil, }, { from: node(2), diagonal: false, to: []graph.Node{simple.Node(1), simple.Node(6)}, }, { from: node(1), diagonal: false, to: []graph.Node{simple.Node(2)}, }, { from: node(1), diagonal: true, to: []graph.Node{simple.Node(2), simple.Node(6)}, }, } for _, test := range reach { g.AllowDiagonal = test.diagonal got := graph.NodesOf(g.From(test.from.ID())) if !reflect.DeepEqual(got, test.to) { t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v", test.from, test.diagonal, got, test.to) } } }