// 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) } } } }