1
exercism fetch go matrix

matrix_test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// 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:
			var _ error = err
			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)
			}
		}
	}
}