skullc-peripherals/Tests/pixelbuffer.cpp

265 lines
5.7 KiB
C++

//
// Created by erki on 13.05.21.
//
#include "utility_fonts_5x7.hpp"
#include "utility_pixelbuffer.hpp"
#include <catch2/catch.hpp>
#define TEST_WIDGET "[utility],[pixelbuffer]"
using PixelBuffer = Utility::PixelBuffer<10, 15>;
using compare_array = std::array<std::uint8_t, 10 * 15>;
using Font = Utility::Font5x7;
TEST_CASE("Pixelbuffer fill fills the array with data.", TEST_WIDGET)
{
SECTION("Fill works as expected")
{
PixelBuffer pb;
pb.fill(100);
for (const auto& px : pb)
{
REQUIRE(px == 100);
}
}
SECTION("Default pixelbuffer is zero-filled.")
{
PixelBuffer pb;
for (const auto& px : pb)
{
REQUIRE(px == 0);
}
}
SECTION("Filled constructor fills the array.")
{
PixelBuffer pb(200);
for (const auto& px : pb)
{
REQUIRE(px == 200);
}
}
}
TEST_CASE("Coordinate access retreives the appropriate pixels.", TEST_WIDGET)
{
PixelBuffer pb(200);
const uint8_t* value_ptr = &pb.at(5, 2);
const uint8_t* aritm_ptr = &(*(pb.cbegin() + (5 + 2 * 10)));
REQUIRE(value_ptr == aritm_ptr);
const uint8_t* value_ptr_c = &pb.at({5, 2});
REQUIRE(value_ptr_c == aritm_ptr);
}
TEST_CASE("Pixelbuffer draws rectangle correctly.", TEST_WIDGET)
{
PixelBuffer pb;
pb.rectangle({0, 0}, {5, 10}, 10);
// clang-format off
compare_array etalon = {
10, 10, 10, 10, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 0, 0,
10, 10, 10, 10, 10, 0, 0, 0, 0,
0
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
TEST_CASE("Pixelbuffer draws line correctly.", TEST_WIDGET)
{
PixelBuffer pb;
SECTION("Straight line on X axis is correct.")
{
pb.line({0, 0}, {3, 0}, 10);
compare_array etalon = {
10, 10, 10};
REQUIRE(pb.data() == etalon);
}
SECTION("Straight line on Y axis is correct.")
{
pb.line({0, 0}, {0, 3}, 10);
// clang-format off
compare_array etalon = {
10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
SECTION("Straight line on X axis is correct with reversed coordinates.")
{
pb.line({3, 0}, {0, 0}, 10);
compare_array etalon = {
10, 10, 10};
REQUIRE(pb.data() == etalon);
}
SECTION("Straight line on Y axis is correct with reversed coordinates.")
{
pb.line({0, 3}, {0, 0}, 10);
// clang-format off
compare_array etalon = {
10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
SECTION("Diagonal line is correct.")
{
pb.line({0, 0}, {4, 4}, 10);
// clang-format off
compare_array etalon = {
10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 10, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 10, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
SECTION("Diagonal line is correct if points are reversed.")
{
pb.line({4, 4}, {0, 0}, 10);
// clang-format off
compare_array etalon = {
10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 10, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 10, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
}
TEST_CASE("Pixelbuffer draws circle properly.", TEST_WIDGET)
{
PixelBuffer pb;
pb.circle({5, 5}, 2, 10);
// clang-format off
compare_array etalon = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 10, 10, 10, 0, 0, 0,
0, 0, 0, 10, 0, 0, 0, 10, 0, 0,
0, 0, 0, 10, 0, 0, 0, 10, 0, 0,
0, 0, 0, 10, 0, 0, 0, 10, 0, 0,
0, 0, 0, 0, 10, 10, 10, 0, 0, 0
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
TEST_CASE("Pixelbuffer outputs fonts correctly.", TEST_WIDGET)
{
PixelBuffer pb;
pb.text<Font>("!", {0, 0}, 0xFF);
// clang-format off
compare_array etalon = {
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
TEST_CASE("Pixelbuffer cuts off fonts when required.", TEST_WIDGET)
{
PixelBuffer pb;
pb.text<Font>("!", {0, 13}, 0xFF);
// clang-format off
compare_array etalon = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0, 0, 0, 0, 0, 0, 0
};
// clang-format on
REQUIRE(pb.data() == etalon);
}
TEST_CASE("Pixelbuffer::View provides the correct offsets.", TEST_WIDGET)
{
PixelBuffer pb;
const auto view = pb.view<2, 2>({1, 1});
const auto* ptr_pb = &pb.at(2, 2);
const auto* ptr_view = &view.at(1, 1);
REQUIRE(ptr_pb == ptr_view);
REQUIRE(decltype(view)::width == 2);
REQUIRE(decltype(view)::height == 2);
}