#define _GNU_SOURCE #include #include #include #include #include #include #include #include "snapdiff.h" static char g_dir[256]; static void fresh_dir(void) { strcpy(g_dir, "/tmp/xce_snapdiff_XXXXXX"); TEST_ASSERT_NOT_NULL(mkdtemp(g_dir)); } static void cleanup_dir(void) { char cmd[512]; snprintf(cmd, sizeof(cmd), "rm -rf %s", g_dir); system(cmd); } static void write_file(const char* path, size_t size, uint8_t fill, size_t flip_at, uint8_t flip_to) { uint8_t* buf = malloc(size); memset(buf, fill, size); if (flip_at < size) buf[flip_at] = flip_to; FILE* fp = fopen(path, "wb"); TEST_ASSERT_NOT_NULL(fp); fwrite(buf, 1, size, fp); fclose(fp); free(buf); } static void test_identical_files(void) { fresh_dir(); char p1[512], p2[512]; snprintf(p1, sizeof(p1), "%s/a.bin", g_dir); snprintf(p2, sizeof(p2), "%s/b.bin", g_dir); write_file(p1, 1000, 0x42, 2000 /* no flip */, 0); write_file(p2, 1000, 0x42, 2000, 0); snapdiff_report_t rep; int rc = snapdiff_paths(p1, p2, stdout, &rep); TEST_ASSERT_EQUAL_INT(0, rc); TEST_ASSERT_EQUAL_INT(1, rep.identical); TEST_ASSERT_EQUAL_INT(-1, (int)rep.diff_offset); cleanup_dir(); } static void test_size_mismatch(void) { fresh_dir(); char p1[512], p2[512]; snprintf(p1, sizeof(p1), "%s/a.bin", g_dir); snprintf(p2, sizeof(p2), "%s/b.bin", g_dir); write_file(p1, 1000, 0x42, 2000, 0); write_file(p2, 999, 0x42, 2000, 0); snapdiff_report_t rep; int rc = snapdiff_paths(p1, p2, stdout, &rep); TEST_ASSERT_EQUAL_INT(1, rc); TEST_ASSERT_EQUAL_INT(1, rep.size_mismatch); TEST_ASSERT_EQUAL_INT(0, rep.identical); cleanup_dir(); } /* bug-1389 regression shape: two SNAPDIFF_CHUNK_SIZE-sized chunks, content * diverges starting at the exact first byte of chunk index 1 — the OPCode_ * snapshotTransfer chunk-boundary corruption signature. */ static void test_diff_at_chunk_boundary_is_flagged(void) { fresh_dir(); char p1[512], p2[512]; snprintf(p1, sizeof(p1), "%s/a.bin", g_dir); snprintf(p2, sizeof(p2), "%s/b.bin", g_dir); size_t size = SNAPDIFF_CHUNK_SIZE * 2; write_file(p1, size, 0x11, size, 0); write_file(p2, size, 0x11, SNAPDIFF_CHUNK_SIZE /* flip first byte of chunk 1 */, 0x22); snapdiff_report_t rep; int rc = snapdiff_paths(p1, p2, stdout, &rep); TEST_ASSERT_EQUAL_INT(1, rc); TEST_ASSERT_EQUAL_INT(0, rep.identical); TEST_ASSERT_EQUAL_INT(SNAPDIFF_CHUNK_SIZE, (int)rep.diff_offset); TEST_ASSERT_EQUAL_INT(1, rep.at_chunk_boundary); TEST_ASSERT_EQUAL_INT(1, (int)rep.chunk_index); cleanup_dir(); } static void test_diff_mid_chunk_is_not_flagged_as_boundary(void) { fresh_dir(); char p1[512], p2[512]; snprintf(p1, sizeof(p1), "%s/a.bin", g_dir); snprintf(p2, sizeof(p2), "%s/b.bin", g_dir); write_file(p1, 1000, 0x11, 2000, 0); write_file(p2, 1000, 0x11, 500 /* mid-file, not a chunk boundary */, 0x22); snapdiff_report_t rep; int rc = snapdiff_paths(p1, p2, stdout, &rep); TEST_ASSERT_EQUAL_INT(1, rc); TEST_ASSERT_EQUAL_INT(500, (int)rep.diff_offset); TEST_ASSERT_EQUAL_INT(0, rep.at_chunk_boundary); cleanup_dir(); } static void test_missing_path_errors(void) { snapdiff_report_t rep; int rc = snapdiff_paths("/tmp/xce_snapdiff_missing_a_zzz", "/tmp/xce_snapdiff_missing_b_zzz", stdout, &rep); TEST_ASSERT_LESS_THAN_INT(0, rc); } void test_snapdiff(void) { RUN_TEST(test_identical_files); RUN_TEST(test_size_mismatch); RUN_TEST(test_diff_at_chunk_boundary_is_flagged); RUN_TEST(test_diff_mid_chunk_is_not_flagged_as_boundary); RUN_TEST(test_missing_path_errors); }