Branch data Line data Source code
1 : : #include "sute.h"
2 : :
3 : : static const char expected_noisy_remove_trailing_slash_stdout_pattern[] =
4 : : "\\A"
5 : : "ERROR: Path normalization; Failed to access non-empty descriptor as a char buffer\n"
6 : : "\\Z";
7 : :
8 : : static const char expected_noisy_remove_trailing_slash_stderr_pattern[] =
9 : : "\\A"
10 : : "ERROR: [^\\n]*Memory management; Invalid arguments for string length helper[^\\n]*\n"
11 : : "ERROR: [^\\n]*Memory management; Expected 1 bytes but descriptor uses 4[^\\n]*\n"
12 : : "ERROR: [^\\n]*Memory management; Descriptor has non-zero length with NULL data pointer[^\\n]*\n"
13 : : "\\Z";
14 : :
15 : : static memory *noisy_non_string_path = NULL;
16 : : static memory *noisy_wrong_type_path = NULL;
17 : : static memory *noisy_invalid_path = NULL;
18 : : static Return noisy_null_status = SUCCESS;
19 : : static Return noisy_non_string_status = SUCCESS;
20 : : static Return noisy_wrong_type_status = SUCCESS;
21 : : static Return noisy_invalid_path_status = SUCCESS;
22 : :
23 : : /**
24 : : * @brief Exercise descriptor edge cases for remove_trailing_slash() under output capture
25 : : *
26 : : * The helper is invoked through match_function_output() so expected diagnostics
27 : : * stay captured instead of leaking into the real terminal output. The individual
28 : : * function statuses are stored in file-scope variables so the outer test
29 : : * function can assert on them after output matching succeeds
30 : : *
31 : : * @return SUCCESS when all negative calls were exercised
32 : : */
33 : 1 : static Return capture_noisy_remove_trailing_slash_cases(void)
34 : : {
35 : : /* Status returned by this function through deliver()
36 : : Default value assumes successful completion */
37 : 1 : Return status = SUCCESS;
38 : :
39 : 1 : noisy_null_status = remove_trailing_slash(NULL);
40 : 1 : noisy_non_string_status = remove_trailing_slash(noisy_non_string_path);
41 : 1 : noisy_wrong_type_status = remove_trailing_slash(noisy_wrong_type_path);
42 : 1 : noisy_invalid_path_status = remove_trailing_slash(noisy_invalid_path);
43 : :
44 : 1 : deliver(status);
45 : : }
46 : :
47 : : /**
48 : : * @brief Helper function to test remove_trailing_slash and compare with expected output
49 : : *
50 : : * This function copies the input string, applies remove_trailing_slash(), and
51 : : * compares the result with the expected output
52 : : *
53 : : * @param input The original path to be processed
54 : : * @param expected The expected output after removing trailing slashes
55 : : */
56 : 17 : static Return test_remove_trailing_slash(
57 : : const char *input,
58 : : const char *expected)
59 : : {
60 : : /* The status that will be returned before exiting */
61 : : /* By default, assumes the function ran without errors */
62 : 17 : Return status = SUCCESS;
63 : :
64 : 17 : m_create(char,temp_buffer,MEMORY_STRING);
65 : 17 : const size_t expected_length = strlen(expected) + 1;
66 : :
67 : 17 : ASSERT(SUCCESS == m_copy_string(temp_buffer,input));
68 : 17 : ASSERT(SUCCESS & remove_trailing_slash(temp_buffer));
69 : :
70 : 17 : const char *buffer_view = m_text(temp_buffer);
71 : :
72 : 17 : ASSERT(buffer_view != NULL);
73 : 17 : ASSERT(0 == strcmp(buffer_view,expected));
74 : 17 : ASSERT(temp_buffer->string_length == expected_length - 1U);
75 : 17 : ASSERT(temp_buffer->length == expected_length);
76 : :
77 : 17 : m_del(temp_buffer);
78 : :
79 : 17 : deliver(status);
80 : : }
81 : :
82 : : /**
83 : : * @brief Helper function to test remove_trailing_slash against a raw char data descriptor
84 : : *
85 : : * @param input_data Raw input bytes to place into the descriptor
86 : : * @param input_size Number of bytes in @p input_data
87 : : * @param expected The expected C string after removing trailing slashes
88 : : * @return Test status indicating success or failure
89 : : */
90 : 2 : static Return test_remove_trailing_slash_data(
91 : : const char *input_data,
92 : : size_t input_size,
93 : : const char *expected)
94 : : {
95 : : /* The status that will be returned before exiting */
96 : : /* By default, assumes the function ran without errors */
97 : 2 : Return status = SUCCESS;
98 : :
99 : 2 : m_create(char,temp_buffer,MEMORY_DATA);
100 : 2 : const size_t expected_length = strlen(expected) + 1;
101 : :
102 : 2 : ASSERT(input_data != NULL);
103 : 2 : ASSERT(SUCCESS == m_copy_buffer(temp_buffer,input_size,input_data));
104 : 2 : ASSERT(SUCCESS & remove_trailing_slash(temp_buffer));
105 : :
106 : 2 : char *buffer_data = m_data(char,temp_buffer);
107 : :
108 : 2 : ASSERT(buffer_data != NULL);
109 : 2 : ASSERT(0 == strcmp(buffer_data,expected));
110 : 2 : ASSERT(temp_buffer->string_length == 0);
111 : 2 : ASSERT(temp_buffer->length == expected_length);
112 : :
113 : 2 : m_del(temp_buffer);
114 : :
115 : 2 : deliver(status);
116 : : }
117 : :
118 : : /**
119 : : * @brief Runs a series of test cases for remove_trailing_slash()
120 : : *
121 : : * Unit Testing of precizer. This function tests various scenarios including:
122 : : * - Removing trailing slashes from paths
123 : : * - Ensuring single '/' paths remain unchanged
124 : : * - Handling edge cases with multiple slashes
125 : : * - Accepting managed char data descriptors that contain a bounded string payload
126 : : * - Compacting descriptor length to visible string plus one terminator
127 : : * - Returning FAILURE for NULL, wrong-width, and data-less non-empty descriptors
128 : : * - Preserving graceful propagated statuses while still trimming
129 : : */
130 : 1 : Return test0022(void)
131 : : {
132 : 1 : INITTEST;
133 : :
134 : : static const struct {
135 : : const char *input;
136 : : const char *expected;
137 : : } test_cases[] = {
138 : : // Basic cases
139 : : {"path/","path"},
140 : : {"folder////","folder"},
141 : : {"/home/user////","/home/user"},
142 : : {"/var/log//","/var/log"},
143 : : {"/usr/local/bin/","/usr/local/bin"},
144 : : {"///home///","///home"},
145 : :
146 : : // Root path cases
147 : : {"/","/"},
148 : : {"////","/"},
149 : :
150 : : // No trailing slashes
151 : : {"path","path"},
152 : : {"/usr/local/bin","/usr/local/bin"},
153 : : {"no/slash/here","no/slash/here"},
154 : :
155 : : // Empty string
156 : : {"",""},
157 : :
158 : : // Edge cases
159 : : {"//double//slash//","//double//slash"},
160 : : {"////multiple///leading/slashes////","////multiple///leading/slashes"},
161 : :
162 : : // Single character paths
163 : : {"a/","a"},
164 : : {"b////","b"},
165 : : {"c","c"},
166 : : {NULL,NULL} // Sentinel value
167 : : };
168 : :
169 [ + + ]: 18 : for(size_t i = 0; test_cases[i].input != NULL; i++)
170 : : {
171 : 17 : ASSERT(SUCCESS & test_remove_trailing_slash(test_cases[i].input,test_cases[i].expected));
172 : : }
173 : :
174 : : static const char data_path_without_terminator[] = {
175 : : 'd','a','t','a'
176 : : };
177 : :
178 : : static const char slashy_data_path_without_terminator[] = {
179 : : 'd','a','t','a','/','/'
180 : : };
181 : :
182 : 1 : ASSERT(SUCCESS & test_remove_trailing_slash_data(
183 : : data_path_without_terminator,
184 : : sizeof(data_path_without_terminator),
185 : : "data"));
186 : 1 : ASSERT(SUCCESS & test_remove_trailing_slash_data(
187 : : slashy_data_path_without_terminator,
188 : : sizeof(slashy_data_path_without_terminator),
189 : : "data"));
190 : :
191 : 1 : m_create(char,non_string_path,MEMORY_DATA);
192 : 1 : ASSERT(SUCCESS == m_copy_buffer(non_string_path,sizeof("data////"),"data////"));
193 : :
194 : 1 : int wrong_type_value = 0;
195 : 1 : memory wrong_type_path = {
196 : : .single_element_size = sizeof(int),
197 : : .actually_allocated_bytes = sizeof(int),
198 : : .length = 1,
199 : : .string_length = 1,
200 : : .is_string = true,
201 : : .data = &wrong_type_value
202 : : };
203 : :
204 : 1 : memory invalid_path = {
205 : : .single_element_size = sizeof(char),
206 : : .actually_allocated_bytes = 1,
207 : : .length = 1,
208 : : .string_length = 0,
209 : : .is_string = true,
210 : : .data = NULL
211 : : };
212 : :
213 : 1 : noisy_non_string_path = non_string_path;
214 : 1 : noisy_wrong_type_path = &wrong_type_path;
215 : 1 : noisy_invalid_path = &invalid_path;
216 : 1 : noisy_null_status = SUCCESS;
217 : 1 : noisy_non_string_status = SUCCESS;
218 : 1 : noisy_wrong_type_status = SUCCESS;
219 : 1 : noisy_invalid_path_status = SUCCESS;
220 : :
221 : 1 : ASSERT(SUCCESS == match_function_output(
222 : : expected_noisy_remove_trailing_slash_stdout_pattern,
223 : : expected_noisy_remove_trailing_slash_stderr_pattern,
224 : : capture_noisy_remove_trailing_slash_cases));
225 : 1 : ASSERT(FAILURE & noisy_null_status);
226 : 1 : ASSERT(TRIUMPH & noisy_non_string_status);
227 : 1 : ASSERT(FAILURE & noisy_wrong_type_status);
228 : 1 : ASSERT(FAILURE & noisy_invalid_path_status);
229 : 1 : char *non_string_path_data = m_data(char,non_string_path);
230 : :
231 : 1 : ASSERT(non_string_path_data != NULL);
232 : 1 : IF(SUCCESS == status)
233 : : {
234 : 1 : ASSERT(0 == strcmp(non_string_path_data,"data"));
235 : 1 : ASSERT(non_string_path->length == sizeof("data"));
236 : 1 : ASSERT(non_string_path->string_length == 0);
237 : : }
238 : 1 : m_del(non_string_path);
239 : :
240 : 1 : m_create(char,hidden_tail_path,MEMORY_STRING);
241 : :
242 : : static const char hidden_tail_bytes[] = {
243 : : 'a','b','c','\0','g','a','r','b','a','g','e','/','/'
244 : : };
245 : 1 : char *hidden_tail_data = NULL;
246 : :
247 : 1 : ASSERT(SUCCESS == m_resize(hidden_tail_path,sizeof(hidden_tail_bytes)));
248 : 1 : hidden_tail_data = m_data(char,hidden_tail_path);
249 : 1 : ASSERT(hidden_tail_data != NULL);
250 : 1 : IF(SUCCESS == status)
251 : : {
252 : 1 : memcpy(hidden_tail_data,hidden_tail_bytes,sizeof(hidden_tail_bytes));
253 : : }
254 : 1 : ASSERT(SUCCESS == m_finalize_string(hidden_tail_path,sizeof("abc") - 1U));
255 : 1 : ASSERT(0 == memcmp(hidden_tail_path->data,hidden_tail_bytes,sizeof(hidden_tail_bytes)));
256 : 1 : ASSERT(SUCCESS & remove_trailing_slash(hidden_tail_path));
257 : 1 : ASSERT(0 == strcmp(m_text(hidden_tail_path),"abc"));
258 : 1 : ASSERT(hidden_tail_path->string_length == strlen("abc"));
259 : 1 : ASSERT(hidden_tail_path->length == sizeof("abc"));
260 : :
261 : 1 : m_del(hidden_tail_path);
262 : :
263 : 1 : m_create(char,slashy_path,MEMORY_STRING);
264 : :
265 : 1 : ASSERT(SUCCESS == m_copy_literal(slashy_path,"abc//"));
266 : 1 : ASSERT(SUCCESS & remove_trailing_slash(slashy_path));
267 : 1 : ASSERT(0 == strcmp(m_text(slashy_path),"abc"));
268 : 1 : ASSERT(slashy_path->string_length == strlen("abc"));
269 : 1 : ASSERT(slashy_path->length == sizeof("abc"));
270 : :
271 : 1 : m_del(slashy_path);
272 : :
273 : 1 : m_create(char,graceful_path,MEMORY_STRING);
274 : 1 : ASSERT(SUCCESS == m_copy_literal(graceful_path,"graceful////"));
275 : :
276 : 1 : IF(SUCCESS == status)
277 : : {
278 : 1 : Return saved_global_status = atomic_exchange(&global_return_status,INFO);
279 : 1 : Return graceful_status = remove_trailing_slash(graceful_path);
280 : 1 : atomic_store(&global_return_status,saved_global_status);
281 : :
282 : 1 : ASSERT(TRIUMPH & graceful_status);
283 : 1 : ASSERT(INFO & graceful_status);
284 : 1 : ASSERT(0 == strcmp(m_text(graceful_path),"graceful"));
285 : 1 : ASSERT(graceful_path->string_length == strlen("graceful"));
286 : 1 : ASSERT(graceful_path->length == sizeof("graceful"));
287 : : }
288 : :
289 : 1 : m_del(graceful_path);
290 : :
291 : 1 : RETURN_STATUS;
292 : : }
|