/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2023 Brett Sheffield <bacs@librecast.net> */

/* test 0119
 *
 * - generate a directory tree
 * - calculate hash for that directory
 * - sync src/ to dst/
 * - bytes synced > 0
 * - compare hashes - MUST match
 * - re-sync
 * - bytes synced == 0
 * - delete a file on dst
 * - compare hashes - MUST not match
 */

#include "test.h"
#include "testdata.h"
#include <sys/types.h>
#include <errno.h>
#include <librecast/mdex.h>
#include <librecast/sync.h>
#include <unistd.h>

#define MAXFILESZ 1048576
#define MAXFILES 10
#define MAXDIRS 5
#define DEPTH 3

int main(int argc, char *argv[])
{
	(void)argc;
	unsigned char root1[HASHSIZE] = "";
	unsigned char root2[HASHSIZE] = "";
	char *src = NULL, *dst = NULL;
	int flags = SYNC_RECURSE | SYNC_OWNER | SYNC_GROUP | SYNC_MODE | SYNC_ATIME | SYNC_MTIME;
	int rc;

	test_name("much ado about directory hashes (part 1)");

	test_log("create source directory tree and files\n");
	rc = test_createtestdirs(basename(argv[0]), &src, &dst);
	if (!test_assert(rc == 0, "test_createtestdirs()")) return test_status;
	rc = test_createtesttree(src, MAXFILESZ, MAXFILES, MAXDIRS, DEPTH, 0);
	if (!test_assert(rc == 0, "test_createtesttree()")) goto err_free_src_dst;

	test_log("calculate root hash of source tree\n");
	rc = mdex_get_directory_root(src, root1);
	if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst;

	test_log("calculate root hash of dst tree\n");
	rc = mdex_get_directory_root(dst, root2);
	if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst;

	/* root hashes differ */
	hash_hex_debug(stderr, root1, HASHSIZE);
	hash_hex_debug(stderr, root2, HASHSIZE);
	test_assert(memcmp(root1, root2, HASHSIZE), "root hashes differ");

	test_log("sync dst from src\n");
	lc_stat_t stats = {0};
	rc = lc_syncfilelocal(dst, src, NULL, &stats, NULL, flags);
	if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst;

	/* Ensure we did something (bytes synced > 0) */
	test_assert(stats.byt_info > 0, "information bytes synced = %zu", stats.byt_info);

	/* (re)calculate root hash of dst tree */
	rc = mdex_get_directory_root(dst, root2);
	if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst;

	/* root hashes match */
	hash_hex_debug(stderr, root1, HASHSIZE);
	hash_hex_debug(stderr, root2, HASHSIZE);
	test_assert(!memcmp(root1, root2, HASHSIZE), "root hashes match (1)");

	test_log("(re)sync dst from src\n");
	memset(&stats, 0, sizeof(stats));
	rc = lc_syncfilelocal(dst, src, NULL, &stats, NULL, flags);
	if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst;

	/* Ensure we did nothing (bytes == 0) */
	test_assert(stats.byt_info == 0, "information bytes synced = %zu", stats.byt_info);

	/* (re)calculate root hash of dst tree */
	rc = mdex_get_directory_root(dst, root2);
	if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst;

	/* root hashes (still) match */
	hash_hex_debug(stderr, root1, HASHSIZE);
	hash_hex_debug(stderr, root2, HASHSIZE);
	test_assert(!memcmp(root1, root2, HASHSIZE), "root hashes match (2)");

	test_log("create new (empty) file in src directory\n");
	char newfile[] = "newfile.XXXXXX";
	char owd[PATH_MAX];
	if (!test_assert(getcwd(owd, sizeof owd) != NULL, "getcwd()")) goto err_free_src_dst;
	rc = chdir(src);
	if (!test_assert(rc == 0, "chdir() %s", src)) goto err_free_src_dst;
#if 0
	rc = test_data_file(newfile, 8, TEST_TMP | TEST_RND);
#else
	rc = mkstemp(newfile); // FIXME
#endif
	if (!test_assert(rc != -1, "mkstemp() %s", newfile)) goto err_free_src_dst;
	close(rc);
	rc = chdir(owd);
	if (!test_assert(rc == 0, "chdir() %s", owd)) goto err_free_src_dst;

	/* (re)calculate root hash of source tree */
	rc = mdex_get_directory_root(src, root1);
	if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst;

	/* root hashes differ */
	hash_hex_debug(stderr, root1, HASHSIZE);
	hash_hex_debug(stderr, root2, HASHSIZE);
	test_assert(memcmp(root1, root2, HASHSIZE), "root hashes differ");

	test_log("(re)sync dst from src\n");
	memset(&stats, 0, sizeof(stats));
	rc = lc_syncfilelocal(dst, src, NULL, &stats, NULL, flags);
	if (!test_assert(rc == 0, "lc_syncfilelocal() returned %i", rc)) goto err_free_src_dst;

	/* (re)calculate root hash of dst tree */
	rc = mdex_get_directory_root(dst, root2);
	if (!test_assert(rc == 0, "mdex_get_directory_root()")) goto err_free_src_dst;

	/* root hashes match (again) */
	hash_hex_debug(stderr, root1, HASHSIZE);
	hash_hex_debug(stderr, root2, HASHSIZE);
	test_assert(!memcmp(root1, root2, HASHSIZE), "root hashes match (3)");

err_free_src_dst:
	free(src); free(dst);
	return test_status;
}
