Skip to content

Commit

Permalink
Merge pull request #2 from Laguna1989/feature/MoreUnitTests
Browse files Browse the repository at this point in the history
Add more unit tests
  • Loading branch information
Laguna1989 authored Oct 13, 2023
2 parents 1b2e37c + 161b8d1 commit 85b5703
Show file tree
Hide file tree
Showing 16 changed files with 545 additions and 129 deletions.
Binary file not shown.
Binary file not shown.
6 changes: 6 additions & 0 deletions impl/aselib/chunk_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ struct CelChunk {
struct TagEntry {
Word_t m_from_frame;
Word_t m_to_frame;
/// Loop direction encoding
///
/// (0 = Forward)
/// (1 = Reverse)
/// (2 = Ping-pong)
/// (3 = Ping-pong Reverse)
Byte_t m_loop_direction;
Word_t m_repeat_animation;
std::string m_tag_name;
Expand Down
1 change: 1 addition & 0 deletions impl/aselib/constants.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "constants.hpp"
22 changes: 22 additions & 0 deletions impl/aselib/constants.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef ASELIB_CONSTANTS_HPP
#define ASELIB_CONSTANTS_HPP

namespace aselib {

namespace magic_numbers {
} // namespace magic_numbers

namespace chunk_type_constants {

inline constexpr auto color_profile = 0x2007;
inline constexpr auto palette = 0x2019;
inline constexpr auto layer = 0x2004;
inline constexpr auto cel = 0x2005;
inline constexpr auto tag = 0x2018;
inline constexpr auto user_data = 0x2020;

} // namespace chunk_type_constants

} // namespace aselib

#endif // ASELIB_CONSTANTS_HPP
14 changes: 1 addition & 13 deletions impl/aselib/image_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ aselib::Image aselib::makeImageFromAse(aselib::AsepriteData const& ase)
std::uint32_t frame_offset_x = i * ase.m_header.m_width_in_pixel;
auto const& f = ase.m_frames[i];

if (f.m_chunks.m_cel_chunks.empty()) {
continue;
}

for (auto const& cel : f.m_chunks.m_cel_chunks) {
for (auto x_in_cel = 0; x_in_cel != cel.m_cell_width; ++x_in_cel) {
for (auto y_in_cel = 0; y_in_cel != cel.m_cell_height; ++y_in_cel) {
Expand All @@ -86,10 +82,6 @@ aselib::Image aselib::makeImageFromLayer(
{
Image img {};

if (ase.m_frames[0].m_chunks.m_layers_chunks.empty()) {
throw std::invalid_argument { "no layer information in first frame" };
}

bool found = false;
std::uint16_t layerID = 0;
for (auto i = 0u; i != ase.m_frames[0].m_chunks.m_layers_chunks.size(); ++i) {
Expand All @@ -115,11 +107,7 @@ aselib::Image aselib::makeImageFromLayer(

std::uint32_t frame_offset_x = i * ase.m_header.m_width_in_pixel;
auto const& f = ase.m_frames[i];

if (f.m_chunks.m_cel_chunks.empty()) {
continue;
}


for (auto const& cel : f.m_chunks.m_cel_chunks) {
if (cel.m_layer_index != layerID) {
continue;
Expand Down
7 changes: 7 additions & 0 deletions impl/aselib/pixel_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,11 @@
#include "pixel_data.hpp"

namespace aselib {

bool operator==(PixelDataRGBA const& lhs, PixelDataRGBA const& rhs)
{
return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a;
}
bool operator!=(PixelDataRGBA const& lhs, PixelDataRGBA const& rhs) { return !(rhs == lhs); }

} // namespace aselib
11 changes: 7 additions & 4 deletions impl/aselib/pixel_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
namespace aselib {

struct PixelDataRGBA {
aselib::Byte_t r;
aselib::Byte_t g;
aselib::Byte_t b;
aselib::Byte_t a;
Byte_t r { 0u };
Byte_t g { 0u };
Byte_t b { 0u };
Byte_t a { 0u };
};

bool operator==(PixelDataRGBA const& lhs, PixelDataRGBA const& rhs);
bool operator!=(PixelDataRGBA const& lhs, PixelDataRGBA const& rhs);

} // namespace aselib

#endif // ASEPRITELIB_PIXEL_DATA_HPP
10 changes: 10 additions & 0 deletions test/unit_tests/aseprite_data_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "catch2/catch.hpp"
#include <aselib/aseprite_data.hpp>

using namespace aselib;

TEST_CASE(
"AsepriteData Constructor raises exception when called invalid filepath", "[AsepriteData]")
{
REQUIRE_THROWS(AsepriteData { "non-existing_file&&++:," });
}
73 changes: 41 additions & 32 deletions test/unit_tests/chunk_data_test.cpp
Original file line number Diff line number Diff line change
@@ -1,41 +1,14 @@
#include "catch2/catch.hpp"
#include <aselib/aseprite_header.hpp>
#include <aselib/chunk_data.hpp>
#include <aselib/frame_header.hpp>
#include <aselib/aseprite_data.hpp>
#include <aselib/parse_functions.hpp>
#include <fstream>
using namespace aselib;

TEST_CASE("parse chunk m_header set correct stream position", "[header]")
{
std::ifstream in { "assets/test/unit/32_bit_1x1_white.aseprite", std::ios::binary };
REQUIRE(in.good());
AsepriteHeader hdr {};
in >> hdr;

REQUIRE(hdr.m_number_of_frames == 1);

FrameHader frameHeader {};
in >> frameHeader;
REQUIRE(in.tellg() == 128 + 16);
REQUIRE(frameHeader.m_number_of_chunks == 5);
REQUIRE(frameHeader.m_magic_number == 0xF1FA);
(void)parseChunkHeader(in);
REQUIRE(in.tellg() == 128 + 16 + 6);
}
using namespace aselib;

TEST_CASE("chunk data", "[header, chunk]")
TEST_CASE("chunk data", "[chunk]")
{
std::ifstream in { "assets/test/unit/32_bit_1x1_white.aseprite", std::ios::binary };
REQUIRE(in.good());
AsepriteHeader header {};
in >> header;

REQUIRE(header.m_number_of_frames == 1);
AsepriteData ase { "assets/test/unit/32_bit_1x1_white.aseprite" };

FrameHader frameHader {};
in >> frameHader;
auto const chunks = parseAllChunks(in, frameHader.m_number_of_chunks);
auto const chunks = ase.m_frames.front().m_chunks;

SECTION("color profile")
{
Expand Down Expand Up @@ -91,3 +64,39 @@ TEST_CASE("chunk data", "[header, chunk]")
SECTION("tags") { REQUIRE(chunks.m_tag_chunks.size() == 0); }
SECTION("user data") { REQUIRE(chunks.m_tag_chunks.size() == 0); }
}

TEST_CASE("UserData Chunk", "[chunk, user data]")
{
AsepriteData const ase { "assets/test/unit/32bit_1x1_white_with_user_data_string.aseprite" };

SECTION("text")
{
REQUIRE(!ase.m_frames.front().m_chunks.m_user_data_chunks.empty());
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_user_data_flags & 1);
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_text == "abcd");
}
SECTION("color")
{
REQUIRE(!ase.m_frames.front().m_chunks.m_user_data_chunks.empty());
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_user_data_flags & 2);
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_color_r == 255);
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_color_g == 0);
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_color_b == 0);
REQUIRE(ase.m_frames.front().m_chunks.m_user_data_chunks.front().m_color_a == 255);
}
}

TEST_CASE("Tag Chunk", "[chunk, tag]")
{
AsepriteData const ase { "assets/test/unit/32bit_1x1_white_with_user_data_string.aseprite" };

REQUIRE(!ase.m_frames.front().m_chunks.m_tag_chunks.empty());
REQUIRE(ase.m_frames.front().m_chunks.m_tag_chunks.front().m_tags.size() == 1);
REQUIRE(ase.m_frames.front().m_chunks.m_tag_chunks.front().m_tags.front().m_tag_name == "tag");
REQUIRE(ase.m_frames.front().m_chunks.m_tag_chunks.front().m_tags.front().m_from_frame == 0);
REQUIRE(ase.m_frames.front().m_chunks.m_tag_chunks.front().m_tags.front().m_to_frame == 0);
REQUIRE(
ase.m_frames.front().m_chunks.m_tag_chunks.front().m_tags.front().m_loop_direction == 0);
REQUIRE(
ase.m_frames.front().m_chunks.m_tag_chunks.front().m_tags.front().m_repeat_animation == 0);
}
23 changes: 23 additions & 0 deletions test/unit_tests/chunk_header_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "catch2/catch.hpp"
#include <aselib/aseprite_header.hpp>
#include <aselib/chunk_data.hpp>
#include <aselib/frame_header.hpp>
#include <aselib/parse_functions.hpp>
#include <fstream>
using namespace aselib;

TEST_CASE("parse first chunk header results in correct stream offset", "[header]")
{
std::ifstream in { "assets/test/unit/32_bit_1x1_white.aseprite", std::ios::binary };
REQUIRE(in.good());
AsepriteHeader hdr {};
in >> hdr;

REQUIRE(hdr.m_number_of_frames == 1);

FrameHader frameHeader {};
in >> frameHeader;
REQUIRE(in.tellg() == 128 + 16);
(void)parseChunkHeader(in);
REQUIRE(in.tellg() == 128 + 16 + 6);
}
97 changes: 27 additions & 70 deletions test/unit_tests/make_image_from_ase_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

using namespace aselib;

TEST_CASE("makeImageFromAse", "[image]")
TEST_CASE("make image from ase with one layer", "[image]")
{
AsepriteData const ase { "assets/test/unit/dino_salto.aseprite" };

Expand All @@ -14,83 +14,40 @@ TEST_CASE("makeImageFromAse", "[image]")
REQUIRE(img.m_width == 408);
REQUIRE(img.m_height == 18);

REQUIRE(img.m_pixels[img.posToIndex(0, 0)].r == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)].g == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)].b == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)].a == 0);

REQUIRE(img.m_pixels[img.posToIndex(8, 7)].r == 40);
REQUIRE(img.m_pixels[img.posToIndex(8, 7)].g == 87);
REQUIRE(img.m_pixels[img.posToIndex(8, 7)].b == 63);
REQUIRE(img.m_pixels[img.posToIndex(8, 7)].a == 255);

REQUIRE(img.m_pixels[img.posToIndex(32, 6)].r == 40);
REQUIRE(img.m_pixels[img.posToIndex(32, 6)].g == 87);
REQUIRE(img.m_pixels[img.posToIndex(32, 6)].b == 63);
REQUIRE(img.m_pixels[img.posToIndex(32, 6)].a == 255);

REQUIRE(img.m_pixels[img.posToIndex(83, 10)].r == 25);
REQUIRE(img.m_pixels[img.posToIndex(83, 10)].g == 46);
REQUIRE(img.m_pixels[img.posToIndex(83, 10)].b == 27);
REQUIRE(img.m_pixels[img.posToIndex(83, 10)].a == 255);

REQUIRE(img.m_pixels[img.posToIndex(270, 12)].r == 138);
REQUIRE(img.m_pixels[img.posToIndex(270, 12)].g == 122);
REQUIRE(img.m_pixels[img.posToIndex(270, 12)].b == 87);
REQUIRE(img.m_pixels[img.posToIndex(270, 12)].a == 255);

REQUIRE(img.m_pixels[img.posToIndex(401, 14)].r == 40);
REQUIRE(img.m_pixels[img.posToIndex(401, 14)].g == 87);
REQUIRE(img.m_pixels[img.posToIndex(401, 14)].b == 63);
REQUIRE(img.m_pixels[img.posToIndex(401, 14)].a == 255);

REQUIRE(img.m_pixels[img.posToIndex(407, 17)].r == 0);
REQUIRE(img.m_pixels[img.posToIndex(407, 17)].g == 0);
REQUIRE(img.m_pixels[img.posToIndex(407, 17)].b == 0);
REQUIRE(img.m_pixels[img.posToIndex(407, 17)].a == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)] == PixelDataRGBA { 0, 0, 0, 0 });
REQUIRE(img.m_pixels[img.posToIndex(8, 7)] == PixelDataRGBA { 40, 87, 63, 255 });
REQUIRE(img.m_pixels[img.posToIndex(32, 6)] == PixelDataRGBA { 40, 87, 63, 255 });
REQUIRE(img.m_pixels[img.posToIndex(83, 10)] == PixelDataRGBA { 25, 46, 27, 255 });
REQUIRE(img.m_pixels[img.posToIndex(270, 12)] == PixelDataRGBA { 138, 122, 87, 255 });
REQUIRE(img.m_pixels[img.posToIndex(401, 14)] == PixelDataRGBA { 40, 87, 63, 255 });
REQUIRE(img.m_pixels[img.posToIndex(407, 17)] == PixelDataRGBA { 0, 0, 0, 0 });
}

