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();
}