Skip to content

Commit

Permalink
Consolidate C and Python tests (#21)
Browse files Browse the repository at this point in the history
* Consolidate Python tests

* Consolidate C tests

* Un-allman
  • Loading branch information
cadmic committed Jun 4, 2024
1 parent fb8a385 commit 5c29148
Show file tree
Hide file tree
Showing 17 changed files with 359 additions and 1,056 deletions.
12 changes: 3 additions & 9 deletions .github/workflows/c_bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,11 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v4

- name: Make C test programs
- name: Make C test program
run: make -C c_bindings BUILD_MODE=release

- name: Test MIO0
run: ./c_bindings/tests/test_mio0.sh

- name: Test Yay0
run: ./c_bindings/tests/test_yay0.sh

- name: Test Yaz0
run: ./c_bindings/tests/test_yaz0.sh
- name: Run tests
run: c_bindings/tests.elf

release:
name: Release ${{ matrix.crate-type }} for ${{ matrix.target }}
Expand Down
10 changes: 2 additions & 8 deletions .github/workflows/python_bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,5 @@ jobs:
- name: Install local crunch64
run: python3 -m pip install ./lib

- name: Test MIO0
run: python3 ./python_bindings/tests/test_mio0.py

- name: Test Yay0
run: python3 ./python_bindings/tests/test_yay0.py

- name: Test Yaz0
run: python3 ./python_bindings/tests/test_yaz0.py
- name: Run tests
run: python3 ./python_bindings/tests.py
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.venv/
target/
*.bin
*.Yay0
Expand Down
12 changes: 6 additions & 6 deletions c_bindings/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ IINC := -I include
WARNINGS := -Wall -Wextra -Wshadow -Werror


C_BINDINGS_TESTS := $(wildcard tests/test_*.c)
C_BINDINGS_ELFS := $(C_BINDINGS_TESTS:.c=.elf)
C_BINDINGS_TESTS := tests.c
C_BINDINGS_ELF := tests.elf

all: $(C_BINDINGS_ELFS)
all: $(C_BINDINGS_ELF)

clean:
$(RM) -rf $(C_BINDINGS_ELFS) tests/*.elf
$(RM) $(C_BINDINGS_ELF)

.PHONY: all clean
.DEFAULT_GOAL := all
Expand All @@ -32,8 +32,8 @@ endif
$(shell cargo build --lib --features c_bindings $(CARGO_FLAGS))


%.elf: %.c $(LIB)
$(CC) $(CSTD) $(CFLAGS) $(IINC) $(WARNINGS) -o $@ tests/utils.c $< -L ../target/$(BUILD_MODE) -Wl,-Bstatic -l crunch64 -Wl,-Bdynamic
$(C_BINDINGS_ELF): $(C_BINDINGS_TESTS) $(LIB)
$(CC) $(CSTD) $(CFLAGS) $(IINC) $(WARNINGS) -o $@ $< -L ../target/$(BUILD_MODE) -Wl,-Bstatic -l crunch64 -Wl,-Bdynamic

# Print target for debugging
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
255 changes: 255 additions & 0 deletions c_bindings/tests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
#include "crunch64.h"

#include <assert.h>
#include <dirent.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef Crunch64Error (*compress_bound_fn)(size_t *dst_size, size_t src_len, const uint8_t *const src);
typedef Crunch64Error (*compress_fn)(size_t *dst_size, uint8_t *dst, size_t src_size, const uint8_t *src);

const char *const crunch64_error_str[] = {
[Crunch64Error_Okay] = "Okay",
[Crunch64Error_InvalidYay0Header] = "Invalid Yay0 header",
[Crunch64Error_InvalidYaz0Header] = "Invalid Yaz0 header",
[Crunch64Error_InvalidMio0Header] = "Invalid Mio0 header",
[Crunch64Error_UnsupportedCompressionType] = "Unsupported compression type",
[Crunch64Error_UnalignedRead] = "Unaligned read",
[Crunch64Error_ByteConversion] = "Byte conversion",
[Crunch64Error_OutOfBounds] = "Out of bounds",
[Crunch64Error_NullPointer] = "Null pointer",
};

const char *get_crunch64_error_str(Crunch64Error error) {
return crunch64_error_str[error];
}

bool has_suffix(const char *str, const char *suffix) {
size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);
return str_len >= suffix_len && strcmp(str + str_len - suffix_len, suffix) == 0;
}

uint8_t *read_binary_file(const char *path, size_t *size) {
assert(path != NULL);
assert(size != NULL);

FILE *f = fopen(path, "rb");
if (f == NULL) {
return NULL;
}

fseek(f, 0, SEEK_END);
*size = ftell(f);
fseek(f, 0, SEEK_SET);

uint8_t *data = malloc(*size * sizeof(uint8_t));
if (data == NULL) {
fclose(f);
return NULL;
}

size_t count = fread(data, sizeof(uint8_t), *size, f);
if (count != *size) {
free(data);
fclose(f);
return NULL;
}

fclose(f);
return data;
}

bool write_binary_file(const char *path, uint8_t *data, size_t size) {
assert(path != NULL);
assert(data != NULL);

FILE *f = fopen(path, "wb");
if (f == NULL) {
return false;
}

size_t count = fwrite(data, sizeof(uint8_t), size, f);
if (count != size) {
return false;
}

fclose(f);

return true;
}

bool compare_buffers(size_t a_size, const uint8_t *a, size_t b_size, const uint8_t *b) {
if (a_size != b_size) {
fprintf(stderr, " sizes don't match\n");
return false;
}

if (memcmp(a, b, a_size) != 0) {
fprintf(stderr, " data doesn't match\n");
return false;
}

fprintf(stderr, " OK\n");

return true;
}

bool test_matching_decompression(compress_bound_fn decompress_bound, compress_fn decompress, size_t bin_size,
uint8_t *bin, size_t compressed_size, uint8_t *compressed_data) {
fprintf(stderr, "Testing matching decompression:\n");

fprintf(stderr, " decompressing: ");
size_t decompressed_size;
uint8_t *decompressed_data = NULL;

Crunch64Error size_request_ok = decompress_bound(&decompressed_size, compressed_size, compressed_data);
if (size_request_ok != Crunch64Error_Okay) {
fprintf(stderr, " failed to request size for buffer. Reason: %s\n", get_crunch64_error_str(size_request_ok));
return false;
}

decompressed_data = malloc(decompressed_size * sizeof(uint8_t));
if (decompressed_data == NULL) {
fprintf(stderr, " malloc fail: 0x%zX bytes\n", decompressed_size * sizeof(uint8_t));
return false;
}

Crunch64Error decompress_ok = decompress(&decompressed_size, decompressed_data, compressed_size, compressed_data);
if (decompress_ok != Crunch64Error_Okay) {
fprintf(stderr, " failed to decompress data. Reason: %s\n", get_crunch64_error_str(decompress_ok));
free(decompressed_data);
return false;
}

fprintf(stderr, " OK\n");

fprintf(stderr, " validating data: ");
bool matches = compare_buffers(decompressed_size, decompressed_data, bin_size, bin);
if (!matches) {
free(decompressed_data);
return false;
}

free(decompressed_data);
return true;
}

bool test_matching_compression(compress_bound_fn compress_bound, compress_fn compress, size_t bin_size, uint8_t *bin,
size_t compressed_size, uint8_t *compressed_data) {
fprintf(stderr, "Testing matching compression:\n");
fprintf(stderr, " compressing: ");

size_t recompressed_size;
uint8_t *recompressed_data = NULL;

Crunch64Error size_request_ok = compress_bound(&recompressed_size, bin_size, bin);
if (size_request_ok != Crunch64Error_Okay) {
fprintf(stderr, " failed to request size for buffer. Reason: %s\n", get_crunch64_error_str(size_request_ok));
return false;
}

recompressed_data = malloc(recompressed_size * sizeof(uint8_t));
if (recompressed_data == NULL) {
fprintf(stderr, " malloc fail: 0x%zX bytes\n", recompressed_size * sizeof(uint8_t));
return false;
}

Crunch64Error compress_ok = compress(&recompressed_size, recompressed_data, bin_size, bin);
if (compress_ok != Crunch64Error_Okay) {
fprintf(stderr, " failed to decompress data. Reason: %s\n", get_crunch64_error_str(compress_ok));
free(recompressed_data);
return false;
}

fprintf(stderr, " OK\n");

fprintf(stderr, " validating data: ");
bool matches = compare_buffers(recompressed_size, recompressed_data, compressed_size, compressed_data);
if (!matches) {
free(recompressed_data);
return false;
}

free(recompressed_data);
return true;
}

int errors = 0;

void run_tests(const char *name, const char *file_extension, compress_bound_fn compress_bound, compress_fn compress,
compress_bound_fn decompress_bound, compress_fn decompress) {
struct dirent *entry;
DIR *dir = opendir("test_data");
if (!dir) {
fprintf(stderr, "Could not open test_data directory\n");
errors++;
return;
}

fprintf(stderr, "Running tests for %s\n", name);
fprintf(stderr, "\n");

bool found_tests = false;
while ((entry = readdir(dir)) != NULL) {
if (!has_suffix(entry->d_name, file_extension)) {
continue;
}

found_tests = true;

char bin_path[512];
snprintf(bin_path, sizeof(bin_path), "test_data/%s", entry->d_name);
bin_path[strlen(bin_path) - strlen(file_extension)] = '\0'; // remove file extension

char compressed_path[512];
snprintf(compressed_path, sizeof(compressed_path), "test_data/%s", entry->d_name);

fprintf(stderr, "Reading file %s\n", bin_path);
size_t bin_size = 0;
uint8_t *bin = read_binary_file(bin_path, &bin_size);
assert(bin_size > 0);
assert(bin != NULL);

fprintf(stderr, "Reading file %s\n", compressed_path);
size_t compressed_data_size = 0;
uint8_t *compressed_data = read_binary_file(compressed_path, &compressed_data_size);
assert(compressed_data_size > 0);
assert(compressed_data != NULL);

if (!test_matching_decompression(decompress_bound, decompress, bin_size, bin, compressed_data_size, compressed_data)) {
errors++;
}
if (!test_matching_compression(compress_bound, compress, bin_size, bin, compressed_data_size, compressed_data)) {
errors++;
}

fprintf(stderr, "\n");

free(bin);
free(compressed_data);
}

if (!found_tests) {
fprintf(stderr, "No test files found for %s\n", name);
errors++;
return;
}
}

int main(void) {
run_tests("yay0", ".Yay0", crunch64_yay0_compress_bound, crunch64_yay0_compress, crunch64_yay0_decompress_bound, crunch64_yay0_decompress);
run_tests("yaz0", ".Yaz0", crunch64_yaz0_compress_bound, crunch64_yaz0_compress, crunch64_yaz0_decompress_bound, crunch64_yaz0_decompress);
run_tests("mio0", ".MIO0", crunch64_mio0_compress_bound, crunch64_mio0_compress, crunch64_mio0_decompress_bound, crunch64_mio0_decompress);

if (errors == 0) {
fprintf(stderr, "All tests passed\n");
return 0;
} else {
fprintf(stderr, "%d tests failed\n", errors);
return 1;
}
}
Loading

0 comments on commit 5c29148

Please sign in to comment.