TEST_CASE("makeImageFromLayer", "[image, layer]")
TEST_CASE("make image from ase with multiple layers", "[image]")
{
AsepriteData const ase { "assets/test/unit/dino_salto.aseprite" };

auto const img = makeImageFromLayer(ase, "Layer 1");
AsepriteData const ase { "assets/test/unit/miner.aseprite" };

REQUIRE(img.m_width == 408);
REQUIRE(img.m_height == 18);

REQUIRE(img.m_pixels[img.posToIndex(0, 0)].r == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)].g == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)].b == 0);
REQUIRE(img.m_pixels[img.posToIndex(0, 0)].a == 0);
auto const img = makeImageFromAse(ase);

REQUIRE(img.m_pixels[img.posToIndex(8, 7)].r == 40);
REQUIRE(img.m_pixels[img.posToIndex(8, 7)].g == 87);
REQUIRE(img.m_pixels[img.posToIndex(8, 7)].b == 63);
REQUIRE(img.m_pixels[img.posToIndex(8, 7)].a == 255);
REQUIRE(img.m_width == 320);
REQUIRE(img.m_height == 32);

REQUIRE(img.m_pixels[img.posToIndex(32, 6)].r == 40);
REQUIRE(img.m_pixels[img.posToIndex(32, 6)].g == 87);
REQUIRE(img.m_pixels[img.posToIndex(32, 6)].b == 63);
REQUIRE(img.m_pixels[img.posToIndex(32, 6)].a == 255);
REQUIRE(img.m_pixels[img.posToIndex(16, 24)] == PixelDataRGBA { 248, 192, 144, 255 });
}

