blob: bdeedb5881d3cb6e94482c426c1033b6151407fb [file] [log] [blame]
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001/* tests for utilities of libmsomcore */
2/*
3 * (C) 2014 Holger Hans Peter Freyther
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010017 */
18
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020019#include <osmocom/gsm/ipa.h>
Harald Welte7869baf2018-07-31 20:25:48 +020020#include <osmocom/gsm/protocol/ipaccess.h>
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020021
22#include <osmocom/core/logging.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010023#include <osmocom/core/utils.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020024#include <osmocom/core/socket.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010025
26#include <stdio.h>
Harald Welte504caac2017-10-27 17:19:59 +020027#include <ctype.h>
Harald Welte15a5f8d2018-06-06 16:58:17 +020028#include <time.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020029#include <netinet/in.h>
30#include <arpa/inet.h>
Neels Hofmeyr7079e692018-12-05 21:02:36 +010031#include <errno.h>
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +010032#include <limits.h>
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +000033#include <inttypes.h>
Neels Hofmeyrd511a9d2023-12-04 07:48:55 +010034#include <string.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010035
36static void hexdump_test(void)
37{
38 uint8_t data[4098];
Neels Hofmeyr0423b612019-01-14 23:32:53 +010039 char buf[256];
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010040 int i;
41
42 for (i = 0; i < ARRAY_SIZE(data); ++i)
43 data[i] = i & 0xff;
44
45 printf("Plain dump\n");
46 printf("%s\n", osmo_hexdump(data, 4));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010047 printf("%s\n", osmo_hexdump_nospc(data, 4));
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010048
49 printf("Corner case\n");
50 printf("%s\n", osmo_hexdump(data, ARRAY_SIZE(data)));
51 printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data)));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010052
53#define _HEXDUMP_BUF_TEST(SIZE, DELIM, DELIM_AFTER) \
54 buf[0] = '!'; \
55 buf[1] = '\0'; \
56 printf("osmo_hexdump_buf(buf, " #SIZE ", data, 4, %s, " #DELIM_AFTER ")\n = \"%s\"\n", \
57 DELIM ? #DELIM : "NULL", \
58 osmo_hexdump_buf(buf, SIZE, data, 4, DELIM, DELIM_AFTER))
59#define HEXDUMP_BUF_TEST(DELIM) \
60 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, false); \
61 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, true); \
62 _HEXDUMP_BUF_TEST(6, DELIM, false); \
63 _HEXDUMP_BUF_TEST(7, DELIM, false); \
64 _HEXDUMP_BUF_TEST(8, DELIM, false); \
65 _HEXDUMP_BUF_TEST(6, DELIM, true); \
66 _HEXDUMP_BUF_TEST(7, DELIM, true); \
67 _HEXDUMP_BUF_TEST(8, DELIM, true)
68
69 HEXDUMP_BUF_TEST("[delim]");
70 HEXDUMP_BUF_TEST(" ");
71 HEXDUMP_BUF_TEST(":");
72 HEXDUMP_BUF_TEST("::");
73 HEXDUMP_BUF_TEST("");
74 HEXDUMP_BUF_TEST(NULL);
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010075}
76
Neels Hofmeyr7adb5672017-02-14 15:48:19 +010077static void hexparse_test(void)
78{
79 int i;
80 int rc;
81 uint8_t data[256];
82
83 printf("\nHexparse 0..255 in lower case\n");
84 memset(data, 0, sizeof(data));
85 rc = osmo_hexparse(
86 "000102030405060708090a0b0c0d0e0f"
87 "101112131415161718191a1b1c1d1e1f"
88 "202122232425262728292a2b2c2d2e2f"
89 "303132333435363738393a3b3c3d3e3f"
90 "404142434445464748494a4b4c4d4e4f"
91 "505152535455565758595a5b5c5d5e5f"
92 "606162636465666768696a6b6c6d6e6f"
93 "707172737475767778797a7b7c7d7e7f"
94 "808182838485868788898a8b8c8d8e8f"
95 "909192939495969798999a9b9c9d9e9f"
96 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
97 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
98 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
99 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
100 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
101 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
102 , data, sizeof(data));
103 printf("rc = %d\n", rc);
104 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
105 for (i = 0; i < sizeof(data); i++)
106 OSMO_ASSERT(data[i] == i);
107
108 printf("Hexparse 0..255 in upper case\n");
109 memset(data, 0, sizeof(data));
110 rc = osmo_hexparse(
111 "000102030405060708090A0B0C0D0E0F"
112 "101112131415161718191A1B1C1D1E1F"
113 "202122232425262728292A2B2C2D2E2F"
114 "303132333435363738393A3B3C3D3E3F"
115 "404142434445464748494A4B4C4D4E4F"
116 "505152535455565758595A5B5C5D5E5F"
117 "606162636465666768696A6B6C6D6E6F"
118 "707172737475767778797A7B7C7D7E7F"
119 "808182838485868788898A8B8C8D8E8F"
120 "909192939495969798999A9B9C9D9E9F"
121 "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
122 "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
123 "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
124 "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
125 "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
126 "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
127 , data, sizeof(data));
128 printf("rc = %d\n", rc);
129 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
130 for (i = 0; i < sizeof(data); i++)
131 OSMO_ASSERT(data[i] == i);
132
133 printf("Hexparse 0..255 in mixed case\n");
134 memset(data, 0, sizeof(data));
135 rc = osmo_hexparse(
136 "000102030405060708090A0B0C0D0E0F"
137 "101112131415161718191A1B1C1D1E1F"
138 "202122232425262728292A2B2C2D2E2F"
139 "303132333435363738393a3b3c3d3e3f"
140 "404142434445464748494A4B4C4D4E4F"
141 "505152535455565758595a5b5c5d5e5f"
142 "606162636465666768696A6B6C6D6E6F"
143 "707172737475767778797A7B7C7D7E7F"
144 "808182838485868788898A8B8C8D8E8F"
145 "909192939495969798999A9B9C9D9E9F"
146 "A0A1A2A3a4a5a6a7a8a9AAABACADAEAF"
147 "B0B1B2B3b4b5b6b7b8b9BABBBCBDBEBF"
148 "C0C1C2C3c4c5c6c7c8c9CACBCCCDCECF"
149 "D0D1D2D3d4d5d6d7d8d9DADBDCDDDEDF"
150 "E0E1E2E3e4e5e6e7e8e9EAEBECEDEEEF"
151 "F0F1F2F3f4f5f6f7f8f9FAFBFCFDFEFF"
152 , data, sizeof(data));
153 printf("rc = %d\n", rc);
154 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
155 for (i = 0; i < sizeof(data); i++)
156 OSMO_ASSERT(data[i] == i);
157
Neels Hofmeyr437ed4a2017-02-14 15:54:31 +0100158 printf("Hexparse 0..255 with whitespace\n");
159 memset(data, 0, sizeof(data));
160 rc = osmo_hexparse(
161 "00 01\t02\r030405060708090A0B0C0D0 E 0 F\n"
162 "10 11\t12\r131415161718191A1B1C1D1 E 1 F\n"
163 "20 21\t22\r232425262728292A2B2C2D2 E 2 F\n"
164 "30 31\t32\r333435363738393a3b3c3d3 e 3 f\n"
165 "40 41\t42\r434445464748494A4B4C4D4 E 4 F\n"
166 "50 51\t52\r535455565758595a5b5c5d5 e 5 f\n"
167 "60 61\t62\r636465666768696A6B6C6D6 E 6 F\n"
168 "70 71\t72\r737475767778797A7B7C7D7 E 7 F\n"
169 "80 81\t82\r838485868788898A8B8C8D8 E 8 F\n"
170 "90 91\t92\r939495969798999A9B9C9D9 E 9 F\n"
171 "A0 A1\tA2\rA3a4a5a6a7a8a9AAABACADA E A F\n"
172 "B0 B1\tB2\rB3b4b5b6b7b8b9BABBBCBDB E B F\n"
173 "C0 C1\tC2\rC3c4c5c6c7c8c9CACBCCCDC E C F \n"
174 "D0 D1\tD2\rD3d4d5d6d7d8d9DADBDCDDD E D F\t\n"
175 "E0 E1\tE2\rE3e4e5e6e7e8e9EAEBECEDE E E F \t\n"
176 "F0 F1\tF2\rF3f4f5f6f7f8f9FAFBFCFDF E F F \t\r\n"
177 , data, sizeof(data));
178 printf("rc = %d\n", rc);
179 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
180 for (i = 0; i < sizeof(data); i++)
181 OSMO_ASSERT(data[i] == i);
182
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100183 printf("Hexparse with buffer too short\n");
184 memset(data, 0, sizeof(data));
185 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0f", data, 15);
186 printf("rc = %d\n", rc);
187
188 printf("Hexparse with uneven amount of digits\n");
189 memset(data, 0, sizeof(data));
190 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0", data, 16);
191 printf("rc = %d\n", rc);
192
193 printf("Hexparse with invalid char\n");
194 memset(data, 0, sizeof(data));
195 rc = osmo_hexparse("0001020304050X0708090a0b0c0d0e0f", data, 16);
196 printf("rc = %d\n", rc);
197}
198
Harald Welte7869baf2018-07-31 20:25:48 +0200199static void test_ipa_ccm_id_resp_parsing(void)
200{
201 struct tlv_parsed tvp;
202 int rc;
203
204 static const uint8_t id_resp_data[] = {
205 0x00, 0x13, IPAC_IDTAG_MACADDR,
206 '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0',
207 0x00, 0x11, IPAC_IDTAG_IPADDR,
208 '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0',
209 0x00, 0x0a, IPAC_IDTAG_UNIT,
210 '1','2','3','4','/','0','/','0','\0',
211 0x00, 0x02, IPAC_IDTAG_LOCATION1,
212 '\0',
213 0x00, 0x0d, IPAC_IDTAG_LOCATION2,
214 'B','T','S','_','N','B','T','1','3','1','G','\0',
215 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS,
216 '1','6','5','a','0','2','9','_','5','5','\0',
217 0x00, 0x14, IPAC_IDTAG_SWVERSION,
218 '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0',
219 0x00, 0x18, IPAC_IDTAG_UNITNAME,
220 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0',
221 0x00, 0x0a, IPAC_IDTAG_SERNR,
222 '0','0','1','1','0','7','8','1','\0'
223 };
224
225 printf("\nTesting IPA CCM ID RESP parsing\n");
226
227 rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data));
228 OSMO_ASSERT(rc == 0);
229
230 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR));
231 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12);
232 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR));
233 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10);
234 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT));
235 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09);
236 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1));
237 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01);
238 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2));
239 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c);
240 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS));
241 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
242 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION));
243 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
244 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13);
245 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME));
246 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17);
247 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR));
248 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09);
249}
250
251static void test_ipa_ccm_id_get_parsing(void)
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200252{
253 struct tlv_parsed tvp;
254 int rc;
255
Harald Welte48fd0192018-07-31 20:19:49 +0200256 /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */
Harald Welte7869baf2018-07-31 20:25:48 +0200257 static const uint8_t id_get_data[] = {
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200258 0x01, 0x08,
259 0x01, 0x07,
260 0x01, 0x02,
261 0x01, 0x03,
262 0x01, 0x04,
263 0x01, 0x05,
264 0x01, 0x01,
265 0x01, 0x00,
266 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30,
267 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
268 };
269
Harald Welte7869baf2018-07-31 20:25:48 +0200270 printf("\nTesting IPA CCM ID GET parsing\n");
271
272 rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data));
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200273 OSMO_ASSERT(rc == 0);
274
275 OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
276 OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0);
277
278 OSMO_ASSERT(TLVP_PRESENT(&tvp, 7));
279 OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0);
280
281 OSMO_ASSERT(TLVP_PRESENT(&tvp, 2));
282 OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0);
283
284 OSMO_ASSERT(TLVP_PRESENT(&tvp, 3));
285 OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0);
286
287 OSMO_ASSERT(TLVP_PRESENT(&tvp, 4));
288 OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0);
289
290 OSMO_ASSERT(TLVP_PRESENT(&tvp, 5));
291 OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0);
292
293 OSMO_ASSERT(TLVP_PRESENT(&tvp, 1));
294 OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0);
295
296 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0));
297 OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0);
298
299 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23));
300 OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16);
301
302 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24));
303 OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16);
304
305 OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
306}
307
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200308static struct {
309 const char *str;
310 int min_digits;
311 int max_digits;
312 bool require_even;
313 bool expect_ok;
314} test_hexstrs[] = {
315 { NULL, 0, 10, false, true },
316 { NULL, 1, 10, false, false },
317 { "", 0, 10, false, true },
318 { "", 1, 10, false, false },
319 { " ", 0, 10, false, false },
320 { "1", 0, 10, false, true },
321 { "1", 1, 10, false, true },
322 { "1", 1, 10, true, false },
323 { "1", 2, 10, false, false },
324 { "123", 1, 10, false, true },
325 { "123", 1, 10, true, false },
326 { "123", 4, 10, false, false },
327 { "1234", 4, 10, true, true },
328 { "12345", 4, 10, true, false },
329 { "123456", 4, 10, true, true },
330 { "1234567", 4, 10, true, false },
331 { "12345678", 4, 10, true, true },
332 { "123456789", 4, 10, true, false },
333 { "123456789a", 4, 10, true, true },
334 { "123456789ab", 4, 10, true, false },
335 { "123456789abc", 4, 10, true, false },
336 { "123456789ab", 4, 10, false, false },
337 { "123456789abc", 4, 10, false, false },
338 { "0123456789abcdefABCDEF", 0, 100, false, true },
339 { "0123456789 abcdef ABCDEF", 0, 100, false, false },
340 { "foobar", 0, 100, false, false },
341 { "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
342 { "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
343 { "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
344};
345
Harald Weltee61d4592022-11-03 11:05:58 +0100346bool test_is_hexstr(void)
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200347{
348 int i;
349 bool pass = true;
350 bool ok = true;
351 printf("\n----- %s\n", __func__);
352
353 for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
354 ok = osmo_is_hexstr(test_hexstrs[i].str,
355 test_hexstrs[i].min_digits,
356 test_hexstrs[i].max_digits,
357 test_hexstrs[i].require_even);
358 pass = pass && (ok == test_hexstrs[i].expect_ok);
359 printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
360 i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
361 test_hexstrs[i].str,
362 test_hexstrs[i].min_digits,
363 test_hexstrs[i].max_digits,
364 test_hexstrs[i].require_even,
365 test_hexstrs[i].expect_ok ? "valid" : "invalid");
366 }
367 return pass;
368}
369
Harald Welte504caac2017-10-27 17:19:59 +0200370struct bcdcheck {
371 uint8_t bcd;
372 char ch;
373};
374
375static const struct bcdcheck bcdchecks[] = {
376 { 0, '0' },
377 { 1, '1' },
378 { 2, '2' },
379 { 3, '3' },
380 { 4, '4' },
381 { 5, '5' },
382 { 6, '6' },
383 { 7, '7' },
384 { 8, '8' },
385 { 9, '9' },
386 { 0xA, 'A' },
387 { 0xB, 'B' },
388 { 0xC, 'C' },
389 { 0xD, 'D' },
390 { 0xE, 'E' },
391 { 0xF, 'F' },
392};
393
394static void bcd_test(void)
395{
396 int i;
397
398 printf("\nTesting BCD conversion\n");
399 for (i = 0; i < ARRAY_SIZE(bcdchecks); i++) {
400 const struct bcdcheck *check = &bcdchecks[i];
401 char ch = osmo_bcd2char(check->bcd);
402 printf("\tval=0x%x, expected=%c, found=%c\n", check->bcd, check->ch, ch);
403 OSMO_ASSERT(osmo_bcd2char(check->bcd) == check->ch);
404 /* test char -> bcd back-coversion */
405 OSMO_ASSERT(osmo_char2bcd(ch) == check->bcd);
406 /* test for lowercase hex char */
407 OSMO_ASSERT(osmo_char2bcd(tolower(ch)) == check->bcd);
408 }
409}
410
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100411struct bcd2str_test {
412 const char *bcd_hex;
413 int start_nibble;
414 int end_nibble;
415 bool allow_hex;
416 size_t str_size;
417 const char *expect_str;
418 int expect_rc;
419};
420
421static const struct bcd2str_test bcd2str_tests[] = {
422 {
423 .bcd_hex = "1a 32 54 76 98 f0",
424 .start_nibble = 1,
425 .end_nibble = 11,
426 .expect_str = "1234567890",
427 .expect_rc = 10,
428 },
429 {
430 .bcd_hex = "1a 32 a4 cb 9d f0",
431 .start_nibble = 1,
432 .end_nibble = 11,
433 .expect_str = "1234ABCD90",
434 .expect_rc = -EINVAL,
435 },
436 {
437 .bcd_hex = "1a 32 a4 cb 9d f0",
438 .start_nibble = 1,
439 .end_nibble = 11,
440 .allow_hex = true,
441 .expect_str = "1234ABCD90",
442 .expect_rc = 10,
443 },
444 {
445 .bcd_hex = "1a 32 54 76 98 f0",
446 .start_nibble = 1,
447 .end_nibble = 12,
448 .expect_str = "1234567890F",
449 .expect_rc = -EINVAL,
450 },
451 {
452 .bcd_hex = "1a 32 54 76 98 f0",
453 .start_nibble = 1,
454 .end_nibble = 12,
455 .allow_hex = true,
456 .expect_str = "1234567890F",
457 .expect_rc = 11,
458 },
459 {
460 .bcd_hex = "1a 32 54 76 98 f0",
461 .start_nibble = 0,
462 .end_nibble = 12,
463 .allow_hex = true,
464 .expect_str = "A1234567890F",
465 .expect_rc = 12,
466 },
467 {
468 .bcd_hex = "1a 32 54 76 98 f0",
469 .start_nibble = 1,
470 .end_nibble = 12,
471 .str_size = 5,
472 .expect_str = "1234",
473 .expect_rc = 11,
474 },
475 {
476 .bcd_hex = "",
477 .start_nibble = 1,
478 .end_nibble = 1,
479 .expect_str = "",
480 .expect_rc = 0,
481 },
482};
483
484static void bcd2str_test(void)
485{
486 int i;
487 uint8_t bcd[64];
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200488 uint8_t bcd2[64];
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100489 int rc;
490
491 printf("\nTesting bcd to string conversion\n");
492
493 for (i = 0; i < ARRAY_SIZE(bcd2str_tests); i++) {
494 const struct bcd2str_test *t = &bcd2str_tests[i];
495 char str[64] = {};
496 size_t str_size = t->str_size ? : sizeof(str);
497
498 osmo_hexparse(t->bcd_hex, bcd, sizeof(bcd));
499
500 printf("- BCD-input='%s' nibbles=[%d..%d[ str_size=%zu\n", t->bcd_hex,
501 t->start_nibble, t->end_nibble, str_size);
502 rc = osmo_bcd2str(str, str_size, bcd, t->start_nibble, t->end_nibble, t->allow_hex);
503
504 printf(" rc=%d\n", rc);
505
506 OSMO_ASSERT(str[str_size-1] == '\0');
507 printf(" -> %s\n", osmo_quote_str(str, -1));
508
509 if (rc != t->expect_rc)
510 printf(" ERROR: expected rc=%d\n", t->expect_rc);
511 if (strcmp(str, t->expect_str))
512 printf(" ERROR: expected result %s\n", osmo_quote_str(t->expect_str, -1));
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200513
514 memset(bcd2, 0xff, sizeof(bcd2));
515 rc = osmo_str2bcd(bcd2, sizeof(bcd2), str, t->start_nibble, -1, t->allow_hex);
516 printf("osmo_str2bcd(start_nibble=%d) -> rc=%d\n", t->start_nibble, rc);
517 if (rc > 0)
518 printf(" = %s\n", osmo_hexdump(bcd2, rc));
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100519 }
520
521 printf("- zero output buffer\n");
522 rc = osmo_bcd2str(NULL, 100, bcd, 1, 2, false);
523 printf(" bcd2str(NULL, ...) -> %d\n", rc);
524 OSMO_ASSERT(rc < 0);
525 rc = osmo_bcd2str((char*)23, 0, bcd, 1, 2, false);
526 printf(" bcd2str(dst, 0, ...) -> %d\n", rc);
527 OSMO_ASSERT(rc < 0);
528}
529
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100530static void str_escape_test(void)
531{
532 int i;
533 int j;
534 uint8_t in_buf[32];
535 char out_buf[11];
536 const char *printable = "printable";
537 const char *res;
538
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100539 printf("\nTesting string escaping: osmo_escape_str()\n");
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100540 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100541 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100542 for (j = 0; j < 16; j++) {
543 for (i = 0; i < 16; i++)
544 in_buf[i] = (j << 4) | i;
545 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
546 }
547
548 printf("- nul terminated:\n");
549 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
550
551 printf("- passthru:\n");
552 res = osmo_escape_str(printable, -1);
Harald Welte98ed3392019-03-28 13:26:53 +0100553 if (strcmp(res, printable))
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100554 printf("NOT passed through! \"%s\"\n", res);
555 else
556 printf("passed through unchanged \"%s\"\n", res);
557
558 printf("- zero length:\n");
559 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
560
561 printf("- truncation when too long:\n");
562 memset(in_buf, 'x', sizeof(in_buf));
563 in_buf[0] = '\a';
564 in_buf[7] = 'E';
565 memset(out_buf, 0x7f, sizeof(out_buf));
566 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
567 OSMO_ASSERT(out_buf[10] == 0x7f);
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100568}
569
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200570static void str_quote_test(void)
571{
572 int i;
573 int j;
574 uint8_t in_buf[32];
575 char out_buf[11];
576 const char *printable = "printable";
577 const char *res;
578
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100579 printf("\nTesting string quoting: osmo_quote_str()\n");
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200580 printf("- all chars from 0 to 255 in batches of 16:\n");
581 in_buf[16] = '\0';
582 for (j = 0; j < 16; j++) {
583 for (i = 0; i < 16; i++)
584 in_buf[i] = (j << 4) | i;
585 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
586 }
587
588 printf("- nul terminated:\n");
589 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
590
591 printf("- never passthru:\n");
592 res = osmo_quote_str(printable, -1);
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100593 if (strcmp(res, printable))
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200594 printf("NOT passed through. '%s'\n", res);
595 else
596 printf("passed through unchanged '%s'\n", res);
597
598 printf("- zero length:\n");
599 printf("'%s'\n", osmo_quote_str("omitted", 0));
600
601 printf("- truncation when too long:\n");
602 memset(in_buf, 'x', sizeof(in_buf));
603 in_buf[0] = '\a';
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100604 in_buf[6] = 'E';
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200605 memset(out_buf, 0x7f, sizeof(out_buf));
606 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
607 OSMO_ASSERT(out_buf[10] == 0x7f);
608
609 printf("- always truncation, even when no escaping needed:\n");
610 memset(in_buf, 'x', sizeof(in_buf));
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100611 in_buf[7] = 'E'; /* dst has 10, less 1 quote and nul, leaves 8, i.e. in[7] is last */
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200612 in_buf[20] = '\0';
613 memset(out_buf, 0x7f, sizeof(out_buf));
614 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
615 OSMO_ASSERT(out_buf[0] == '"');
616
617 printf("- try to feed too little buf for quoting:\n");
618 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
619
620 printf("- NULL string becomes a \"NULL\" literal:\n");
621 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
622}
623
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100624static void str_escape3_test(void)
625{
626 int i;
627 int j;
628 uint8_t in_buf[32];
629 char out_buf[11];
630 const char *printable = "printable";
631 const char *res;
632 void *ctx = talloc_named_const(NULL, 0, __func__);
633
634 printf("\nTesting string escaping: osmo_escape_cstr_buf()\n");
635 printf("- all chars from 0 to 255 in batches of 16:\n");
636 in_buf[16] = '\0';
637 for (j = 0; j < 16; j++) {
638 for (i = 0; i < 16; i++)
639 in_buf[i] = (j << 4) | i;
640 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, (const char*)in_buf, 16));
641 }
642
643 printf("- nul terminated:\n");
644 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "termi\nated", -1));
645
646 printf("- passthru:\n");
647 res = osmo_escape_cstr_c(ctx, printable, -1);
648 if (strcmp(res, printable))
649 printf("NOT passed through! \"%s\"\n", res);
650 else
651 printf("passed through unchanged \"%s\"\n", res);
652
653 printf("- zero length:\n");
654 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "omitted", 0));
655
656 printf("- truncation when too long:\n");
657 memset(in_buf, 'x', sizeof(in_buf));
658 in_buf[0] = '\a';
659 in_buf[7] = 'E';
660 memset(out_buf, 0x7f, sizeof(out_buf));
661 osmo_escape_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
662 printf("\"%s\"\n", out_buf);
663 OSMO_ASSERT(out_buf[10] == 0x7f);
664
665 printf("- Test escaping an escaped string:\n");
666 res = "\x02\x03\n";
667 for (i = 0; i <= 3; i++) {
668 res = osmo_escape_cstr_c(ctx, res, -1);
669 printf("%d: '%s'\n", i, res);
670 }
671
672 talloc_free(ctx);
673}
674
675static void str_quote3_test(void)
676{
677 int i;
678 int j;
679 uint8_t in_buf[32];
680 char out_buf[11];
681 const char *printable = "printable";
682 const char *res;
683 void *ctx = talloc_named_const(NULL, 0, __func__);
684
685 printf("\nTesting string quoting: osmo_quote_cstr_buf()\n");
686 printf("- all chars from 0 to 255 in batches of 16:\n");
687 in_buf[16] = '\0';
688 for (j = 0; j < 16; j++) {
689 for (i = 0; i < 16; i++)
690 in_buf[i] = (j << 4) | i;
691 printf("%s\n", osmo_quote_cstr_c(ctx, (const char*)in_buf, 16));
692 }
693
694 printf("- nul terminated:\n");
695 printf("'%s'\n", osmo_quote_cstr_c(ctx, "termi\nated", -1));
696
697 printf("- never passthru:\n");
698 res = osmo_quote_cstr_c(ctx, printable, -1);
699 if (strcmp(res, printable))
700 printf("NOT passed through. '%s'\n", res);
701 else
702 printf("passed through unchanged '%s'\n", res);
703
704 printf("- zero length:\n");
705 printf("'%s'\n", osmo_quote_cstr_c(ctx, "omitted", 0));
706
707 printf("- truncation when too long:\n");
708 memset(in_buf, 'x', sizeof(in_buf));
709 in_buf[0] = '\a';
710 in_buf[6] = 'E';
711 memset(out_buf, 0x7f, sizeof(out_buf));
712 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
713 printf("'%s'\n", out_buf);
714 OSMO_ASSERT(out_buf[10] == 0x7f);
715
716 printf("- always truncation, even when no escaping needed:\n");
717 memset(in_buf, 'x', sizeof(in_buf));
718 in_buf[7] = 'E'; /* dst has 10, less 1 quote and nul, leaves 8, i.e. in[7] is last */
719 in_buf[20] = '\0';
720 memset(out_buf, 0x7f, sizeof(out_buf));
721 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, -1);
722 printf("'%s'\n", out_buf);
723 OSMO_ASSERT(out_buf[0] == '"');
724 OSMO_ASSERT(out_buf[10] == 0x7f);
725
726 printf("- try to feed too little buf for quoting:\n");
727 osmo_quote_cstr_buf(out_buf, 2, "", -1);
728 printf("'%s'\n", out_buf);
729
730 printf("- Test quoting a quoted+escaped string:\n");
731 res = "\x02\x03\n";
732 for (i = 0; i <= 3; i++) {
733 res = osmo_quote_cstr_c(ctx, res, -1);
734 printf("%d: %s\n", i, res);
735 }
736
737 printf("- Test C-string equivalence:\n");
738#define TEST_STR "\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
739#define EMPTY_STR ""
740 printf("strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)) == %d\n",
741 strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)));
742 printf("strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)) == %d\n",
743 strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)));
744 printf("strcmp(\"NULL\", osmo_quote_cstr_c(ctx, NULL, -1)) == %d\n",
745 strcmp("NULL", osmo_quote_cstr_c(ctx, NULL, -1)));
746
747 talloc_free(ctx);
748}
749
Harald Welte15a5f8d2018-06-06 16:58:17 +0200750static void isqrt_test(void)
751{
752 int i;
753
754 printf("\nTesting integer square-root\n");
755 srand(time(NULL));
756 for (i = 0; i < 1024; i++) {
757 uint16_t x;
758 uint32_t r = rand();
759 if (RAND_MAX < UINT16_MAX)
760 x = r * (UINT16_MAX/RAND_MAX);
761 else
762 x = r;
Neels Hofmeyr6979c542018-07-19 22:05:21 +0200763 uint32_t sq = (uint32_t)x*x;
Harald Welte15a5f8d2018-06-06 16:58:17 +0200764 uint32_t y = osmo_isqrt32(sq);
765 if (y != x)
766 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
767 }
768}
769
Philipp Maier94705d02023-01-11 10:55:47 +0100770static void mod_test_mod(int x, int y, int expected_result)
771{
772 int result;
773 result = x % y;
774 printf(" %d mod %d = %d = %d\n", x, y, result, expected_result);
775 OSMO_ASSERT(result == expected_result);
776}
777
778static void mod_test_mod_flr(int x, int y, int expected_result)
779{
780 int result;
781 result = OSMO_MOD_FLR(x, y);
782 printf(" %d mod_flr %d = %d = %d\n", x, y, result, expected_result);
783 OSMO_ASSERT(result == expected_result);
784}
785
786static void mod_test_mod_euc(int x, int y, int expected_result)
787{
788 int result;
789 result = OSMO_MOD_EUC(x, y);
790 printf(" %d mod_euc %d = %d = %d\n", x, y, result, expected_result);
791 OSMO_ASSERT(result == expected_result);
792}
793
794static void mod_test(void)
795{
796 /* See also: Daan Leijen, Division and Modulus for Computer
797 * Scientists, section 1.3 */
798
799 printf("\nTesting built in truncated modulo for comparison:\n");
800 mod_test_mod(8, 3, 2);
801 mod_test_mod(8, -3, 2);
802 mod_test_mod(-8, 3, -2);
803 mod_test_mod(-8, -3, -2);
804 mod_test_mod(1, 2, 1);
805 mod_test_mod(1, -2, 1);
806 mod_test_mod(-1, 2, -1);
807 mod_test_mod(-1, -2, -1);
808
809 printf("\nTesting OSMO_MOD_FLR():\n");
810 mod_test_mod_flr(8, 3, 2);
811 mod_test_mod_flr(8, -3, -1);
812 mod_test_mod_flr(-8, 3, 1);
813 mod_test_mod_flr(-8, -3, -2);
814 mod_test_mod_flr(1, 2, 1);
815 mod_test_mod_flr(1, -2, -1);
816 mod_test_mod_flr(-1, 2, 1);
817 mod_test_mod_flr(-1, -2, -1);
818
819 printf("\nTesting OSMO_MOD_EUC():\n");
820 mod_test_mod_euc(8, 3, 2);
821 mod_test_mod_euc(8, -3, 2);
822 mod_test_mod_euc(-8, 3, 1);
823 mod_test_mod_euc(-8, -3, 1);
824 mod_test_mod_euc(1, 2, 1);
825 mod_test_mod_euc(1, -2, 1);
826 mod_test_mod_euc(-1, 2, 1);
827 mod_test_mod_euc(-1, -2, 1);
828}
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200829
830struct osmo_sockaddr_to_str_and_uint_test_case {
831 uint16_t port;
832 bool omit_port;
833 const char *addr;
834 unsigned int addr_len;
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200835 int address_family; /* AF_INET / AF_INET6 */
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200836 bool omit_addr;
837 unsigned int expect_rc;
838 const char *expect_returned_addr;
839};
840
841struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
842 {
843 .port = 0,
844 .addr = "0.0.0.0",
845 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200846 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200847 .expect_rc = 7,
848 },
849 {
850 .port = 65535,
851 .addr = "255.255.255.255",
852 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200853 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200854 .expect_rc = 15,
855 },
856 {
857 .port = 1234,
858 .addr = "234.23.42.123",
859 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200860 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200861 .expect_rc = 13,
862 },
863 {
864 .port = 1234,
865 .addr = "234.23.42.123",
866 .addr_len = 10,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200867 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200868 .expect_rc = 13,
869 .expect_returned_addr = "234.23.42",
870 },
871 {
872 .port = 1234,
873 .omit_port = true,
874 .addr = "234.23.42.123",
875 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200876 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200877 .expect_rc = 13,
878 },
879 {
880 .port = 1234,
881 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200882 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200883 .omit_addr = true,
884 .expect_rc = 0,
885 .expect_returned_addr = "",
886 },
887 {
888 .port = 1234,
889 .addr = "234.23.42.123",
890 .addr_len = 0,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200891 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200892 .expect_rc = 13,
893 .expect_returned_addr = "",
894 },
895 {
896 .port = 1234,
897 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200898 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200899 .omit_port = true,
900 .omit_addr = true,
901 .expect_rc = 0,
902 .expect_returned_addr = "",
903 },
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200904 {
905 .port = 1234,
906 .addr = "::",
907 .addr_len = 20,
908 .address_family = AF_INET6,
909 .expect_rc = 2,
910 },
911 {
912 .port = 1234,
913 .addr = "::1",
914 .addr_len = 20,
915 .address_family = AF_INET6,
916 .expect_rc = 3,
917 },
918 {
919 .port = 1234,
920 .addr = "::1",
921 .addr_len = 20,
922 .address_family = AF_INET6,
923 .omit_port = true,
924 .omit_addr = false,
925 .expect_rc = 3,
926 },
927 {
928 .port = 1234,
929 .addr = "::1",
930 .addr_len = 20,
931 .address_family = AF_INET6,
932 .omit_port = false,
933 .omit_addr = true,
934 .expect_rc = 0,
935 .expect_returned_addr = "",
936 },
937 {
938 .port = 1234,
939 .addr = "fd02:db8:1::1",
940 .addr_len = 20,
941 .address_family = AF_INET6,
942 .expect_rc = 13,
943 },
944 {
945 .port = 1234,
946 .addr = "2001:db8:1::ab9:C0A8:102",
947 .addr_len = 40,
948 .address_family = AF_INET6,
949 .expect_rc = 24,
950 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
951 },
952 {
953 .port = 1234,
954 .addr = "2001:0db8:0001:0000:0000:0ab9:C0A8:0102",
955 .addr_len = 32,
956 .address_family = AF_INET6,
957 .expect_rc = 24,
958 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
959 },
960 {
961 .port = 1234,
962 .addr = "::ffff:192.168.20.34",
963 .addr_len = 32,
964 .address_family = AF_INET6,
965 .expect_rc = 20,
966 .expect_returned_addr = "::ffff:192.168.20.34",
967 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200968};
969
970static void osmo_sockaddr_to_str_and_uint_test(void)
971{
972 int i;
973 printf("\n%s\n", __func__);
974
975 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
976 struct osmo_sockaddr_to_str_and_uint_test_case *t =
977 &osmo_sockaddr_to_str_and_uint_test_data[i];
978
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200979 struct sockaddr_storage sa;
980 struct sockaddr_in *sin;
981 struct sockaddr_in6 *sin6;
982 sa.ss_family = t->address_family;
983 switch (t->address_family) {
984 case AF_INET:
985 sin = (struct sockaddr_in *)&sa;
986 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin->sin_addr) == 1);
987 sin->sin_port = htons(t->port);
988 break;
989 case AF_INET6:
990 sin6 = (struct sockaddr_in6 *)&sa;
991 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin6->sin6_addr) == 1);
992 sin6->sin6_port = htons(t->port);
993 break;
994 default:
995 OSMO_ASSERT(0);
996 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200997
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200998 char addr[INET6_ADDRSTRLEN] = {};
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200999 uint16_t port = 0;
1000 unsigned int rc;
1001
1002 rc = osmo_sockaddr_to_str_and_uint(
1003 t->omit_addr? NULL : addr, t->addr_len,
1004 t->omit_port? NULL : &port,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +02001005 (const struct sockaddr *)&sa);
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001006
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +02001007 printf("[%d] [%s]:%u%s%s addr_len=%u --> [%s]:%u rc=%u\n",
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001008 i,
1009 t->addr ? : "-",
1010 t->port,
1011 t->omit_addr ? " (omit addr)" : "",
1012 t->omit_port ? " (omit port)" : "",
1013 t->addr_len,
1014 addr, port, rc);
1015 if (rc != t->expect_rc)
1016 printf("ERROR: Expected rc = %u\n", t->expect_rc);
1017 if (!t->expect_returned_addr)
1018 t->expect_returned_addr = t->addr;
1019 if (strcmp(t->expect_returned_addr, addr))
1020 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
1021 if (!t->omit_port && port != t->port)
1022 printf("ERROR: Expected port = %u\n", t->port);
1023 }
1024}
1025
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001026struct osmo_str_tolowupper_test_data {
1027 const char *in;
1028 bool use_static_buf;
1029 size_t buflen;
1030 const char *expect_lower;
1031 const char *expect_upper;
1032 size_t expect_rc;
1033 size_t expect_rc_inplace;
1034};
1035
1036struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
1037 {
1038 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1039 .use_static_buf = true,
1040 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
1041 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1042 },
1043 {
1044 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1045 .buflen = 99,
1046 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
1047 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1048 .expect_rc = 62,
1049 .expect_rc_inplace = 62,
1050 },
1051 {
1052 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1053 .buflen = 0,
1054 .expect_lower = "Unset",
1055 .expect_upper = "Unset",
1056 .expect_rc = 62,
1057 .expect_rc_inplace = 0,
1058 },
1059 {
1060 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1061 .buflen = 1,
1062 .expect_lower = "",
1063 .expect_upper = "",
1064 .expect_rc = 62,
1065 .expect_rc_inplace = 0,
1066 },
1067 {
1068 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1069 .buflen = 2,
1070 .expect_lower = "a",
1071 .expect_upper = "A",
1072 .expect_rc = 62,
1073 .expect_rc_inplace = 1,
1074 },
1075 {
1076 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1077 .buflen = 28,
1078 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
1079 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
1080 .expect_rc = 62,
1081 .expect_rc_inplace = 27,
1082 },
1083};
1084
1085
Harald Weltee61d4592022-11-03 11:05:58 +01001086static void osmo_str_tolowupper_test(void)
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001087{
1088 int i;
1089 char buf[128];
1090 bool ok = true;
1091 printf("\n%s\n", __func__);
1092
1093 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
1094 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
1095 size_t rc = 0;
1096 const char *res;
1097
1098 /* tolower */
1099 if (d->use_static_buf) {
1100 res = osmo_str_tolower(d->in);
1101 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
1102 printf(" = %s\n", osmo_quote_str(res, -1));
1103 } else {
1104 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1105 osmo_strlcpy(buf, "Unset", sizeof(buf));
1106 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
1107 res = buf;
1108 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1109 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1110 }
1111
1112 if (strcmp(res, d->expect_lower)) {
1113 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1114 " got %s\n", i, osmo_quote_str(res, -1));
1115 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1116 ok = false;
1117 }
1118
1119 if (!d->use_static_buf && d->expect_rc != rc) {
1120 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1121 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1122 ok = false;
1123 }
1124
1125 /* tolower, in-place */
1126 if (!d->use_static_buf) {
1127 osmo_strlcpy(buf,
1128 d->buflen ? d->in : "Unset",
1129 sizeof(buf));
1130 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
1131 res = buf;
1132 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
1133 d->buflen, osmo_quote_str(d->in, -1));
1134 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1135
1136 if (strcmp(res, d->expect_lower)) {
1137 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1138 " got %s\n", i, osmo_quote_str(res, -1));
1139 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1140 ok = false;
1141 }
1142
1143 if (d->expect_rc_inplace != rc) {
1144 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1145 " got rc=%zu, expected rc=%zu\n",
1146 i, rc, d->expect_rc_inplace);
1147 ok = false;
1148 }
1149 }
1150
1151 /* toupper */
1152 if (d->use_static_buf) {
1153 res = osmo_str_toupper(d->in);
1154 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
1155 printf(" = %s\n", osmo_quote_str(res, -1));
1156 } else {
1157 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1158 osmo_strlcpy(buf, "Unset", sizeof(buf));
1159 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
1160 res = buf;
1161 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1162 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1163 }
1164
1165 if (strcmp(res, d->expect_upper)) {
1166 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1167 " got %s\n", i, osmo_quote_str(res, -1));
1168 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1169 ok = false;
1170 }
1171
1172 if (!d->use_static_buf && d->expect_rc != rc) {
1173 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1174 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1175 ok = false;
1176 }
1177
1178 /* toupper, in-place */
1179 if (!d->use_static_buf) {
1180 osmo_strlcpy(buf,
1181 d->buflen ? d->in : "Unset",
1182 sizeof(buf));
1183 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
1184 res = buf;
1185 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
1186 d->buflen, osmo_quote_str(d->in, -1));
1187 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1188
1189 if (strcmp(res, d->expect_upper)) {
1190 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1191 " got %s\n", i, osmo_quote_str(res, -1));
1192 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1193 ok = false;
1194 }
1195
1196 if (d->expect_rc_inplace != rc) {
1197 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1198 " got rc=%zu, expected rc=%zu\n",
1199 i, rc, d->expect_rc_inplace);
1200 ok = false;
1201 }
1202 }
1203 }
1204
1205 OSMO_ASSERT(ok);
1206}
1207
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001208/* Copy of the examples from OSMO_STRBUF_APPEND() */
1209int print_spaces(char *dst, size_t dst_len, int argument)
1210{
1211 int i;
1212 if (argument < 0)
1213 return -EINVAL;
1214 for (i = 0; i < argument && i < dst_len; i++)
1215 dst[i] = ' ';
1216 if (dst_len)
1217 dst[OSMO_MIN(dst_len - 1, argument)] = '\0';
1218 return argument;
1219}
1220
1221void strbuf_example(char *buf, size_t buflen)
1222{
1223 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1224
1225 OSMO_STRBUF_APPEND(sb, print_spaces, 5);
1226 OSMO_STRBUF_APPEND(sb, snprintf, "The answer is %d but what is the question?", 42);
1227 OSMO_STRBUF_APPEND(sb, print_spaces, 423423);
1228
1229 printf("%s\n", buf);
1230 printf("would have needed %zu bytes\n", sb.chars_needed);
1231}
1232
1233/* Copy of the examples from OSMO_STRBUF_PRINTF() */
1234int strbuf_example2(char *buf, size_t buflen)
1235{
1236 int i;
1237 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1238
1239 OSMO_STRBUF_PRINTF(sb, "T minus");
1240 for (i = 10; i; i--)
1241 OSMO_STRBUF_PRINTF(sb, " %d", i);
1242 OSMO_STRBUF_PRINTF(sb, " ... Lift off!");
1243
1244 return sb.chars_needed;
1245}
1246
1247int strbuf_cascade(char *buf, size_t buflen)
1248{
1249 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1250
1251 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1252 OSMO_STRBUF_PRINTF(sb, " -- ");
1253 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1254 OSMO_STRBUF_PRINTF(sb, " -- ");
1255 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1256
1257 return sb.chars_needed;
1258}
1259
Harald Weltee61d4592022-11-03 11:05:58 +01001260void strbuf_test(void)
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001261{
1262 char buf[256];
1263 int rc;
1264 printf("\n%s\n", __func__);
1265
1266 printf("OSMO_STRBUF_APPEND():\n");
1267 strbuf_example(buf, 23);
1268
1269 printf("\nOSMO_STRBUF_PRINTF():\n");
1270 rc = strbuf_example2(buf, 23);
1271 printf("1: (need %d chars, had size=23) %s\n", rc, buf);
1272
1273 rc = strbuf_example2(buf, rc);
1274 printf("2: (need %d chars, had size=%d) %s\n", rc, rc, buf);
1275
1276 rc = strbuf_example2(buf, rc + 1);
1277 printf("3: (need %d chars, had size=%d+1) %s\n", rc, rc, buf);
1278
1279 rc = strbuf_example2(buf, 0);
1280 snprintf(buf, sizeof(buf), "0x2b 0x2b 0x2b...");
1281 printf("4: (need %d chars, had size=0) %s\n", rc, buf);
1282
1283 rc = strbuf_example2(NULL, 99);
1284 printf("5: (need %d chars, had NULL buffer)\n", rc);
1285
1286 printf("\ncascade:\n");
1287 rc = strbuf_cascade(buf, sizeof(buf));
1288 printf("(need %d chars)\n%s\n", rc, buf);
1289 rc = strbuf_cascade(buf, 63);
1290 printf("(need %d chars, had size=63) %s\n", rc, buf);
1291}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001292
Harald Weltee61d4592022-11-03 11:05:58 +01001293void strbuf_test_nolen(void)
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001294{
1295 char buf[20];
1296 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1297 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1298 printf("\n%s\n", __func__);
1299
1300 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1301 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1302 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1303 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1304
1305 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1306 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1307 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1308}
1309
Neels Hofmeyrd511a9d2023-12-04 07:48:55 +01001310void strbuf_test_tail_for_buflen(size_t buflen)
1311{
1312 char buf[buflen];
1313 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1314 printf("\n%s(%zu)\n", __func__, buflen);
1315
1316#define SHOW(N) \
1317 printf(#N ": %s sb.chars_needed=%zu sb.pos=&sb.buf[%d]\n", \
1318 osmo_quote_str(buf, -1), sb.chars_needed, (int)(sb.pos - sb.buf))
1319
1320 /* shorten in steps using OSMO_STRBUF_DROP_TAIL(), removing and re-adding a trailing newline. */
1321 OSMO_STRBUF_PRINTF(sb, "banananana\n");
1322 SHOW(1);
1323 OSMO_STRBUF_DROP_TAIL(sb, 3);
1324 SHOW(2);
1325 OSMO_STRBUF_PRINTF(sb, "\n");
1326 SHOW(3);
1327 OSMO_STRBUF_DROP_TAIL(sb, 3);
1328 SHOW(4);
1329 OSMO_STRBUF_PRINTF(sb, "\n");
1330 SHOW(5);
1331
1332 /* drop trailing newline */
1333 OSMO_STRBUF_DROP_TAIL(sb, 1);
1334 SHOW(6);
1335
1336 /* test writing something to the end and letting OSMO_STRBUF_ADDED_TAIL() know later */
1337 int n = OSMO_MIN(6, OSMO_STRBUF_REMAIN(sb));
1338 if (n)
1339 memcpy(sb.pos, "bread\n", n);
1340 OSMO_STRBUF_ADDED_TAIL(sb, 6);
1341 SHOW(7);
1342}
1343
1344void strbuf_test_tail(void)
1345{
1346 strbuf_test_tail_for_buflen(64);
1347 strbuf_test_tail_for_buflen(32);
1348 strbuf_test_tail_for_buflen(16);
1349 strbuf_test_tail_for_buflen(8);
1350 strbuf_test_tail_for_buflen(4);
1351 strbuf_test_tail_for_buflen(1);
1352}
1353
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001354static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1355{
1356 bool rc = osmo_str_startswith(str, startswith_str);
1357 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1358 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1359 if (rc != expect_rc)
1360 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1361}
1362
Harald Weltee61d4592022-11-03 11:05:58 +01001363static void startswith_test(void)
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001364{
1365 printf("\n%s()\n", __func__);
1366 startswith_test_str(NULL, NULL, true);
1367 startswith_test_str("", NULL, true);
1368 startswith_test_str(NULL, "", true);
1369 startswith_test_str("", "", true);
1370 startswith_test_str("abc", NULL, true);
1371 startswith_test_str("abc", "", true);
1372 startswith_test_str(NULL, "abc", false);
1373 startswith_test_str("", "abc", false);
1374 startswith_test_str("abc", "a", true);
1375 startswith_test_str("abc", "ab", true);
1376 startswith_test_str("abc", "abc", true);
1377 startswith_test_str("abc", "abcd", false);
1378 startswith_test_str("abc", "xyz", false);
1379}
1380
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001381static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1382{
1383 if (!arg)
1384 return -EINVAL;
1385 return snprintf(buf, buflen, "%s", arg);
1386}
1387
1388static char *foo_name_c(void *ctx, const char *arg)
1389{
1390 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1391}
1392
1393static char *foo_name_c_null(void *ctx, const char *arg)
1394{
1395 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1396}
1397
1398static char *foo_name_c_zero(void *ctx, const char *arg)
1399{
1400 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1401}
1402
1403static char *foo_name_c_zero_null(void *ctx, const char *arg)
1404{
1405 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1406}
1407
Harald Weltee61d4592022-11-03 11:05:58 +01001408static void name_c_impl_test(void)
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001409{
1410 char *test_strs[] = {
1411 "test",
1412 "longer than 10 chars",
1413 NULL,
1414 };
1415 struct {
1416 const char *label;
1417 char *(*func)(void *, const char*);
1418 } funcs[] = {
1419 {
1420 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1421 foo_name_c,
1422 },
1423 {
1424 "OSMO_NAME_C_IMPL(10, NULL)",
1425 foo_name_c_null,
1426 },
1427 {
1428 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1429 foo_name_c_zero,
1430 },
1431 {
1432 "OSMO_NAME_C_IMPL(0, NULL)",
1433 foo_name_c_zero_null,
1434 },
1435 };
1436
1437 int i;
1438 void *ctx = talloc_named_const(NULL, 0, __func__);
1439 int allocs = talloc_total_blocks(ctx);
1440
1441 printf("\n%s\n", __func__);
1442 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1443 char *test_str = test_strs[i];
1444 int j;
1445 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1446
1447 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1448 char *str = funcs[j].func(ctx, test_str);
1449 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1450 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1451 if (str) {
1452 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1453 talloc_free(str);
1454 }
1455 printf("\n");
1456 }
1457 }
1458 talloc_free(ctx);
1459}
1460
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001461static void osmo_print_n_test(void)
1462{
1463 struct token_test {
1464 const char *src;
1465 size_t token_len;
1466 size_t buf_size;
1467 const char *expect_token;
1468 int expect_rc;
1469 };
1470 struct token_test tests[] = {
1471 { "foo=bar", 3, 100, "foo", 3 },
1472 { "foo", 10, 100, "foo", 3 },
1473 { "foo", 3, 100, "foo", 3 },
1474 { NULL, 10, 100, "", 0 },
1475 { "", 10, 100, "", 0 },
1476 { "foo=bar", 0, 100, "", 0 },
1477
1478 { "foo=bar", 3, 2, "f", 3 },
1479 { "foo", 10, 2, "f", 3 },
1480 { "foo", 3, 2, "f", 3 },
1481 { NULL, 10, 2, "", 0 },
1482 { "", 10, 2, "", 0 },
1483 { "foo=bar", 0, 2, "", 0 },
1484
1485 { "foo=bar", 3, 1, "", 3 },
1486 { "foo", 10, 1, "", 3 },
1487 { "foo", 3, 1, "", 3 },
1488 { NULL, 10, 1, "", 0 },
1489 { "", 10, 1, "", 0 },
1490 { "foo=bar", 0, 1, "", 0 },
1491
1492 { "foo=bar", 3, 0, "unchanged", 3 },
1493 { "foo", 10, 0, "unchanged", 3 },
1494 { "foo", 3, 0, "unchanged", 3 },
1495 { NULL, 10, 0, "unchanged", 0 },
1496 { "", 10, 0, "unchanged", 0 },
1497 { "foo=bar", 0, 0, "unchanged", 0 },
1498 };
1499 struct token_test *t;
1500 printf("\n%s()\n", __func__);
1501 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1502 char buf[100] = "unchanged";
1503 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1504 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1505 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1506 if (strcmp(buf, t->expect_token))
1507 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1508 if (rc != t->expect_rc)
1509 printf(" ERROR: expected rc %d", t->expect_rc);
1510 printf("\n");
1511 }
1512}
1513
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001514static void osmo_strnchr_test(void)
1515{
1516 struct test {
1517 const char *haystack;
1518 size_t haystack_len;
1519 const char *needle;
1520 int expect_offset;
1521 };
1522 struct test tests[] = {
1523 { "foo=bar", 8, "=", 3 },
1524 { "foo=bar", 4, "=", 3 },
1525 { "foo=bar", 3, "=", -1 },
1526 { "foo=bar", 0, "=", -1 },
1527 { "foo\0=bar", 9, "=", -1 },
1528 { "foo\0=bar", 9, "\0", 3 },
1529 };
1530 struct test *t;
1531 printf("\n%s()\n", __func__);
1532 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1533 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1534 int offset = -1;
1535 if (r)
1536 offset = r - t->haystack;
1537 printf("osmo_strnchr(%s, %zu, ",
1538 osmo_quote_str(t->haystack, -1), t->haystack_len);
1539 printf("'%s') -> %d",
1540 osmo_escape_str(t->needle, 1), offset);
1541 if (offset != t->expect_offset)
1542 printf(" ERROR expected %d", t->expect_offset);
1543 printf("\n");
1544 }
1545}
1546
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001547struct float_str_to_int_test {
1548 unsigned int precision;
1549 const char *str;
1550 int64_t expect_val;
1551 int expect_err;
1552};
1553struct float_str_to_int_test float_str_to_int_tests[] = {
1554 { 0, "0", 0 },
1555 { 0, "1", 1 },
1556 { 0, "12.345", 12 },
1557 { 0, "+12.345", 12 },
1558 { 0, "-12.345", -12 },
1559 { 0, "0.345", 0 },
1560 { 0, ".345", 0 },
1561 { 0, "-0.345", 0 },
1562 { 0, "-.345", 0 },
1563 { 0, "12.", 12 },
1564 { 0, "-180", -180 },
1565 { 0, "180", 180 },
1566 { 0, "360", 360 },
1567 { 0, "123.4567890123", 123 },
1568 { 0, "123.4567890123456789012345", 123 },
1569 { 0, "9223372036854775807", 9223372036854775807LL },
1570 { 0, "-9223372036854775807", -9223372036854775807LL },
1571 { 0, "-9223372036854775808", .expect_err = -ERANGE },
1572 { 0, "9223372036854775808", .expect_err = -ERANGE },
1573 { 0, "-9223372036854775809", .expect_err = -ERANGE },
1574 { 0, "100000000000000000000", .expect_err = -ERANGE },
1575 { 0, "-100000000000000000000", .expect_err = -ERANGE },
1576 { 0, "999999999999999999999999999.99", .expect_err = -ERANGE },
1577 { 0, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1578 { 0, "1.2.3", .expect_err = -EINVAL },
1579 { 0, "foo", .expect_err = -EINVAL },
1580 { 0, "1.foo", .expect_err = -EINVAL },
1581 { 0, "1.foo", .expect_err = -EINVAL },
1582 { 0, "12.-345", .expect_err = -EINVAL },
1583 { 0, "-12.-345", .expect_err = -EINVAL },
1584 { 0, "12.+345", .expect_err = -EINVAL },
1585 { 0, "+12.+345", .expect_err = -EINVAL },
1586 { 0, "", .expect_err = -EINVAL },
1587 { 0, NULL, .expect_err = -EINVAL },
1588
1589 { 1, "0", 0 },
1590 { 1, "1", 10 },
1591 { 1, "12.345", 123 },
1592 { 1, "+12.345", 123 },
1593 { 1, "-12.345", -123 },
1594 { 1, "0.345", 3 },
1595 { 1, ".345", 3 },
1596 { 1, "-0.345", -3 },
1597 { 1, "-.345", -3 },
1598 { 1, "12.", 120 },
1599 { 1, "-180", -1800 },
1600 { 1, "180", 1800 },
1601 { 1, "360", 3600 },
1602 { 1, "123.4567890123", 1234 },
1603 { 1, "123.4567890123456789012345", 1234 },
1604 { 1, "922337203685477580.7", 9223372036854775807LL },
1605 { 1, "-922337203685477580.7", -9223372036854775807LL },
1606 { 1, "-922337203685477580.8", .expect_err = -ERANGE },
1607 { 1, "922337203685477580.8", .expect_err = -ERANGE },
1608 { 1, "-922337203685477580.9", .expect_err = -ERANGE },
1609 { 1, "100000000000000000000", .expect_err = -ERANGE },
1610 { 1, "-100000000000000000000", .expect_err = -ERANGE },
1611 { 1, "999999999999999999999999999.99", .expect_err = -ERANGE },
1612 { 1, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1613 { 1, "1.2.3", .expect_err = -EINVAL },
1614 { 1, "foo", .expect_err = -EINVAL },
1615 { 1, "1.foo", .expect_err = -EINVAL },
1616 { 1, "1.foo", .expect_err = -EINVAL },
1617 { 1, "12.-345", .expect_err = -EINVAL },
1618 { 1, "-12.-345", .expect_err = -EINVAL },
1619 { 1, "12.+345", .expect_err = -EINVAL },
1620 { 1, "+12.+345", .expect_err = -EINVAL },
1621 { 1, "", .expect_err = -EINVAL },
1622 { 1, NULL, .expect_err = -EINVAL },
1623
1624 { 6, "0", 0 },
1625 { 6, "1", 1000000 },
1626 { 6, "12.345", 12345000 },
1627 { 6, "+12.345", 12345000 },
1628 { 6, "-12.345", -12345000 },
1629 { 6, "0.345", 345000 },
1630 { 6, ".345", 345000 },
1631 { 6, "-0.345", -345000 },
1632 { 6, "-.345", -345000 },
1633 { 6, "12.", 12000000 },
1634 { 6, "-180", -180000000 },
1635 { 6, "180", 180000000 },
1636 { 6, "360", 360000000 },
1637 { 6, "123.4567890123", 123456789 },
1638 { 6, "123.4567890123456789012345", 123456789 },
1639 { 6, "9223372036854.775807", 9223372036854775807LL },
1640 { 6, "-9223372036854.775807", -9223372036854775807LL },
1641 { 6, "-9223372036854.775808", .expect_err = -ERANGE },
1642 { 6, "9223372036854.775808", .expect_err = -ERANGE },
1643 { 6, "-9223372036854.775809", .expect_err = -ERANGE },
1644 { 6, "100000000000000000000", .expect_err = -ERANGE },
1645 { 6, "-100000000000000000000", .expect_err = -ERANGE },
1646 { 6, "999999999999999999999999999.99", .expect_err = -ERANGE },
1647 { 6, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1648 { 6, "1.2.3", .expect_err = -EINVAL },
1649 { 6, "foo", .expect_err = -EINVAL },
1650 { 6, "1.foo", .expect_err = -EINVAL },
1651 { 6, "1.foo", .expect_err = -EINVAL },
1652 { 6, "12.-345", .expect_err = -EINVAL },
1653 { 6, "-12.-345", .expect_err = -EINVAL },
1654 { 6, "12.+345", .expect_err = -EINVAL },
1655 { 6, "+12.+345", .expect_err = -EINVAL },
1656 { 6, "", .expect_err = -EINVAL },
1657 { 6, NULL, .expect_err = -EINVAL },
1658
1659 { 18, "0", 0 },
1660 { 18, "1", 1000000000000000000LL },
1661 { 18, "1.2345", 1234500000000000000LL },
1662 { 18, "+1.2345", 1234500000000000000LL },
1663 { 18, "-1.2345", -1234500000000000000LL },
1664 { 18, "0.345", 345000000000000000LL },
1665 { 18, ".345", 345000000000000000LL },
1666 { 18, "-0.345", -345000000000000000LL },
1667 { 18, "-.345", -345000000000000000LL },
1668 { 18, "2.", 2000000000000000000LL },
1669 { 18, "-8", -8000000000000000000LL },
1670 { 18, "1.234567890123", 1234567890123000000LL },
1671 { 18, "1.234567890123456789012345", 1234567890123456789LL },
1672 { 18, "123.4567890123", .expect_err = -ERANGE },
1673 { 18, "9.223372036854775807", 9223372036854775807LL },
1674 { 18, "-9.223372036854775807", -9223372036854775807LL },
1675 { 18, "-9.223372036854775808", .expect_err = -ERANGE },
1676 { 18, "9.223372036854775808", .expect_err = -ERANGE },
1677 { 18, "-9.223372036854775809", .expect_err = -ERANGE },
1678 { 18, "100000000000000000000", .expect_err = -ERANGE },
1679 { 18, "-100000000000000000000", .expect_err = -ERANGE },
1680 { 18, "999999999999999999999999999.99", .expect_err = -ERANGE },
1681 { 18, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1682 { 18, "1.2.3", .expect_err = -EINVAL },
1683 { 18, "foo", .expect_err = -EINVAL },
1684 { 18, "1.foo", .expect_err = -EINVAL },
1685 { 18, "1.foo", .expect_err = -EINVAL },
1686 { 18, "12.-345", .expect_err = -EINVAL },
1687 { 18, "-12.-345", .expect_err = -EINVAL },
1688 { 18, "12.+345", .expect_err = -EINVAL },
1689 { 18, "+12.+345", .expect_err = -EINVAL },
1690 { 18, "", .expect_err = -EINVAL },
1691 { 18, NULL, .expect_err = -EINVAL },
1692
1693 { 19, "0", 0 },
1694 { 19, ".1", 1000000000000000000LL },
1695 { 19, ".12345", 1234500000000000000LL },
1696 { 19, "+.12345", 1234500000000000000LL },
1697 { 19, "-.12345", -1234500000000000000LL },
1698 { 19, "0.0345", 345000000000000000LL },
1699 { 19, ".0345", 345000000000000000LL },
1700 { 19, "-0.0345", -345000000000000000LL },
1701 { 19, "-.0345", -345000000000000000LL },
1702 { 19, ".2", 2000000000000000000LL },
1703 { 19, "-.8", -8000000000000000000LL },
1704 { 19, ".1234567890123", 1234567890123000000LL },
1705 { 19, ".1234567890123456789012345", 1234567890123456789LL },
1706 { 19, "123.4567890123", .expect_err = -ERANGE },
1707 { 19, ".9223372036854775807", 9223372036854775807LL },
1708 { 19, "-.9223372036854775807", -9223372036854775807LL },
1709 { 19, "-.9223372036854775808", .expect_err = -ERANGE },
1710 { 19, ".9223372036854775808", .expect_err = -ERANGE },
1711 { 19, "-.9223372036854775809", .expect_err = -ERANGE },
1712 { 19, "100000000000000000000", .expect_err = -ERANGE },
1713 { 19, "-100000000000000000000", .expect_err = -ERANGE },
1714 { 19, "999999999999999999999999999.99", .expect_err = -ERANGE },
1715 { 19, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1716 { 19, "1.2.3", .expect_err = -EINVAL },
1717 { 19, "foo", .expect_err = -EINVAL },
1718 { 19, "1.foo", .expect_err = -EINVAL },
1719 { 19, "1.foo", .expect_err = -EINVAL },
1720 { 19, "12.-345", .expect_err = -EINVAL },
1721 { 19, "-12.-345", .expect_err = -EINVAL },
1722 { 19, "12.+345", .expect_err = -EINVAL },
1723 { 19, "+12.+345", .expect_err = -EINVAL },
1724 { 19, "", .expect_err = -EINVAL },
1725 { 19, NULL, .expect_err = -EINVAL },
1726
1727 { 20, "0", 0 },
1728 { 20, ".01", 1000000000000000000LL },
1729 { 20, ".012345", 1234500000000000000LL },
1730 { 20, "+.012345", 1234500000000000000LL },
1731 { 20, "-.012345", -1234500000000000000LL },
1732 { 20, "0.00345", 345000000000000000LL },
1733 { 20, ".00345", 345000000000000000LL },
1734 { 20, "-0.00345", -345000000000000000LL },
1735 { 20, "-.00345", -345000000000000000LL },
1736 { 20, ".02", 2000000000000000000LL },
1737 { 20, "-.08", -8000000000000000000LL },
1738 { 20, ".01234567890123", 1234567890123000000LL },
1739 { 20, ".01234567890123456789012345", 1234567890123456789LL },
1740 { 20, "12.34567890123", .expect_err = -ERANGE },
1741 { 20, ".09223372036854775807", 9223372036854775807LL },
1742 { 20, "-.09223372036854775807", -9223372036854775807LL },
1743 { 20, "-.09223372036854775808", .expect_err = -ERANGE },
1744 { 20, ".09223372036854775808", .expect_err = -ERANGE },
1745 { 20, "-.09223372036854775809", .expect_err = -ERANGE },
1746 { 20, ".1", .expect_err = -ERANGE },
1747 { 20, "-.1", .expect_err = -ERANGE },
1748 { 20, "999999999999999999999999999.99", .expect_err = -ERANGE },
1749 { 20, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1750 { 20, "1.2.3", .expect_err = -EINVAL },
1751 { 20, "foo", .expect_err = -EINVAL },
1752 { 20, "1.foo", .expect_err = -EINVAL },
1753 { 20, "1.foo", .expect_err = -EINVAL },
1754 { 20, "12.-345", .expect_err = -EINVAL },
1755 { 20, "-12.-345", .expect_err = -EINVAL },
1756 { 20, "12.+345", .expect_err = -EINVAL },
1757 { 20, "+12.+345", .expect_err = -EINVAL },
1758 { 20, "", .expect_err = -EINVAL },
1759 { 20, NULL, .expect_err = -EINVAL },
1760
1761 { 25, "0", 0 },
1762 { 25, ".0000001", 1000000000000000000LL },
1763 { 25, ".00000012345", 1234500000000000000LL },
1764 { 25, "+.00000012345", 1234500000000000000LL },
1765 { 25, "-.00000012345", -1234500000000000000LL },
1766 { 25, "0.0000000345", 345000000000000000LL },
1767 { 25, ".0000000345", 345000000000000000LL },
1768 { 25, "-0.0000000345", -345000000000000000LL },
1769 { 25, "-.0000000345", -345000000000000000LL },
1770 { 25, ".0000002", 2000000000000000000LL },
1771 { 25, "-.0000008", -8000000000000000000LL },
1772 { 25, ".0000001234567890123", 1234567890123000000LL },
1773 { 25, ".0000001234567890123456789012345", 1234567890123456789LL },
1774 { 25, ".0001234567890123", .expect_err = -ERANGE },
1775 { 25, ".0000009223372036854775807", 9223372036854775807LL },
1776 { 25, "-.0000009223372036854775807", -9223372036854775807LL },
1777 { 25, "-.0000009223372036854775808", .expect_err = -ERANGE },
1778 { 25, ".0000009223372036854775808", .expect_err = -ERANGE },
1779 { 25, "-.0000009223372036854775809", .expect_err = -ERANGE },
1780 { 25, ".000001", .expect_err = -ERANGE },
1781 { 25, "-.000001", .expect_err = -ERANGE },
1782 { 25, "999999999999999999999999999.99", .expect_err = -ERANGE },
1783 { 25, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1784 { 25, "1.2.3", .expect_err = -EINVAL },
1785 { 25, "foo", .expect_err = -EINVAL },
1786 { 25, "1.foo", .expect_err = -EINVAL },
1787 { 25, "1.foo", .expect_err = -EINVAL },
1788 { 25, "12.-345", .expect_err = -EINVAL },
1789 { 25, "-12.-345", .expect_err = -EINVAL },
1790 { 25, "12.+345", .expect_err = -EINVAL },
1791 { 25, "+12.+345", .expect_err = -EINVAL },
1792 { 25, "", .expect_err = -EINVAL },
1793 { 25, NULL, .expect_err = -EINVAL },
1794};
1795const char *errno_str(int rc)
1796{
Neels Hofmeyr47773342021-09-05 18:48:31 +02001797 switch (rc) {
1798 case -EINVAL:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001799 return "=-EINVAL";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001800 case -ERANGE:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001801 return "=-ERANGE";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001802 case -E2BIG:
1803 return "=-E2BIG";
1804 case -EOVERFLOW:
1805 return "=-EOVERFLOW";
1806 default:
1807 return "";
1808 }
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001809}
Harald Weltee61d4592022-11-03 11:05:58 +01001810void test_float_str_to_int(void)
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001811{
1812 const struct float_str_to_int_test *t;
1813 printf("--- %s\n", __func__);
1814 for (t = float_str_to_int_tests; (t - float_str_to_int_tests) < ARRAY_SIZE(float_str_to_int_tests); t++) {
1815 int rc;
1816 int64_t val;
1817 rc = osmo_float_str_to_int(&val, t->str, t->precision);
1818 printf("osmo_float_str_to_int(%s, %u) -> rc=%d%s val=%" PRId64 "\n",
1819 osmo_quote_str(t->str, -1), t->precision, rc, errno_str(rc), val);
1820
1821 if (rc != t->expect_err)
1822 printf(" ERROR: expected rc=%d%s\n", t->expect_err, errno_str(t->expect_err));
1823 if (val != t->expect_val)
1824 printf(" ERROR: expected val=%" PRId64 "\n", t->expect_val);
1825 if (rc != t->expect_err||val != t->expect_val)
1826 exit(0);
1827 }
1828}
1829
1830struct int_to_float_str_test {
1831 unsigned int precision;
1832 int64_t val;
1833 const char *expect_str;
1834};
1835struct int_to_float_str_test int_to_float_str_tests[] = {
1836 { 0, 0, "0" },
1837 { 0, 1, "1" },
1838 { 0, 1000000, "1000000" },
1839 { 0, -1000000, "-1000000" },
1840 { 0, 1000001, "1000001" },
1841 { 0, -1000001, "-1000001" },
1842 { 0, 1000100, "1000100" },
1843 { 0, -1010000, "-1010000" },
1844 { 0, 1100000, "1100000" },
1845 { 0, 10000000, "10000000" },
1846 { 0, -10000000, "-10000000" },
1847 { 0, 100000000, "100000000" },
1848 { 0, -100000000, "-100000000" },
1849 { 0, 9223372036854775807, "9223372036854775807" },
1850 { 0, -9223372036854775807, "-9223372036854775807" },
1851 { 0, INT64_MIN, "-ERR" },
1852
1853 { 1, 0, "0" },
1854 { 1, 1, "0.1" },
1855 { 1, 1000000, "100000" },
1856 { 1, -1000000, "-100000" },
1857 { 1, 1000001, "100000.1" },
1858 { 1, -1000001, "-100000.1" },
1859 { 1, 1000100, "100010" },
1860 { 1, -1010000, "-101000" },
1861 { 1, 1100000, "110000" },
1862 { 1, 10000000, "1000000" },
1863 { 1, -10000000, "-1000000" },
1864 { 1, 100000000, "10000000" },
1865 { 1, -100000000, "-10000000" },
1866 { 1, 9223372036854775807, "922337203685477580.7" },
1867 { 1, -9223372036854775807, "-922337203685477580.7" },
1868 { 1, INT64_MIN, "-ERR" },
1869
1870 { 3, 0, "0" },
1871 { 3, 1, "0.001" },
1872 { 3, 1000000, "1000" },
1873 { 3, -1000000, "-1000" },
1874 { 3, 1000001, "1000.001" },
1875 { 3, -1000001, "-1000.001" },
1876 { 3, 1000100, "1000.1" },
1877 { 3, -1010000, "-1010" },
1878 { 3, 1100000, "1100" },
1879 { 3, 10000000, "10000" },
1880 { 3, -10000000, "-10000" },
1881 { 3, 100000000, "100000" },
1882 { 3, -100000000, "-100000" },
1883 { 3, 9223372036854775807, "9223372036854775.807" },
1884 { 3, -9223372036854775807, "-9223372036854775.807" },
1885 { 3, INT64_MIN, "-ERR" },
1886
1887 { 6, 0, "0" },
1888 { 6, 1, "0.000001" },
1889 { 6, 1000000, "1" },
1890 { 6, -1000000, "-1" },
1891 { 6, 1000001, "1.000001" },
1892 { 6, -1000001, "-1.000001" },
1893 { 6, 1000100, "1.0001" },
1894 { 6, -1010000, "-1.01" },
1895 { 6, 1100000, "1.1" },
1896 { 6, 10000000, "10" },
1897 { 6, -10000000, "-10" },
1898 { 6, 100000000, "100" },
1899 { 6, -100000000, "-100" },
1900 { 6, 9223372036854775807, "9223372036854.775807" },
1901 { 6, -9223372036854775807, "-9223372036854.775807" },
1902 { 6, INT64_MIN, "-ERR" },
1903
1904 { 17, 0, "0" },
1905 { 17, 1, "0.00000000000000001" },
1906 { 17, 1000000, "0.00000000001" },
1907 { 17, -1000000, "-0.00000000001" },
1908 { 17, 1000001, "0.00000000001000001" },
1909 { 17, -1000001, "-0.00000000001000001" },
1910 { 17, 1000100, "0.000000000010001" },
1911 { 17, -1010000, "-0.0000000000101" },
1912 { 17, 1100000, "0.000000000011" },
1913 { 17, 10000000, "0.0000000001" },
1914 { 17, -10000000, "-0.0000000001" },
1915 { 17, 100000000, "0.000000001" },
1916 { 17, -100000000, "-0.000000001" },
1917 { 17, 9223372036854775807, "92.23372036854775807" },
1918 { 17, -9223372036854775807, "-92.23372036854775807" },
1919 { 17, INT64_MIN, "-ERR" },
1920
1921 { 18, 0, "0" },
1922 { 18, 1, "0.000000000000000001" },
1923 { 18, 1000000, "0.000000000001" },
1924 { 18, -1000000, "-0.000000000001" },
1925 { 18, 1000001, "0.000000000001000001" },
1926 { 18, -1000001, "-0.000000000001000001" },
1927 { 18, 1000100, "0.0000000000010001" },
1928 { 18, -1010000, "-0.00000000000101" },
1929 { 18, 1100000, "0.0000000000011" },
1930 { 18, 10000000, "0.00000000001" },
1931 { 18, -10000000, "-0.00000000001" },
1932 { 18, 100000000, "0.0000000001" },
1933 { 18, -100000000, "-0.0000000001" },
1934 { 18, 9223372036854775807, "9.223372036854775807" },
1935 { 18, -9223372036854775807, "-9.223372036854775807" },
1936 { 18, INT64_MIN, "-ERR" },
1937
1938 { 19, 0, "0" },
1939 { 19, 1, "0.0000000000000000001" },
1940 { 19, 1000000, "0.0000000000001" },
1941 { 19, -1000000, "-0.0000000000001" },
1942 { 19, 1000001, "0.0000000000001000001" },
1943 { 19, -1000001, "-0.0000000000001000001" },
1944 { 19, 1000100, "0.00000000000010001" },
1945 { 19, -1010000, "-0.000000000000101" },
1946 { 19, 1100000, "0.00000000000011" },
1947 { 19, 10000000, "0.000000000001" },
1948 { 19, -10000000, "-0.000000000001" },
1949 { 19, 100000000, "0.00000000001" },
1950 { 19, -100000000, "-0.00000000001" },
1951 { 19, 9223372036854775807, "0.9223372036854775807" },
1952 { 19, -9223372036854775807, "-0.9223372036854775807" },
1953 { 19, INT64_MIN, "-ERR" },
1954
1955 { 23, 0, "0" },
1956 { 23, 1, "0.00000000000000000000001" },
1957 { 23, 1000000, "0.00000000000000001" },
1958 { 23, -1000000, "-0.00000000000000001" },
1959 { 23, 1000001, "0.00000000000000001000001" },
1960 { 23, -1000001, "-0.00000000000000001000001" },
1961 { 23, 1000100, "0.000000000000000010001" },
1962 { 23, -1010000, "-0.0000000000000000101" },
1963 { 23, 1100000, "0.000000000000000011" },
1964 { 23, 10000000, "0.0000000000000001" },
1965 { 23, -10000000, "-0.0000000000000001" },
1966 { 23, 100000000, "0.000000000000001" },
1967 { 23, -100000000, "-0.000000000000001" },
1968 { 23, 9223372036854775807, "0.00009223372036854775807" },
1969 { 23, -9223372036854775807, "-0.00009223372036854775807" },
1970 { 23, INT64_MIN, "-ERR" },
1971};
Harald Weltee61d4592022-11-03 11:05:58 +01001972void test_int_to_float_str(void)
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001973{
1974 const struct int_to_float_str_test *t;
1975 printf("--- %s\n", __func__);
1976 for (t = int_to_float_str_tests;
1977 (t - int_to_float_str_tests) < ARRAY_SIZE(int_to_float_str_tests);
1978 t++) {
1979 char buf[128];
1980 int rc;
1981 rc = osmo_int_to_float_str_buf(buf, sizeof(buf), t->val, t->precision);
1982 printf("osmo_int_to_float_str_buf(%" PRId64 ", %u) -> rc=%d str=%s\n", t->val, t->precision, rc,
1983 osmo_quote_str(buf, -1));
1984
1985 if (rc != strlen(buf))
1986 printf(" ERROR: expected rc=%zu\n", strlen(buf));
1987 if (strcmp(buf, t->expect_str))
1988 printf(" ERROR: expected str=%s\n", osmo_quote_str(t->expect_str, -1));
1989 if (rc != strlen(buf) || strcmp(buf, t->expect_str))
1990 exit(0);
1991 }
1992}
1993
Neels Hofmeyr47773342021-09-05 18:48:31 +02001994struct str_to_int_test {
1995 const char *str;
1996 int base;
1997 int min_val;
1998 int max_val;
1999 int expect_rc;
2000 int expect_val;
2001};
2002/* Avoid using INT_MAX and INT_MIN because that would produce different test output on different architectures */
2003struct str_to_int_test str_to_int_tests[] = {
2004 { NULL, 10, -1000, 1000, -EINVAL, 0 },
2005 { "", 10, -1000, 1000, -EINVAL, 0 },
2006 { " ", 10, -1000, 1000, -EINVAL, 0 },
2007 { "-", 10, -1000, 1000, -EINVAL, 0 },
2008 { "--", 10, -1000, 1000, -EINVAL, 0 },
2009 { "+", 10, -1000, 1000, -EINVAL, 0 },
2010 { "++", 10, -1000, 1000, -EINVAL, 0 },
2011
2012 { "0", 10, -1000, 1000, 0, 0 },
2013 { "1", 10, -1000, 1000, 0, 1 },
2014 { "+1", 10, -1000, 1000, 0, 1 },
2015 { "-1", 10, -1000, 1000, 0, -1 },
2016 { "1000", 10, -1000, 1000, 0, 1000 },
2017 { "+1000", 10, -1000, 1000, 0, 1000 },
2018 { "-1000", 10, -1000, 1000, 0, -1000 },
2019 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
2020 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
2021 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
2022
2023 { "0", 16, -1000, 1000, 0, 0 },
2024 { "1", 16, -1000, 1000, 0, 1 },
2025 { "0x1", 16, -1000, 1000, 0, 1 },
2026 { "+1", 16, -1000, 1000, 0, 1 },
2027 { "-1", 16, -1000, 1000, 0, -1 },
2028 { "+0x1", 16, -1000, 1000, 0, 1 },
2029 { "-0x1", 16, -1000, 1000, 0, -1 },
2030 { "3e8", 16, -1000, 1000, 0, 1000 },
2031 { "3E8", 16, -1000, 1000, 0, 1000 },
2032 { "0x3e8", 16, -1000, 1000, 0, 1000 },
2033 { "0x3E8", 16, -1000, 1000, 0, 1000 },
2034 { "+3e8", 16, -1000, 1000, 0, 1000 },
2035 { "+3E8", 16, -1000, 1000, 0, 1000 },
2036 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
2037 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
2038 { "-3e8", 16, -1000, 1000, 0, -1000 },
2039 { "-3E8", 16, -1000, 1000, 0, -1000 },
2040 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
2041 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
2042 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
2043 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
2044 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2045 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2046 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2047 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2048 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2049 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2050 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2051 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2052 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2053 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2054
2055 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2056 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2057 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2058 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2059 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2060 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2061 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2062};
Harald Weltee61d4592022-11-03 11:05:58 +01002063void test_str_to_int(void)
Neels Hofmeyr47773342021-09-05 18:48:31 +02002064{
2065 const struct str_to_int_test *t;
2066 printf("--- %s\n", __func__);
2067 for (t = str_to_int_tests; (t - str_to_int_tests) < ARRAY_SIZE(str_to_int_tests); t++) {
2068 int rc;
2069 int val;
2070 rc = osmo_str_to_int(&val, t->str, t->base, t->min_val, t->max_val);
2071 printf("osmo_str_to_int(%s, %d, %d, %d) -> rc=%d%s val=%d\n",
2072 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2073
2074 if (rc != t->expect_rc)
2075 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2076 if (val != t->expect_val)
2077 printf(" ERROR: expected val=%d\n", t->expect_val);
2078 }
2079}
2080
2081struct str_to_int64_test {
2082 const char *str;
2083 int base;
2084 int64_t min_val;
2085 int64_t max_val;
2086 int expect_rc;
2087 int64_t expect_val;
2088};
2089struct str_to_int64_test str_to_int64_tests[] = {
2090 { NULL, 10, -1000, 1000, -EINVAL, 0 },
2091 { "", 10, -1000, 1000, -EINVAL, 0 },
2092 { " ", 10, -1000, 1000, -EINVAL, 0 },
2093 { "-", 10, -1000, 1000, -EINVAL, 0 },
2094 { "--", 10, -1000, 1000, -EINVAL, 0 },
2095 { "+", 10, -1000, 1000, -EINVAL, 0 },
2096 { "++", 10, -1000, 1000, -EINVAL, 0 },
2097
2098 { "0", 10, -1000, 1000, 0, 0 },
2099 { "1", 10, -1000, 1000, 0, 1 },
2100 { "+1", 10, -1000, 1000, 0, 1 },
2101 { "-1", 10, -1000, 1000, 0, -1 },
2102 { "1000", 10, -1000, 1000, 0, 1000 },
2103 { "+1000", 10, -1000, 1000, 0, 1000 },
2104 { "-1000", 10, -1000, 1000, 0, -1000 },
2105 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
2106 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
2107 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
2108
2109 { "0", 16, -1000, 1000, 0, 0 },
2110 { "1", 16, -1000, 1000, 0, 1 },
2111 { "0x1", 16, -1000, 1000, 0, 1 },
2112 { "+1", 16, -1000, 1000, 0, 1 },
2113 { "-1", 16, -1000, 1000, 0, -1 },
2114 { "+0x1", 16, -1000, 1000, 0, 1 },
2115 { "-0x1", 16, -1000, 1000, 0, -1 },
2116 { "3e8", 16, -1000, 1000, 0, 1000 },
2117 { "3E8", 16, -1000, 1000, 0, 1000 },
2118 { "0x3e8", 16, -1000, 1000, 0, 1000 },
2119 { "0x3E8", 16, -1000, 1000, 0, 1000 },
2120 { "+3e8", 16, -1000, 1000, 0, 1000 },
2121 { "+3E8", 16, -1000, 1000, 0, 1000 },
2122 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
2123 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
2124 { "-3e8", 16, -1000, 1000, 0, -1000 },
2125 { "-3E8", 16, -1000, 1000, 0, -1000 },
2126 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
2127 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
2128 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
2129 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
2130 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2131 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2132 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2133 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2134 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2135 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2136 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2137 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2138 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2139 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2140
2141 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2142 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2143 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2144 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2145 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2146 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2147 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2148
2149 { "-9223372036854775808", 10, INT64_MIN, INT64_MAX, 0, INT64_MIN },
2150 { "9223372036854775807", 10, INT64_MIN, INT64_MAX, 0, INT64_MAX },
2151
2152 { "-9223372036854775809", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MIN },
2153 { "9223372036854775808", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MAX },
2154
2155 { "-9223372036854775808", 10, -1000, 1000, -ERANGE, INT64_MIN },
2156 { "9223372036854775807", 10, -1000, 1000, -ERANGE, INT64_MAX },
2157 { "-9223372036854775809", 10, -1000, 1000, -EOVERFLOW, INT64_MIN },
2158 { "9223372036854775808", 10, -1000, 1000, -EOVERFLOW, INT64_MAX },
2159};
Harald Weltee61d4592022-11-03 11:05:58 +01002160void test_str_to_int64(void)
Neels Hofmeyr47773342021-09-05 18:48:31 +02002161{
2162 const struct str_to_int64_test *t;
2163 printf("--- %s\n", __func__);
2164 for (t = str_to_int64_tests; (t - str_to_int64_tests) < ARRAY_SIZE(str_to_int64_tests); t++) {
2165 int rc;
2166 int64_t val;
2167 rc = osmo_str_to_int64(&val, t->str, t->base, t->min_val, t->max_val);
2168 printf("osmo_str_to_int64(%s, %d, %"PRId64", %"PRId64") -> rc=%d%s val=%"PRId64"\n",
2169 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2170
2171 if (rc != t->expect_rc)
2172 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2173 if (val != t->expect_val)
2174 printf(" ERROR: expected val=%"PRId64"\n", t->expect_val);
2175 }
2176}
2177
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002178int main(int argc, char **argv)
2179{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02002180 static const struct log_info log_info = {};
2181 log_init(&log_info, NULL);
2182
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002183 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01002184 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02002185 test_ipa_ccm_id_get_parsing();
2186 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02002187 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02002188 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01002189 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01002190 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02002191 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01002192 str_escape3_test();
2193 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02002194 isqrt_test();
Philipp Maier94705d02023-01-11 10:55:47 +01002195 mod_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02002196 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02002197 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01002198 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02002199 strbuf_test_nolen();
Neels Hofmeyrd511a9d2023-12-04 07:48:55 +01002200 strbuf_test_tail();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01002201 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01002202 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01002203 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01002204 osmo_strnchr_test();
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00002205 test_float_str_to_int();
2206 test_int_to_float_str();
Neels Hofmeyr47773342021-09-05 18:48:31 +02002207 test_str_to_int();
2208 test_str_to_int64();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002209 return 0;
2210}