yaze 0.2.0
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
compression_test.cc
Go to the documentation of this file.
2
3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
5
6#include <array>
7
8#include "absl/status/statusor.h"
9#include "app/rom.h"
10
11#define BUILD_HEADER(command, length) (command << 5) + (length - 1)
12
13namespace yaze {
14namespace test {
15namespace gfx {
16
17using yaze::app::Rom;
29
30using ::testing::ElementsAre;
31using ::testing::ElementsAreArray;
32using ::testing::TypedEq;
33
34namespace {
35
36std::vector<uint8_t> ExpectCompressOk(Rom& rom, uchar* in, int in_size) {
37 auto load_status = rom.LoadFromPointer(in, in_size, false);
38 EXPECT_TRUE(load_status.ok());
39 auto compression_status = CompressV3(rom.vector(), 0, in_size);
40 EXPECT_TRUE(compression_status.ok());
41 auto compressed_bytes = std::move(*compression_status);
42 return compressed_bytes;
43}
44
45std::vector<uint8_t> ExpectDecompressBytesOk(Rom& rom,
46 std::vector<uint8_t>& in) {
47 auto load_status = rom.LoadFromBytes(in);
48 EXPECT_TRUE(load_status.ok());
49 auto decompression_status = DecompressV2(rom.data(), 0, in.size());
50 EXPECT_TRUE(decompression_status.ok());
51 auto decompressed_bytes = std::move(*decompression_status);
52 return decompressed_bytes;
53}
54
55std::vector<uint8_t> ExpectDecompressOk(Rom& rom, uchar* in, int in_size) {
56 auto load_status = rom.LoadFromPointer(in, in_size, false);
57 EXPECT_TRUE(load_status.ok());
58 auto decompression_status = DecompressV2(rom.data(), 0, in_size);
59 EXPECT_TRUE(decompression_status.ok());
60 auto decompressed_bytes = std::move(*decompression_status);
61 return decompressed_bytes;
62}
63
64std::shared_ptr<CompressionPiece> ExpectNewCompressionPieceOk(
65 const char command, const int length, const std::string args,
66 const int argument_length) {
67 auto new_piece = std::make_shared<CompressionPiece>(command, length, args,
68 argument_length);
69 EXPECT_TRUE(new_piece != nullptr);
70 return new_piece;
71}
72
73// Helper function to assert compression quality.
75 const std::vector<uint8_t>& uncompressed_data,
76 const std::vector<uint8_t>& expected_compressed_data) {
77 absl::StatusOr<std::vector<uint8_t>> result =
78 CompressV3(uncompressed_data, 0, uncompressed_data.size(), 0, false);
79 ASSERT_TRUE(result.ok());
80 auto compressed_data = std::move(*result);
81 EXPECT_THAT(compressed_data, ElementsAreArray(expected_compressed_data));
82}
83
84std::vector<uint8_t> ExpectCompressV3Ok(const std::vector<uint8_t>& uncompressed_data,
85 const std::vector<uint8_t>& expected_compressed_data) {
86 absl::StatusOr<std::vector<uint8_t>> result =
87 CompressV3(uncompressed_data, 0, uncompressed_data.size(), 0, false);
88 EXPECT_TRUE(result.ok());
89 auto compressed_data = std::move(*result);
90 return compressed_data;
91}
92
94 int leftUncompressedSize, int repeatedByteSize, int rightUncompressedSize) {
95 std::vector<uint8_t> result(
96 leftUncompressedSize + repeatedByteSize + rightUncompressedSize, 0);
97 std::fill_n(result.begin() + leftUncompressedSize, repeatedByteSize, 0x00);
98 return result;
99}
100
101} // namespace
102
103TEST(LC_LZ2_CompressionTest, TrivialRepeatedBytes) {
104 AssertCompressionQuality({0x00, 0x00, 0x00}, {0x22, 0x00, 0xFF});
105}
106
107TEST(LC_LZ2_CompressionTest, RepeatedBytesBetweenUncompressable) {
108 AssertCompressionQuality({0x01, 0x00, 0x00, 0x00, 0x10},
109 {0x04, 0x01, 0x00, 0x00, 0x00, 0x10, 0xFF});
110}
111
112TEST(LC_LZ2_CompressionTest, RepeatedBytesBeforeUncompressable) {
113 AssertCompressionQuality({0x00, 0x00, 0x00, 0x10},
114 {0x22, 0x00, 0x00, 0x10, 0xFF});
115}
116
117TEST(LC_LZ2_CompressionTest, RepeatedBytesAfterUncompressable) {
118 AssertCompressionQuality({0x01, 0x00, 0x00, 0x00},
119 {0x00, 0x01, 0x22, 0x00, 0xFF});
120}
121
122TEST(LC_LZ2_CompressionTest, RepeatedBytesAfterUncompressableRepeated) {
123 AssertCompressionQuality(
124 {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02},
125 {0x22, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x02, 0xFF});
126}
127
128TEST(LC_LZ2_CompressionTest, RepeatedBytesBeforeUncompressableRepeated) {
129 AssertCompressionQuality(
130 {0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00},
131 {0x04, 0x01, 0x00, 0x00, 0x00, 0x02, 0x22, 0x00, 0xFF});
132}
133
134TEST(LC_LZ2_CompressionTest, NewDecompressionPieceOk) {
135 char command = 1;
136 int length = 1;
137 char args[] = "aaa";
138 int argument_length = 0x02;
139 CompressionPiece old_piece;
140 old_piece.command = command;
141 old_piece.length = length;
142 old_piece.argument = args;
143 old_piece.argument_length = argument_length;
144 old_piece.next = nullptr;
145
146 auto new_piece = ExpectNewCompressionPieceOk(0x01, 0x01, "aaa", 0x02);
147
148 EXPECT_EQ(old_piece.command, new_piece->command);
149 EXPECT_EQ(old_piece.length, new_piece->length);
150 ASSERT_EQ(old_piece.argument_length, new_piece->argument_length);
151 for (int i = 0; i < old_piece.argument_length; ++i) {
152 EXPECT_EQ(old_piece.argument[i], new_piece->argument[i]);
153 }
154}
155
156// TODO: Check why header built is off by one
157// 0x25 instead of 0x24
158TEST(LC_LZ2_CompressionTest, CompressionSingleSet) {
159 Rom rom;
160 uchar single_set[5] = {0x2A, 0x2A, 0x2A, 0x2A, 0x2A};
161 uchar single_set_expected[3] = {BUILD_HEADER(1, 5), 0x2A, 0xFF};
162
163 auto comp_result = ExpectCompressOk(rom, single_set, 5);
164 EXPECT_THAT(single_set_expected, ElementsAreArray(comp_result.data(), 3));
165}
166
167TEST(LC_LZ2_CompressionTest, CompressionSingleWord) {
168 Rom rom;
169 uchar single_word[6] = {0x2A, 0x01, 0x2A, 0x01, 0x2A, 0x01};
170 uchar single_word_expected[4] = {BUILD_HEADER(0x02, 0x06), 0x2A, 0x01, 0xFF};
171
172 auto comp_result = ExpectCompressOk(rom, single_word, 6);
173 EXPECT_THAT(single_word_expected, ElementsAreArray(comp_result.data(), 4));
174}
175
176TEST(LC_LZ2_CompressionTest, CompressionSingleIncrement) {
177 Rom rom;
178 uchar single_inc[3] = {0x01, 0x02, 0x03};
179 uchar single_inc_expected[3] = {BUILD_HEADER(0x03, 0x03), 0x01, 0xFF};
180 auto comp_result = ExpectCompressOk(rom, single_inc, 3);
181 EXPECT_THAT(single_inc_expected, ElementsAreArray(comp_result.data(), 3));
182}
183
184TEST(LC_LZ2_CompressionTest, CompressionSingleCopy) {
185 Rom rom;
186 uchar single_copy[4] = {0x03, 0x0A, 0x07, 0x14};
187 uchar single_copy_expected[6] = {
188 BUILD_HEADER(0x00, 0x04), 0x03, 0x0A, 0x07, 0x14, 0xFF};
189 auto comp_result = ExpectCompressOk(rom, single_copy, 4);
190 EXPECT_THAT(single_copy_expected, ElementsAreArray(comp_result.data(), 6));
191}
192
193TEST(LC_LZ2_CompressionTest, CompressionSingleOverflowIncrement) {
194 AssertCompressionQuality({0xFE, 0xFF, 0x00, 0x01},
195 {BUILD_HEADER(0x03, 0x04), 0xFE, 0xFF});
196}
350// Tests for HandleDirectCopy
351
352TEST(HandleDirectCopyTest, NotDirectCopyWithAccumulatedBytes) {
353 CompressionContext context({0x01, 0x02, 0x03}, 0, 3);
354 context.cmd_with_max = kCommandByteFill;
355 context.comp_accumulator = 2;
356 HandleDirectCopy(context);
357 EXPECT_EQ(context.compressed_data.size(), 3);
358}
359
360TEST(HandleDirectCopyTest, NotDirectCopyWithoutAccumulatedBytes) {
361 CompressionContext context({0x01, 0x02, 0x03}, 0, 3);
362 context.cmd_with_max = kCommandByteFill;
363 HandleDirectCopy(context);
364 EXPECT_EQ(context.compressed_data.size(), 2); // Header + 1 byte
365}
366
367TEST(HandleDirectCopyTest, AccumulateBytesWithoutMax) {
368 CompressionContext context({0x01, 0x02, 0x03}, 0, 3);
369 context.cmd_with_max = kCommandDirectCopy;
370 HandleDirectCopy(context);
371 EXPECT_EQ(context.comp_accumulator, 1);
372 EXPECT_EQ(context.compressed_data.size(), 0); // No data added yet
373}
374
375// Tests for CheckIncByteV3
376
377TEST(CheckIncByteV3Test, IncreasingSequence) {
378 CompressionContext context({0x01, 0x02, 0x03}, 0, 3);
379 CheckIncByteV3(context);
380 EXPECT_EQ(context.current_cmd.data_size[kCommandIncreasingFill], 3);
381}
382
383TEST(CheckIncByteV3Test, IncreasingSequenceSurroundedByIdenticalBytes) {
384 CompressionContext context({0x01, 0x02, 0x03, 0x04, 0x01}, 1,
385 3); // Start from index 1
386 CheckIncByteV3(context);
387 EXPECT_EQ(context.current_cmd.data_size[kCommandIncreasingFill],
388 0); // Reset to prioritize direct copy
389}
390
391TEST(CheckIncByteV3Test, NotAnIncreasingSequence) {
392 CompressionContext context({0x01, 0x01, 0x03}, 0, 3);
393 CheckIncByteV3(context);
394 EXPECT_EQ(context.current_cmd.data_size[kCommandIncreasingFill],
395 1); // Only one byte is detected
396}
397
398TEST(LC_LZ2_CompressionTest, DecompressionValidCommand) {
399 Rom rom;
400 std::vector<uint8_t> simple_copy_input = {BUILD_HEADER(0x00, 0x02), 0x2A, 0x45, 0xFF};
401 uchar simple_copy_output[2] = {0x2A, 0x45};
402 auto decomp_result = ExpectDecompressBytesOk(rom, simple_copy_input);
403 EXPECT_THAT(simple_copy_output, ElementsAreArray(decomp_result.data(), 2));
404}
405
406TEST(LC_LZ2_CompressionTest, DecompressionMixingCommand) {
407 Rom rom;
408 uchar random1_i[11] = {BUILD_HEADER(0x01, 0x03),
409 0x2A,
410 BUILD_HEADER(0x00, 0x04),
411 0x01,
412 0x02,
413 0x03,
414 0x04,
415 BUILD_HEADER(0x02, 0x02),
416 0x0B,
417 0x16,
418 0xFF};
419 uchar random1_o[9] = {42, 42, 42, 1, 2, 3, 4, 11, 22};
420 auto decomp_result = ExpectDecompressOk(rom, random1_i, 11);
421 EXPECT_THAT(random1_o, ElementsAreArray(decomp_result.data(), 9));
422}
423
424} // namespace gfx
425} // namespace test
426} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:145
auto vector() const
Definition rom.h:471
auto data()
Definition rom.h:470
absl::Status LoadFromBytes(const std::vector< uint8_t > &data)
Definition rom.cc:243
absl::Status LoadFromPointer(uchar *data, size_t length, bool z3_load=true)
Definition rom.cc:191
#define BUILD_HEADER(command, length)
Definition compression.h:12
unsigned char uchar
Definition constants.h:121
constexpr int kCommandLongLength
Definition compression.h:43
constexpr int kCommandByteFill
Definition compression.h:39
absl::StatusOr< std::vector< uint8_t > > CompressV3(const std::vector< uint8_t > &data, const int start, const int length, int mode, bool check)
Compresses a buffer of data using the LC_LZ2 algorithm.
constexpr int kCommandIncreasingFill
Definition compression.h:41
constexpr int kCommandDirectCopy
Definition compression.h:38
absl::StatusOr< std::vector< uint8_t > > CompressV2(const uchar *data, const int start, const int length, int mode, bool check)
Compresses a buffer of data using the LC_LZ2 algorithm.
absl::StatusOr< std::vector< uint8_t > > DecompressV2(const uchar *data, int offset, int size, int mode)
Decompresses a buffer of data using the LC_LZ2 algorithm.
constexpr int kCommandRepeatingBytes
Definition compression.h:42
constexpr int kCommandWordFill
Definition compression.h:40
std::vector< uint8_t > CreateRepeatedBetweenUncompressable(int leftUncompressedSize, int repeatedByteSize, int rightUncompressedSize)
std::vector< uint8_t > ExpectDecompressBytesOk(Rom &rom, std::vector< uint8_t > &in)
std::vector< uint8_t > ExpectCompressOk(Rom &rom, uchar *in, int in_size)
void AssertCompressionQuality(const std::vector< uint8_t > &uncompressed_data, const std::vector< uint8_t > &expected_compressed_data)
std::vector< uint8_t > ExpectCompressV3Ok(const std::vector< uint8_t > &uncompressed_data, const std::vector< uint8_t > &expected_compressed_data)
std::shared_ptr< CompressionPiece > ExpectNewCompressionPieceOk(const char command, const int length, const std::string args, const int argument_length)
std::vector< uint8_t > ExpectDecompressOk(Rom &rom, uchar *in, int in_size)
TEST(LC_LZ2_CompressionTest, TrivialRepeatedBytes)
Definition common.cc:21
std::shared_ptr< CompressionPiece > next
Definition compression.h:77