matrix_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /**
  2. * Unit tests for Matrix
  3. *
  4. * Copyright 2015, Klaus Post
  5. * Copyright 2015, Backblaze, Inc. All rights reserved.
  6. */
  7. package reedsolomon
  8. import (
  9. "testing"
  10. )
  11. // TestNewMatrix - Tests validate the result for invalid input and the allocations made by newMatrix method.
  12. func TestNewMatrix(t *testing.T) {
  13. testCases := []struct {
  14. rows int
  15. columns int
  16. // flag to indicate whether the test should pass.
  17. shouldPass bool
  18. expectedResult matrix
  19. expectedErr error
  20. }{
  21. // Test case - 1.
  22. // Test case with a negative row size.
  23. {-1, 10, false, nil, errInvalidRowSize},
  24. // Test case - 2.
  25. // Test case with a negative column size.
  26. {10, -1, false, nil, errInvalidColSize},
  27. // Test case - 3.
  28. // Test case with negative value for both row and column size.
  29. {-1, -1, false, nil, errInvalidRowSize},
  30. // Test case - 4.
  31. // Test case with 0 value for row size.
  32. {0, 10, false, nil, errInvalidRowSize},
  33. // Test case - 5.
  34. // Test case with 0 value for column size.
  35. {-1, 0, false, nil, errInvalidRowSize},
  36. // Test case - 6.
  37. // Test case with 0 value for both row and column size.
  38. {0, 0, false, nil, errInvalidRowSize},
  39. }
  40. for i, testCase := range testCases {
  41. actualResult, actualErr := newMatrix(testCase.rows, testCase.columns)
  42. if actualErr != nil && testCase.shouldPass {
  43. t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, actualErr.Error())
  44. }
  45. if actualErr == nil && !testCase.shouldPass {
  46. t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead.", i+1, testCase.expectedErr)
  47. }
  48. // Failed as expected, but does it fail for the expected reason.
  49. if actualErr != nil && !testCase.shouldPass {
  50. if testCase.expectedErr != actualErr {
  51. t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead.", i+1, testCase.expectedErr, actualErr)
  52. }
  53. }
  54. // Test passes as expected, but the output values
  55. // are verified for correctness here.
  56. if actualErr == nil && testCase.shouldPass {
  57. if testCase.rows != len(actualResult) {
  58. // End the tests here if the the size doesn't match number of rows.
  59. t.Fatalf("Test %d: Expected the size of the row of the new matrix to be `%d`, but instead found `%d`", i+1, testCase.rows, len(actualResult))
  60. }
  61. // Iterating over each row and validating the size of the column.
  62. for j, row := range actualResult {
  63. // If the row check passes, verify the size of each columns.
  64. if testCase.columns != len(row) {
  65. t.Errorf("Test %d: Row %d: Expected the size of the column of the new matrix to be `%d`, but instead found `%d`", i+1, j+1, testCase.columns, len(row))
  66. }
  67. }
  68. }
  69. }
  70. }
  71. // TestMatrixIdentity - validates the method for returning identity matrix of given size.
  72. func TestMatrixIdentity(t *testing.T) {
  73. m, err := identityMatrix(3)
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. str := m.String()
  78. expect := "[[1, 0, 0], [0, 1, 0], [0, 0, 1]]"
  79. if str != expect {
  80. t.Fatal(str, "!=", expect)
  81. }
  82. }
  83. // Tests validate the output of matrix multiplication method.
  84. func TestMatrixMultiply(t *testing.T) {
  85. m1, err := newMatrixData(
  86. [][]byte{
  87. []byte{1, 2},
  88. []byte{3, 4},
  89. })
  90. if err != nil {
  91. t.Fatal(err)
  92. }
  93. m2, err := newMatrixData(
  94. [][]byte{
  95. []byte{5, 6},
  96. []byte{7, 8},
  97. })
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. actual, err := m1.Multiply(m2)
  102. if err != nil {
  103. t.Fatal(err)
  104. }
  105. str := actual.String()
  106. expect := "[[11, 22], [19, 42]]"
  107. if str != expect {
  108. t.Fatal(str, "!=", expect)
  109. }
  110. }
  111. // Tests validate the output of the method with computes inverse of matrix.
  112. func TestMatrixInverse(t *testing.T) {
  113. testCases := []struct {
  114. matrixData [][]byte
  115. // expected inverse matrix.
  116. expectedResult string
  117. // flag indicating whether the test should pass.
  118. shouldPass bool
  119. expectedErr error
  120. }{
  121. // Test case - 1.
  122. // Test case validating inverse of the input Matrix.
  123. {
  124. // input data to construct the matrix.
  125. [][]byte{
  126. []byte{56, 23, 98},
  127. []byte{3, 100, 200},
  128. []byte{45, 201, 123},
  129. },
  130. // expected Inverse matrix.
  131. "[[175, 133, 33], [130, 13, 245], [112, 35, 126]]",
  132. // test is expected to pass.
  133. true,
  134. nil,
  135. },
  136. // Test case - 2.
  137. // Test case validating inverse of the input Matrix.
  138. {
  139. // input data to construct the matrix.
  140. [][]byte{
  141. []byte{1, 0, 0, 0, 0},
  142. []byte{0, 1, 0, 0, 0},
  143. []byte{0, 0, 0, 1, 0},
  144. []byte{0, 0, 0, 0, 1},
  145. []byte{7, 7, 6, 6, 1},
  146. },
  147. // expectedInverse matrix.
  148. "[[1, 0, 0, 0, 0]," +
  149. " [0, 1, 0, 0, 0]," +
  150. " [123, 123, 1, 122, 122]," +
  151. " [0, 0, 1, 0, 0]," +
  152. " [0, 0, 0, 1, 0]]",
  153. // test is expected to pass.
  154. true,
  155. nil,
  156. },
  157. // Test case with a non-square matrix.
  158. // expected to fail with errNotSquare.
  159. {
  160. [][]byte{
  161. []byte{56, 23},
  162. []byte{3, 100},
  163. []byte{45, 201},
  164. },
  165. "",
  166. false,
  167. errNotSquare,
  168. },
  169. // Test case with singular matrix.
  170. // expected to fail with error errSingular.
  171. {
  172. [][]byte{
  173. []byte{4, 2},
  174. []byte{12, 6},
  175. },
  176. "",
  177. false,
  178. errSingular,
  179. },
  180. }
  181. for i, testCase := range testCases {
  182. m, err := newMatrixData(testCase.matrixData)
  183. if err != nil {
  184. t.Fatalf("Test %d: Failed initializing new Matrix : %s", i+1, err)
  185. }
  186. actualResult, actualErr := m.Invert()
  187. if actualErr != nil && testCase.shouldPass {
  188. t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, actualErr.Error())
  189. }
  190. if actualErr == nil && !testCase.shouldPass {
  191. t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead.", i+1, testCase.expectedErr)
  192. }
  193. // Failed as expected, but does it fail for the expected reason.
  194. if actualErr != nil && !testCase.shouldPass {
  195. if testCase.expectedErr != actualErr {
  196. t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead.", i+1, testCase.expectedErr, actualErr)
  197. }
  198. }
  199. // Test passes as expected, but the output values
  200. // are verified for correctness here.
  201. if actualErr == nil && testCase.shouldPass {
  202. if testCase.expectedResult != actualResult.String() {
  203. t.Errorf("Test %d: The inverse matrix doesn't match the expected result", i+1)
  204. }
  205. }
  206. }
  207. }