exercism/go/matrix/matrix_test.go

266 lines
5.4 KiB
Go

// For the Matrix exercise in Go you have to do a few things not mentioned
// in the README.
//
// 1. You must implement a constructor and methods Rows() and Cols() as
// described in the README, but Rows() and Cols must return results that
// are independent from the original matrix. That is, you should be able
// to do as you please with the results without affecting the matrix.
//
// 2. You must implement a method Set(row, col, val) for setting a matrix
// element.
//
// 3. As usual in Go, you must detect and return error conditions.
package matrix
import (
"reflect"
"testing"
)
var tests = []struct {
in string
ok bool
rows [][]int
cols [][]int
}{
{"1 2\n10 20",
true,
[][]int{
{1, 2},
{10, 20},
},
[][]int{
{1, 10},
{2, 20},
},
},
{"9 7\n8 6",
true,
[][]int{
{9, 7},
{8, 6},
},
[][]int{
{9, 8},
{7, 6},
},
},
{"9 8 7\n19 18 17",
true,
[][]int{
{9, 8, 7},
{19, 18, 17},
},
[][]int{
{9, 19},
{8, 18},
{7, 17},
},
},
{"1 4 9\n16 25 36",
true,
[][]int{
{1, 4, 9},
{16, 25, 36},
},
[][]int{
{1, 16},
{4, 25},
{9, 36},
},
},
{"1 2 3\n4 5 6\n7 8 9\n 8 7 6",
true,
[][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{8, 7, 6},
},
[][]int{
{1, 4, 7, 8},
{2, 5, 8, 7},
{3, 6, 9, 6},
},
},
{"89 1903 3\n18 3 1\n9 4 800",
true,
[][]int{
{89, 1903, 3},
{18, 3, 1},
{9, 4, 800},
},
[][]int{
{89, 18, 9},
{1903, 3, 4},
{3, 1, 800},
},
},
{"1 2 3", // valid, 1 row, 3 columns
true,
[][]int{
{1, 2, 3},
},
[][]int{
{1},
{2},
{3},
},
},
{"1\n2\n3", // valid, 3 rows, 1 column
true,
[][]int{
{1},
{2},
{3},
},
[][]int{
{1, 2, 3},
},
},
{"0", // valid, 1 row, 1 column
true,
[][]int{
{0},
},
[][]int{
{0},
},
},
{"9223372036854775808", false, nil, nil}, // overflows int64
{"1 2\n10 20 30", false, nil, nil}, // uneven rows
{"\n3 4\n5 6", false, nil, nil}, // first row empty
{"1 2\n\n5 6", false, nil, nil}, // middle row empty
{"1 2\n3 4\n", false, nil, nil}, // last row empty
{"2.7", false, nil, nil}, // non-int
{"cat", false, nil, nil}, // non-numeric
// undefined
// {"\n\n", // valid?, 3 rows, 0 columns
// {"", // valid?, 0 rows, 0 columns
}
func TestNew(t *testing.T) {
for _, test := range tests {
m, err := New(test.in)
switch {
case err != nil:
if test.ok {
t.Fatalf("New(%q) returned error %q. Error not expected",
test.in, err)
}
case !test.ok:
t.Fatalf("New(%q) = %v, %v. Expected non-nil error.",
test.in, m, err)
case m == nil:
t.Fatalf("New(%q) = %v, want non-nil *Matrix",
test.in, m)
}
}
}
func TestRows(t *testing.T) {
for _, test := range tests {
if !test.ok {
continue
}
m, err := New(test.in)
if err != nil {
t.Skip("Need working New for TestRows")
}
r := m.Rows()
if len(r) == 0 && len(test.rows) == 0 {
continue // agreement, and nothing more to test
}
if !reflect.DeepEqual(r, test.rows) {
t.Fatalf("New(%q).Rows() = %v, want %v", test.in, r, test.rows)
}
if len(r[0]) == 0 {
continue // not currently in test data, but anyway
}
r[0][0]++
if !reflect.DeepEqual(m.Rows(), test.rows) {
t.Fatalf("Matrix.Rows() returned slice based on Matrix " +
"representation. Want independent copy of element data.")
}
}
}
func TestCols(t *testing.T) {
for _, test := range tests {
if !test.ok {
continue
}
m, err := New(test.in)
if err != nil {
t.Skip("Need working New for TestCols")
}
c := m.Cols()
if len(c) == 0 && len(test.cols) == 0 {
continue // agreement, and nothing more to test
}
if !reflect.DeepEqual(c, test.cols) {
t.Fatalf("New(%q).Cols() = %v, want %v", test.in, c, test.cols)
}
if len(c[0]) == 0 {
continue // not currently in test data, but anyway
}
c[0][0]++
if !reflect.DeepEqual(m.Cols(), test.cols) {
t.Fatalf("Matrix.Cols() returned slice based on Matrix " +
"representation. Want independent copy of element data.")
}
}
}
func TestSet(t *testing.T) {
s := "1 2 3\n4 5 6\n7 8 9"
m, err := New(s)
if err != nil {
t.Skip("Need working New for TestSet")
}
xr := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
if !reflect.DeepEqual(m.Rows(), xr) {
t.Skip("Need working Rows for TestSet")
}
xc := [][]int{{1, 4, 7}, {2, 5, 8}, {3, 6, 9}}
if !reflect.DeepEqual(m.Cols(), xc) {
t.Skip("Need working Cols for TestSet")
}
// test each corner, each side, and an interior element
for r := 0; r < 3; r++ {
for c := 0; c < 3; c++ {
m, _ = New(s)
val := 10 + r*3 + c
if ok := m.Set(r, c, val); !ok {
t.Fatalf("Matrix(%q).Set(%d, %d, %d) returned !ok, want ok.",
s, r, c, val)
}
xr = [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
xc = [][]int{{1, 4, 7}, {2, 5, 8}, {3, 6, 9}}
xr[r][c] = val
xc[c][r] = val
if res := m.Rows(); !reflect.DeepEqual(res, xr) {
t.Fatalf("Matrix(%q).Set(%d, %d, %d), Rows() = %v, want %v",
s, r, c, val, res, xr)
}
if res := m.Cols(); !reflect.DeepEqual(res, xc) {
t.Fatalf("Matrix(%q).Set(%d, %d, %d), Cols() = %v, want %v",
s, r, c, val, res, xc)
}
}
}
// test 1 and 2 off each corner and side
m, _ = New(s)
for _, r := range []int{-2, -1, 0, 3, 4} {
for _, c := range []int{-2, -1, 0, 3, 4} {
if r == 0 && c == 0 {
continue
}
if ok := m.Set(r, c, 0); ok {
t.Fatalf("Matrix(%q).Set(%d, %d, 0) = ok, want !ok", s, r, c)
}
}
}
}