mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,9 @@
|
||||
#include "../test.h" // IWYU pragma: keep
|
||||
|
||||
#include <toolbox/compress.h>
|
||||
#include <toolbox/md5_calc.h>
|
||||
#include <toolbox/tar/tar_archive.h>
|
||||
#include <toolbox/dir_walk.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
@@ -56,7 +59,7 @@ static void compress_test_reference_comp_decomp() {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
uint8_t* temp_buffer = malloc(1024);
|
||||
Compress* comp = compress_alloc(1024);
|
||||
Compress* comp = compress_alloc(CompressTypeHeatshrink, &compress_config_heatshrink_default);
|
||||
|
||||
size_t encoded_size = 0;
|
||||
mu_assert(
|
||||
@@ -98,7 +101,7 @@ static void compress_test_random_comp_decomp() {
|
||||
// We only fill half of the buffer with random data, so if anything goes wrong, there's no overflow
|
||||
static const size_t src_data_size = src_buffer_size / 2;
|
||||
|
||||
Compress* comp = compress_alloc(src_buffer_size);
|
||||
Compress* comp = compress_alloc(CompressTypeHeatshrink, &compress_config_heatshrink_default);
|
||||
uint8_t* src_buff = malloc(src_buffer_size);
|
||||
uint8_t* encoded_buff = malloc(encoded_buffer_size);
|
||||
uint8_t* decoded_buff = malloc(src_buffer_size);
|
||||
@@ -146,9 +149,200 @@ static void compress_test_random_comp_decomp() {
|
||||
compress_free(comp);
|
||||
}
|
||||
|
||||
static int32_t hs_unpacker_file_read(void* context, uint8_t* buffer, size_t size) {
|
||||
File* file = (File*)context;
|
||||
return storage_file_read(file, buffer, size);
|
||||
}
|
||||
|
||||
static int32_t hs_unpacker_file_write(void* context, uint8_t* buffer, size_t size) {
|
||||
File* file = (File*)context;
|
||||
return storage_file_write(file, buffer, size);
|
||||
}
|
||||
/*
|
||||
Source file was generated with:
|
||||
```python3
|
||||
import random, string
|
||||
random.seed(1337)
|
||||
with open("hsstream.out.bin", "wb") as f:
|
||||
for c in random.choices(string.printable, k=1024):
|
||||
for _ in range(random.randint(1, 10)):
|
||||
f.write(c.encode())
|
||||
```
|
||||
|
||||
It was compressed with heatshrink using the following command:
|
||||
`python3 -m heatshrink2 compress -w 9 -l 4 hsstream.out.bin hsstream.in.bin`
|
||||
*/
|
||||
|
||||
#define HSSTREAM_IN COMPRESS_UNIT_TESTS_PATH("hsstream.in.bin")
|
||||
#define HSSTREAM_OUT COMPRESS_UNIT_TESTS_PATH("hsstream.out.bin")
|
||||
|
||||
static void compress_test_heatshrink_stream() {
|
||||
Storage* api = furi_record_open(RECORD_STORAGE);
|
||||
File* comp_file = storage_file_alloc(api);
|
||||
File* dest_file = storage_file_alloc(api);
|
||||
|
||||
CompressConfigHeatshrink config = {
|
||||
.window_sz2 = 9,
|
||||
.lookahead_sz2 = 4,
|
||||
.input_buffer_sz = 128,
|
||||
};
|
||||
Compress* compress = compress_alloc(CompressTypeHeatshrink, &config);
|
||||
|
||||
do {
|
||||
storage_simply_remove(api, HSSTREAM_OUT);
|
||||
|
||||
mu_assert(
|
||||
storage_file_open(comp_file, HSSTREAM_IN, FSAM_READ, FSOM_OPEN_EXISTING),
|
||||
"Failed to open compressed file");
|
||||
|
||||
mu_assert(
|
||||
storage_file_open(dest_file, HSSTREAM_OUT, FSAM_WRITE, FSOM_OPEN_ALWAYS),
|
||||
"Failed to open decompressed file");
|
||||
|
||||
mu_assert(
|
||||
compress_decode_streamed(
|
||||
compress, hs_unpacker_file_read, comp_file, hs_unpacker_file_write, dest_file),
|
||||
"Decompression failed");
|
||||
|
||||
storage_file_close(dest_file);
|
||||
|
||||
unsigned char md5[16];
|
||||
FS_Error file_error;
|
||||
mu_assert(
|
||||
md5_calc_file(dest_file, HSSTREAM_OUT, md5, &file_error), "Failed to calculate md5");
|
||||
|
||||
const unsigned char expected_md5[16] = {
|
||||
0xa3,
|
||||
0x70,
|
||||
0xe8,
|
||||
0x8b,
|
||||
0xa9,
|
||||
0x42,
|
||||
0x74,
|
||||
0xf4,
|
||||
0xaa,
|
||||
0x12,
|
||||
0x8d,
|
||||
0x41,
|
||||
0xd2,
|
||||
0xb6,
|
||||
0x71,
|
||||
0xc9};
|
||||
mu_assert(memcmp(md5, expected_md5, sizeof(md5)) == 0, "MD5 mismatch after decompression");
|
||||
|
||||
storage_simply_remove(api, HSSTREAM_OUT);
|
||||
} while(false);
|
||||
|
||||
compress_free(compress);
|
||||
storage_file_free(comp_file);
|
||||
storage_file_free(dest_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
#define HS_TAR_PATH COMPRESS_UNIT_TESTS_PATH("test.ths")
|
||||
#define HS_TAR_EXTRACT_PATH COMPRESS_UNIT_TESTS_PATH("tar_out")
|
||||
|
||||
static bool file_counter(const char* name, bool is_dir, void* context) {
|
||||
UNUSED(name);
|
||||
UNUSED(is_dir);
|
||||
int32_t* n_entries = (int32_t*)context;
|
||||
(*n_entries)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Heatshrink tar file contents and MD5 sums:
|
||||
file1.txt: 64295676ceed5cce2d0dcac402e4bda4
|
||||
file2.txt: 188f67f297eedd7bf3d6a4d3c2fc31c4
|
||||
dir/file3.txt: 34d98ad8135ffe502dba374690136d16
|
||||
dir/big_file.txt: ee169c1e1791a4d319dbfaefaa850e98
|
||||
dir/nested_dir/file4.txt: e099fcb2aaa0672375eaedc549247ee6
|
||||
dir/nested_dir/empty_file.txt: d41d8cd98f00b204e9800998ecf8427e
|
||||
|
||||
XOR of all MD5 sums: 92ed5729786d0e1176d047e35f52d376
|
||||
*/
|
||||
|
||||
static void compress_test_heatshrink_tar() {
|
||||
Storage* api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
TarArchive* archive = tar_archive_alloc(api);
|
||||
FuriString* path = furi_string_alloc();
|
||||
FileInfo fileinfo;
|
||||
File* file = storage_file_alloc(api);
|
||||
|
||||
do {
|
||||
storage_simply_remove_recursive(api, HS_TAR_EXTRACT_PATH);
|
||||
|
||||
mu_assert(storage_simply_mkdir(api, HS_TAR_EXTRACT_PATH), "Failed to create extract dir");
|
||||
|
||||
mu_assert(
|
||||
tar_archive_get_mode_for_path(HS_TAR_PATH) == TarOpenModeReadHeatshrink,
|
||||
"Invalid mode for heatshrink tar");
|
||||
|
||||
mu_assert(
|
||||
tar_archive_open(archive, HS_TAR_PATH, TarOpenModeReadHeatshrink),
|
||||
"Failed to open heatshrink tar");
|
||||
|
||||
int32_t n_entries = 0;
|
||||
tar_archive_set_file_callback(archive, file_counter, &n_entries);
|
||||
|
||||
mu_assert(
|
||||
tar_archive_unpack_to(archive, HS_TAR_EXTRACT_PATH, NULL),
|
||||
"Failed to unpack heatshrink tar");
|
||||
|
||||
mu_assert(n_entries == 9, "Invalid number of entries in heatshrink tar");
|
||||
|
||||
uint8_t md5_total[16] = {0}, md5_file[16];
|
||||
|
||||
DirWalk* dir_walk = dir_walk_alloc(api);
|
||||
mu_assert(dir_walk_open(dir_walk, HS_TAR_EXTRACT_PATH), "Failed to open dirwalk");
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
continue;
|
||||
}
|
||||
mu_assert(
|
||||
md5_calc_file(file, furi_string_get_cstr(path), md5_file, NULL),
|
||||
"Failed to calc md5");
|
||||
|
||||
for(size_t i = 0; i < 16; i++) {
|
||||
md5_total[i] ^= md5_file[i];
|
||||
}
|
||||
}
|
||||
dir_walk_free(dir_walk);
|
||||
|
||||
static const unsigned char expected_md5[16] = {
|
||||
0x92,
|
||||
0xed,
|
||||
0x57,
|
||||
0x29,
|
||||
0x78,
|
||||
0x6d,
|
||||
0x0e,
|
||||
0x11,
|
||||
0x76,
|
||||
0xd0,
|
||||
0x47,
|
||||
0xe3,
|
||||
0x5f,
|
||||
0x52,
|
||||
0xd3,
|
||||
0x76};
|
||||
mu_assert(memcmp(md5_total, expected_md5, sizeof(md5_total)) == 0, "MD5 mismatch");
|
||||
|
||||
storage_simply_remove_recursive(api, HS_TAR_EXTRACT_PATH);
|
||||
} while(false);
|
||||
|
||||
storage_file_free(file);
|
||||
furi_string_free(path);
|
||||
tar_archive_free(archive);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_compress) {
|
||||
MU_RUN_TEST(compress_test_random_comp_decomp);
|
||||
MU_RUN_TEST(compress_test_reference_comp_decomp);
|
||||
MU_RUN_TEST(compress_test_heatshrink_stream);
|
||||
MU_RUN_TEST(compress_test_heatshrink_tar);
|
||||
}
|
||||
|
||||
int run_minunit_test_compress(void) {
|
||||
|
||||
Reference in New Issue
Block a user