Added tests for image reading

This commit is contained in:
Leonetienne 2022-03-06 12:08:26 +01:00
parent f279ffb50f
commit eb4fc0e964
11 changed files with 153 additions and 4 deletions

View File

@ -6,7 +6,7 @@ using namespace Leonetienne::BmpPP;
int main() { int main() {
/*
BMP bmp({800, 600}, Colormode::RGB); BMP bmp({800, 600}, Colormode::RGB);
for (int x = 0; x < 800; x++) for (int x = 0; x < 800; x++)
@ -20,7 +20,9 @@ int main() {
); );
} }
*/ bmp.Write("write.bmp");
/*
BMP bmp; BMP bmp;
@ -32,7 +34,7 @@ int main() {
if (!bmp.Write("testwrite.bmp")) if (!bmp.Write("testwrite.bmp"))
std::cerr << "What the hell" << std::endl; std::cerr << "What the hell" << std::endl;
*/
return 0; return 0;
} }

View File

@ -2,6 +2,7 @@
#define BMPPP_BMP_H #define BMPPP_BMP_H
#include <Eule/Vector2.h> #include <Eule/Vector2.h>
#include <Eule/Rect.h>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include "Colormodes.h" #include "Colormodes.h"
@ -87,6 +88,9 @@ namespace Leonetienne::BmpPP {
//! Will swap two channels. Useful for, for example, easy BGR to RGB conversion. //! Will swap two channels. Useful for, for example, easy BGR to RGB conversion.
void SwapChannels(const std::size_t& channel1, const std::size_t& channel2); void SwapChannels(const std::size_t& channel1, const std::size_t& channel2);
//! Will copy the specified rectangle-area, and return it as a new image
BMP Crop(const Eule::Rect& area);
private: private:
Eule::Vector2i size; Eule::Vector2i size;
Colormode colormode; Colormode colormode;

View File

@ -21,4 +21,12 @@ add_executable(Test
BmpHeader.cpp BmpHeader.cpp
ReInitialize.cpp ReInitialize.cpp
Uninitialized.cpp Uninitialized.cpp
Read.cpp
)
# Move test images to build dir
ADD_CUSTOM_COMMAND(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/TestAssets/ $<TARGET_FILE_DIR:${PROJECT_NAME}>
) )

131
Test/Read.cpp Normal file
View File

@ -0,0 +1,131 @@
#include <Bmp.h>
#include "Catch2.h"
#include <tuple>
#include <Eule/Math.h>
using namespace Leonetienne::BmpPP;
using namespace Eule;
#define IMSIZE Vector2i(800, 600)
namespace {
inline std::tuple<std::uint8_t, std::uint8_t, std::uint8_t, std::uint8_t>
ColorGradient(const Vector2i& pos)
{
std::uint8_t r, g, b, a;
// This assumes IMSIZE.x >= IMSIZE.y
r = ((float)pos.x / (float)IMSIZE.x) * 255.0f;
g = (1.0f - (float)pos.x / (float)IMSIZE.x) * 255.0f;
b = (1.0f - (float)pos.y / (float)IMSIZE.x) * 255.0f;
a = Math::Clamp(((float)pos.y / (float)IMSIZE.x) * 2 * 255.0f, 0.0, 255.0);
return std::make_tuple(r, g, b, a);
}
}
// Tests that reading an image works at all, without throwing an exception or crashing the program
TEST_CASE(__FILE__"/ReadingDoesntCrash", "[Read]")
{
SECTION("RGB image with BITMAPV5HEADER") {
// Read RGB gradient image
BMP bmp("base_gradient.bmp");
}
SECTION("RGBA image with BITMAPV5HEADER") {
// Read RGBA gradient image
BMP bmp("basea_gradient.bmp");
}
return;
}
// Tests that an image is initialized after being read
TEST_CASE(__FILE__"/InitializedAfterReading", "[Read]")
{
// Read RGB gradient image
BMP bmp("base_gradient.bmp");
REQUIRE(bmp.IsInitialized());
return;
}
// Tests that images read the correct metadata (bit depth and resolution)
TEST_CASE(__FILE__"/MetadataIsCorrect", "[Read]")
{
// Read RGB gradient image
SECTION("RGB image with BITMAPV5HEADER") {
// Read RGB gradient image
BMP bmp("base_gradient.bmp");
REQUIRE(bmp.GetDimensions() == IMSIZE);
REQUIRE(bmp.GetColormode() == Colormode::RGB);
}
SECTION("RGBA image with BITMAPV5HEADER") {
// Read RGBA gradient image
BMP bmp("basea_gradient.bmp");
REQUIRE(bmp.GetDimensions() == IMSIZE);
REQUIRE(bmp.GetColormode() == Colormode::RGBA);
}
return;
}
// Tests that reading an image works, by comparing the resulting pixel
// values with the algorithm that created them
TEST_CASE(__FILE__"/CompareRGB", "[Read]")
{
// Read RGB gradient image
BMP bmp("base_gradient.bmp");
// Compare each pixel to the algorithm that has once created it
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const auto expected_pixel_values = ColorGradient(Vector2i(x, y));
const uint8_t* pxBase = bmp.GetPixel(Vector2i(x, y));
const auto actual_pixel_values =
std::make_tuple(
*(pxBase + 0),
*(pxBase + 1),
*(pxBase + 2),
std::get<3>(expected_pixel_values) // Since our image doesn't contain an ALPHA channel, let's copy it from the expected value
);
REQUIRE(actual_pixel_values == expected_pixel_values);
}
return;
}
// Tests that reading an image works, by comparing the resulting pixel
// values with the algorithm that created them
TEST_CASE(__FILE__"/CompareRGBA", "[Read]")
{
// Read RGBA gradient image
BMP bmp("basea_gradient.bmp");
// Compare each pixel to the algorithm that has once created it
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const auto expected_pixel_values = ColorGradient(Vector2i(x, y));
const uint8_t* pxBase = bmp.GetPixel(Vector2i(x, y));
const auto actual_pixel_values =
std::make_tuple(
*(pxBase + 0),
*(pxBase + 1),
*(pxBase + 2),
*(pxBase + 3)
);
REQUIRE(actual_pixel_values == expected_pixel_values);
}
return;
}
#undef IMSIZE

2
Test/TestAssets/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Allow images used for tests
!*.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -0,0 +1 @@
base*.bmp is always RGB, basea*.bmp is always RGBA.

View File

@ -3,6 +3,7 @@
#include "Catch2.h" #include "Catch2.h"
using namespace Leonetienne::BmpPP; using namespace Leonetienne::BmpPP;
using namespace Eule;
// Tests that trying to interrogate any getter/Write() on an uninitialized image results in a runtime error // Tests that trying to interrogate any getter/Write() on an uninitialized image results in a runtime error
TEST_CASE(__FILE__"/RuntimeErrorOnUninitialized", "[Uninitialized]") TEST_CASE(__FILE__"/RuntimeErrorOnUninitialized", "[Uninitialized]")
@ -65,7 +66,7 @@ TEST_CASE(__FILE__"/UninitializedImageIsUninitialized", "[Uninitialized]")
// Tests that an image constructed via dimensions is initialized // Tests that an image constructed via dimensions is initialized
TEST_CASE(__FILE__"/ConstructedByDimensionsIsInitialized", "[Uninitialized]") TEST_CASE(__FILE__"/ConstructedByDimensionsIsInitialized", "[Uninitialized]")
{ {
BMP bmp({800, 600}); BMP bmp(Vector2i(800, 600));
REQUIRE(bmp.IsInitialized()); REQUIRE(bmp.IsInitialized());
return; return;