#include "unity/unity.h" #include "zlib.h" #include #include #include /* Unity setUp/tearDown */ void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* Helpers */ static char *make_temp_filename(char *buf, size_t buflen) { /* Use tmpnam to generate a unique name. */ if (buf == NULL || buflen < L_tmpnam) return NULL; char *res = tmpnam(buf); if (res == NULL) return NULL; /* Ensure it's a normal C string path in buf */ /* tmpnam writes into buf when provided */ return buf; } static int write_gzip_file(const char *path, const void *data, unsigned len) { gzFile gz = gzopen(path, "wb"); if (gz == NULL) return -1; int written = gzwrite(gz, data, (unsigned)len); int close_ret = gzclose(gz); if (written != (int)len) return -2; if (close_ret != Z_OK) return -3; return 0; } static int corrupt_file_last_byte(const char *path) { FILE *fp = fopen(path, "rb+"); if (!fp) return -1; if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); return -2; } long sz = ftell(fp); if (sz <= 0) { fclose(fp); return -3; } if (fseek(fp, -1L, SEEK_END) != 0) { fclose(fp); return -4; } int c = fgetc(fp); if (c == EOF) { fclose(fp); return -5; } if (fseek(fp, -1L, SEEK_END) != 0) { fclose(fp); return -6; } if (fputc((c ^ 0xFF) & 0xFF, fp) == EOF) { fclose(fp); return -7; } if (fclose(fp) != 0) return -8; return 0; } /* Tests */ void test_gzclearerr_null_does_not_crash(void) { /* Just ensure it doesn't crash */ gzclearerr(NULL); TEST_ASSERT_TRUE(1); /* If we reached here, no crash */ } void test_gzclearerr_clears_eof_and_past_after_read_past_end(void) { char path[L_tmpnam]; TEST_ASSERT_NOT_NULL(make_temp_filename(path, sizeof(path))); const char *payload = "Hello, world!"; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(path, payload, (unsigned)strlen(payload))); gzFile gz = gzopen(path, "rb"); TEST_ASSERT_NOT_NULL(gz); /* Read until EOF using gzgetc to ensure we step past end and set 'past' */ int ch; while ((ch = gzgetc(gz)) != -1) { /* consume */ } /* At this point, either EOF or error; for a valid gzip, should be EOF */ int errnum_before = Z_OK; const char *msg_before = gzerror(gz, &errnum_before); (void)msg_before; /* not strictly needed */ TEST_ASSERT_EQUAL_INT(Z_OK, errnum_before); /* should be OK at EOF */ TEST_ASSERT_EQUAL_INT(1, gzeof(gz)); /* 'past' should be true after EOF */ /* Now clear error/eof */ gzclearerr(gz); int errnum_after = -1; const char *msg_after = gzerror(gz, &errnum_after); TEST_ASSERT_EQUAL_INT(Z_OK, errnum_after); TEST_ASSERT_NOT_NULL(msg_after); TEST_ASSERT_EQUAL_STRING("", msg_after); TEST_ASSERT_EQUAL_INT(0, gzeof(gz)); /* eof/past cleared */ TEST_ASSERT_EQUAL_INT(Z_OK, gzclose(gz)); remove(path); } void test_gzclearerr_clears_error_and_message_after_crc_error(void) { char path[L_tmpnam]; TEST_ASSERT_NOT_NULL(make_temp_filename(path, sizeof(path))); const char *payload = "This will be corrupted."; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(path, payload, (unsigned)strlen(payload))); /* Corrupt the file to induce a CRC/data error on read */ TEST_ASSERT_EQUAL_INT(0, corrupt_file_last_byte(path)); gzFile gz = gzopen(path, "rb"); TEST_ASSERT_NOT_NULL(gz); /* Read until error */ unsigned char buf[64]; int ret; int saw_error = 0; while ((ret = gzread(gz, buf, sizeof(buf))) > 0) { /* consume */ } if (ret == -1) { saw_error = 1; } TEST_ASSERT_EQUAL_INT(1, saw_error); int errnum_before = Z_OK; const char *msg_before = gzerror(gz, &errnum_before); TEST_ASSERT_NOT_NULL(msg_before); TEST_ASSERT_NOT_EQUAL(Z_OK, errnum_before); TEST_ASSERT_TRUE(msg_before[0] != '\0'); /* should have a message */ /* Now clear error */ gzclearerr(gz); int errnum_after = -1; const char *msg_after = gzerror(gz, &errnum_after); TEST_ASSERT_EQUAL_INT(Z_OK, errnum_after); TEST_ASSERT_NOT_NULL(msg_after); TEST_ASSERT_EQUAL_STRING("", msg_after); /* gzeof() should be 0; error cleared and not at EOF */ TEST_ASSERT_EQUAL_INT(0, gzeof(gz)); /* Cleanup */ TEST_ASSERT_EQUAL_INT(Z_OK, gzclose(gz)); remove(path); } void test_gzclearerr_on_write_mode_noop_and_ok(void) { char path[L_tmpnam]; TEST_ASSERT_NOT_NULL(make_temp_filename(path, sizeof(path))); gzFile gz = gzopen(path, "wb"); TEST_ASSERT_NOT_NULL(gz); /* Ensure starting state is OK */ int errnum_before = -1; const char *msg_before = gzerror(gz, &errnum_before); TEST_ASSERT_EQUAL_INT(Z_OK, errnum_before); TEST_ASSERT_NOT_NULL(msg_before); /* Call gzclearerr; in write mode it should simply ensure err is Z_OK (no eof flags to clear) */ gzclearerr(gz); int errnum_after = -1; const char *msg_after = gzerror(gz, &errnum_after); TEST_ASSERT_EQUAL_INT(Z_OK, errnum_after); TEST_ASSERT_NOT_NULL(msg_after); TEST_ASSERT_TRUE(msg_after[0] == '\0' || msg_after == msg_before); /* Cleanup */ TEST_ASSERT_EQUAL_INT(Z_OK, gzclose(gz)); remove(path); } /* Main */ int main(void) { UNITY_BEGIN(); RUN_TEST(test_gzclearerr_null_does_not_crash); RUN_TEST(test_gzclearerr_clears_eof_and_past_after_read_past_end); RUN_TEST(test_gzclearerr_clears_error_and_message_after_crc_error); RUN_TEST(test_gzclearerr_on_write_mode_noop_and_ok); return UNITY_END(); }