Login
1 branch 0 tags
Ben (Desktop/Arch) Added a testsuite 7a0c574 28 days ago 84 Commits
moon / tests / test_helpers.c
#include "test_helpers.h"

#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "storage.h"

#define TEST_ROOT_FS "./sdcard/.tests"
#define COPY_BUF_SIZE 1024

static bool remove_tree_fs(const char* path) {
	struct stat st;
	if (lstat(path, &st) != 0) {
		return errno == ENOENT;
	}

	if (!S_ISDIR(st.st_mode)) {
		return unlink(path) == 0;
	}

	DIR* dir = opendir(path);
	if (!dir) {
		return false;
	}

	struct dirent* entry;
	while ((entry = readdir(dir)) != NULL) {
		if (strcmp(entry->d_name, ".") == 0 ||
		    strcmp(entry->d_name, "..") == 0) {
			continue;
		}

		char child[512];
		int written =
		    snprintf(child, sizeof(child), "%s/%s", path, entry->d_name);
		if (written < 0 || written >= (int)sizeof(child)) {
			closedir(dir);
			return false;
		}
		if (!remove_tree_fs(child)) {
			closedir(dir);
			return false;
		}
	}

	closedir(dir);
	return rmdir(path) == 0;
}

bool test_storage_mkdir_p(const char* dir_rel) {
	if (!dir_rel || !dir_rel[0]) {
		return false;
	}

	char tmp[STORAGE_MAX_PATH];
	size_t offset = 0;
	if (dir_rel[0] == '/') {
		offset = 1;
	}

	snprintf(tmp, sizeof(tmp), "%s", dir_rel + offset);

	for (char* p = tmp; *p; p++) {
		if (*p == '/') {
			*p = '\0';
			if (tmp[0] && !storage_mkdir(tmp)) {
				return false;
			}
			*p = '/';
		}
	}

	return tmp[0] ? storage_mkdir(tmp) : false;
}

static bool ensure_parent_dir(const char* storage_rel) {
	char path[STORAGE_MAX_PATH];
	snprintf(path, sizeof(path), "%s", storage_rel);
	char* slash = strrchr(path, '/');
	if (!slash) {
		return true;
	}
	*slash = '\0';
	if (!path[0]) {
		return true;
	}
	return test_storage_mkdir_p(path);
}

static bool copy_file_to_storage_path(const char* fs_src, const char* storage_dst) {
	if (!ensure_parent_dir(storage_dst)) {
		return false;
	}

	FILE* src = fopen(fs_src, "rb");
	if (!src) {
		return false;
	}

	storage_file_t dst = storage_open(storage_dst, "w");
	if (!dst) {
		fclose(src);
		return false;
	}

	char buf[COPY_BUF_SIZE];
	size_t n;
	while ((n = fread(buf, 1, sizeof(buf), src)) > 0) {
		if (storage_write(dst, buf, n) != n) {
			storage_close(dst);
			fclose(src);
			return false;
		}
	}

	storage_close(dst);
	fclose(src);
	return true;
}

bool test_prepare_storage(void) {
	if (!storage_init()) {
		return false;
	}
	if (!remove_tree_fs(TEST_ROOT_FS)) {
		return false;
	}
	return storage_mkdir(".tests");
}

bool test_copy_fixture_to_storage(const char* fixture_rel,
                                  const char* storage_rel) {
	if (!fixture_rel || !storage_rel) {
		return false;
	}

	char fixture_path[512];
	int written = snprintf(fixture_path, sizeof(fixture_path),
	                       "tests/fixtures/%s", fixture_rel);
	if (written < 0 || written >= (int)sizeof(fixture_path)) {
		return false;
	}

	return copy_file_to_storage_path(fixture_path, storage_rel);
}

bool test_copy_storage_file(const char* src_rel, const char* dst_rel) {
	if (!src_rel || !dst_rel) {
		return false;
	}
	if (!ensure_parent_dir(dst_rel)) {
		return false;
	}

	storage_file_t src = storage_open(src_rel, "r");
	if (!src) {
		return false;
	}

	storage_file_t dst = storage_open(dst_rel, "w");
	if (!dst) {
		storage_close(src);
		return false;
	}

	char buf[COPY_BUF_SIZE];
	size_t n;
	while ((n = storage_read(src, buf, sizeof(buf))) > 0) {
		if (storage_write(dst, buf, n) != n) {
			storage_close(dst);
			storage_close(src);
			return false;
		}
	}

	storage_close(dst);
	storage_close(src);
	return true;
}

bool test_write_storage_text(const char* storage_rel, const char* text) {
	if (!storage_rel || !text) {
		return false;
	}
	if (!ensure_parent_dir(storage_rel)) {
		return false;
	}

	storage_file_t f = storage_open(storage_rel, "w");
	if (!f) {
		return false;
	}
	
	size_t len = strlen(text);
	bool ok = storage_write(f, text, len) == len;
	storage_close(f);
	return ok;
}

bool test_storage_file_exists(const char* storage_rel) {
	storage_file_t f = storage_open(storage_rel, "r");
	if (!f) {
		return false;
	}
	storage_close(f);
	return true;
}

bool test_preserve_storage_file(const char* path,
                                const char* backup_path,
                                bool* had_original) {
	if (!path || !backup_path || !had_original) {
		return false;
	}

	*had_original = false;
	if (!test_storage_file_exists(path)) {
		return true;
	}

	if (!test_copy_storage_file(path, backup_path)) {
		return false;
	}

	*had_original = true;
	return true;
}

bool test_restore_storage_file(const char* path,
                               const char* backup_path,
                               bool had_original) {
	if (!path || !backup_path) {
		return false;
	}

	if (had_original) {
		return test_copy_storage_file(backup_path, path);
	}

	return storage_remove(path);
}