REQUIRE(img.m_pixels[img.posToIndex(83, 10)].r == 25);
REQUIRE(img.m_pixels[img.posToIndex(83, 10)].g == 46);
REQUIRE(img.m_pixels[img.posToIndex(83, 10)].b == 27);
REQUIRE(img.m_pixels[img.posToIndex(83, 10)].a == 255);
TEST_CASE("make image from ase with two layers and opacity", "[image]")
{
AsepriteData const ase {
"assets/test/unit/32_bit_2x2_white_with_transparent_overlay.aseprite"
};

REQUIRE(img.m_pixels[img.posToIndex(270, 12)].r == 138);
REQUIRE(img.m_pixels[img.posToIndex(270, 12)].g == 122);
REQUIRE(img.m_pixels[img.posToIndex(270, 12)].b == 87);
REQUIRE(img.m_pixels[img.posToIndex(270, 12)].a == 255);
auto const img = makeImageFromAse(ase);

REQUIRE(img.m_pixels[img.posToIndex(401, 14)].r == 40);
REQUIRE(img.m_pixels[img.posToIndex(401, 14)].g == 87);
REQUIRE(img.m_pixels[img.posToIndex(401, 14)].b == 63);
REQUIRE(img.m_pixels[img.posToIndex(401, 14)].a == 255);
REQUIRE(img.m_width == 2);
REQUIRE(img.m_height == 2);

REQUIRE(img.m_pixels[img.posToIndex(407, 17)].r == 0);
REQUIRE(img.m_pixels[img.posToIndex(407, 17)].g == 0);
REQUIRE(img.m_pixels[img.posToIndex(407, 17)].b == 0);
REQUIRE(img.m_pixels[img.posToIndex(407, 17)].a == 0);
REQUIRE(img.getPixelAt(0, 0) == PixelDataRGBA { 255, 155, 155, 255 });
REQUIRE(img.getPixelAt(1, 0) == PixelDataRGBA { 155, 255, 155, 255 });
REQUIRE(img.getPixelAt(0, 1) == PixelDataRGBA { 255, 255, 255, 255 });
REQUIRE(img.getPixelAt(1, 1) == PixelDataRGBA { 155, 155, 255, 255 });
}
Loading

0 comments on commit 85b5703

Please sign in to comment.