הערה (קובץ קוד)
קובץ זה הוא קובץ קוד מסוג CPP.
#include <iostream>
#include <sstream>
#include <string>
#include "Matrix.h"
#include "MataMvidia.h"
#include "tests_matamvidia_extra.h"
using namespace std;
// ─── Test infrastructure ────────────────────────────────────────────────────
static int passed = 0, failed = 0;
#define CHECK(label, expr) \
do { \
if (expr) { \
std::cout << " [PASS] " << label << "\n"; \
++passed; \
} else { \
std::cout << " [FAIL] " << label \
<< " (" << __FILE__ << ":" << __LINE__ << ")\n";\
++failed; \
} \
} while (0)
// ─── Helper ─────────────────────────────────────────────────────────────────
static Matrix make2x2(int a, int b, int c, int d) {
Matrix m(2, 2);
m(0,0)=a; m(0,1)=b;
m(1,0)=c; m(1,1)=d;
return m;
}
static Matrix make3x3(int vals[9]) {
Matrix m(3, 3);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
m(i, j) = vals[i*3+j];
return m;
}
// ─── Matrix Tests ────────────────────────────────────────────────────────────
void test_matrix_construction() {
cout << "\n[Matrix Construction]\n";
Matrix zero;
CHECK("default constructor rows/cols are 0 (no crash)", true); // just don't crash
Matrix m(3, 4, 7);
bool allSeven = true;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
if (m(i,j) != 7) allSeven = false;
CHECK("fill-value constructor sets all cells", allSeven);
Matrix m2(2, 2, 0);
CHECK("fill-value 0 constructor", m2(0,0)==0 && m2(1,1)==0);
Matrix m1x1(1, 1, 42);
CHECK("1x1 matrix value", m1x1(0,0) == 42);
}
void test_matrix_copy() {
cout << "\n[Matrix Copy & Assignment]\n";
Matrix a = make2x2(1, 2, 3, 4);
Matrix b(a);
CHECK("copy constructor produces equal matrix", a == b);
b(0,0) = 99;
CHECK("copy is independent (deep copy)", a(0,0) == 1);
Matrix c(2,2);
c = a;
CHECK("assignment operator works", c == a);
c(1,1) = 55;
CHECK("assigned copy is independent", a(1,1) == 4);
// self-assignment
a = a;
CHECK("self-assignment safe", a(0,0) == 1 && a(1,1) == 4);
}
void test_matrix_addition() {
cout << "\n[Matrix Addition]\n";
Matrix a = make2x2(1, 2, 3, 4);
Matrix b = make2x2(5, 6, 7, 8);
Matrix c = a + b;
CHECK("operator+ (0,0)", c(0,0) == 6);
CHECK("operator+ (0,1)", c(0,1) == 8);
CHECK("operator+ (1,0)", c(1,0) == 10);
CHECK("operator+ (1,1)", c(1,1) == 12);
Matrix d = a;
d += b;
CHECK("operator+= matches operator+", d == c);
// Adding zero matrix
Matrix zero(2,2,0);
CHECK("adding zero matrix is identity", a + zero == a);
}
void test_matrix_subtraction() {
cout << "\n[Matrix Subtraction]\n";
Matrix a = make2x2(10, 8, 6, 4);
Matrix b = make2x2(1, 2, 3, 4);
Matrix c = a - b;
CHECK("operator- (0,0)", c(0,0) == 9);
CHECK("operator- (1,1)", c(1,1) == 0);
Matrix d = a;
d -= b;
CHECK("operator-= matches operator-", d == c);
// a - a = zero
Matrix zero(2,2,0);
CHECK("a - a == zero", a - a == zero);
}
void test_matrix_multiplication() {
cout << "\n[Matrix Multiplication]\n";
Matrix a = make2x2(1, 2, 3, 4);
Matrix b = make2x2(5, 6, 7, 8);
Matrix c = a * b;
// [1*5+2*7, 1*6+2*8, 3*5+4*7, 3*6+4*8] = [19,22,43,50]
CHECK("operator* (0,0)", c(0,0) == 19);
CHECK("operator* (0,1)", c(0,1) == 22);
CHECK("operator* (1,0)", c(1,0) == 43);
CHECK("operator* (1,1)", c(1,1) == 50);
Matrix d = a;
d *= b;
CHECK("operator*= matches operator*", d == c);
// non-square: 2x3 * 3x2
Matrix p(2, 3, 0);
p(0,0)=1; p(0,1)=2; p(0,2)=3;
p(1,0)=4; p(1,1)=5; p(1,2)=6;
Matrix q(3, 2, 0);
q(0,0)=7; q(0,1)=8;
q(1,0)=9; q(1,1)=10;
q(2,0)=11; q(2,1)=12;
Matrix pq = p * q;
// row0: 1*7+2*9+3*11=58, 1*8+2*10+3*12=64
// row1: 4*7+5*9+6*11=139, 4*8+5*10+6*12=154
CHECK("non-square multiply (0,0)", pq(0,0) == 58);
CHECK("non-square multiply (0,1)", pq(0,1) == 64);
CHECK("non-square multiply (1,0)", pq(1,0) == 139);
CHECK("non-square multiply (1,1)", pq(1,1) == 154);
}
void test_matrix_scalar_multiplication() {
cout << "\n[Matrix Scalar Multiplication]\n";
Matrix a = make2x2(1, 2, 3, 4);
Matrix b = a * 3;
CHECK("mat * scalar (0,0)", b(0,0) == 3);
CHECK("mat * scalar (1,1)", b(1,1) == 12);
Matrix c = 3 * a;
CHECK("scalar * mat == mat * scalar", b == c);
Matrix d = a;
d *= 2;
CHECK("operator*= scalar", d(0,1) == 4 && d(1,0) == 6);
CHECK("multiply by 0 gives zero matrix", (a * 0) == Matrix(2,2,0));
CHECK("multiply by 1 is identity", (a * 1) == a);
CHECK("multiply by -1 == unary minus", (a * -1) == -a);
}
void test_matrix_unary_minus() {
cout << "\n[Matrix Unary Minus]\n";
Matrix a = make2x2(1, -2, 0, 4);
Matrix neg = -a;
CHECK("unary minus (0,0)", neg(0,0) == -1);
CHECK("unary minus (0,1)", neg(0,1) == 2);
CHECK("unary minus (1,0)", neg(1,0) == 0);
CHECK("unary minus negated back", -neg == a);
}
void test_matrix_equality() {
cout << "\n[Matrix Equality]\n";
Matrix a = make2x2(1,2,3,4);
Matrix b = make2x2(1,2,3,4);
Matrix c = make2x2(1,2,3,5);
CHECK("equal matrices", a == b);
CHECK("unequal matrices !=", a != c);
CHECK("different size matrices !=", a != Matrix(3,3,0));
}
void test_matrix_transpose() {
cout << "\n[Matrix Transpose]\n";
Matrix a = make2x2(1,2,3,4);
Matrix t = a.transpose();
CHECK("transpose (0,1) swapped", t(0,1) == 3);
CHECK("transpose (1,0) swapped", t(1,0) == 2);
CHECK("double transpose is identity", t.transpose() == a);
// non-square 2x3
Matrix m(2,3,0);
m(0,0)=1; m(0,1)=2; m(0,2)=3;
m(1,0)=4; m(1,1)=5; m(1,2)=6;
Matrix mt = m.transpose();
CHECK("non-square transpose dims (row)", mt(0,0)==1 && mt(1,0)==2 && mt(2,0)==3);
CHECK("non-square transpose dims (col)", mt(0,1)==4 && mt(1,1)==5 && mt(2,1)==6);
}
void test_matrix_rotate() {
cout << "\n[Matrix Rotate]\n";
Matrix a = make2x2(1,2,3,4);
// CW: top-left→top-right, bottom-left→top-left, etc.
// original: CW:
// 1 2 → 3 1
// 3 4 4 2
Matrix cw = a.rotateClockwise();
CHECK("CW (0,0)", cw(0,0) == 3);
CHECK("CW (0,1)", cw(0,1) == 1);
CHECK("CW (1,0)", cw(1,0) == 4);
CHECK("CW (1,1)", cw(1,1) == 2);
// CCW: 1 2 → 2 4 / 1 3
// 3 4
Matrix ccw = a.rotateCounterClockwise();
CHECK("CCW (0,0)", ccw(0,0) == 2);
CHECK("CCW (0,1)", ccw(0,1) == 4);
CHECK("CCW (1,0)", ccw(1,0) == 1);
CHECK("CCW (1,1)", ccw(1,1) == 3);
CHECK("CW then CCW is identity", a.rotateClockwise().rotateCounterClockwise() == a);
CHECK("CCW then CW is identity", a.rotateCounterClockwise().rotateClockwise() == a);
CHECK("4x CW is identity", a.rotateClockwise().rotateClockwise().rotateClockwise().rotateClockwise() == a);
}
void test_matrix_frobenius_norm() {
cout << "\n[Matrix Frobenius Norm]\n";
Matrix a = make2x2(1, 0, 0, 1); // identity → norm = sqrt(2)
double norm = Matrix::CalcFrobeniusNorm(a);
CHECK("identity 2x2 norm ≈ sqrt(2)", norm > 1.41 && norm < 1.42);
Matrix b(2,2,0);
CHECK("zero matrix norm == 0", Matrix::CalcFrobeniusNorm(b) == 0.0);
Matrix c = make2x2(3, 4, 0, 0); // sqrt(9+16) = 5
CHECK("3-4-0-0 norm == 5", Matrix::CalcFrobeniusNorm(c) == 5.0);
}
void test_matrix_determinant() {
cout << "\n[Matrix Determinant]\n";
Matrix a = make2x2(1,2,3,4); // det = 1*4 - 2*3 = -2
CHECK("2x2 determinant", Matrix::CalcDeterminant(a) == -2);
Matrix identity2 = make2x2(1,0,0,1);
CHECK("2x2 identity det == 1", Matrix::CalcDeterminant(identity2) == 1);
// 3x3
int v[] = {1,2,3, 4,5,6, 7,8,9};
Matrix m3 = make3x3(v);
CHECK("singular 3x3 det == 0", Matrix::CalcDeterminant(m3) == 0);
int v2[] = {2,0,0, 0,3,0, 0,0,4};
Matrix diag = make3x3(v2);
CHECK("diagonal 3x3 det == 24", Matrix::CalcDeterminant(diag) == 24);
Matrix m1x1(1, 1, 7);
CHECK("1x1 determinant", Matrix::CalcDeterminant(m1x1) == 7);
}
void test_matrix_output() {
cout << "\n[Matrix Output]\n";
Matrix a = make2x2(5,6,7,8);
std::ostringstream oss;
oss << a;
string out = oss.str();
CHECK("output contains |5|", out.find("|5|") != string::npos);
CHECK("output contains |8|", out.find("|8|") != string::npos);
}
// ─── MataMvidia Tests ────────────────────────────────────────────────────────
static MataMvidia make_movie(const string& name="TestMovie",
const string& author="Tester",
int numFrames=2) {
Matrix* arr = new Matrix[numFrames];
for (int i = 0; i < numFrames; i++)
arr[i] = make2x2(i*10+1, i*10+2, i*10+3, i*10+4);
MataMvidia mv(name, author, arr, numFrames);
delete[] arr;
return mv;
}
void test_matamvidia_construction() {
cout << "\n[MataMvidia Construction]\n";
Matrix arr[3];
arr[0] = make2x2(1,2,3,4);
arr[1] = make2x2(5,6,7,8);
arr[2] = make2x2(9,10,11,12);
MataMvidia mv("Film", "Director", arr, 3);
CHECK("frame 0 correct", mv[0] == arr[0]);
CHECK("frame 1 correct", mv[1] == arr[1]);
CHECK("frame 2 correct", mv[2] == arr[2]);
}
void test_matamvidia_copy() {
cout << "\n[MataMvidia Copy & Assignment]\n";
MataMvidia mv = make_movie();
MataMvidia mv2(mv);
CHECK("copy constructor: frame 0 equal", mv2[0] == mv[0]);
mv2[0](0,0) = 999;
CHECK("copy is deep (modifying copy doesn't affect original)", mv[0](0,0) != 999);
MataMvidia mv3 = make_movie("Other","Auth");
mv3 = mv;
CHECK("assignment: frame 0 equal", mv3[0] == mv[0]);
mv3[0](0,0) = 777;
CHECK("assigned copy is deep", mv[0](0,0) != 777);
// self-assignment
mv = mv;
CHECK("self-assignment safe", mv[0](0,0) == 1);
}
void test_matamvidia_append_frame() {
cout << "\n[MataMvidia Append Frame]\n";
MataMvidia mv = make_movie("M","A",1);
Matrix extra = make2x2(9,9,9,9);
mv += extra;
CHECK("frame count grows after += frame", mv[1] == extra);
// append many frames (triggers expand)
for (int i = 0; i < 20; i++) {
Matrix f = make2x2(i,i,i,i);
mv += f;
}
CHECK("after 20 appends, frame 2 value", mv[2](0,0) == 0);
CHECK("last appended frame correct", mv[21](0,0) == 19);
}
void test_matamvidia_append_movie() {
cout << "\n[MataMvidia Append Movie]\n";
Matrix a1[2] = { make2x2(1,1,1,1), make2x2(2,2,2,2) };
Matrix a2[2] = { make2x2(3,3,3,3), make2x2(4,4,4,4) };
MataMvidia mv1("A","x", a1, 2);
MataMvidia mv2("B","y", a2, 2);
mv1 += mv2;
CHECK("+= movie: frame 2 is first of mv2", mv1[2] == a2[0]);
CHECK("+= movie: frame 3 is second of mv2", mv1[3] == a2[1]);
CHECK("+= movie: original frames unchanged", mv1[0] == a1[0]);
}
void test_matamvidia_operator_plus() {
cout << "\n[MataMvidia operator+]\n";
Matrix a1[2] = { make2x2(1,2,3,4), make2x2(5,6,7,8) };
Matrix a2[2] = { make2x2(9,10,11,12), make2x2(13,14,15,16) };
MataMvidia mv1("M1","A", a1, 2);
MataMvidia mv2("M2","B", a2, 2);
MataMvidia mv3 = mv1 + mv2;
CHECK("operator+: first frame from mv1", mv3[0] == a1[0]);
CHECK("operator+: second frame from mv1", mv3[1] == a1[1]);
CHECK("operator+: third frame from mv2", mv3[2] == a2[0]);
CHECK("operator+: fourth frame from mv2", mv3[3] == a2[1]);
// originals unchanged
CHECK("mv1 unchanged after +", mv1[0] == a1[0]);
CHECK("mv2 unchanged after +", mv2[0] == a2[0]);
}
void test_matamvidia_index_access() {
cout << "\n[MataMvidia Index Access]\n";
MataMvidia mv = make_movie("M","A",3);
Matrix f = mv[1];
CHECK("const [] access", f == mv[1]);
mv[0](0,0) = 42;
CHECK("non-const [] allows mutation", mv[0](0,0) == 42);
}
void test_matamvidia_output() {
cout << "\n[MataMvidia Output]\n";
Matrix arr[1] = { make2x2(1,2,3,4) };
MataMvidia mv("CoolFilm","CoolAuthor",arr,1);
std::ostringstream oss;
oss << mv;
string out = oss.str();
CHECK("output has movie name", out.find("CoolFilm") != string::npos);
CHECK("output has author", out.find("CoolAuthor") != string::npos);
CHECK("output has Frame 0", out.find("Frame 0") != string::npos);
CHECK("output has End marker", out.find("-----End of Movie-----") != string::npos);
CHECK("output has frame contents", out.find("|1|") != string::npos);
}
void test_matamvidia_large_expand() {
cout << "\n[MataMvidia Large Expand]\n";
Matrix arr[1] = { make2x2(0,0,0,0) };
MataMvidia mv("X","Y",arr,1);
// Force multiple expansions
for (int i = 1; i <= 50; i++) {
mv += make2x2(i, i, i, i);
}
CHECK("after 50 appends, frame 50 correct", mv[50](0,0) == 50);
CHECK("frame 1 still correct after many expands", mv[1](0,0) == 1);
CHECK("frame 25 correct", mv[25](0,0) == 25);
}
void test_matamvidia_append_to_empty_movie() {
cout << "\n[MataMvidia Edge: 0-frame base]\n";
Matrix empty[1] = { make2x2(7,7,7,7) };
MataMvidia mv("Empty","Nobody", empty, 1);
// Not truly empty since MataMvidia needs >=1 to construct,
// but test single-frame movie appended to
mv += make2x2(8,8,8,8);
CHECK("single-frame base + 1 frame", mv[1](0,0) == 8);
}
// ─── Main ────────────────────────────────────────────────────────────────────
int main() {
cout << "========================================\n";
cout << " WET Part: Full Test Suite\n";
cout << "========================================\n";
// Matrix
test_matrix_construction();
test_matrix_copy();
test_matrix_addition();
test_matrix_subtraction();
test_matrix_multiplication();
test_matrix_scalar_multiplication();
test_matrix_unary_minus();
test_matrix_equality();
test_matrix_transpose();
test_matrix_rotate();
test_matrix_frobenius_norm();
test_matrix_determinant();
test_matrix_output();
// MataMvidia
test_matamvidia_construction();
test_matamvidia_copy();
test_matamvidia_append_frame();
test_matamvidia_append_movie();
test_matamvidia_operator_plus();
test_matamvidia_index_access();
test_matamvidia_output();
test_matamvidia_large_expand();
test_matamvidia_append_to_empty_movie();
// Extra MataMvidia tests
cout << "\n--- Extra MataMvidia Tests ---\n";
test_frame_order_preserved();
test_mixed_frame_sizes();
test_copy_ctor_independence_both_ways();
test_chained_assignment();
test_append_movie_doesnt_alter_argument();
test_plus_doesnt_alter_arguments();
test_plus_result_length();
test_self_append();
test_sequential_frame_appends();
test_sequential_movie_appends();
test_chained_plus();
test_nonconst_index_mutation();
test_const_index_access();
test_output_frame_count();
test_output_names_with_spaces();
test_expansion_data_integrity();
test_single_frame_movies_combined();
test_appended_frame_not_aliased();
test_plus_result_independent();
test_many_movies_concatenated();
passed += getCounterPassed();
failed += getCounterFailed();
cout << "\n========================================\n";
cout << " Results: " << passed << " passed, " << failed << " failed\n";
cout << "========================================\n";
return failed == 0 ? 0 : 1;
}