blob: 9ab12a15ad6f5888df954c1ba7befabd0b14f31a [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
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001283 printf("\ncascade:\n");
1284 rc = strbuf_cascade(buf, sizeof(buf));
1285 printf("(need %d chars)\n%s\n", rc, buf);
1286 rc = strbuf_cascade(buf, 63);
1287 printf("(need %d chars, had size=63) %s\n", rc, buf);
1288}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001289
Harald Weltee61d4592022-11-03 11:05:58 +01001290void strbuf_test_nolen(void)
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001291{
1292 char buf[20];
1293 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1294 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1295 printf("\n%s\n", __func__);
1296
1297 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1298 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1299 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1300 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1301
1302 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1303 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1304 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1305}
1306
Neels Hofmeyrd511a9d2023-12-04 07:48:55 +01001307void strbuf_test_tail_for_buflen(size_t buflen)
1308{
1309 char buf[buflen];
1310 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1311 printf("\n%s(%zu)\n", __func__, buflen);
1312
1313#define SHOW(N) \
1314 printf(#N ": %s sb.chars_needed=%zu sb.pos=&sb.buf[%d]\n", \
1315 osmo_quote_str(buf, -1), sb.chars_needed, (int)(sb.pos - sb.buf))
1316
1317 /* shorten in steps using OSMO_STRBUF_DROP_TAIL(), removing and re-adding a trailing newline. */
1318 OSMO_STRBUF_PRINTF(sb, "banananana\n");
1319 SHOW(1);
1320 OSMO_STRBUF_DROP_TAIL(sb, 3);
1321 SHOW(2);
1322 OSMO_STRBUF_PRINTF(sb, "\n");
1323 SHOW(3);
1324 OSMO_STRBUF_DROP_TAIL(sb, 3);
1325 SHOW(4);
1326 OSMO_STRBUF_PRINTF(sb, "\n");
1327 SHOW(5);
1328
1329 /* drop trailing newline */
1330 OSMO_STRBUF_DROP_TAIL(sb, 1);
1331 SHOW(6);
1332
1333 /* test writing something to the end and letting OSMO_STRBUF_ADDED_TAIL() know later */
1334 int n = OSMO_MIN(6, OSMO_STRBUF_REMAIN(sb));
1335 if (n)
1336 memcpy(sb.pos, "bread\n", n);
1337 OSMO_STRBUF_ADDED_TAIL(sb, 6);
1338 SHOW(7);
1339}
1340
1341void strbuf_test_tail(void)
1342{
1343 strbuf_test_tail_for_buflen(64);
1344 strbuf_test_tail_for_buflen(32);
1345 strbuf_test_tail_for_buflen(16);
1346 strbuf_test_tail_for_buflen(8);
1347 strbuf_test_tail_for_buflen(4);
1348 strbuf_test_tail_for_buflen(1);
1349}
1350
Vadim Yanitskiy9df820b2023-12-11 13:34:02 +07001351void strbuf_test_remain_char_count(void)
1352{
1353 char buf[20];
1354 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1355
1356 printf("\n%s\n", __func__);
1357
1358 printf("remaining space: %zu\n", OSMO_STRBUF_REMAIN(sb));
1359 printf("current char count: %zu\n", OSMO_STRBUF_CHAR_COUNT(sb));
1360
1361 printf("populating the buffer\n");
1362 OSMO_STRBUF_PRINTF(sb, "osmocom");
1363
1364 printf("remaining space: %zu\n", OSMO_STRBUF_REMAIN(sb));
1365 printf("current char count: %zu\n", OSMO_STRBUF_CHAR_COUNT(sb));
1366}
1367
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001368static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1369{
1370 bool rc = osmo_str_startswith(str, startswith_str);
1371 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1372 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1373 if (rc != expect_rc)
1374 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1375}
1376
Harald Weltee61d4592022-11-03 11:05:58 +01001377static void startswith_test(void)
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001378{
1379 printf("\n%s()\n", __func__);
1380 startswith_test_str(NULL, NULL, true);
1381 startswith_test_str("", NULL, true);
1382 startswith_test_str(NULL, "", true);
1383 startswith_test_str("", "", true);
1384 startswith_test_str("abc", NULL, true);
1385 startswith_test_str("abc", "", true);
1386 startswith_test_str(NULL, "abc", false);
1387 startswith_test_str("", "abc", false);
1388 startswith_test_str("abc", "a", true);
1389 startswith_test_str("abc", "ab", true);
1390 startswith_test_str("abc", "abc", true);
1391 startswith_test_str("abc", "abcd", false);
1392 startswith_test_str("abc", "xyz", false);
1393}
1394
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001395static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1396{
1397 if (!arg)
1398 return -EINVAL;
1399 return snprintf(buf, buflen, "%s", arg);
1400}
1401
1402static char *foo_name_c(void *ctx, const char *arg)
1403{
1404 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1405}
1406
1407static char *foo_name_c_null(void *ctx, const char *arg)
1408{
1409 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1410}
1411
1412static char *foo_name_c_zero(void *ctx, const char *arg)
1413{
1414 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1415}
1416
1417static char *foo_name_c_zero_null(void *ctx, const char *arg)
1418{
1419 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1420}
1421
Harald Weltee61d4592022-11-03 11:05:58 +01001422static void name_c_impl_test(void)
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001423{
1424 char *test_strs[] = {
1425 "test",
1426 "longer than 10 chars",
1427 NULL,
1428 };
1429 struct {
1430 const char *label;
1431 char *(*func)(void *, const char*);
1432 } funcs[] = {
1433 {
1434 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1435 foo_name_c,
1436 },
1437 {
1438 "OSMO_NAME_C_IMPL(10, NULL)",
1439 foo_name_c_null,
1440 },
1441 {
1442 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1443 foo_name_c_zero,
1444 },
1445 {
1446 "OSMO_NAME_C_IMPL(0, NULL)",
1447 foo_name_c_zero_null,
1448 },
1449 };
1450
1451 int i;
1452 void *ctx = talloc_named_const(NULL, 0, __func__);
1453 int allocs = talloc_total_blocks(ctx);
1454
1455 printf("\n%s\n", __func__);
1456 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1457 char *test_str = test_strs[i];
1458 int j;
1459 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1460
1461 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1462 char *str = funcs[j].func(ctx, test_str);
1463 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1464 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1465 if (str) {
1466 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1467 talloc_free(str);
1468 }
1469 printf("\n");
1470 }
1471 }
1472 talloc_free(ctx);
1473}
1474
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001475static void osmo_print_n_test(void)
1476{
1477 struct token_test {
1478 const char *src;
1479 size_t token_len;
1480 size_t buf_size;
1481 const char *expect_token;
1482 int expect_rc;
1483 };
1484 struct token_test tests[] = {
1485 { "foo=bar", 3, 100, "foo", 3 },
1486 { "foo", 10, 100, "foo", 3 },
1487 { "foo", 3, 100, "foo", 3 },
1488 { NULL, 10, 100, "", 0 },
1489 { "", 10, 100, "", 0 },
1490 { "foo=bar", 0, 100, "", 0 },
1491
1492 { "foo=bar", 3, 2, "f", 3 },
1493 { "foo", 10, 2, "f", 3 },
1494 { "foo", 3, 2, "f", 3 },
1495 { NULL, 10, 2, "", 0 },
1496 { "", 10, 2, "", 0 },
1497 { "foo=bar", 0, 2, "", 0 },
1498
1499 { "foo=bar", 3, 1, "", 3 },
1500 { "foo", 10, 1, "", 3 },
1501 { "foo", 3, 1, "", 3 },
1502 { NULL, 10, 1, "", 0 },
1503 { "", 10, 1, "", 0 },
1504 { "foo=bar", 0, 1, "", 0 },
1505
1506 { "foo=bar", 3, 0, "unchanged", 3 },
1507 { "foo", 10, 0, "unchanged", 3 },
1508 { "foo", 3, 0, "unchanged", 3 },
1509 { NULL, 10, 0, "unchanged", 0 },
1510 { "", 10, 0, "unchanged", 0 },
1511 { "foo=bar", 0, 0, "unchanged", 0 },
1512 };
1513 struct token_test *t;
1514 printf("\n%s()\n", __func__);
1515 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1516 char buf[100] = "unchanged";
1517 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1518 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1519 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1520 if (strcmp(buf, t->expect_token))
1521 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1522 if (rc != t->expect_rc)
1523 printf(" ERROR: expected rc %d", t->expect_rc);
1524 printf("\n");
1525 }
1526}
1527
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001528static void osmo_strnchr_test(void)
1529{
1530 struct test {
1531 const char *haystack;
1532 size_t haystack_len;
1533 const char *needle;
1534 int expect_offset;
1535 };
1536 struct test tests[] = {
1537 { "foo=bar", 8, "=", 3 },
1538 { "foo=bar", 4, "=", 3 },
1539 { "foo=bar", 3, "=", -1 },
1540 { "foo=bar", 0, "=", -1 },
1541 { "foo\0=bar", 9, "=", -1 },
1542 { "foo\0=bar", 9, "\0", 3 },
1543 };
1544 struct test *t;
1545 printf("\n%s()\n", __func__);
1546 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1547 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1548 int offset = -1;
1549 if (r)
1550 offset = r - t->haystack;
1551 printf("osmo_strnchr(%s, %zu, ",
1552 osmo_quote_str(t->haystack, -1), t->haystack_len);
1553 printf("'%s') -> %d",
1554 osmo_escape_str(t->needle, 1), offset);
1555 if (offset != t->expect_offset)
1556 printf(" ERROR expected %d", t->expect_offset);
1557 printf("\n");
1558 }
1559}
1560
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001561struct float_str_to_int_test {
1562 unsigned int precision;
1563 const char *str;
1564 int64_t expect_val;
1565 int expect_err;
1566};
1567struct float_str_to_int_test float_str_to_int_tests[] = {
1568 { 0, "0", 0 },
1569 { 0, "1", 1 },
1570 { 0, "12.345", 12 },
1571 { 0, "+12.345", 12 },
1572 { 0, "-12.345", -12 },
1573 { 0, "0.345", 0 },
1574 { 0, ".345", 0 },
1575 { 0, "-0.345", 0 },
1576 { 0, "-.345", 0 },
1577 { 0, "12.", 12 },
1578 { 0, "-180", -180 },
1579 { 0, "180", 180 },
1580 { 0, "360", 360 },
1581 { 0, "123.4567890123", 123 },
1582 { 0, "123.4567890123456789012345", 123 },
1583 { 0, "9223372036854775807", 9223372036854775807LL },
1584 { 0, "-9223372036854775807", -9223372036854775807LL },
1585 { 0, "-9223372036854775808", .expect_err = -ERANGE },
1586 { 0, "9223372036854775808", .expect_err = -ERANGE },
1587 { 0, "-9223372036854775809", .expect_err = -ERANGE },
1588 { 0, "100000000000000000000", .expect_err = -ERANGE },
1589 { 0, "-100000000000000000000", .expect_err = -ERANGE },
1590 { 0, "999999999999999999999999999.99", .expect_err = -ERANGE },
1591 { 0, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1592 { 0, "1.2.3", .expect_err = -EINVAL },
1593 { 0, "foo", .expect_err = -EINVAL },
1594 { 0, "1.foo", .expect_err = -EINVAL },
1595 { 0, "1.foo", .expect_err = -EINVAL },
1596 { 0, "12.-345", .expect_err = -EINVAL },
1597 { 0, "-12.-345", .expect_err = -EINVAL },
1598 { 0, "12.+345", .expect_err = -EINVAL },
1599 { 0, "+12.+345", .expect_err = -EINVAL },
1600 { 0, "", .expect_err = -EINVAL },
1601 { 0, NULL, .expect_err = -EINVAL },
1602
1603 { 1, "0", 0 },
1604 { 1, "1", 10 },
1605 { 1, "12.345", 123 },
1606 { 1, "+12.345", 123 },
1607 { 1, "-12.345", -123 },
1608 { 1, "0.345", 3 },
1609 { 1, ".345", 3 },
1610 { 1, "-0.345", -3 },
1611 { 1, "-.345", -3 },
1612 { 1, "12.", 120 },
1613 { 1, "-180", -1800 },
1614 { 1, "180", 1800 },
1615 { 1, "360", 3600 },
1616 { 1, "123.4567890123", 1234 },
1617 { 1, "123.4567890123456789012345", 1234 },
1618 { 1, "922337203685477580.7", 9223372036854775807LL },
1619 { 1, "-922337203685477580.7", -9223372036854775807LL },
1620 { 1, "-922337203685477580.8", .expect_err = -ERANGE },
1621 { 1, "922337203685477580.8", .expect_err = -ERANGE },
1622 { 1, "-922337203685477580.9", .expect_err = -ERANGE },
1623 { 1, "100000000000000000000", .expect_err = -ERANGE },
1624 { 1, "-100000000000000000000", .expect_err = -ERANGE },
1625 { 1, "999999999999999999999999999.99", .expect_err = -ERANGE },
1626 { 1, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1627 { 1, "1.2.3", .expect_err = -EINVAL },
1628 { 1, "foo", .expect_err = -EINVAL },
1629 { 1, "1.foo", .expect_err = -EINVAL },
1630 { 1, "1.foo", .expect_err = -EINVAL },
1631 { 1, "12.-345", .expect_err = -EINVAL },
1632 { 1, "-12.-345", .expect_err = -EINVAL },
1633 { 1, "12.+345", .expect_err = -EINVAL },
1634 { 1, "+12.+345", .expect_err = -EINVAL },
1635 { 1, "", .expect_err = -EINVAL },
1636 { 1, NULL, .expect_err = -EINVAL },
1637
1638 { 6, "0", 0 },
1639 { 6, "1", 1000000 },
1640 { 6, "12.345", 12345000 },
1641 { 6, "+12.345", 12345000 },
1642 { 6, "-12.345", -12345000 },
1643 { 6, "0.345", 345000 },
1644 { 6, ".345", 345000 },
1645 { 6, "-0.345", -345000 },
1646 { 6, "-.345", -345000 },
1647 { 6, "12.", 12000000 },
1648 { 6, "-180", -180000000 },
1649 { 6, "180", 180000000 },
1650 { 6, "360", 360000000 },
1651 { 6, "123.4567890123", 123456789 },
1652 { 6, "123.4567890123456789012345", 123456789 },
1653 { 6, "9223372036854.775807", 9223372036854775807LL },
1654 { 6, "-9223372036854.775807", -9223372036854775807LL },
1655 { 6, "-9223372036854.775808", .expect_err = -ERANGE },
1656 { 6, "9223372036854.775808", .expect_err = -ERANGE },
1657 { 6, "-9223372036854.775809", .expect_err = -ERANGE },
1658 { 6, "100000000000000000000", .expect_err = -ERANGE },
1659 { 6, "-100000000000000000000", .expect_err = -ERANGE },
1660 { 6, "999999999999999999999999999.99", .expect_err = -ERANGE },
1661 { 6, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1662 { 6, "1.2.3", .expect_err = -EINVAL },
1663 { 6, "foo", .expect_err = -EINVAL },
1664 { 6, "1.foo", .expect_err = -EINVAL },
1665 { 6, "1.foo", .expect_err = -EINVAL },
1666 { 6, "12.-345", .expect_err = -EINVAL },
1667 { 6, "-12.-345", .expect_err = -EINVAL },
1668 { 6, "12.+345", .expect_err = -EINVAL },
1669 { 6, "+12.+345", .expect_err = -EINVAL },
1670 { 6, "", .expect_err = -EINVAL },
1671 { 6, NULL, .expect_err = -EINVAL },
1672
1673 { 18, "0", 0 },
1674 { 18, "1", 1000000000000000000LL },
1675 { 18, "1.2345", 1234500000000000000LL },
1676 { 18, "+1.2345", 1234500000000000000LL },
1677 { 18, "-1.2345", -1234500000000000000LL },
1678 { 18, "0.345", 345000000000000000LL },
1679 { 18, ".345", 345000000000000000LL },
1680 { 18, "-0.345", -345000000000000000LL },
1681 { 18, "-.345", -345000000000000000LL },
1682 { 18, "2.", 2000000000000000000LL },
1683 { 18, "-8", -8000000000000000000LL },
1684 { 18, "1.234567890123", 1234567890123000000LL },
1685 { 18, "1.234567890123456789012345", 1234567890123456789LL },
1686 { 18, "123.4567890123", .expect_err = -ERANGE },
1687 { 18, "9.223372036854775807", 9223372036854775807LL },
1688 { 18, "-9.223372036854775807", -9223372036854775807LL },
1689 { 18, "-9.223372036854775808", .expect_err = -ERANGE },
1690 { 18, "9.223372036854775808", .expect_err = -ERANGE },
1691 { 18, "-9.223372036854775809", .expect_err = -ERANGE },
1692 { 18, "100000000000000000000", .expect_err = -ERANGE },
1693 { 18, "-100000000000000000000", .expect_err = -ERANGE },
1694 { 18, "999999999999999999999999999.99", .expect_err = -ERANGE },
1695 { 18, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1696 { 18, "1.2.3", .expect_err = -EINVAL },
1697 { 18, "foo", .expect_err = -EINVAL },
1698 { 18, "1.foo", .expect_err = -EINVAL },
1699 { 18, "1.foo", .expect_err = -EINVAL },
1700 { 18, "12.-345", .expect_err = -EINVAL },
1701 { 18, "-12.-345", .expect_err = -EINVAL },
1702 { 18, "12.+345", .expect_err = -EINVAL },
1703 { 18, "+12.+345", .expect_err = -EINVAL },
1704 { 18, "", .expect_err = -EINVAL },
1705 { 18, NULL, .expect_err = -EINVAL },
1706
1707 { 19, "0", 0 },
1708 { 19, ".1", 1000000000000000000LL },
1709 { 19, ".12345", 1234500000000000000LL },
1710 { 19, "+.12345", 1234500000000000000LL },
1711 { 19, "-.12345", -1234500000000000000LL },
1712 { 19, "0.0345", 345000000000000000LL },
1713 { 19, ".0345", 345000000000000000LL },
1714 { 19, "-0.0345", -345000000000000000LL },
1715 { 19, "-.0345", -345000000000000000LL },
1716 { 19, ".2", 2000000000000000000LL },
1717 { 19, "-.8", -8000000000000000000LL },
1718 { 19, ".1234567890123", 1234567890123000000LL },
1719 { 19, ".1234567890123456789012345", 1234567890123456789LL },
1720 { 19, "123.4567890123", .expect_err = -ERANGE },
1721 { 19, ".9223372036854775807", 9223372036854775807LL },
1722 { 19, "-.9223372036854775807", -9223372036854775807LL },
1723 { 19, "-.9223372036854775808", .expect_err = -ERANGE },
1724 { 19, ".9223372036854775808", .expect_err = -ERANGE },
1725 { 19, "-.9223372036854775809", .expect_err = -ERANGE },
1726 { 19, "100000000000000000000", .expect_err = -ERANGE },
1727 { 19, "-100000000000000000000", .expect_err = -ERANGE },
1728 { 19, "999999999999999999999999999.99", .expect_err = -ERANGE },
1729 { 19, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1730 { 19, "1.2.3", .expect_err = -EINVAL },
1731 { 19, "foo", .expect_err = -EINVAL },
1732 { 19, "1.foo", .expect_err = -EINVAL },
1733 { 19, "1.foo", .expect_err = -EINVAL },
1734 { 19, "12.-345", .expect_err = -EINVAL },
1735 { 19, "-12.-345", .expect_err = -EINVAL },
1736 { 19, "12.+345", .expect_err = -EINVAL },
1737 { 19, "+12.+345", .expect_err = -EINVAL },
1738 { 19, "", .expect_err = -EINVAL },
1739 { 19, NULL, .expect_err = -EINVAL },
1740
1741 { 20, "0", 0 },
1742 { 20, ".01", 1000000000000000000LL },
1743 { 20, ".012345", 1234500000000000000LL },
1744 { 20, "+.012345", 1234500000000000000LL },
1745 { 20, "-.012345", -1234500000000000000LL },
1746 { 20, "0.00345", 345000000000000000LL },
1747 { 20, ".00345", 345000000000000000LL },
1748 { 20, "-0.00345", -345000000000000000LL },
1749 { 20, "-.00345", -345000000000000000LL },
1750 { 20, ".02", 2000000000000000000LL },
1751 { 20, "-.08", -8000000000000000000LL },
1752 { 20, ".01234567890123", 1234567890123000000LL },
1753 { 20, ".01234567890123456789012345", 1234567890123456789LL },
1754 { 20, "12.34567890123", .expect_err = -ERANGE },
1755 { 20, ".09223372036854775807", 9223372036854775807LL },
1756 { 20, "-.09223372036854775807", -9223372036854775807LL },
1757 { 20, "-.09223372036854775808", .expect_err = -ERANGE },
1758 { 20, ".09223372036854775808", .expect_err = -ERANGE },
1759 { 20, "-.09223372036854775809", .expect_err = -ERANGE },
1760 { 20, ".1", .expect_err = -ERANGE },
1761 { 20, "-.1", .expect_err = -ERANGE },
1762 { 20, "999999999999999999999999999.99", .expect_err = -ERANGE },
1763 { 20, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1764 { 20, "1.2.3", .expect_err = -EINVAL },
1765 { 20, "foo", .expect_err = -EINVAL },
1766 { 20, "1.foo", .expect_err = -EINVAL },
1767 { 20, "1.foo", .expect_err = -EINVAL },
1768 { 20, "12.-345", .expect_err = -EINVAL },
1769 { 20, "-12.-345", .expect_err = -EINVAL },
1770 { 20, "12.+345", .expect_err = -EINVAL },
1771 { 20, "+12.+345", .expect_err = -EINVAL },
1772 { 20, "", .expect_err = -EINVAL },
1773 { 20, NULL, .expect_err = -EINVAL },
1774
1775 { 25, "0", 0 },
1776 { 25, ".0000001", 1000000000000000000LL },
1777 { 25, ".00000012345", 1234500000000000000LL },
1778 { 25, "+.00000012345", 1234500000000000000LL },
1779 { 25, "-.00000012345", -1234500000000000000LL },
1780 { 25, "0.0000000345", 345000000000000000LL },
1781 { 25, ".0000000345", 345000000000000000LL },
1782 { 25, "-0.0000000345", -345000000000000000LL },
1783 { 25, "-.0000000345", -345000000000000000LL },
1784 { 25, ".0000002", 2000000000000000000LL },
1785 { 25, "-.0000008", -8000000000000000000LL },
1786 { 25, ".0000001234567890123", 1234567890123000000LL },
1787 { 25, ".0000001234567890123456789012345", 1234567890123456789LL },
1788 { 25, ".0001234567890123", .expect_err = -ERANGE },
1789 { 25, ".0000009223372036854775807", 9223372036854775807LL },
1790 { 25, "-.0000009223372036854775807", -9223372036854775807LL },
1791 { 25, "-.0000009223372036854775808", .expect_err = -ERANGE },
1792 { 25, ".0000009223372036854775808", .expect_err = -ERANGE },
1793 { 25, "-.0000009223372036854775809", .expect_err = -ERANGE },
1794 { 25, ".000001", .expect_err = -ERANGE },
1795 { 25, "-.000001", .expect_err = -ERANGE },
1796 { 25, "999999999999999999999999999.99", .expect_err = -ERANGE },
1797 { 25, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1798 { 25, "1.2.3", .expect_err = -EINVAL },
1799 { 25, "foo", .expect_err = -EINVAL },
1800 { 25, "1.foo", .expect_err = -EINVAL },
1801 { 25, "1.foo", .expect_err = -EINVAL },
1802 { 25, "12.-345", .expect_err = -EINVAL },
1803 { 25, "-12.-345", .expect_err = -EINVAL },
1804 { 25, "12.+345", .expect_err = -EINVAL },
1805 { 25, "+12.+345", .expect_err = -EINVAL },
1806 { 25, "", .expect_err = -EINVAL },
1807 { 25, NULL, .expect_err = -EINVAL },
1808};
1809const char *errno_str(int rc)
1810{
Neels Hofmeyr47773342021-09-05 18:48:31 +02001811 switch (rc) {
1812 case -EINVAL:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001813 return "=-EINVAL";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001814 case -ERANGE:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001815 return "=-ERANGE";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001816 case -E2BIG:
1817 return "=-E2BIG";
1818 case -EOVERFLOW:
1819 return "=-EOVERFLOW";
1820 default:
1821 return "";
1822 }
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001823}
Harald Weltee61d4592022-11-03 11:05:58 +01001824void test_float_str_to_int(void)
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001825{
1826 const struct float_str_to_int_test *t;
1827 printf("--- %s\n", __func__);
1828 for (t = float_str_to_int_tests; (t - float_str_to_int_tests) < ARRAY_SIZE(float_str_to_int_tests); t++) {
1829 int rc;
1830 int64_t val;
1831 rc = osmo_float_str_to_int(&val, t->str, t->precision);
1832 printf("osmo_float_str_to_int(%s, %u) -> rc=%d%s val=%" PRId64 "\n",
1833 osmo_quote_str(t->str, -1), t->precision, rc, errno_str(rc), val);
1834
1835 if (rc != t->expect_err)
1836 printf(" ERROR: expected rc=%d%s\n", t->expect_err, errno_str(t->expect_err));
1837 if (val != t->expect_val)
1838 printf(" ERROR: expected val=%" PRId64 "\n", t->expect_val);
1839 if (rc != t->expect_err||val != t->expect_val)
1840 exit(0);
1841 }
1842}
1843
1844struct int_to_float_str_test {
1845 unsigned int precision;
1846 int64_t val;
1847 const char *expect_str;
1848};
1849struct int_to_float_str_test int_to_float_str_tests[] = {
1850 { 0, 0, "0" },
1851 { 0, 1, "1" },
1852 { 0, 1000000, "1000000" },
1853 { 0, -1000000, "-1000000" },
1854 { 0, 1000001, "1000001" },
1855 { 0, -1000001, "-1000001" },
1856 { 0, 1000100, "1000100" },
1857 { 0, -1010000, "-1010000" },
1858 { 0, 1100000, "1100000" },
1859 { 0, 10000000, "10000000" },
1860 { 0, -10000000, "-10000000" },
1861 { 0, 100000000, "100000000" },
1862 { 0, -100000000, "-100000000" },
1863 { 0, 9223372036854775807, "9223372036854775807" },
1864 { 0, -9223372036854775807, "-9223372036854775807" },
1865 { 0, INT64_MIN, "-ERR" },
1866
1867 { 1, 0, "0" },
1868 { 1, 1, "0.1" },
1869 { 1, 1000000, "100000" },
1870 { 1, -1000000, "-100000" },
1871 { 1, 1000001, "100000.1" },
1872 { 1, -1000001, "-100000.1" },
1873 { 1, 1000100, "100010" },
1874 { 1, -1010000, "-101000" },
1875 { 1, 1100000, "110000" },
1876 { 1, 10000000, "1000000" },
1877 { 1, -10000000, "-1000000" },
1878 { 1, 100000000, "10000000" },
1879 { 1, -100000000, "-10000000" },
1880 { 1, 9223372036854775807, "922337203685477580.7" },
1881 { 1, -9223372036854775807, "-922337203685477580.7" },
1882 { 1, INT64_MIN, "-ERR" },
1883
1884 { 3, 0, "0" },
1885 { 3, 1, "0.001" },
1886 { 3, 1000000, "1000" },
1887 { 3, -1000000, "-1000" },
1888 { 3, 1000001, "1000.001" },
1889 { 3, -1000001, "-1000.001" },
1890 { 3, 1000100, "1000.1" },
1891 { 3, -1010000, "-1010" },
1892 { 3, 1100000, "1100" },
1893 { 3, 10000000, "10000" },
1894 { 3, -10000000, "-10000" },
1895 { 3, 100000000, "100000" },
1896 { 3, -100000000, "-100000" },
1897 { 3, 9223372036854775807, "9223372036854775.807" },
1898 { 3, -9223372036854775807, "-9223372036854775.807" },
1899 { 3, INT64_MIN, "-ERR" },
1900
1901 { 6, 0, "0" },
1902 { 6, 1, "0.000001" },
1903 { 6, 1000000, "1" },
1904 { 6, -1000000, "-1" },
1905 { 6, 1000001, "1.000001" },
1906 { 6, -1000001, "-1.000001" },
1907 { 6, 1000100, "1.0001" },
1908 { 6, -1010000, "-1.01" },
1909 { 6, 1100000, "1.1" },
1910 { 6, 10000000, "10" },
1911 { 6, -10000000, "-10" },
1912 { 6, 100000000, "100" },
1913 { 6, -100000000, "-100" },
1914 { 6, 9223372036854775807, "9223372036854.775807" },
1915 { 6, -9223372036854775807, "-9223372036854.775807" },
1916 { 6, INT64_MIN, "-ERR" },
1917
1918 { 17, 0, "0" },
1919 { 17, 1, "0.00000000000000001" },
1920 { 17, 1000000, "0.00000000001" },
1921 { 17, -1000000, "-0.00000000001" },
1922 { 17, 1000001, "0.00000000001000001" },
1923 { 17, -1000001, "-0.00000000001000001" },
1924 { 17, 1000100, "0.000000000010001" },
1925 { 17, -1010000, "-0.0000000000101" },
1926 { 17, 1100000, "0.000000000011" },
1927 { 17, 10000000, "0.0000000001" },
1928 { 17, -10000000, "-0.0000000001" },
1929 { 17, 100000000, "0.000000001" },
1930 { 17, -100000000, "-0.000000001" },
1931 { 17, 9223372036854775807, "92.23372036854775807" },
1932 { 17, -9223372036854775807, "-92.23372036854775807" },
1933 { 17, INT64_MIN, "-ERR" },
1934
1935 { 18, 0, "0" },
1936 { 18, 1, "0.000000000000000001" },
1937 { 18, 1000000, "0.000000000001" },
1938 { 18, -1000000, "-0.000000000001" },
1939 { 18, 1000001, "0.000000000001000001" },
1940 { 18, -1000001, "-0.000000000001000001" },
1941 { 18, 1000100, "0.0000000000010001" },
1942 { 18, -1010000, "-0.00000000000101" },
1943 { 18, 1100000, "0.0000000000011" },
1944 { 18, 10000000, "0.00000000001" },
1945 { 18, -10000000, "-0.00000000001" },
1946 { 18, 100000000, "0.0000000001" },
1947 { 18, -100000000, "-0.0000000001" },
1948 { 18, 9223372036854775807, "9.223372036854775807" },
1949 { 18, -9223372036854775807, "-9.223372036854775807" },
1950 { 18, INT64_MIN, "-ERR" },
1951
1952 { 19, 0, "0" },
1953 { 19, 1, "0.0000000000000000001" },
1954 { 19, 1000000, "0.0000000000001" },
1955 { 19, -1000000, "-0.0000000000001" },
1956 { 19, 1000001, "0.0000000000001000001" },
1957 { 19, -1000001, "-0.0000000000001000001" },
1958 { 19, 1000100, "0.00000000000010001" },
1959 { 19, -1010000, "-0.000000000000101" },
1960 { 19, 1100000, "0.00000000000011" },
1961 { 19, 10000000, "0.000000000001" },
1962 { 19, -10000000, "-0.000000000001" },
1963 { 19, 100000000, "0.00000000001" },
1964 { 19, -100000000, "-0.00000000001" },
1965 { 19, 9223372036854775807, "0.9223372036854775807" },
1966 { 19, -9223372036854775807, "-0.9223372036854775807" },
1967 { 19, INT64_MIN, "-ERR" },
1968
1969 { 23, 0, "0" },
1970 { 23, 1, "0.00000000000000000000001" },
1971 { 23, 1000000, "0.00000000000000001" },
1972 { 23, -1000000, "-0.00000000000000001" },
1973 { 23, 1000001, "0.00000000000000001000001" },
1974 { 23, -1000001, "-0.00000000000000001000001" },
1975 { 23, 1000100, "0.000000000000000010001" },
1976 { 23, -1010000, "-0.0000000000000000101" },
1977 { 23, 1100000, "0.000000000000000011" },
1978 { 23, 10000000, "0.0000000000000001" },
1979 { 23, -10000000, "-0.0000000000000001" },
1980 { 23, 100000000, "0.000000000000001" },
1981 { 23, -100000000, "-0.000000000000001" },
1982 { 23, 9223372036854775807, "0.00009223372036854775807" },
1983 { 23, -9223372036854775807, "-0.00009223372036854775807" },
1984 { 23, INT64_MIN, "-ERR" },
1985};
Harald Weltee61d4592022-11-03 11:05:58 +01001986void test_int_to_float_str(void)
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001987{
1988 const struct int_to_float_str_test *t;
1989 printf("--- %s\n", __func__);
1990 for (t = int_to_float_str_tests;
1991 (t - int_to_float_str_tests) < ARRAY_SIZE(int_to_float_str_tests);
1992 t++) {
1993 char buf[128];
1994 int rc;
1995 rc = osmo_int_to_float_str_buf(buf, sizeof(buf), t->val, t->precision);
1996 printf("osmo_int_to_float_str_buf(%" PRId64 ", %u) -> rc=%d str=%s\n", t->val, t->precision, rc,
1997 osmo_quote_str(buf, -1));
1998
1999 if (rc != strlen(buf))
2000 printf(" ERROR: expected rc=%zu\n", strlen(buf));
2001 if (strcmp(buf, t->expect_str))
2002 printf(" ERROR: expected str=%s\n", osmo_quote_str(t->expect_str, -1));
2003 if (rc != strlen(buf) || strcmp(buf, t->expect_str))
2004 exit(0);
2005 }
2006}
2007
Neels Hofmeyr47773342021-09-05 18:48:31 +02002008struct str_to_int_test {
2009 const char *str;
2010 int base;
2011 int min_val;
2012 int max_val;
2013 int expect_rc;
2014 int expect_val;
2015};
2016/* Avoid using INT_MAX and INT_MIN because that would produce different test output on different architectures */
2017struct str_to_int_test str_to_int_tests[] = {
2018 { NULL, 10, -1000, 1000, -EINVAL, 0 },
2019 { "", 10, -1000, 1000, -EINVAL, 0 },
2020 { " ", 10, -1000, 1000, -EINVAL, 0 },
2021 { "-", 10, -1000, 1000, -EINVAL, 0 },
2022 { "--", 10, -1000, 1000, -EINVAL, 0 },
2023 { "+", 10, -1000, 1000, -EINVAL, 0 },
2024 { "++", 10, -1000, 1000, -EINVAL, 0 },
2025
2026 { "0", 10, -1000, 1000, 0, 0 },
2027 { "1", 10, -1000, 1000, 0, 1 },
2028 { "+1", 10, -1000, 1000, 0, 1 },
2029 { "-1", 10, -1000, 1000, 0, -1 },
2030 { "1000", 10, -1000, 1000, 0, 1000 },
2031 { "+1000", 10, -1000, 1000, 0, 1000 },
2032 { "-1000", 10, -1000, 1000, 0, -1000 },
2033 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
2034 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
2035 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
2036
2037 { "0", 16, -1000, 1000, 0, 0 },
2038 { "1", 16, -1000, 1000, 0, 1 },
2039 { "0x1", 16, -1000, 1000, 0, 1 },
2040 { "+1", 16, -1000, 1000, 0, 1 },
2041 { "-1", 16, -1000, 1000, 0, -1 },
2042 { "+0x1", 16, -1000, 1000, 0, 1 },
2043 { "-0x1", 16, -1000, 1000, 0, -1 },
2044 { "3e8", 16, -1000, 1000, 0, 1000 },
2045 { "3E8", 16, -1000, 1000, 0, 1000 },
2046 { "0x3e8", 16, -1000, 1000, 0, 1000 },
2047 { "0x3E8", 16, -1000, 1000, 0, 1000 },
2048 { "+3e8", 16, -1000, 1000, 0, 1000 },
2049 { "+3E8", 16, -1000, 1000, 0, 1000 },
2050 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
2051 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
2052 { "-3e8", 16, -1000, 1000, 0, -1000 },
2053 { "-3E8", 16, -1000, 1000, 0, -1000 },
2054 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
2055 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
2056 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
2057 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
2058 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2059 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2060 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2061 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2062 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2063 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2064 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2065 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2066 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2067 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2068
2069 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2070 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2071 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2072 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2073 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2074 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2075 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2076};
Harald Weltee61d4592022-11-03 11:05:58 +01002077void test_str_to_int(void)
Neels Hofmeyr47773342021-09-05 18:48:31 +02002078{
2079 const struct str_to_int_test *t;
2080 printf("--- %s\n", __func__);
2081 for (t = str_to_int_tests; (t - str_to_int_tests) < ARRAY_SIZE(str_to_int_tests); t++) {
2082 int rc;
2083 int val;
2084 rc = osmo_str_to_int(&val, t->str, t->base, t->min_val, t->max_val);
2085 printf("osmo_str_to_int(%s, %d, %d, %d) -> rc=%d%s val=%d\n",
2086 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2087
2088 if (rc != t->expect_rc)
2089 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2090 if (val != t->expect_val)
2091 printf(" ERROR: expected val=%d\n", t->expect_val);
2092 }
2093}
2094
2095struct str_to_int64_test {
2096 const char *str;
2097 int base;
2098 int64_t min_val;
2099 int64_t max_val;
2100 int expect_rc;
2101 int64_t expect_val;
2102};
2103struct str_to_int64_test str_to_int64_tests[] = {
2104 { NULL, 10, -1000, 1000, -EINVAL, 0 },
2105 { "", 10, -1000, 1000, -EINVAL, 0 },
2106 { " ", 10, -1000, 1000, -EINVAL, 0 },
2107 { "-", 10, -1000, 1000, -EINVAL, 0 },
2108 { "--", 10, -1000, 1000, -EINVAL, 0 },
2109 { "+", 10, -1000, 1000, -EINVAL, 0 },
2110 { "++", 10, -1000, 1000, -EINVAL, 0 },
2111
2112 { "0", 10, -1000, 1000, 0, 0 },
2113 { "1", 10, -1000, 1000, 0, 1 },
2114 { "+1", 10, -1000, 1000, 0, 1 },
2115 { "-1", 10, -1000, 1000, 0, -1 },
2116 { "1000", 10, -1000, 1000, 0, 1000 },
2117 { "+1000", 10, -1000, 1000, 0, 1000 },
2118 { "-1000", 10, -1000, 1000, 0, -1000 },
2119 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
2120 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
2121 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
2122
2123 { "0", 16, -1000, 1000, 0, 0 },
2124 { "1", 16, -1000, 1000, 0, 1 },
2125 { "0x1", 16, -1000, 1000, 0, 1 },
2126 { "+1", 16, -1000, 1000, 0, 1 },
2127 { "-1", 16, -1000, 1000, 0, -1 },
2128 { "+0x1", 16, -1000, 1000, 0, 1 },
2129 { "-0x1", 16, -1000, 1000, 0, -1 },
2130 { "3e8", 16, -1000, 1000, 0, 1000 },
2131 { "3E8", 16, -1000, 1000, 0, 1000 },
2132 { "0x3e8", 16, -1000, 1000, 0, 1000 },
2133 { "0x3E8", 16, -1000, 1000, 0, 1000 },
2134 { "+3e8", 16, -1000, 1000, 0, 1000 },
2135 { "+3E8", 16, -1000, 1000, 0, 1000 },
2136 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
2137 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
2138 { "-3e8", 16, -1000, 1000, 0, -1000 },
2139 { "-3E8", 16, -1000, 1000, 0, -1000 },
2140 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
2141 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
2142 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
2143 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
2144 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2145 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2146 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2147 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2148 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2149 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2150 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2151 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2152 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2153 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2154
2155 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2156 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2157 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2158 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2159 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2160 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2161 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2162
2163 { "-9223372036854775808", 10, INT64_MIN, INT64_MAX, 0, INT64_MIN },
2164 { "9223372036854775807", 10, INT64_MIN, INT64_MAX, 0, INT64_MAX },
2165
2166 { "-9223372036854775809", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MIN },
2167 { "9223372036854775808", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MAX },
2168
2169 { "-9223372036854775808", 10, -1000, 1000, -ERANGE, INT64_MIN },
2170 { "9223372036854775807", 10, -1000, 1000, -ERANGE, INT64_MAX },
2171 { "-9223372036854775809", 10, -1000, 1000, -EOVERFLOW, INT64_MIN },
2172 { "9223372036854775808", 10, -1000, 1000, -EOVERFLOW, INT64_MAX },
2173};
Harald Weltee61d4592022-11-03 11:05:58 +01002174void test_str_to_int64(void)
Neels Hofmeyr47773342021-09-05 18:48:31 +02002175{
2176 const struct str_to_int64_test *t;
2177 printf("--- %s\n", __func__);
2178 for (t = str_to_int64_tests; (t - str_to_int64_tests) < ARRAY_SIZE(str_to_int64_tests); t++) {
2179 int rc;
2180 int64_t val;
2181 rc = osmo_str_to_int64(&val, t->str, t->base, t->min_val, t->max_val);
2182 printf("osmo_str_to_int64(%s, %d, %"PRId64", %"PRId64") -> rc=%d%s val=%"PRId64"\n",
2183 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2184
2185 if (rc != t->expect_rc)
2186 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2187 if (val != t->expect_val)
2188 printf(" ERROR: expected val=%"PRId64"\n", t->expect_val);
2189 }
2190}
2191
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002192int main(int argc, char **argv)
2193{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02002194 static const struct log_info log_info = {};
2195 log_init(&log_info, NULL);
2196
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002197 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01002198 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02002199 test_ipa_ccm_id_get_parsing();
2200 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02002201 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02002202 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01002203 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01002204 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02002205 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01002206 str_escape3_test();
2207 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02002208 isqrt_test();
Philipp Maier94705d02023-01-11 10:55:47 +01002209 mod_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02002210 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02002211 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01002212 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02002213 strbuf_test_nolen();
Neels Hofmeyrd511a9d2023-12-04 07:48:55 +01002214 strbuf_test_tail();
Vadim Yanitskiy9df820b2023-12-11 13:34:02 +07002215 strbuf_test_remain_char_count();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01002216 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01002217 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01002218 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01002219 osmo_strnchr_test();
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00002220 test_float_str_to_int();
2221 test_int_to_float_str();
Neels Hofmeyr47773342021-09-05 18:48:31 +02002222 test_str_to_int();
2223 test_str_to_int64();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002224 return 0;
2225}