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