#include "Testing.h" #include <cassert> #include <iostream> #include <array> #include "Vec3.h" #include "Mat4.h" #include "Ray.h" namespace test { void vec3_test () { std::cout << "======================" << std::endl; std::cout << " Testing Vec3 " << std::endl; std::cout << "======================" << std::endl; { // do not tolerate any memory overhead std::cout << " sizeof(Vec3) == 3 bytes: "; assert (sizeof (util::Vec3) == 3 * sizeof (float)); std::cout << "passed." << std::endl; } { std::cout << " constructor & index operator: "; util::Vec3 a; assert (a[0] == 0 && a[1] == 0 && a[2] == 0); util::Vec3 b (1, 2, 3); assert (b[0] == 1 && b[1] == 2 && b[2] == 3); std::cout << "passed." << std::endl; } { std::cout << " read-only access to const object: "; const util::Vec3 a (1, 2, 3); // the next line will throw a compiler error if there is no proper // "operator[] const" assert (a[1] == 2); std::cout << "passed." << std::endl; } { std::cout << " write access to a non-const object: "; util::Vec3 a (1, 2, 3); a[1] = 4; assert (a[0] == 1 && a[1] == 4 && a[2] == 3); std::cout << "passed." << std::endl; } { std::cout << " comparison: "; util::Vec3 a (1, 2, 3), b (1, 2, 3), c (1, 2, 9), d (4, 5, 6); assert (a == b); assert (a == a); assert (a != c); assert (b != d); assert (!(a != b)); std::cout << "passed." << std::endl; } { // should work out of the box when using std container (!) std::cout << " assignment: "; util::Vec3 a (1, 2, 3); std::cout << a[0] << " "; // to make sure these values are not optimized away! a = util::Vec3 (4, 5, 6); assert (a[0] == 4 && a[1] == 5 && a[2] == 6); std::cout << "passed." << std::endl; } { std::cout << " addition: "; util::Vec3 a (1, 2, 3), b (4, 5, 6); a += b; assert (a == util::Vec3 (5, 7, 9)); auto c = a + util::Vec3 (1, 1, 1); assert (c == util::Vec3 (6, 8, 10)); util::Vec3 one (1, 1, 1), four (4, 4, 4); one += one + one + one; assert (one == four); util::Vec3 x (0, 0, 0), y (1, 1, 1), z (2, 2, 2); y += z; assert (y == util::Vec3 (3, 3, 3)); std::cout << "passed." << std::endl; } { std::cout << " unary minus: "; util::Vec3 a (1, 2, 3); assert (-a == util::Vec3 (-1, -2, -3)); std::cout << "passed." << std::endl; } { std::cout << " dot product: "; util::Vec3 a (1, 2, 3); assert (dot (a, a) == 1 * 1 + 2 * 2 + 3 * 3); std::cout << "passed." << std::endl; } { // these tests will not compile if you forgot to declare // some methods const std::cout << " constness: "; const util::Vec3 a (1, 2, 3); assert (a[1] == 2); assert (a == a); assert (!(a != a)); assert (a + a == util::Vec3 (2, 4, 6)); assert (-a == util::Vec3 (-1, -2, -3)); assert (dot (a, a) == 1 * 1 + 2 * 2 + 3 * 3); std::cout << "passed." << std::endl; } { auto round_to_6 = [](float x) {int temp = x * 1000000; return temp / 1000000.0; }; std::cout << " length and normalize: "; const util::Vec3 a (1, 2, 3); assert (a.length () == (float)sqrt (14)); assert (a.normalize ()[0] == (float)(1 / sqrt (14))); util::Vec3 b (2, 2, 1); assert (b.length () == 3); assert (b.normalize ()[1] == (float)(2.0 / 3.0)); std::cout << "passed." << std::endl; } std::cout << "all util::Vec3 tests passed." << std::endl << std::endl; } void mat4_test () { std::cout << "======================" << std::endl; std::cout << " Testing Mat4 " << std::endl; std::cout << "======================" << std::endl; { // do not tolerate any memory overhead std::cout << " sizeof(Mat4) == 16 bytes: "; assert (sizeof (util::Mat4) == 16 * sizeof (float)); std::cout << "passed." << std::endl; } { std::cout << " constructor & index operator: "; util::Mat4 a; assert (a == util::identity ()); util::Mat4 b ({ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }); assert ((b[{0, 0}]) == 1 && (b[{1, 0}]) == 5 && (b[{3, 3}]) == 16); std::cout << "passed." << std::endl; } { std::cout << " read-only access to const object: "; const util::Mat4 a ({ 1, 2, 3,4,5,6,7,8,9,10,11,12,13,14,15,16 }); // the next line will throw a compiler error if there is no proper // "operator[] const" assert ((a[{0, 2}]) == 3); std::cout << "passed." << std::endl; } { std::cout << " write access to a non-const object: "; util::Mat4 a ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); a[{0, 2}] = 4; //assert (a (0, 0) == 1 && a (0, 2) == 4 && a (2, 3) == 12); std::cout << "passed." << std::endl; } { std::cout << " comparison: "; util::Mat4 a ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }) , b ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }) , c ({ 1, 2, 9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }) , d ({ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }); assert (a == b); assert (a == a); assert (a != c); assert (b != d); assert (!(a != b)); std::cout << "passed." << std::endl; } { // should work out of the box when using std container (!) std::cout << " assignment: "; util::Mat4 a ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); std::cout << a[{0, 0}] << " "; // to make sure these values are not optimized away! a = util::Mat4 ({ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }); assert ((a[{0, 0}]) == 4 && (a[{0, 1}]) == 5 && (a[{0, 2}]) == 6 && (a[{1, 2}]) == 10); std::cout << "passed." << std::endl; } { std::cout << " multiplication: "; util::Mat4 a ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }) , b ({ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }); util::Mat4 c = a * b; assert (c == util::Mat4 ({ 174,196,218,240,286,324,362,400,398,452,506,560,510,580,650,720 })); auto d = a * util::identity (); assert (d == a); util::Mat4 one ({ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }), four ({ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }); one = one * one; assert (one == four); util::Mat4 x ({ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }), y ({ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }); util::Mat4 z = x * y; assert (z == util::Mat4 ({ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 })); std::cout << "passed." << std::endl; } { std::cout << " transpose: "; util::Mat4 a ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); util::Mat4 b = a.transpose (); assert (b == util::Mat4 ({ 1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16 })); util::Mat4 c ({ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }); assert (c == c.transpose ()); assert (util::identity () == util::identity ().transpose ()); std::cout << "passed." << std::endl; } { // these tests will not compile if you forgot to declare // some methods const std::cout << " constness: "; const util::Mat4 a ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); assert ((a[{0, 1}]) == 2); assert (a == a); assert (!(a != a)); std::cout << "passed." << std::endl; } { std::cout << " factory methods: "; util::Mat4 s = util::scale (util::Vec3 (2, 3, 4)); assert ((s[{0, 0}]) == 2 && (s[{1, 1}]) == 3 && (s[{2, 2}]) == 4); util::Mat4 t = util::translate (util::Vec3 (1, -3, 4)); assert ((t[{0, 3}]) == 1 && (t[{1, 3}]) == -3 && (t[{2, 3}]) == 4); auto round_to_6 = [](float x) {int temp = x * 1000000; return temp / 1000000.0; }; util::Mat4 r = util::rotate (util::Vec3 (1, 0, 0), 40); float r11 = round_to_6 (r[{1, 1}]); float r12 = round_to_6 (r[{1, 2}]); float r21 = round_to_6 (r[{2, 1}]); float r22 = round_to_6 (r[{2, 2}]); assert ((r[{0, 0}]) == 1 && r11 == (float)0.766044&& r12 == (float)-0.642787&& r21 == (float)0.642787&& r22 == (float) 0.766044); std::cout << "passed." << std::endl; } { std::cout << " transform: "; auto round_to_5 = [](float x) {int temp = x * 100000; return temp / 100000.0; }; util::Vec3 x = util::Vec3 (2, 4, -5); util::Mat4 rota = util::rotate (util::Vec3 (1, 0, 0), 40); util::Mat4 tran = util::translate (util::Vec3 (1, 1, 1)); util::Vec3 y = rota.transformPoint (x); assert (round_to_5 (y[1]) == 6.27811 && round_to_5 (y[2]) == -1.25907); y = tran.transformPoint (x); assert (round_to_5 (y[1]) == 5 && round_to_5 (y[2]) == -4); y = tran.transformDir (x); assert (round_to_5 (y[1]) == 4 && round_to_5 (y[2]) == -5); std::cout << "passed." << std::endl; } { std::cout << " position: "; util::Mat4 x ({ 0,0,0,3,0,0,1,5,1,2,3,-4,2,2,2,2 }); util::Vec3 vec = x.position (); assert (vec[0] == 3 && vec[1] == 5 && vec[2] == -4); std::cout << "passed." << std::endl; } std::cout << "all util::Mat4 tests passed." << std::endl << std::endl; } void ray_test () { std::cout << "======================" << std::endl; std::cout << " Testing Ray " << std::endl; std::cout << "======================" << std::endl; { // do not tolerate any memory overhead std::cout << " sizeof(Ray) == 36 bytes: "; assert (sizeof (cam::Ray) == 36); std::cout << "passed." << std::endl; } { std::cout << " point_at and borders: "; cam::Ray x (util::Vec3 (1, 1, 1), util::Vec3 (2, 0, 1), 0, 5000, false); assert (x (1) == util::Vec3 (3, 1, 2)); assert (x.in_range (400) && !x.in_range (-1) && !x.in_range (50000)); cam::Ray y (util::Vec3 (2, 4, -3), util::Vec3 (4, -3, 1), 0, 5000, false); assert (y (5) == util::Vec3 (22, -11, 2)); std::cout << "passed." << std::endl; } { auto round_to_4 = [](float x) {int temp = x * 10000; return temp / 10000.0; }; std::cout << " normalize: "; cam::Ray x (util::Vec3 (1, 1, 1), util::Vec3 (0, 0, 5), 0, 5000, true); assert (x (1) == util::Vec3 (1, 1, 2)); cam::Ray y (util::Vec3 (0, 0, 0), util::Vec3 (3, 3, 3), 0, 5000, true); assert (round_to_4 (y (2)[0]) == 1.1547); std::cout << "passed." << std::endl; } std::cout << "all cam::Ray tests passed." << std::endl << std::endl; } }