File size: 5,785 Bytes
e996a55 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
#include "unity/unity.h"
#include "zlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Declare the target function with a compatible prototype.
We use void* for the state parameter to avoid depending on internal headers. */
extern void gz_error(void *state, int err, const char *msg);
static void remove_if_exists(const char *path) {
if (path) {
remove(path);
}
}
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
static gzFile open_temp_gz(const char *path, const char *mode) {
remove_if_exists(path);
gzFile f = gzopen(path, mode);
TEST_ASSERT_MESSAGE(f != NULL, "gzopen failed to create/open temporary gzip file");
return f;
}
static void close_and_cleanup(gzFile f, const char *path) {
if (f) {
int rc = gzclose(f);
TEST_ASSERT_MESSAGE(rc == Z_OK, "gzclose failed");
}
remove_if_exists(path);
}
/* Test: gz_error with (Z_OK, NULL) clears error and leaves empty message. */
void test_gz_error_clears_with_null_message(void) {
const char *path = "tmp_gzlib_gz_error_clear.gz";
gzFile f = open_temp_gz(path, "wb");
/* Ensure we start clean */
int errnum = 777;
const char *msg = gzerror(f, &errnum);
TEST_ASSERT_EQUAL_INT(Z_OK, errnum);
TEST_ASSERT_NOT_NULL(msg);
/* Explicitly clear with Z_OK and NULL message */
gz_error((void*)f, Z_OK, NULL);
errnum = 777;
msg = gzerror(f, &errnum);
TEST_ASSERT_EQUAL_INT(Z_OK, errnum);
/* When no message is set, gzerror returns an empty string */
TEST_ASSERT_NOT_NULL(msg);
TEST_ASSERT_EQUAL_UINT32(0, (unsigned)strlen(msg));
close_and_cleanup(f, path);
}
/* Test: gz_error sets error code and allocates message "path: msg". */
void test_gz_error_sets_message_with_path_prefix(void) {
const char *path = "tmp_gzlib_gz_error_basic.gz";
gzFile f = open_temp_gz(path, "wb");
const char *user_msg = "whoops";
gz_error((void*)f, Z_STREAM_ERROR, user_msg);
int errnum = 0;
const char *ret = gzerror(f, &errnum);
TEST_ASSERT_EQUAL_INT(Z_STREAM_ERROR, errnum);
TEST_ASSERT_NOT_NULL(ret);
char expected[512];
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(expected, sizeof(expected), "%s: %s", path, user_msg);
#else
strcpy(expected, path);
strcat(expected, ": ");
strcat(expected, user_msg);
#endif
TEST_ASSERT_EQUAL_STRING(expected, ret);
close_and_cleanup(f, path);
}
/* Test: Calling gz_error repeatedly replaces the previous message and updates the code. */
void test_gz_error_replaces_previous_message(void) {
const char *path = "tmp_gzlib_gz_error_replace.gz";
gzFile f = open_temp_gz(path, "wb");
gz_error((void*)f, Z_DATA_ERROR, "first");
int err1 = 0;
const char *msg1 = gzerror(f, &err1);
TEST_ASSERT_EQUAL_INT(Z_DATA_ERROR, err1);
TEST_ASSERT_NOT_NULL(msg1);
gz_error((void*)f, Z_BUF_ERROR, "second");
int err2 = 0;
const char *msg2 = gzerror(f, &err2);
TEST_ASSERT_EQUAL_INT(Z_BUF_ERROR, err2);
TEST_ASSERT_NOT_NULL(msg2);
/* Pointer should change because a new allocation occurs for the new message */
TEST_ASSERT_NOT_EQUAL(msg1, msg2);
char expected[512];
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(expected, sizeof(expected), "%s: %s", path, "second");
#else
strcpy(expected, path);
strcat(expected, ": ");
strcat(expected, "second");
#endif
TEST_ASSERT_EQUAL_STRING(expected, msg2);
close_and_cleanup(f, path);
}
/* Test: Z_MEM_ERROR returns the literal "out of memory" and does not allocate a message. */
void test_gz_error_mem_error_returns_literal(void) {
const char *path = "tmp_gzlib_gz_error_mem.gz";
gzFile f = open_temp_gz(path, "wb");
/* Trigger a memory error; the message argument should be ignored for allocation. */
gz_error((void*)f, Z_MEM_ERROR, "ignored");
int err = 0;
const char *ret = gzerror(f, &err);
TEST_ASSERT_EQUAL_INT(Z_MEM_ERROR, err);
TEST_ASSERT_NOT_NULL(ret);
TEST_ASSERT_EQUAL_STRING("out of memory", ret);
/* After a mem error, subsequent errors should still work and set a message */
gz_error((void*)f, Z_STREAM_ERROR, "later");
err = 0;
ret = gzerror(f, &err);
TEST_ASSERT_EQUAL_INT(Z_STREAM_ERROR, err);
char expected[512];
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(expected, sizeof(expected), "%s: %s", path, "later");
#else
strcpy(expected, path);
strcat(expected, ": ");
strcat(expected, "later");
#endif
TEST_ASSERT_EQUAL_STRING(expected, ret);
close_and_cleanup(f, path);
}
/* Test: Z_OK with a non-NULL message stores a message while err stays Z_OK. */
void test_gz_error_ok_with_message_stores_message(void) {
const char *path = "tmp_gzlib_gz_error_okmsg.gz";
gzFile f = open_temp_gz(path, "wb");
gz_error((void*)f, Z_OK, "note");
int err = 0;
const char *ret = gzerror(f, &err);
TEST_ASSERT_EQUAL_INT(Z_OK, err);
TEST_ASSERT_NOT_NULL(ret);
char expected[512];
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(expected, sizeof(expected), "%s: %s", path, "note");
#else
strcpy(expected, path);
strcat(expected, ": ");
strcat(expected, "note");
#endif
TEST_ASSERT_EQUAL_STRING(expected, ret);
close_and_cleanup(f, path);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_gz_error_clears_with_null_message);
RUN_TEST(test_gz_error_sets_message_with_path_prefix);
RUN_TEST(test_gz_error_replaces_previous_message);
RUN_TEST(test_gz_error_mem_error_returns_literal);
RUN_TEST(test_gz_error_ok_with_message_stores_message);
return UNITY_END();
} |