gonum.org/v1/gonum@v0.14.0/graph/path/internal/testgraphs/grid_test.go (about)

     1  // Copyright ©2014 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 testgraphs
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  
    14  	"gonum.org/v1/gonum/graph"
    15  	"gonum.org/v1/gonum/graph/simple"
    16  )
    17  
    18  var _ graph.Graph = (*Grid)(nil)
    19  
    20  func join(g ...string) string { return strings.Join(g, "\n") }
    21  
    22  type node int64
    23  
    24  func (n node) ID() int64 { return int64(n) }
    25  
    26  func TestGrid(t *testing.T) {
    27  	t.Parallel()
    28  	g := NewGrid(4, 4, false)
    29  
    30  	got := g.String()
    31  	want := join(
    32  		"****",
    33  		"****",
    34  		"****",
    35  		"****",
    36  	)
    37  	if got != want {
    38  		t.Fatalf("unexpected grid rendering:\ngot: %q\nwant:%q", got, want)
    39  	}
    40  
    41  	var ops = []struct {
    42  		r, c  int
    43  		state bool
    44  		want  string
    45  	}{
    46  		{
    47  			r: 0, c: 1,
    48  			state: true,
    49  			want: join(
    50  				"*.**",
    51  				"****",
    52  				"****",
    53  				"****",
    54  			),
    55  		},
    56  		{
    57  			r: 0, c: 1,
    58  			state: false,
    59  			want: join(
    60  				"****",
    61  				"****",
    62  				"****",
    63  				"****",
    64  			),
    65  		},
    66  		{
    67  			r: 0, c: 1,
    68  			state: true,
    69  			want: join(
    70  				"*.**",
    71  				"****",
    72  				"****",
    73  				"****",
    74  			),
    75  		},
    76  		{
    77  			r: 0, c: 2,
    78  			state: true,
    79  			want: join(
    80  				"*..*",
    81  				"****",
    82  				"****",
    83  				"****",
    84  			),
    85  		},
    86  		{
    87  			r: 1, c: 2,
    88  			state: true,
    89  			want: join(
    90  				"*..*",
    91  				"**.*",
    92  				"****",
    93  				"****",
    94  			),
    95  		},
    96  		{
    97  			r: 2, c: 2,
    98  			state: true,
    99  			want: join(
   100  				"*..*",
   101  				"**.*",
   102  				"**.*",
   103  				"****",
   104  			),
   105  		},
   106  		{
   107  			r: 3, c: 2,
   108  			state: true,
   109  			want: join(
   110  				"*..*",
   111  				"**.*",
   112  				"**.*",
   113  				"**.*",
   114  			),
   115  		},
   116  	}
   117  	for _, test := range ops {
   118  		g.Set(test.r, test.c, test.state)
   119  		got := g.String()
   120  		if got != test.want {
   121  			t.Fatalf("unexpected grid rendering after set (%d, %d) open state to %t:\ngot: %q\nwant:%q",
   122  				test.r, test.c, test.state, got, test.want)
   123  		}
   124  	}
   125  
   126  	// Match the last state from the loop against the
   127  	// explicit description of the grid.
   128  	got = NewGridFrom(
   129  		"*..*",
   130  		"**.*",
   131  		"**.*",
   132  		"**.*",
   133  	).String()
   134  	want = g.String()
   135  	if got != want {
   136  		t.Fatalf("unexpected grid rendering from NewGridFrom:\ngot: %q\nwant:%q", got, want)
   137  	}
   138  
   139  	var paths = []struct {
   140  		path     []graph.Node
   141  		diagonal bool
   142  		want     string
   143  	}{
   144  		{
   145  			path:     nil,
   146  			diagonal: false,
   147  			want: join(
   148  				"*..*",
   149  				"**.*",
   150  				"**.*",
   151  				"**.*",
   152  			),
   153  		},
   154  		{
   155  			path:     []graph.Node{node(1), node(2), node(6), node(10), node(14)},
   156  			diagonal: false,
   157  			want: join(
   158  				"*So*",
   159  				"**o*",
   160  				"**o*",
   161  				"**G*",
   162  			),
   163  		},
   164  		{
   165  			path:     []graph.Node{node(1), node(6), node(10), node(14)},
   166  			diagonal: false,
   167  			want: join(
   168  				"*S.*",
   169  				"**!*",
   170  				"**.*",
   171  				"**.*",
   172  			),
   173  		},
   174  		{
   175  			path:     []graph.Node{node(1), node(6), node(10), node(14)},
   176  			diagonal: true,
   177  			want: join(
   178  				"*S.*",
   179  				"**o*",
   180  				"**o*",
   181  				"**G*",
   182  			),
   183  		},
   184  		{
   185  			path:     []graph.Node{node(1), node(5), node(9)},
   186  			diagonal: false,
   187  			want: join(
   188  				"*S.*",
   189  				"*!.*",
   190  				"**.*",
   191  				"**.*",
   192  			),
   193  		},
   194  	}
   195  	for _, test := range paths {
   196  		g.AllowDiagonal = test.diagonal
   197  		got, err := g.Render(test.path)
   198  		errored := err != nil
   199  		if bytes.Contains(got, []byte{'!'}) != errored {
   200  			t.Fatalf("unexpected error return: got:%v want:%v", err, errors.New("grid: not a path in graph"))
   201  		}
   202  		if string(got) != test.want {
   203  			t.Fatalf("unexpected grid path rendering for %v:\ngot: %q\nwant:%q", test.path, got, want)
   204  		}
   205  	}
   206  
   207  	var coords = []struct {
   208  		r, c int
   209  		id   int64
   210  	}{
   211  		{r: 0, c: 0, id: 0},
   212  		{r: 0, c: 3, id: 3},
   213  		{r: 3, c: 0, id: 12},
   214  		{r: 3, c: 3, id: 15},
   215  	}
   216  	for _, test := range coords {
   217  		if id := g.NodeAt(test.r, test.c).ID(); id != test.id {
   218  			t.Fatalf("unexpected ID for node at (%d, %d):\ngot: %d\nwant:%d", test.r, test.c, id, test.id)
   219  		}
   220  		if r, c := g.RowCol(test.id); r != test.r || c != test.c {
   221  			t.Fatalf("unexpected row/col for node %d:\ngot: (%d, %d)\nwant:(%d, %d)", test.id, r, c, test.r, test.c)
   222  		}
   223  	}
   224  
   225  	var reach = []struct {
   226  		from     graph.Node
   227  		diagonal bool
   228  		to       []graph.Node
   229  	}{
   230  		{
   231  			from:     node(0),
   232  			diagonal: false,
   233  			to:       nil,
   234  		},
   235  		{
   236  			from:     node(2),
   237  			diagonal: false,
   238  			to:       []graph.Node{simple.Node(1), simple.Node(6)},
   239  		},
   240  		{
   241  			from:     node(1),
   242  			diagonal: false,
   243  			to:       []graph.Node{simple.Node(2)},
   244  		},
   245  		{
   246  			from:     node(1),
   247  			diagonal: true,
   248  			to:       []graph.Node{simple.Node(2), simple.Node(6)},
   249  		},
   250  	}
   251  	for _, test := range reach {
   252  		g.AllowDiagonal = test.diagonal
   253  		got := graph.NodesOf(g.From(test.from.ID()))
   254  		if !reflect.DeepEqual(got, test.to) {
   255  			t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v",
   256  				test.from, test.diagonal, got, test.to)
   257  		}
   258  	}
   259  }