Skip to content
Snippets Groups Projects
Testing.cpp 11 KiB
Newer Older
Postea's avatar
Postea committed
#include "Testing.h"
#include "../camera/Ray.h"
#include "../tools/Mat4.h"
#include "../tools/Vec3.h"
#include <array>
Postea's avatar
Postea committed
#include <cassert>
#include <iostream>

namespace test {
void vec3_test()
{
    std::cout << "======================" << std::endl;
    std::cout << "     Testing Vec3    " << std::endl;
    std::cout << "======================" << std::endl;
Postea's avatar
Postea committed

    {
        // 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));
Postea's avatar
Postea committed

        std::cout << "passed." << std::endl;
    }
Postea's avatar
Postea committed

    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;
Postea's avatar
Postea committed

    {
        // 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);
Postea's avatar
Postea committed

        std::cout << "passed." << std::endl;
    }
Postea's avatar
Postea committed

    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;
Postea's avatar
Postea committed

    {
        // 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;
}
Postea's avatar
Postea committed
}