Branch data Line data Source code
1 : : #include "test_librational_all.h"
2 : : #include <errno.h>
3 : : #include <limits.h>
4 : :
5 : : /* The expected stdout pattern is strict and covers the whole demonstration output.
6 : : * Non-decimal negative output depends on the platform width of int, so
7 : : * the test_librational_0002 suite uses a static assertion to keep these expectations
8 : : * tied to the supported 32-bit int targets */
9 : : static const char expected_itoa_stdout_pattern[] =
10 : : "\\A"
11 : : "=== Testing extreme values ===\n"
12 : : "Value: 2147483647 \\(decimal\\)\n"
13 : : "Base 10 result: 2147483647, 2147483647\n"
14 : : "-------------------\n"
15 : : "Value: -2147483648 \\(decimal\\)\n"
16 : : "Base 10 result: -2147483648, -2147483648\n"
17 : : "-------------------\n"
18 : : "Value: -2147483648 \\(decimal\\)\n"
19 : : "Base 16 result: 80000000, Should show in hex\n"
20 : : "-------------------\n"
21 : : "\n"
22 : : "=== Testing regular values ===\n"
23 : : "Value: 255 \\(decimal\\)\n"
24 : : "Base 16 result: FF, FF\n"
25 : : "-------------------\n"
26 : : "Value: 255 \\(decimal\\)\n"
27 : : "Base 2 result: 11111111, 11111111\n"
28 : : "-------------------\n"
29 : : "Value: -255 \\(decimal\\)\n"
30 : : "Base 10 result: -255, -255\n"
31 : : "-------------------\n"
32 : : "\n"
33 : : "=== Testing zero ===\n"
34 : : "Value: 0 \\(decimal\\)\n"
35 : : "Base 10 result: 0, 0\n"
36 : : "-------------------\n"
37 : : "Value: 0 \\(decimal\\)\n"
38 : : "Base 16 result: 0, 0\n"
39 : : "-------------------\n"
40 : : "Value: 0 \\(decimal\\)\n"
41 : : "Base 2 result: 0, 0\n"
42 : : "-------------------\n"
43 : : "\n"
44 : : "=== Testing different bases ===\n"
45 : : "Value: 12345 \\(decimal\\)\n"
46 : : "Base 36 result: 9IX, Maximum supported base\n"
47 : : "-------------------\n"
48 : : "Value: 12345 \\(decimal\\)\n"
49 : : "Base 16 result: 3039, Common hex value\n"
50 : : "-------------------\n"
51 : : "Value: 12345 \\(decimal\\)\n"
52 : : "Base 8 result: 30071, Octal\n"
53 : : "-------------------\n"
54 : : "\n"
55 : : "=== Testing negative values ===\n"
56 : : "Value: -12345 \\(decimal\\)\n"
57 : : "Base 10 result: -12345, Only base 10 shows negative sign\n"
58 : : "-------------------\n"
59 : : "Value: -12345 \\(decimal\\)\n"
60 : : "Base 16 result: FFFFCFC7, Should show unsigned hex\n"
61 : : "-------------------\n"
62 : : "Value: -1 \\(decimal\\)\n"
63 : : "Base 2 result: 11111111111111111111111111111111, All bits set\n"
64 : : "-------------------\n"
65 : : "\n"
66 : : "=== Few more examples ===\n"
67 : : "12345\n"
68 : : "FF\n"
69 : : "1111\n"
70 : : "-789\n"
71 : : "0\n"
72 : : "Number: 1567\n"
73 : : "Base: 10\tConverted String: 1567\n"
74 : : "Base: 2\t\tConverted String: 11000011111\n"
75 : : "Base: 8\t\tConverted String: 3037\n"
76 : : "Base: 16\tConverted String: 61F\n"
77 : : "\n"
78 : : "=== Invalid base handling ===\n"
79 : : "Base 0 result: '', errno: 22\n"
80 : : "Base 1 result: '', errno: 22\n"
81 : : "Base 37 result: '', errno: 22\n"
82 : : "\n"
83 : : "=== NULL buffer handling ===\n"
84 : : "NULL buffer result: NULL, errno: 22\\Z";
85 : :
86 : 15 : static void test_conversion(
87 : : int value,
88 : : unsigned int base,
89 : : const char *reference_text)
90 : : {
91 : : char buffer[66]; /* 64 bits + sign + null terminator */
92 : 15 : itoa(value,buffer,base);
93 : :
94 : : /* Print the converted value next to reference text for the strict stdout pattern */
95 : 15 : printf("Value: %d (decimal)\n",value);
96 : 15 : printf("Base %2u result: %s, %s\n",base,buffer,reference_text);
97 : 15 : printf("-------------------\n");
98 : 15 : }
99 : :
100 : : /**
101 : : * @brief Test program for itoa function
102 : : *
103 : : * @note Tests edge cases and different bases with special focus on
104 : : * negative numbers and MIN/MAX integer values
105 : : */
106 : 1 : static void test_itoa(void)
107 : : {
108 : : /* Test extreme values */
109 : 1 : printf("=== Testing extreme values ===\n");
110 : 1 : test_conversion(INT_MAX,10,"2147483647");
111 : 1 : test_conversion(INT_MIN,10,"-2147483648");
112 : 1 : test_conversion(INT_MIN,16,"Should show in hex");
113 : :
114 : : /* Test regular cases */
115 : 1 : printf("\n=== Testing regular values ===\n");
116 : 1 : test_conversion(255,16,"FF");
117 : 1 : test_conversion(255,2,"11111111");
118 : 1 : test_conversion(-255,10,"-255");
119 : :
120 : : /* Test zero handling */
121 : 1 : printf("\n=== Testing zero ===\n");
122 : 1 : test_conversion(0,10,"0");
123 : 1 : test_conversion(0,16,"0");
124 : 1 : test_conversion(0,2,"0");
125 : :
126 : : /* Test larger bases */
127 : 1 : printf("\n=== Testing different bases ===\n");
128 : 1 : test_conversion(12345,36,"Maximum supported base");
129 : 1 : test_conversion(12345,16,"Common hex value");
130 : 1 : test_conversion(12345,8,"Octal");
131 : :
132 : : /* Test negative values in different bases */
133 : 1 : printf("\n=== Testing negative values ===\n");
134 : 1 : test_conversion(-12345,10,"Only base 10 shows negative sign");
135 : 1 : test_conversion(-12345,16,"Should show unsigned hex");
136 : 1 : test_conversion(-1,2,"All bits set");
137 : :
138 : 1 : printf("\n=== Few more examples ===\n");
139 : : char buffer[33]; /* Buffer for 32-bit integer */
140 : :
141 : : /* Decimal conversion */
142 : 1 : itoa(12345,buffer,10);
143 : 1 : puts(buffer);
144 : :
145 : : /* Hexadecimal conversion */
146 : 1 : itoa(255,buffer,16);
147 : 1 : puts(buffer);
148 : :
149 : : /* Binary conversion */
150 : 1 : itoa(15,buffer,2);
151 : 1 : puts(buffer);
152 : :
153 : : /* Negative number */
154 : 1 : itoa(-789,buffer,10);
155 : 1 : puts(buffer);
156 : :
157 : : /* Zero case */
158 : 1 : itoa(0,buffer,10);
159 : 1 : puts(buffer);
160 : :
161 : : char str[100];
162 : 1 : printf("Number: %d\nBase: %d\tConverted String: %s\n",1567,10,itoa(1567,str,10));
163 : 1 : printf("Base: %d\t\tConverted String: %s\n",2,itoa(1567,str,2));
164 : 1 : printf("Base: %d\t\tConverted String: %s\n",8,itoa(1567,str,8));
165 : 1 : printf("Base: %d\tConverted String: %s\n",16,itoa(1567,str,16));
166 : :
167 : 1 : printf("\n=== Invalid base handling ===\n");
168 : : char errbuf[4];
169 : 1 : char *ret = NULL;
170 : :
171 : 1 : errno = 0;
172 : 1 : ret = itoa(123,errbuf,0);
173 [ + - ]: 1 : printf("Base 0 result: '%s', errno: %d\n",ret ? ret : "NULL",errno);
174 : :
175 : 1 : errno = 0;
176 : 1 : ret = itoa(123,errbuf,1);
177 [ + - ]: 1 : printf("Base 1 result: '%s', errno: %d\n",ret ? ret : "NULL",errno);
178 : :
179 : 1 : errno = 0;
180 : 1 : ret = itoa(123,errbuf,37);
181 [ + - ]: 1 : printf("Base 37 result: '%s', errno: %d\n",ret ? ret : "NULL",errno);
182 : :
183 : 1 : printf("\n=== NULL buffer handling ===\n");
184 : 1 : errno = 0;
185 : 1 : ret = itoa(123,NULL,10);
186 [ - + ]: 1 : printf("NULL buffer result: %s, errno: %d\n",ret ? "non-NULL" : "NULL",errno);
187 : 1 : }
188 : :
189 : 1 : static Return capture_librational_itoa_output(void)
190 : : {
191 : 1 : INITTEST;
192 : :
193 : 1 : test_itoa();
194 : :
195 : 1 : deliver(status);
196 : : }
197 : :
198 : : /**
199 : : * @brief Check that the itoa() demonstration output remains unchanged
200 : : *
201 : : * @return Return describing success or failure
202 : : */
203 : 1 : static Return test_librational_0002_1(void)
204 : : {
205 : 1 : INITTEST;
206 : :
207 : 1 : ASSERT(SUCCESS == match_function_output(
208 : : expected_itoa_stdout_pattern,
209 : : NULL,
210 : : capture_librational_itoa_output));
211 : :
212 : 1 : RETURN_STATUS;
213 : : }
214 : :
215 : : /**
216 : : * @brief Check itoa() conversions and error paths directly
217 : : *
218 : : * @details This block exercises the key textual invariants without relying
219 : : * on demonstration text: INT_MIN and INT_MAX in base 10 (which exercise
220 : : * the UB-avoidance path documented in rational_itoa.c), zero handling
221 : : * across multiple bases, the unsigned bit-pattern representation of
222 : : * negative values in bases other than 10, the use of letters A-Z by the
223 : : * maximum supported base 36, and the documented error paths
224 : : *
225 : : * @return Return describing success or failure
226 : : */
227 : 1 : static Return test_librational_0002_2(void)
228 : : {
229 : 1 : INITTEST;
230 : :
231 : : char ibuf[64]; /* Large enough to hold a 32-bit value printed in base 2 (32 chars + terminator) */
232 : 1 : char *iret = NULL;
233 : :
234 : : /* Extreme values in base 10. INT_MIN exercises the UB-avoidance path inside itoa() */
235 : 1 : iret = itoa(INT_MAX,ibuf,10);
236 : 1 : ASSERT(iret == ibuf);
237 : 1 : ASSERT(0 == strcmp(ibuf,"2147483647"));
238 : :
239 : 1 : iret = itoa(INT_MIN,ibuf,10);
240 : 1 : ASSERT(iret == ibuf);
241 : 1 : ASSERT(0 == strcmp(ibuf,"-2147483648"));
242 : :
243 : 1 : iret = itoa(INT_MIN,ibuf,16);
244 : 1 : ASSERT(iret == ibuf);
245 : 1 : ASSERT(0 == strcmp(ibuf,"80000000"));
246 : :
247 : : /* Zero must format as "0" regardless of base */
248 : 1 : iret = itoa(0,ibuf,10);
249 : 1 : ASSERT(iret == ibuf);
250 : 1 : ASSERT(0 == strcmp(ibuf,"0"));
251 : :
252 : 1 : iret = itoa(0,ibuf,16);
253 : 1 : ASSERT(iret == ibuf);
254 : 1 : ASSERT(0 == strcmp(ibuf,"0"));
255 : :
256 : 1 : iret = itoa(0,ibuf,2);
257 : 1 : ASSERT(iret == ibuf);
258 : 1 : ASSERT(0 == strcmp(ibuf,"0"));
259 : :
260 : : /* Negative values in bases other than 10 must be printed as the unsigned bit pattern */
261 : 1 : iret = itoa(-1,ibuf,16);
262 : 1 : ASSERT(iret == ibuf);
263 : 1 : ASSERT(0 == strcmp(ibuf,"FFFFFFFF"));
264 : :
265 : 1 : iret = itoa(-1,ibuf,2);
266 : 1 : ASSERT(iret == ibuf);
267 : 1 : ASSERT(0 == strcmp(ibuf,"11111111111111111111111111111111"));
268 : :
269 : 1 : iret = itoa(-12345,ibuf,16);
270 : 1 : ASSERT(iret == ibuf);
271 : 1 : ASSERT(0 == strcmp(ibuf,"FFFFCFC7"));
272 : :
273 : : /* Common non-decimal bases must use the expected digits for positive values */
274 : 1 : iret = itoa(255,ibuf,16);
275 : 1 : ASSERT(iret == ibuf);
276 : 1 : ASSERT(0 == strcmp(ibuf,"FF"));
277 : :
278 : 1 : iret = itoa(255,ibuf,2);
279 : 1 : ASSERT(iret == ibuf);
280 : 1 : ASSERT(0 == strcmp(ibuf,"11111111"));
281 : :
282 : 1 : iret = itoa(12345,ibuf,16);
283 : 1 : ASSERT(iret == ibuf);
284 : 1 : ASSERT(0 == strcmp(ibuf,"3039"));
285 : :
286 : 1 : iret = itoa(12345,ibuf,8);
287 : 1 : ASSERT(iret == ibuf);
288 : 1 : ASSERT(0 == strcmp(ibuf,"30071"));
289 : :
290 : : /* Base 36 is the maximum supported base and must use letters A-Z for digits >= 10 */
291 : 1 : iret = itoa(35,ibuf,36);
292 : 1 : ASSERT(iret == ibuf);
293 : 1 : ASSERT(0 == strcmp(ibuf,"Z"));
294 : :
295 : 1 : iret = itoa(12345,ibuf,36);
296 : 1 : ASSERT(iret == ibuf);
297 : 1 : ASSERT(0 == strcmp(ibuf,"9IX"));
298 : :
299 : : /* Error paths: invalid bases and NULL output buffer.
300 : : * buffer[0] is pre-set to a non-NUL sentinel before each call so the ASSERT
301 : : * below verifies that itoa() actually wrote the terminator on the error path,
302 : : * rather than just leaving the prior buffer contents intact */
303 : : char buffer[8];
304 : 1 : char *result = NULL;
305 : :
306 : 1 : errno = 0;
307 : 1 : buffer[0] = 'X';
308 : 1 : result = itoa(123,buffer,0);
309 : 1 : ASSERT(result == buffer);
310 : 1 : ASSERT(errno == EINVAL);
311 : 1 : ASSERT(buffer[0] == '\0');
312 : :
313 : 1 : errno = 0;
314 : 1 : buffer[0] = 'Y';
315 : 1 : result = itoa(123,buffer,1);
316 : 1 : ASSERT(result == buffer);
317 : 1 : ASSERT(errno == EINVAL);
318 : 1 : ASSERT(buffer[0] == '\0');
319 : :
320 : 1 : errno = 0;
321 : 1 : buffer[0] = 'Z';
322 : 1 : result = itoa(123,buffer,37);
323 : 1 : ASSERT(result == buffer);
324 : 1 : ASSERT(errno == EINVAL);
325 : 1 : ASSERT(buffer[0] == '\0');
326 : :
327 : 1 : errno = 0;
328 : 1 : result = itoa(123,NULL,10);
329 : 1 : ASSERT(result == NULL);
330 : 1 : ASSERT(errno == EINVAL);
331 : :
332 : 1 : RETURN_STATUS;
333 : : }
334 : :
335 : : /**
336 : : * @brief Run librational itoa conversion tests
337 : : *
338 : : * @details The suite runs in two independent blocks. The first captures
339 : : * the stdout produced by test_itoa() and matches it against a strict
340 : : * full-output regex. The second uses direct ASSERT checks for boundary
341 : : * values, supported bases, negative values, and error paths
342 : : *
343 : : * @return Return describing success or failure
344 : : */
345 : 1 : Return test_librational_0002(void)
346 : : {
347 : 1 : INITTEST;
348 : :
349 : : /* The hex and binary representations of negative ints below assume 32-bit int.
350 : : * The supported targets (Linux x86_64) satisfy this; the static assertion
351 : : * prevents silent breakage on any future port to a target with a wider int */
352 : : _Static_assert(sizeof(int) * CHAR_BIT == 32,"test_librational_0002 expects a 32-bit int for stable hex and binary expectations");
353 : :
354 : 1 : TEST(test_librational_0002_1,"itoa() demonstration output matches the strict full pattern");
355 : 1 : TEST(test_librational_0002_2,"itoa() converts boundaries, bases, negatives and error paths");
356 : :
357 : 1 : RETURN_STATUS;
358 : : }
|