Line data Source code
1 : #include <gmock/gmock.h>
2 : #include <gtest/gtest.h>
3 :
4 : #include <cfloat>
5 : #include <initializer_list>
6 : #include <iostream>
7 : #include <vector>
8 :
9 : #include "matrix.hpp"
10 :
11 : #define DOUBLE_NEAR(x) DoubleNear((x), DBL_EPSILON)
12 :
13 : using namespace testing;
14 : using namespace std;
15 :
16 : class TestThatMatrix : public Test
17 : {
18 : public:
19 : int m{3}, n{5};
20 : std::unique_ptr<matrix<double>> smart{nullptr};
21 : matrix<double>* A{nullptr};
22 :
23 23 : void SetUp() override
24 : {
25 23 : smart.reset(new matrix<double>(m, n, vector<double>(m * n, 0.0)));
26 23 : A = smart.get();
27 23 : }
28 :
29 23 : void TearDown() override {}
30 : };
31 :
32 2 : TEST_F(TestThatMatrix, CanAccessDeclaredMatrixInSetup)
33 : {
34 1 : (*A)(1, 1) = 1.0;
35 1 : (*A)(2, 2) = 1.0;
36 1 : (*A)(3, 3) = 1.0;
37 : // For testing, exercise output operator <<
38 1 : cout << "Rows [" + to_string((*A).get_rows()) + "]\n";
39 1 : cout << "A =\n" << (*A) << '\n';
40 1 : ASSERT_THAT((*A)(2, 2), DoubleEq(1.0));
41 : }
42 :
43 2 : TEST_F(TestThatMatrix, CanConstructAnUninitializedMatrixSepcifyingRowsCols)
44 : {
45 1 : ASSERT_NO_THROW(matrix<double> M(2, 2));
46 : }
47 :
48 2 : TEST_F(TestThatMatrix, ConstructorRowsColsThrowsWheneverRowsIsNegative)
49 : {
50 : // Interesting. Didn't know this was automatically taken care of by STL
51 4 : ASSERT_THROW(matrix<double> M(-1, 2), std::bad_array_new_length);
52 : }
53 :
54 2 : TEST_F(TestThatMatrix, ConstructorRowsColsThrowsWheneverRowsIsZero)
55 : {
56 4 : ASSERT_ANY_THROW(matrix<double> M(0, 2));
57 : }
58 :
59 2 : TEST_F(TestThatMatrix, ConstructorRowsColsThrowsWheneverColsIsNegative)
60 : {
61 : // Interesting. Didn't know this was automatically taken care of by STL
62 4 : ASSERT_THROW(matrix<double> M(2, -1), std::bad_array_new_length);
63 : }
64 :
65 2 : TEST_F(TestThatMatrix, ConstructorRowsColsThrowsWheneverColsIsZero)
66 : {
67 4 : ASSERT_THROW(matrix<double> M(2, 0), std::exception);
68 : }
69 :
70 2 : TEST_F(TestThatMatrix, get_rowsWorks)
71 : {
72 2 : matrix<double> M(4, 7);
73 :
74 : // Validate these getters
75 1 : EXPECT_THAT(M.get_rows(), Eq(4));
76 1 : }
77 :
78 2 : TEST_F(TestThatMatrix, get_colsWorks)
79 : {
80 2 : matrix<double> M(4, 7);
81 :
82 : // Validate these getters
83 1 : EXPECT_THAT(M.get_rows(), Eq(4));
84 1 : }
85 :
86 2 : TEST_F(TestThatMatrix,
87 : CanConstructAnUninitializedMatrixSepcifyingRowsColsANDInitialiseIt)
88 : {
89 2 : matrix<int> M(4, 7);
90 :
91 : // Must be able to modify the element to do this
92 1 : M(1, 1) = 1;
93 1 : M(1, 2) = 5;
94 1 : M(1, 3) = 9;
95 1 : M(1, 4) = 13;
96 1 : M(1, 5) = 17;
97 1 : M(1, 6) = 21;
98 1 : M(1, 7) = 25;
99 1 : M(2, 1) = 2;
100 1 : M(2, 2) = 6;
101 1 : M(2, 3) = 10;
102 1 : M(2, 4) = 14;
103 1 : M(2, 5) = 18;
104 1 : M(2, 6) = 22;
105 1 : M(2, 7) = 26;
106 1 : M(3, 1) = 3;
107 1 : M(3, 2) = 7;
108 1 : M(3, 3) = 11;
109 1 : M(3, 4) = 15;
110 1 : M(3, 5) = 19;
111 1 : M(3, 6) = 23;
112 1 : M(3, 7) = 27;
113 1 : M(4, 1) = 4;
114 1 : M(4, 2) = 8;
115 1 : M(4, 3) = 12;
116 1 : M(4, 4) = 16;
117 1 : M(4, 5) = 20;
118 1 : M(4, 6) = 24;
119 1 : M(4, 7) = 28;
120 :
121 1 : EXPECT_THAT(M.get_rows(), Eq(4));
122 1 : EXPECT_THAT(M.get_cols(), Eq(7));
123 :
124 : // Must be able to access, but not modify, the element to do this
125 8 : for (size_t j{1}; j <= M.get_cols(); j++)
126 35 : for (size_t i{1}; i <= M.get_rows(); i++)
127 28 : EXPECT_THAT(M(i, j), Eq(M.get_rows() * (j - 1) + i));
128 :
129 : // // Printing verification does work
130 : // cout << "M =\n"
131 : // << M << '\n';
132 1 : }
133 :
134 2 : TEST_F(TestThatMatrix, ImplementsCopyConstructorCorrectly)
135 : {
136 2 : matrix<double> M1(4, 2);
137 :
138 1 : M1(1, 1) = 1;
139 1 : M1(1, 2) = 5;
140 1 : M1(2, 1) = 2;
141 1 : M1(2, 2) = 6;
142 1 : M1(3, 1) = 3;
143 1 : M1(3, 2) = 7;
144 1 : M1(4, 1) = 4;
145 1 : M1(4, 2) = 8;
146 :
147 : // Test that matrix inputed and retrieved correctly
148 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
149 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
150 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
151 :
152 : // Test the copy constructor
153 2 : matrix<double> M2{M1};
154 :
155 : // Test that matrix M1 hasn't changed
156 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
157 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
158 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
159 :
160 : // Test that matrix M2 equals M1 (Copy performed correctly)
161 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
162 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
163 8 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
164 :
165 : // Test that copies are independent, the default copy constructor overridden
166 1 : M2(1, 2) = 3;
167 :
168 : // Test that matrix M1 hasn't changed
169 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
170 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
171 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
172 :
173 : // Test that matrix M2 has 3 in correct position
174 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
175 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
176 8 : if (i == 1 and j == 2)
177 : {
178 1 : EXPECT_THAT(M2(i, j), Eq(3));
179 : }
180 : else
181 : {
182 7 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
183 : }
184 1 : }
185 :
186 2 : TEST_F(TestThatMatrix, ImplementsCopyAssignmentCorrectly)
187 : {
188 2 : matrix<double> M1(4, 2);
189 :
190 1 : M1(1, 1) = 1;
191 1 : M1(1, 2) = 5;
192 1 : M1(2, 1) = 2;
193 1 : M1(2, 2) = 6;
194 1 : M1(3, 1) = 3;
195 1 : M1(3, 2) = 7;
196 1 : M1(4, 1) = 4;
197 1 : M1(4, 2) = 8;
198 :
199 : // Test that matrix inputed and retrieved correctly
200 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
201 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
202 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
203 :
204 : // Test the copy constructor
205 2 : matrix<double> M2(4, 2);
206 :
207 : // If quick return doesn't work, them no code coverage! No Idea how else to
208 : // test this.
209 1 : M1 = M1;
210 :
211 1 : M2 = M1;
212 :
213 : // Test that matrix M1 hasn't changed
214 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
215 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
216 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
217 :
218 : // Test that matrix M2 equals M1 (Copy performed correctly)
219 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
220 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
221 8 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
222 :
223 : // Test that copies are independent, the default copy constructor overridden
224 1 : M2(2, 1) = 4;
225 :
226 : // Test that matrix M1 hasn't changed
227 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
228 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
229 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
230 :
231 : // Test that matrix M2 has 3 in correct position
232 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
233 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
234 8 : if (i == 2 and j == 1)
235 : {
236 1 : EXPECT_THAT(M2(i, j), Eq(4));
237 : }
238 : else
239 : {
240 7 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
241 : }
242 1 : }
243 :
244 2 : TEST_F(TestThatMatrix, ImplementsMoveConstructorCorrectly)
245 : {
246 2 : matrix<double> M1(4, 2);
247 :
248 1 : M1(1, 1) = 1;
249 1 : M1(1, 2) = 5;
250 1 : M1(2, 1) = 2;
251 1 : M1(2, 2) = 6;
252 1 : M1(3, 1) = 3;
253 1 : M1(3, 2) = 7;
254 1 : M1(4, 1) = 4;
255 1 : M1(4, 2) = 8;
256 :
257 : // Test that matrix inputed and retrieved correctly
258 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
259 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
260 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
261 :
262 : // Test the Move constructor. Move is from smart pointer?
263 2 : matrix<double> M2 = move(M1);
264 :
265 : // Test that matrix M1 hasn't changed
266 1 : EXPECT_THAT(M1.get_cols(), Eq(0));
267 1 : EXPECT_THAT(M1.get_rows(), Eq(0));
268 1 : EXPECT_EQ(&M1(1, 1), nullptr);
269 :
270 : // Test that matrix M2 equals old M1 (Move performed correctly)
271 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
272 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
273 8 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
274 :
275 : // Test that copies are independent, the default copy constructor overridden
276 1 : M2(1, 1) = 5;
277 :
278 : // Test that matrix M2 has 5 in correct position
279 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
280 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
281 8 : if (i == 1 and j == 1)
282 : {
283 1 : EXPECT_THAT(M2(i, j), Eq(5));
284 : }
285 : else
286 : {
287 7 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
288 : }
289 1 : }
290 :
291 2 : TEST_F(TestThatMatrix, ImplementsMoveAssignmentCorrectly)
292 : {
293 2 : matrix<double> M1(4, 2);
294 :
295 1 : M1(1, 1) = 1;
296 1 : M1(1, 2) = 5;
297 1 : M1(2, 1) = 2;
298 1 : M1(2, 2) = 6;
299 1 : M1(3, 1) = 3;
300 1 : M1(3, 2) = 7;
301 1 : M1(4, 1) = 4;
302 1 : M1(4, 2) = 8;
303 :
304 : // Test that matrix inputed and retrieved correctly
305 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
306 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
307 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
308 :
309 : // Test the Move constructor. Move is from smart pointer?
310 2 : matrix<double> M2(4, 2);
311 :
312 : // If quick return doesn't work, them matrix erases itself and this test
313 : // cannot pass.
314 1 : M1 = move(M1);
315 :
316 : // Test that matrix inputed and retrieved correctly
317 3 : for (size_t j{1}; j <= M1.get_cols(); j++)
318 10 : for (size_t i{1}; i <= M1.get_rows(); i++)
319 8 : EXPECT_THAT(M1(i, j), Eq(M1.get_rows() * (j - 1) + i));
320 :
321 1 : M2 = move(M1);
322 :
323 : // Test that matrix M1 hasn't changed
324 1 : EXPECT_THAT(M1.get_cols(), Eq(0));
325 1 : EXPECT_THAT(M1.get_rows(), Eq(0));
326 1 : EXPECT_EQ(&M1(1, 1), nullptr);
327 :
328 : // Test that matrix M2 equals old M1 (Move performed correctly)
329 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
330 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
331 8 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
332 :
333 : // Test that copies are independent, the default copy constructor overridden
334 1 : M2(1, 1) = 5;
335 :
336 : // Test that matrix M2 has 5 in correct position
337 3 : for (size_t j{1}; j <= M2.get_cols(); j++)
338 10 : for (size_t i{1}; i <= M2.get_rows(); i++)
339 8 : if (i == 1 and j == 1)
340 : {
341 1 : EXPECT_THAT(M2(i, j), Eq(5));
342 : }
343 : else
344 : {
345 7 : EXPECT_THAT(M2(i, j), Eq(M2.get_rows() * (j - 1) + i));
346 : }
347 1 : }
348 :
349 2 : TEST_F(TestThatMatrix, CannotDoCopyAssignmentWheneverDimensionsDonotAgree)
350 : {
351 1 : matrix<double> M1(4, 2);
352 1 : matrix<double> M2(2, 4);
353 :
354 2 : ASSERT_THROW(M1 = M2, std::exception);
355 : }
356 :
357 2 : TEST_F(TestThatMatrix, CannotDoMoveAssignmentWheneverDimensionsDonotAgree)
358 : {
359 1 : matrix<double> M1(4, 2);
360 1 : matrix<double> M2(2, 4);
361 :
362 2 : ASSERT_THROW(M1 = move(M2), std::exception);
363 : }
364 :
365 2 : TEST_F(TestThatMatrix, HasDiagonalMatrixConstructorWithVector)
366 : {
367 2 : std::vector<int> v{1, 2, 3};
368 2 : matrix<int> M(v);
369 :
370 1 : EXPECT_THAT(M.get_cols(), Eq(v.size()));
371 1 : EXPECT_THAT(M.get_rows(), Eq(v.size()));
372 :
373 4 : for (size_t j{1}; j <= M.get_cols(); j++)
374 12 : for (size_t i{1}; i <= M.get_rows(); i++)
375 9 : if (i == j)
376 : {
377 3 : EXPECT_THAT(M(i, j), Eq(v[ i - 1 ]));
378 : }
379 : else
380 : {
381 6 : EXPECT_THAT(M(i, j), Eq(0));
382 : }
383 1 : }
384 :
385 2 : TEST_F(TestThatMatrix, HasDiagonalMatrixConstructorWithInitializerList)
386 : {
387 2 : std::vector<int> v{1, 2, 3, 4};
388 2 : matrix<int> M{1, 2, 3, 4};
389 :
390 1 : EXPECT_THAT(M.get_cols(), Eq(v.size()));
391 1 : EXPECT_THAT(M.get_rows(), Eq(v.size()));
392 :
393 5 : for (size_t j{1}; j <= M.get_cols(); j++)
394 20 : for (size_t i{1}; i <= M.get_rows(); i++)
395 16 : if (i == j)
396 : {
397 4 : EXPECT_THAT(M(i, j), Eq(v[ i - 1 ]));
398 : }
399 : else
400 : {
401 12 : EXPECT_THAT(M(i, j), Eq(0));
402 : }
403 1 : }
404 :
405 2 : TEST_F(TestThatMatrix, ThrowErrorForFullMatrixConstructorWithMEqualZero)
406 : {
407 2 : vector<int> v{1, 2, 3, 4, 5};
408 1 : EXPECT_THAT(v.size(), Eq(n));
409 1 : EXPECT_THAT(n, Gt(0));
410 4 : EXPECT_THROW(matrix<int> M(0, n, v), std::exception);
411 : //// Printing verification does work: Connot get here due to constructor throw
412 : // cout << "M =\n"
413 : // << M << '\n';
414 1 : }
415 :
416 2 : TEST_F(TestThatMatrix, ThrowErrorForFullMatrixConstructorWithNEqualZero)
417 : {
418 2 : vector<int> v{1, 2, 3};
419 1 : EXPECT_THAT(v.size(), Eq(m));
420 1 : EXPECT_THAT(m, Gt(0));
421 4 : EXPECT_THROW(matrix<int> M(m, 0, v), std::exception);
422 : //// Printing verification does work: Connot get here due to constructor throw
423 : // cout << "M =\n"
424 : // << M << '\n';
425 1 : }
426 :
427 2 : TEST_F(
428 : TestThatMatrix,
429 : ThrowErrorForFullMatrixConstructorWithVectorOfSizeZeroAndMTimeNIsPositive)
430 : {
431 2 : vector<int> v{};
432 1 : EXPECT_THAT(v.size(), Eq(0));
433 1 : EXPECT_THAT(m, Gt(0));
434 1 : EXPECT_THAT(n, Gt(0));
435 4 : EXPECT_THROW(matrix<int> M(m, n, v), std::exception);
436 1 : }
437 :
438 2 : TEST_F(TestThatMatrix,
439 : ThrowErrorForFullMatrixConstructorWithVectorOfSizeNotEqualToMByN)
440 : {
441 2 : vector<int> v((m + 1) * n);
442 1 : EXPECT_THAT(v.size(), Eq((m + 1) * n));
443 4 : EXPECT_THROW(matrix<int> M(m, n, v), std::exception);
444 1 : }
445 :
446 2 : TEST_F(TestThatMatrix, HasFullMatrixConstructorWithVector)
447 : {
448 2 : matrix<int> M(2, 3, vector<int>{1, 2, 3, 4, 5, 6});
449 :
450 1 : EXPECT_THAT(M.get_cols(), Eq(3));
451 1 : EXPECT_THAT(M.get_rows(), Eq(2));
452 :
453 1 : EXPECT_THAT(M(1, 1), Eq(1));
454 1 : EXPECT_THAT(M(1, 2), Eq(3));
455 1 : EXPECT_THAT(M(1, 3), Eq(5));
456 1 : EXPECT_THAT(M(2, 1), Eq(2));
457 1 : EXPECT_THAT(M(2, 2), Eq(4));
458 1 : EXPECT_THAT(M(2, 3), Eq(6));
459 1 : }
460 :
461 2 : TEST_F(TestThatMatrix, HasFullMatrixConstructorWithInitializerList)
462 : {
463 2 : matrix<int> M(2, 2, {1, 2, 3, 4});
464 :
465 1 : EXPECT_THAT(M.get_cols(), Eq(2));
466 1 : EXPECT_THAT(M.get_rows(), Eq(2));
467 :
468 1 : EXPECT_THAT(M(1, 1), Eq(1));
469 1 : EXPECT_THAT(M(1, 2), Eq(3));
470 1 : EXPECT_THAT(M(2, 1), Eq(2));
471 1 : EXPECT_THAT(M(2, 2), Eq(4));
472 1 : }
473 :
474 : // This use cases are possible
475 : // // initializer_list constructor will be used: create a 2x2 diagonal matrix
476 : // with 1, 2 on the diagonal cout << "matrix{1, 2}:\n"; cout << matrix<int>{1,
477 : // 2};
478 : // // (size_t, size_t) constructor will be used: create an UNINITIALIZED 1x2
479 : // matrix cout << "matrix(1, 2):\n"; cout << matrix<int>(1, 2);
|