blob: 7e0e3d3cf66b69b8f4f222f08e5504958e99d211 [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 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020023#include <osmocom/gsm/ipa.h>
Harald Welte7869baf2018-07-31 20:25:48 +020024#include <osmocom/gsm/protocol/ipaccess.h>
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020025
26#include <osmocom/core/logging.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010027#include <osmocom/core/utils.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020028#include <osmocom/core/socket.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010029
30#include <stdio.h>
Harald Welte504caac2017-10-27 17:19:59 +020031#include <ctype.h>
Harald Welte15a5f8d2018-06-06 16:58:17 +020032#include <time.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020033#include <netinet/in.h>
34#include <arpa/inet.h>
Neels Hofmeyr7079e692018-12-05 21:02:36 +010035#include <errno.h>
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +010036#include <limits.h>
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +000037#include <inttypes.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010038
39static void hexdump_test(void)
40{
41 uint8_t data[4098];
Neels Hofmeyr0423b612019-01-14 23:32:53 +010042 char buf[256];
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010043 int i;
44
45 for (i = 0; i < ARRAY_SIZE(data); ++i)
46 data[i] = i & 0xff;
47
48 printf("Plain dump\n");
49 printf("%s\n", osmo_hexdump(data, 4));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010050 printf("%s\n", osmo_hexdump_nospc(data, 4));
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010051
52 printf("Corner case\n");
53 printf("%s\n", osmo_hexdump(data, ARRAY_SIZE(data)));
54 printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data)));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010055
56#define _HEXDUMP_BUF_TEST(SIZE, DELIM, DELIM_AFTER) \
57 buf[0] = '!'; \
58 buf[1] = '\0'; \
59 printf("osmo_hexdump_buf(buf, " #SIZE ", data, 4, %s, " #DELIM_AFTER ")\n = \"%s\"\n", \
60 DELIM ? #DELIM : "NULL", \
61 osmo_hexdump_buf(buf, SIZE, data, 4, DELIM, DELIM_AFTER))
62#define HEXDUMP_BUF_TEST(DELIM) \
63 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, false); \
64 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, true); \
65 _HEXDUMP_BUF_TEST(6, DELIM, false); \
66 _HEXDUMP_BUF_TEST(7, DELIM, false); \
67 _HEXDUMP_BUF_TEST(8, DELIM, false); \
68 _HEXDUMP_BUF_TEST(6, DELIM, true); \
69 _HEXDUMP_BUF_TEST(7, DELIM, true); \
70 _HEXDUMP_BUF_TEST(8, DELIM, true)
71
72 HEXDUMP_BUF_TEST("[delim]");
73 HEXDUMP_BUF_TEST(" ");
74 HEXDUMP_BUF_TEST(":");
75 HEXDUMP_BUF_TEST("::");
76 HEXDUMP_BUF_TEST("");
77 HEXDUMP_BUF_TEST(NULL);
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010078}
79
Neels Hofmeyr7adb5672017-02-14 15:48:19 +010080static void hexparse_test(void)
81{
82 int i;
83 int rc;
84 uint8_t data[256];
85
86 printf("\nHexparse 0..255 in lower case\n");
87 memset(data, 0, sizeof(data));
88 rc = osmo_hexparse(
89 "000102030405060708090a0b0c0d0e0f"
90 "101112131415161718191a1b1c1d1e1f"
91 "202122232425262728292a2b2c2d2e2f"
92 "303132333435363738393a3b3c3d3e3f"
93 "404142434445464748494a4b4c4d4e4f"
94 "505152535455565758595a5b5c5d5e5f"
95 "606162636465666768696a6b6c6d6e6f"
96 "707172737475767778797a7b7c7d7e7f"
97 "808182838485868788898a8b8c8d8e8f"
98 "909192939495969798999a9b9c9d9e9f"
99 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
100 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
101 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
102 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
103 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
104 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
105 , data, sizeof(data));
106 printf("rc = %d\n", rc);
107 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
108 for (i = 0; i < sizeof(data); i++)
109 OSMO_ASSERT(data[i] == i);
110
111 printf("Hexparse 0..255 in upper case\n");
112 memset(data, 0, sizeof(data));
113 rc = osmo_hexparse(
114 "000102030405060708090A0B0C0D0E0F"
115 "101112131415161718191A1B1C1D1E1F"
116 "202122232425262728292A2B2C2D2E2F"
117 "303132333435363738393A3B3C3D3E3F"
118 "404142434445464748494A4B4C4D4E4F"
119 "505152535455565758595A5B5C5D5E5F"
120 "606162636465666768696A6B6C6D6E6F"
121 "707172737475767778797A7B7C7D7E7F"
122 "808182838485868788898A8B8C8D8E8F"
123 "909192939495969798999A9B9C9D9E9F"
124 "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
125 "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
126 "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
127 "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
128 "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
129 "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
130 , data, sizeof(data));
131 printf("rc = %d\n", rc);
132 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
133 for (i = 0; i < sizeof(data); i++)
134 OSMO_ASSERT(data[i] == i);
135
136 printf("Hexparse 0..255 in mixed case\n");
137 memset(data, 0, sizeof(data));
138 rc = osmo_hexparse(
139 "000102030405060708090A0B0C0D0E0F"
140 "101112131415161718191A1B1C1D1E1F"
141 "202122232425262728292A2B2C2D2E2F"
142 "303132333435363738393a3b3c3d3e3f"
143 "404142434445464748494A4B4C4D4E4F"
144 "505152535455565758595a5b5c5d5e5f"
145 "606162636465666768696A6B6C6D6E6F"
146 "707172737475767778797A7B7C7D7E7F"
147 "808182838485868788898A8B8C8D8E8F"
148 "909192939495969798999A9B9C9D9E9F"
149 "A0A1A2A3a4a5a6a7a8a9AAABACADAEAF"
150 "B0B1B2B3b4b5b6b7b8b9BABBBCBDBEBF"
151 "C0C1C2C3c4c5c6c7c8c9CACBCCCDCECF"
152 "D0D1D2D3d4d5d6d7d8d9DADBDCDDDEDF"
153 "E0E1E2E3e4e5e6e7e8e9EAEBECEDEEEF"
154 "F0F1F2F3f4f5f6f7f8f9FAFBFCFDFEFF"
155 , data, sizeof(data));
156 printf("rc = %d\n", rc);
157 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
158 for (i = 0; i < sizeof(data); i++)
159 OSMO_ASSERT(data[i] == i);
160
Neels Hofmeyr437ed4a2017-02-14 15:54:31 +0100161 printf("Hexparse 0..255 with whitespace\n");
162 memset(data, 0, sizeof(data));
163 rc = osmo_hexparse(
164 "00 01\t02\r030405060708090A0B0C0D0 E 0 F\n"
165 "10 11\t12\r131415161718191A1B1C1D1 E 1 F\n"
166 "20 21\t22\r232425262728292A2B2C2D2 E 2 F\n"
167 "30 31\t32\r333435363738393a3b3c3d3 e 3 f\n"
168 "40 41\t42\r434445464748494A4B4C4D4 E 4 F\n"
169 "50 51\t52\r535455565758595a5b5c5d5 e 5 f\n"
170 "60 61\t62\r636465666768696A6B6C6D6 E 6 F\n"
171 "70 71\t72\r737475767778797A7B7C7D7 E 7 F\n"
172 "80 81\t82\r838485868788898A8B8C8D8 E 8 F\n"
173 "90 91\t92\r939495969798999A9B9C9D9 E 9 F\n"
174 "A0 A1\tA2\rA3a4a5a6a7a8a9AAABACADA E A F\n"
175 "B0 B1\tB2\rB3b4b5b6b7b8b9BABBBCBDB E B F\n"
176 "C0 C1\tC2\rC3c4c5c6c7c8c9CACBCCCDC E C F \n"
177 "D0 D1\tD2\rD3d4d5d6d7d8d9DADBDCDDD E D F\t\n"
178 "E0 E1\tE2\rE3e4e5e6e7e8e9EAEBECEDE E E F \t\n"
179 "F0 F1\tF2\rF3f4f5f6f7f8f9FAFBFCFDF E F F \t\r\n"
180 , data, sizeof(data));
181 printf("rc = %d\n", rc);
182 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
183 for (i = 0; i < sizeof(data); i++)
184 OSMO_ASSERT(data[i] == i);
185
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100186 printf("Hexparse with buffer too short\n");
187 memset(data, 0, sizeof(data));
188 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0f", data, 15);
189 printf("rc = %d\n", rc);
190
191 printf("Hexparse with uneven amount of digits\n");
192 memset(data, 0, sizeof(data));
193 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0", data, 16);
194 printf("rc = %d\n", rc);
195
196 printf("Hexparse with invalid char\n");
197 memset(data, 0, sizeof(data));
198 rc = osmo_hexparse("0001020304050X0708090a0b0c0d0e0f", data, 16);
199 printf("rc = %d\n", rc);
200}
201
Harald Welte7869baf2018-07-31 20:25:48 +0200202static void test_ipa_ccm_id_resp_parsing(void)
203{
204 struct tlv_parsed tvp;
205 int rc;
206
207 static const uint8_t id_resp_data[] = {
208 0x00, 0x13, IPAC_IDTAG_MACADDR,
209 '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0',
210 0x00, 0x11, IPAC_IDTAG_IPADDR,
211 '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0',
212 0x00, 0x0a, IPAC_IDTAG_UNIT,
213 '1','2','3','4','/','0','/','0','\0',
214 0x00, 0x02, IPAC_IDTAG_LOCATION1,
215 '\0',
216 0x00, 0x0d, IPAC_IDTAG_LOCATION2,
217 'B','T','S','_','N','B','T','1','3','1','G','\0',
218 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS,
219 '1','6','5','a','0','2','9','_','5','5','\0',
220 0x00, 0x14, IPAC_IDTAG_SWVERSION,
221 '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0',
222 0x00, 0x18, IPAC_IDTAG_UNITNAME,
223 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0',
224 0x00, 0x0a, IPAC_IDTAG_SERNR,
225 '0','0','1','1','0','7','8','1','\0'
226 };
227
228 printf("\nTesting IPA CCM ID RESP parsing\n");
229
230 rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data));
231 OSMO_ASSERT(rc == 0);
232
233 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR));
234 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12);
235 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR));
236 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10);
237 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT));
238 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09);
239 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1));
240 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01);
241 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2));
242 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c);
243 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS));
244 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
245 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION));
246 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
247 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13);
248 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME));
249 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17);
250 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR));
251 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09);
252}
253
254static void test_ipa_ccm_id_get_parsing(void)
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200255{
256 struct tlv_parsed tvp;
257 int rc;
258
Harald Welte48fd0192018-07-31 20:19:49 +0200259 /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */
Harald Welte7869baf2018-07-31 20:25:48 +0200260 static const uint8_t id_get_data[] = {
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200261 0x01, 0x08,
262 0x01, 0x07,
263 0x01, 0x02,
264 0x01, 0x03,
265 0x01, 0x04,
266 0x01, 0x05,
267 0x01, 0x01,
268 0x01, 0x00,
269 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30,
270 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
271 };
272
Harald Welte7869baf2018-07-31 20:25:48 +0200273 printf("\nTesting IPA CCM ID GET parsing\n");
274
275 rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data));
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200276 OSMO_ASSERT(rc == 0);
277
278 OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
279 OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0);
280
281 OSMO_ASSERT(TLVP_PRESENT(&tvp, 7));
282 OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0);
283
284 OSMO_ASSERT(TLVP_PRESENT(&tvp, 2));
285 OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0);
286
287 OSMO_ASSERT(TLVP_PRESENT(&tvp, 3));
288 OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0);
289
290 OSMO_ASSERT(TLVP_PRESENT(&tvp, 4));
291 OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0);
292
293 OSMO_ASSERT(TLVP_PRESENT(&tvp, 5));
294 OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0);
295
296 OSMO_ASSERT(TLVP_PRESENT(&tvp, 1));
297 OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0);
298
299 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0));
300 OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0);
301
302 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23));
303 OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16);
304
305 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24));
306 OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16);
307
308 OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
309}
310
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200311static struct {
312 const char *str;
313 int min_digits;
314 int max_digits;
315 bool require_even;
316 bool expect_ok;
317} test_hexstrs[] = {
318 { NULL, 0, 10, false, true },
319 { NULL, 1, 10, false, false },
320 { "", 0, 10, false, true },
321 { "", 1, 10, false, false },
322 { " ", 0, 10, false, false },
323 { "1", 0, 10, false, true },
324 { "1", 1, 10, false, true },
325 { "1", 1, 10, true, false },
326 { "1", 2, 10, false, false },
327 { "123", 1, 10, false, true },
328 { "123", 1, 10, true, false },
329 { "123", 4, 10, false, false },
330 { "1234", 4, 10, true, true },
331 { "12345", 4, 10, true, false },
332 { "123456", 4, 10, true, true },
333 { "1234567", 4, 10, true, false },
334 { "12345678", 4, 10, true, true },
335 { "123456789", 4, 10, true, false },
336 { "123456789a", 4, 10, true, true },
337 { "123456789ab", 4, 10, true, false },
338 { "123456789abc", 4, 10, true, false },
339 { "123456789ab", 4, 10, false, false },
340 { "123456789abc", 4, 10, false, false },
341 { "0123456789abcdefABCDEF", 0, 100, false, true },
342 { "0123456789 abcdef ABCDEF", 0, 100, false, false },
343 { "foobar", 0, 100, false, false },
344 { "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
345 { "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
346 { "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
347};
348
349bool test_is_hexstr()
350{
351 int i;
352 bool pass = true;
353 bool ok = true;
354 printf("\n----- %s\n", __func__);
355
356 for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
357 ok = osmo_is_hexstr(test_hexstrs[i].str,
358 test_hexstrs[i].min_digits,
359 test_hexstrs[i].max_digits,
360 test_hexstrs[i].require_even);
361 pass = pass && (ok == test_hexstrs[i].expect_ok);
362 printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
363 i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
364 test_hexstrs[i].str,
365 test_hexstrs[i].min_digits,
366 test_hexstrs[i].max_digits,
367 test_hexstrs[i].require_even,
368 test_hexstrs[i].expect_ok ? "valid" : "invalid");
369 }
370 return pass;
371}
372
Harald Welte504caac2017-10-27 17:19:59 +0200373struct bcdcheck {
374 uint8_t bcd;
375 char ch;
376};
377
378static const struct bcdcheck bcdchecks[] = {
379 { 0, '0' },
380 { 1, '1' },
381 { 2, '2' },
382 { 3, '3' },
383 { 4, '4' },
384 { 5, '5' },
385 { 6, '6' },
386 { 7, '7' },
387 { 8, '8' },
388 { 9, '9' },
389 { 0xA, 'A' },
390 { 0xB, 'B' },
391 { 0xC, 'C' },
392 { 0xD, 'D' },
393 { 0xE, 'E' },
394 { 0xF, 'F' },
395};
396
397static void bcd_test(void)
398{
399 int i;
400
401 printf("\nTesting BCD conversion\n");
402 for (i = 0; i < ARRAY_SIZE(bcdchecks); i++) {
403 const struct bcdcheck *check = &bcdchecks[i];
404 char ch = osmo_bcd2char(check->bcd);
405 printf("\tval=0x%x, expected=%c, found=%c\n", check->bcd, check->ch, ch);
406 OSMO_ASSERT(osmo_bcd2char(check->bcd) == check->ch);
407 /* test char -> bcd back-coversion */
408 OSMO_ASSERT(osmo_char2bcd(ch) == check->bcd);
409 /* test for lowercase hex char */
410 OSMO_ASSERT(osmo_char2bcd(tolower(ch)) == check->bcd);
411 }
412}
413
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100414struct bcd2str_test {
415 const char *bcd_hex;
416 int start_nibble;
417 int end_nibble;
418 bool allow_hex;
419 size_t str_size;
420 const char *expect_str;
421 int expect_rc;
422};
423
424static const struct bcd2str_test bcd2str_tests[] = {
425 {
426 .bcd_hex = "1a 32 54 76 98 f0",
427 .start_nibble = 1,
428 .end_nibble = 11,
429 .expect_str = "1234567890",
430 .expect_rc = 10,
431 },
432 {
433 .bcd_hex = "1a 32 a4 cb 9d f0",
434 .start_nibble = 1,
435 .end_nibble = 11,
436 .expect_str = "1234ABCD90",
437 .expect_rc = -EINVAL,
438 },
439 {
440 .bcd_hex = "1a 32 a4 cb 9d f0",
441 .start_nibble = 1,
442 .end_nibble = 11,
443 .allow_hex = true,
444 .expect_str = "1234ABCD90",
445 .expect_rc = 10,
446 },
447 {
448 .bcd_hex = "1a 32 54 76 98 f0",
449 .start_nibble = 1,
450 .end_nibble = 12,
451 .expect_str = "1234567890F",
452 .expect_rc = -EINVAL,
453 },
454 {
455 .bcd_hex = "1a 32 54 76 98 f0",
456 .start_nibble = 1,
457 .end_nibble = 12,
458 .allow_hex = true,
459 .expect_str = "1234567890F",
460 .expect_rc = 11,
461 },
462 {
463 .bcd_hex = "1a 32 54 76 98 f0",
464 .start_nibble = 0,
465 .end_nibble = 12,
466 .allow_hex = true,
467 .expect_str = "A1234567890F",
468 .expect_rc = 12,
469 },
470 {
471 .bcd_hex = "1a 32 54 76 98 f0",
472 .start_nibble = 1,
473 .end_nibble = 12,
474 .str_size = 5,
475 .expect_str = "1234",
476 .expect_rc = 11,
477 },
478 {
479 .bcd_hex = "",
480 .start_nibble = 1,
481 .end_nibble = 1,
482 .expect_str = "",
483 .expect_rc = 0,
484 },
485};
486
487static void bcd2str_test(void)
488{
489 int i;
490 uint8_t bcd[64];
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200491 uint8_t bcd2[64];
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100492 int rc;
493
494 printf("\nTesting bcd to string conversion\n");
495
496 for (i = 0; i < ARRAY_SIZE(bcd2str_tests); i++) {
497 const struct bcd2str_test *t = &bcd2str_tests[i];
498 char str[64] = {};
499 size_t str_size = t->str_size ? : sizeof(str);
500
501 osmo_hexparse(t->bcd_hex, bcd, sizeof(bcd));
502
503 printf("- BCD-input='%s' nibbles=[%d..%d[ str_size=%zu\n", t->bcd_hex,
504 t->start_nibble, t->end_nibble, str_size);
505 rc = osmo_bcd2str(str, str_size, bcd, t->start_nibble, t->end_nibble, t->allow_hex);
506
507 printf(" rc=%d\n", rc);
508
509 OSMO_ASSERT(str[str_size-1] == '\0');
510 printf(" -> %s\n", osmo_quote_str(str, -1));
511
512 if (rc != t->expect_rc)
513 printf(" ERROR: expected rc=%d\n", t->expect_rc);
514 if (strcmp(str, t->expect_str))
515 printf(" ERROR: expected result %s\n", osmo_quote_str(t->expect_str, -1));
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200516
517 memset(bcd2, 0xff, sizeof(bcd2));
518 rc = osmo_str2bcd(bcd2, sizeof(bcd2), str, t->start_nibble, -1, t->allow_hex);
519 printf("osmo_str2bcd(start_nibble=%d) -> rc=%d\n", t->start_nibble, rc);
520 if (rc > 0)
521 printf(" = %s\n", osmo_hexdump(bcd2, rc));
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100522 }
523
524 printf("- zero output buffer\n");
525 rc = osmo_bcd2str(NULL, 100, bcd, 1, 2, false);
526 printf(" bcd2str(NULL, ...) -> %d\n", rc);
527 OSMO_ASSERT(rc < 0);
528 rc = osmo_bcd2str((char*)23, 0, bcd, 1, 2, false);
529 printf(" bcd2str(dst, 0, ...) -> %d\n", rc);
530 OSMO_ASSERT(rc < 0);
531}
532
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100533static void str_escape_test(void)
534{
535 int i;
536 int j;
537 uint8_t in_buf[32];
538 char out_buf[11];
539 const char *printable = "printable";
540 const char *res;
541
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100542 printf("\nTesting string escaping: osmo_escape_str()\n");
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100543 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100544 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100545 for (j = 0; j < 16; j++) {
546 for (i = 0; i < 16; i++)
547 in_buf[i] = (j << 4) | i;
548 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
549 }
550
551 printf("- nul terminated:\n");
552 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
553
554 printf("- passthru:\n");
555 res = osmo_escape_str(printable, -1);
Harald Welte98ed3392019-03-28 13:26:53 +0100556 if (strcmp(res, printable))
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100557 printf("NOT passed through! \"%s\"\n", res);
558 else
559 printf("passed through unchanged \"%s\"\n", res);
560
561 printf("- zero length:\n");
562 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
563
564 printf("- truncation when too long:\n");
565 memset(in_buf, 'x', sizeof(in_buf));
566 in_buf[0] = '\a';
567 in_buf[7] = 'E';
568 memset(out_buf, 0x7f, sizeof(out_buf));
569 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
570 OSMO_ASSERT(out_buf[10] == 0x7f);
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100571}
572
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200573static void str_quote_test(void)
574{
575 int i;
576 int j;
577 uint8_t in_buf[32];
578 char out_buf[11];
579 const char *printable = "printable";
580 const char *res;
581
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100582 printf("\nTesting string quoting: osmo_quote_str()\n");
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200583 printf("- all chars from 0 to 255 in batches of 16:\n");
584 in_buf[16] = '\0';
585 for (j = 0; j < 16; j++) {
586 for (i = 0; i < 16; i++)
587 in_buf[i] = (j << 4) | i;
588 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
589 }
590
591 printf("- nul terminated:\n");
592 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
593
594 printf("- never passthru:\n");
595 res = osmo_quote_str(printable, -1);
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100596 if (strcmp(res, printable))
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200597 printf("NOT passed through. '%s'\n", res);
598 else
599 printf("passed through unchanged '%s'\n", res);
600
601 printf("- zero length:\n");
602 printf("'%s'\n", osmo_quote_str("omitted", 0));
603
604 printf("- truncation when too long:\n");
605 memset(in_buf, 'x', sizeof(in_buf));
606 in_buf[0] = '\a';
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100607 in_buf[6] = 'E';
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200608 memset(out_buf, 0x7f, sizeof(out_buf));
609 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
610 OSMO_ASSERT(out_buf[10] == 0x7f);
611
612 printf("- always truncation, even when no escaping needed:\n");
613 memset(in_buf, 'x', sizeof(in_buf));
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100614 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 +0200615 in_buf[20] = '\0';
616 memset(out_buf, 0x7f, sizeof(out_buf));
617 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
618 OSMO_ASSERT(out_buf[0] == '"');
619
620 printf("- try to feed too little buf for quoting:\n");
621 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
622
623 printf("- NULL string becomes a \"NULL\" literal:\n");
624 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
625}
626
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100627static void str_escape3_test(void)
628{
629 int i;
630 int j;
631 uint8_t in_buf[32];
632 char out_buf[11];
633 const char *printable = "printable";
634 const char *res;
635 void *ctx = talloc_named_const(NULL, 0, __func__);
636
637 printf("\nTesting string escaping: osmo_escape_cstr_buf()\n");
638 printf("- all chars from 0 to 255 in batches of 16:\n");
639 in_buf[16] = '\0';
640 for (j = 0; j < 16; j++) {
641 for (i = 0; i < 16; i++)
642 in_buf[i] = (j << 4) | i;
643 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, (const char*)in_buf, 16));
644 }
645
646 printf("- nul terminated:\n");
647 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "termi\nated", -1));
648
649 printf("- passthru:\n");
650 res = osmo_escape_cstr_c(ctx, printable, -1);
651 if (strcmp(res, printable))
652 printf("NOT passed through! \"%s\"\n", res);
653 else
654 printf("passed through unchanged \"%s\"\n", res);
655
656 printf("- zero length:\n");
657 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "omitted", 0));
658
659 printf("- truncation when too long:\n");
660 memset(in_buf, 'x', sizeof(in_buf));
661 in_buf[0] = '\a';
662 in_buf[7] = 'E';
663 memset(out_buf, 0x7f, sizeof(out_buf));
664 osmo_escape_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
665 printf("\"%s\"\n", out_buf);
666 OSMO_ASSERT(out_buf[10] == 0x7f);
667
668 printf("- Test escaping an escaped string:\n");
669 res = "\x02\x03\n";
670 for (i = 0; i <= 3; i++) {
671 res = osmo_escape_cstr_c(ctx, res, -1);
672 printf("%d: '%s'\n", i, res);
673 }
674
675 talloc_free(ctx);
676}
677
678static void str_quote3_test(void)
679{
680 int i;
681 int j;
682 uint8_t in_buf[32];
683 char out_buf[11];
684 const char *printable = "printable";
685 const char *res;
686 void *ctx = talloc_named_const(NULL, 0, __func__);
687
688 printf("\nTesting string quoting: osmo_quote_cstr_buf()\n");
689 printf("- all chars from 0 to 255 in batches of 16:\n");
690 in_buf[16] = '\0';
691 for (j = 0; j < 16; j++) {
692 for (i = 0; i < 16; i++)
693 in_buf[i] = (j << 4) | i;
694 printf("%s\n", osmo_quote_cstr_c(ctx, (const char*)in_buf, 16));
695 }
696
697 printf("- nul terminated:\n");
698 printf("'%s'\n", osmo_quote_cstr_c(ctx, "termi\nated", -1));
699
700 printf("- never passthru:\n");
701 res = osmo_quote_cstr_c(ctx, printable, -1);
702 if (strcmp(res, printable))
703 printf("NOT passed through. '%s'\n", res);
704 else
705 printf("passed through unchanged '%s'\n", res);
706
707 printf("- zero length:\n");
708 printf("'%s'\n", osmo_quote_cstr_c(ctx, "omitted", 0));
709
710 printf("- truncation when too long:\n");
711 memset(in_buf, 'x', sizeof(in_buf));
712 in_buf[0] = '\a';
713 in_buf[6] = 'E';
714 memset(out_buf, 0x7f, sizeof(out_buf));
715 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
716 printf("'%s'\n", out_buf);
717 OSMO_ASSERT(out_buf[10] == 0x7f);
718
719 printf("- always truncation, even when no escaping needed:\n");
720 memset(in_buf, 'x', sizeof(in_buf));
721 in_buf[7] = 'E'; /* dst has 10, less 1 quote and nul, leaves 8, i.e. in[7] is last */
722 in_buf[20] = '\0';
723 memset(out_buf, 0x7f, sizeof(out_buf));
724 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, -1);
725 printf("'%s'\n", out_buf);
726 OSMO_ASSERT(out_buf[0] == '"');
727 OSMO_ASSERT(out_buf[10] == 0x7f);
728
729 printf("- try to feed too little buf for quoting:\n");
730 osmo_quote_cstr_buf(out_buf, 2, "", -1);
731 printf("'%s'\n", out_buf);
732
733 printf("- Test quoting a quoted+escaped string:\n");
734 res = "\x02\x03\n";
735 for (i = 0; i <= 3; i++) {
736 res = osmo_quote_cstr_c(ctx, res, -1);
737 printf("%d: %s\n", i, res);
738 }
739
740 printf("- Test C-string equivalence:\n");
741#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"
742#define EMPTY_STR ""
743 printf("strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)) == %d\n",
744 strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)));
745 printf("strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)) == %d\n",
746 strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)));
747 printf("strcmp(\"NULL\", osmo_quote_cstr_c(ctx, NULL, -1)) == %d\n",
748 strcmp("NULL", osmo_quote_cstr_c(ctx, NULL, -1)));
749
750 talloc_free(ctx);
751}
752
Harald Welte15a5f8d2018-06-06 16:58:17 +0200753static void isqrt_test(void)
754{
755 int i;
756
757 printf("\nTesting integer square-root\n");
758 srand(time(NULL));
759 for (i = 0; i < 1024; i++) {
760 uint16_t x;
761 uint32_t r = rand();
762 if (RAND_MAX < UINT16_MAX)
763 x = r * (UINT16_MAX/RAND_MAX);
764 else
765 x = r;
Neels Hofmeyr6979c542018-07-19 22:05:21 +0200766 uint32_t sq = (uint32_t)x*x;
Harald Welte15a5f8d2018-06-06 16:58:17 +0200767 uint32_t y = osmo_isqrt32(sq);
768 if (y != x)
769 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
770 }
771}
772
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200773
774struct osmo_sockaddr_to_str_and_uint_test_case {
775 uint16_t port;
776 bool omit_port;
777 const char *addr;
778 unsigned int addr_len;
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200779 int address_family; /* AF_INET / AF_INET6 */
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200780 bool omit_addr;
781 unsigned int expect_rc;
782 const char *expect_returned_addr;
783};
784
785struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
786 {
787 .port = 0,
788 .addr = "0.0.0.0",
789 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200790 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200791 .expect_rc = 7,
792 },
793 {
794 .port = 65535,
795 .addr = "255.255.255.255",
796 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200797 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200798 .expect_rc = 15,
799 },
800 {
801 .port = 1234,
802 .addr = "234.23.42.123",
803 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200804 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200805 .expect_rc = 13,
806 },
807 {
808 .port = 1234,
809 .addr = "234.23.42.123",
810 .addr_len = 10,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200811 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200812 .expect_rc = 13,
813 .expect_returned_addr = "234.23.42",
814 },
815 {
816 .port = 1234,
817 .omit_port = true,
818 .addr = "234.23.42.123",
819 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200820 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200821 .expect_rc = 13,
822 },
823 {
824 .port = 1234,
825 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200826 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200827 .omit_addr = true,
828 .expect_rc = 0,
829 .expect_returned_addr = "",
830 },
831 {
832 .port = 1234,
833 .addr = "234.23.42.123",
834 .addr_len = 0,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200835 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200836 .expect_rc = 13,
837 .expect_returned_addr = "",
838 },
839 {
840 .port = 1234,
841 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200842 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200843 .omit_port = true,
844 .omit_addr = true,
845 .expect_rc = 0,
846 .expect_returned_addr = "",
847 },
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200848 {
849 .port = 1234,
850 .addr = "::",
851 .addr_len = 20,
852 .address_family = AF_INET6,
853 .expect_rc = 2,
854 },
855 {
856 .port = 1234,
857 .addr = "::1",
858 .addr_len = 20,
859 .address_family = AF_INET6,
860 .expect_rc = 3,
861 },
862 {
863 .port = 1234,
864 .addr = "::1",
865 .addr_len = 20,
866 .address_family = AF_INET6,
867 .omit_port = true,
868 .omit_addr = false,
869 .expect_rc = 3,
870 },
871 {
872 .port = 1234,
873 .addr = "::1",
874 .addr_len = 20,
875 .address_family = AF_INET6,
876 .omit_port = false,
877 .omit_addr = true,
878 .expect_rc = 0,
879 .expect_returned_addr = "",
880 },
881 {
882 .port = 1234,
883 .addr = "fd02:db8:1::1",
884 .addr_len = 20,
885 .address_family = AF_INET6,
886 .expect_rc = 13,
887 },
888 {
889 .port = 1234,
890 .addr = "2001:db8:1::ab9:C0A8:102",
891 .addr_len = 40,
892 .address_family = AF_INET6,
893 .expect_rc = 24,
894 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
895 },
896 {
897 .port = 1234,
898 .addr = "2001:0db8:0001:0000:0000:0ab9:C0A8:0102",
899 .addr_len = 32,
900 .address_family = AF_INET6,
901 .expect_rc = 24,
902 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
903 },
904 {
905 .port = 1234,
906 .addr = "::ffff:192.168.20.34",
907 .addr_len = 32,
908 .address_family = AF_INET6,
909 .expect_rc = 20,
910 .expect_returned_addr = "::ffff:192.168.20.34",
911 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200912};
913
914static void osmo_sockaddr_to_str_and_uint_test(void)
915{
916 int i;
917 printf("\n%s\n", __func__);
918
919 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
920 struct osmo_sockaddr_to_str_and_uint_test_case *t =
921 &osmo_sockaddr_to_str_and_uint_test_data[i];
922
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200923 struct sockaddr_storage sa;
924 struct sockaddr_in *sin;
925 struct sockaddr_in6 *sin6;
926 sa.ss_family = t->address_family;
927 switch (t->address_family) {
928 case AF_INET:
929 sin = (struct sockaddr_in *)&sa;
930 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin->sin_addr) == 1);
931 sin->sin_port = htons(t->port);
932 break;
933 case AF_INET6:
934 sin6 = (struct sockaddr_in6 *)&sa;
935 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin6->sin6_addr) == 1);
936 sin6->sin6_port = htons(t->port);
937 break;
938 default:
939 OSMO_ASSERT(0);
940 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200941
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200942 char addr[INET6_ADDRSTRLEN] = {};
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200943 uint16_t port = 0;
944 unsigned int rc;
945
946 rc = osmo_sockaddr_to_str_and_uint(
947 t->omit_addr? NULL : addr, t->addr_len,
948 t->omit_port? NULL : &port,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200949 (const struct sockaddr *)&sa);
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200950
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200951 printf("[%d] [%s]:%u%s%s addr_len=%u --> [%s]:%u rc=%u\n",
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200952 i,
953 t->addr ? : "-",
954 t->port,
955 t->omit_addr ? " (omit addr)" : "",
956 t->omit_port ? " (omit port)" : "",
957 t->addr_len,
958 addr, port, rc);
959 if (rc != t->expect_rc)
960 printf("ERROR: Expected rc = %u\n", t->expect_rc);
961 if (!t->expect_returned_addr)
962 t->expect_returned_addr = t->addr;
963 if (strcmp(t->expect_returned_addr, addr))
964 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
965 if (!t->omit_port && port != t->port)
966 printf("ERROR: Expected port = %u\n", t->port);
967 }
968}
969
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200970struct osmo_str_tolowupper_test_data {
971 const char *in;
972 bool use_static_buf;
973 size_t buflen;
974 const char *expect_lower;
975 const char *expect_upper;
976 size_t expect_rc;
977 size_t expect_rc_inplace;
978};
979
980struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
981 {
982 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
983 .use_static_buf = true,
984 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
985 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
986 },
987 {
988 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
989 .buflen = 99,
990 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
991 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
992 .expect_rc = 62,
993 .expect_rc_inplace = 62,
994 },
995 {
996 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
997 .buflen = 0,
998 .expect_lower = "Unset",
999 .expect_upper = "Unset",
1000 .expect_rc = 62,
1001 .expect_rc_inplace = 0,
1002 },
1003 {
1004 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1005 .buflen = 1,
1006 .expect_lower = "",
1007 .expect_upper = "",
1008 .expect_rc = 62,
1009 .expect_rc_inplace = 0,
1010 },
1011 {
1012 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1013 .buflen = 2,
1014 .expect_lower = "a",
1015 .expect_upper = "A",
1016 .expect_rc = 62,
1017 .expect_rc_inplace = 1,
1018 },
1019 {
1020 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1021 .buflen = 28,
1022 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
1023 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
1024 .expect_rc = 62,
1025 .expect_rc_inplace = 27,
1026 },
1027};
1028
1029
1030static void osmo_str_tolowupper_test()
1031{
1032 int i;
1033 char buf[128];
1034 bool ok = true;
1035 printf("\n%s\n", __func__);
1036
1037 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
1038 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
1039 size_t rc = 0;
1040 const char *res;
1041
1042 /* tolower */
1043 if (d->use_static_buf) {
1044 res = osmo_str_tolower(d->in);
1045 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
1046 printf(" = %s\n", osmo_quote_str(res, -1));
1047 } else {
1048 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1049 osmo_strlcpy(buf, "Unset", sizeof(buf));
1050 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
1051 res = buf;
1052 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1053 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1054 }
1055
1056 if (strcmp(res, d->expect_lower)) {
1057 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1058 " got %s\n", i, osmo_quote_str(res, -1));
1059 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1060 ok = false;
1061 }
1062
1063 if (!d->use_static_buf && d->expect_rc != rc) {
1064 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1065 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1066 ok = false;
1067 }
1068
1069 /* tolower, in-place */
1070 if (!d->use_static_buf) {
1071 osmo_strlcpy(buf,
1072 d->buflen ? d->in : "Unset",
1073 sizeof(buf));
1074 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
1075 res = buf;
1076 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
1077 d->buflen, osmo_quote_str(d->in, -1));
1078 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1079
1080 if (strcmp(res, d->expect_lower)) {
1081 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1082 " got %s\n", i, osmo_quote_str(res, -1));
1083 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1084 ok = false;
1085 }
1086
1087 if (d->expect_rc_inplace != rc) {
1088 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1089 " got rc=%zu, expected rc=%zu\n",
1090 i, rc, d->expect_rc_inplace);
1091 ok = false;
1092 }
1093 }
1094
1095 /* toupper */
1096 if (d->use_static_buf) {
1097 res = osmo_str_toupper(d->in);
1098 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
1099 printf(" = %s\n", osmo_quote_str(res, -1));
1100 } else {
1101 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1102 osmo_strlcpy(buf, "Unset", sizeof(buf));
1103 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
1104 res = buf;
1105 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1106 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1107 }
1108
1109 if (strcmp(res, d->expect_upper)) {
1110 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1111 " got %s\n", i, osmo_quote_str(res, -1));
1112 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1113 ok = false;
1114 }
1115
1116 if (!d->use_static_buf && d->expect_rc != rc) {
1117 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1118 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1119 ok = false;
1120 }
1121
1122 /* toupper, in-place */
1123 if (!d->use_static_buf) {
1124 osmo_strlcpy(buf,
1125 d->buflen ? d->in : "Unset",
1126 sizeof(buf));
1127 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
1128 res = buf;
1129 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
1130 d->buflen, osmo_quote_str(d->in, -1));
1131 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1132
1133 if (strcmp(res, d->expect_upper)) {
1134 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1135 " got %s\n", i, osmo_quote_str(res, -1));
1136 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1137 ok = false;
1138 }
1139
1140 if (d->expect_rc_inplace != rc) {
1141 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1142 " got rc=%zu, expected rc=%zu\n",
1143 i, rc, d->expect_rc_inplace);
1144 ok = false;
1145 }
1146 }
1147 }
1148
1149 OSMO_ASSERT(ok);
1150}
1151
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001152/* Copy of the examples from OSMO_STRBUF_APPEND() */
1153int print_spaces(char *dst, size_t dst_len, int argument)
1154{
1155 int i;
1156 if (argument < 0)
1157 return -EINVAL;
1158 for (i = 0; i < argument && i < dst_len; i++)
1159 dst[i] = ' ';
1160 if (dst_len)
1161 dst[OSMO_MIN(dst_len - 1, argument)] = '\0';
1162 return argument;
1163}
1164
1165void strbuf_example(char *buf, size_t buflen)
1166{
1167 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1168
1169 OSMO_STRBUF_APPEND(sb, print_spaces, 5);
1170 OSMO_STRBUF_APPEND(sb, snprintf, "The answer is %d but what is the question?", 42);
1171 OSMO_STRBUF_APPEND(sb, print_spaces, 423423);
1172
1173 printf("%s\n", buf);
1174 printf("would have needed %zu bytes\n", sb.chars_needed);
1175}
1176
1177/* Copy of the examples from OSMO_STRBUF_PRINTF() */
1178int strbuf_example2(char *buf, size_t buflen)
1179{
1180 int i;
1181 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1182
1183 OSMO_STRBUF_PRINTF(sb, "T minus");
1184 for (i = 10; i; i--)
1185 OSMO_STRBUF_PRINTF(sb, " %d", i);
1186 OSMO_STRBUF_PRINTF(sb, " ... Lift off!");
1187
1188 return sb.chars_needed;
1189}
1190
1191int strbuf_cascade(char *buf, size_t buflen)
1192{
1193 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1194
1195 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1196 OSMO_STRBUF_PRINTF(sb, " -- ");
1197 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1198 OSMO_STRBUF_PRINTF(sb, " -- ");
1199 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1200
1201 return sb.chars_needed;
1202}
1203
1204void strbuf_test()
1205{
1206 char buf[256];
1207 int rc;
1208 printf("\n%s\n", __func__);
1209
1210 printf("OSMO_STRBUF_APPEND():\n");
1211 strbuf_example(buf, 23);
1212
1213 printf("\nOSMO_STRBUF_PRINTF():\n");
1214 rc = strbuf_example2(buf, 23);
1215 printf("1: (need %d chars, had size=23) %s\n", rc, buf);
1216
1217 rc = strbuf_example2(buf, rc);
1218 printf("2: (need %d chars, had size=%d) %s\n", rc, rc, buf);
1219
1220 rc = strbuf_example2(buf, rc + 1);
1221 printf("3: (need %d chars, had size=%d+1) %s\n", rc, rc, buf);
1222
1223 rc = strbuf_example2(buf, 0);
1224 snprintf(buf, sizeof(buf), "0x2b 0x2b 0x2b...");
1225 printf("4: (need %d chars, had size=0) %s\n", rc, buf);
1226
1227 rc = strbuf_example2(NULL, 99);
1228 printf("5: (need %d chars, had NULL buffer)\n", rc);
1229
1230 printf("\ncascade:\n");
1231 rc = strbuf_cascade(buf, sizeof(buf));
1232 printf("(need %d chars)\n%s\n", rc, buf);
1233 rc = strbuf_cascade(buf, 63);
1234 printf("(need %d chars, had size=63) %s\n", rc, buf);
1235}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001236
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001237void strbuf_test_nolen()
1238{
1239 char buf[20];
1240 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1241 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1242 printf("\n%s\n", __func__);
1243
1244 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1245 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1246 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1247 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1248
1249 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1250 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1251 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1252}
1253
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001254static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1255{
1256 bool rc = osmo_str_startswith(str, startswith_str);
1257 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1258 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1259 if (rc != expect_rc)
1260 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1261}
1262
1263static void startswith_test()
1264{
1265 printf("\n%s()\n", __func__);
1266 startswith_test_str(NULL, NULL, true);
1267 startswith_test_str("", NULL, true);
1268 startswith_test_str(NULL, "", true);
1269 startswith_test_str("", "", true);
1270 startswith_test_str("abc", NULL, true);
1271 startswith_test_str("abc", "", true);
1272 startswith_test_str(NULL, "abc", false);
1273 startswith_test_str("", "abc", false);
1274 startswith_test_str("abc", "a", true);
1275 startswith_test_str("abc", "ab", true);
1276 startswith_test_str("abc", "abc", true);
1277 startswith_test_str("abc", "abcd", false);
1278 startswith_test_str("abc", "xyz", false);
1279}
1280
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001281static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1282{
1283 if (!arg)
1284 return -EINVAL;
1285 return snprintf(buf, buflen, "%s", arg);
1286}
1287
1288static char *foo_name_c(void *ctx, const char *arg)
1289{
1290 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1291}
1292
1293static char *foo_name_c_null(void *ctx, const char *arg)
1294{
1295 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1296}
1297
1298static char *foo_name_c_zero(void *ctx, const char *arg)
1299{
1300 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1301}
1302
1303static char *foo_name_c_zero_null(void *ctx, const char *arg)
1304{
1305 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1306}
1307
1308static void name_c_impl_test()
1309{
1310 char *test_strs[] = {
1311 "test",
1312 "longer than 10 chars",
1313 NULL,
1314 };
1315 struct {
1316 const char *label;
1317 char *(*func)(void *, const char*);
1318 } funcs[] = {
1319 {
1320 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1321 foo_name_c,
1322 },
1323 {
1324 "OSMO_NAME_C_IMPL(10, NULL)",
1325 foo_name_c_null,
1326 },
1327 {
1328 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1329 foo_name_c_zero,
1330 },
1331 {
1332 "OSMO_NAME_C_IMPL(0, NULL)",
1333 foo_name_c_zero_null,
1334 },
1335 };
1336
1337 int i;
1338 void *ctx = talloc_named_const(NULL, 0, __func__);
1339 int allocs = talloc_total_blocks(ctx);
1340
1341 printf("\n%s\n", __func__);
1342 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1343 char *test_str = test_strs[i];
1344 int j;
1345 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1346
1347 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1348 char *str = funcs[j].func(ctx, test_str);
1349 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1350 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1351 if (str) {
1352 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1353 talloc_free(str);
1354 }
1355 printf("\n");
1356 }
1357 }
1358 talloc_free(ctx);
1359}
1360
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001361static void osmo_print_n_test(void)
1362{
1363 struct token_test {
1364 const char *src;
1365 size_t token_len;
1366 size_t buf_size;
1367 const char *expect_token;
1368 int expect_rc;
1369 };
1370 struct token_test tests[] = {
1371 { "foo=bar", 3, 100, "foo", 3 },
1372 { "foo", 10, 100, "foo", 3 },
1373 { "foo", 3, 100, "foo", 3 },
1374 { NULL, 10, 100, "", 0 },
1375 { "", 10, 100, "", 0 },
1376 { "foo=bar", 0, 100, "", 0 },
1377
1378 { "foo=bar", 3, 2, "f", 3 },
1379 { "foo", 10, 2, "f", 3 },
1380 { "foo", 3, 2, "f", 3 },
1381 { NULL, 10, 2, "", 0 },
1382 { "", 10, 2, "", 0 },
1383 { "foo=bar", 0, 2, "", 0 },
1384
1385 { "foo=bar", 3, 1, "", 3 },
1386 { "foo", 10, 1, "", 3 },
1387 { "foo", 3, 1, "", 3 },
1388 { NULL, 10, 1, "", 0 },
1389 { "", 10, 1, "", 0 },
1390 { "foo=bar", 0, 1, "", 0 },
1391
1392 { "foo=bar", 3, 0, "unchanged", 3 },
1393 { "foo", 10, 0, "unchanged", 3 },
1394 { "foo", 3, 0, "unchanged", 3 },
1395 { NULL, 10, 0, "unchanged", 0 },
1396 { "", 10, 0, "unchanged", 0 },
1397 { "foo=bar", 0, 0, "unchanged", 0 },
1398 };
1399 struct token_test *t;
1400 printf("\n%s()\n", __func__);
1401 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1402 char buf[100] = "unchanged";
1403 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1404 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1405 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1406 if (strcmp(buf, t->expect_token))
1407 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1408 if (rc != t->expect_rc)
1409 printf(" ERROR: expected rc %d", t->expect_rc);
1410 printf("\n");
1411 }
1412}
1413
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001414static void osmo_strnchr_test(void)
1415{
1416 struct test {
1417 const char *haystack;
1418 size_t haystack_len;
1419 const char *needle;
1420 int expect_offset;
1421 };
1422 struct test tests[] = {
1423 { "foo=bar", 8, "=", 3 },
1424 { "foo=bar", 4, "=", 3 },
1425 { "foo=bar", 3, "=", -1 },
1426 { "foo=bar", 0, "=", -1 },
1427 { "foo\0=bar", 9, "=", -1 },
1428 { "foo\0=bar", 9, "\0", 3 },
1429 };
1430 struct test *t;
1431 printf("\n%s()\n", __func__);
1432 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1433 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1434 int offset = -1;
1435 if (r)
1436 offset = r - t->haystack;
1437 printf("osmo_strnchr(%s, %zu, ",
1438 osmo_quote_str(t->haystack, -1), t->haystack_len);
1439 printf("'%s') -> %d",
1440 osmo_escape_str(t->needle, 1), offset);
1441 if (offset != t->expect_offset)
1442 printf(" ERROR expected %d", t->expect_offset);
1443 printf("\n");
1444 }
1445}
1446
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001447struct float_str_to_int_test {
1448 unsigned int precision;
1449 const char *str;
1450 int64_t expect_val;
1451 int expect_err;
1452};
1453struct float_str_to_int_test float_str_to_int_tests[] = {
1454 { 0, "0", 0 },
1455 { 0, "1", 1 },
1456 { 0, "12.345", 12 },
1457 { 0, "+12.345", 12 },
1458 { 0, "-12.345", -12 },
1459 { 0, "0.345", 0 },
1460 { 0, ".345", 0 },
1461 { 0, "-0.345", 0 },
1462 { 0, "-.345", 0 },
1463 { 0, "12.", 12 },
1464 { 0, "-180", -180 },
1465 { 0, "180", 180 },
1466 { 0, "360", 360 },
1467 { 0, "123.4567890123", 123 },
1468 { 0, "123.4567890123456789012345", 123 },
1469 { 0, "9223372036854775807", 9223372036854775807LL },
1470 { 0, "-9223372036854775807", -9223372036854775807LL },
1471 { 0, "-9223372036854775808", .expect_err = -ERANGE },
1472 { 0, "9223372036854775808", .expect_err = -ERANGE },
1473 { 0, "-9223372036854775809", .expect_err = -ERANGE },
1474 { 0, "100000000000000000000", .expect_err = -ERANGE },
1475 { 0, "-100000000000000000000", .expect_err = -ERANGE },
1476 { 0, "999999999999999999999999999.99", .expect_err = -ERANGE },
1477 { 0, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1478 { 0, "1.2.3", .expect_err = -EINVAL },
1479 { 0, "foo", .expect_err = -EINVAL },
1480 { 0, "1.foo", .expect_err = -EINVAL },
1481 { 0, "1.foo", .expect_err = -EINVAL },
1482 { 0, "12.-345", .expect_err = -EINVAL },
1483 { 0, "-12.-345", .expect_err = -EINVAL },
1484 { 0, "12.+345", .expect_err = -EINVAL },
1485 { 0, "+12.+345", .expect_err = -EINVAL },
1486 { 0, "", .expect_err = -EINVAL },
1487 { 0, NULL, .expect_err = -EINVAL },
1488
1489 { 1, "0", 0 },
1490 { 1, "1", 10 },
1491 { 1, "12.345", 123 },
1492 { 1, "+12.345", 123 },
1493 { 1, "-12.345", -123 },
1494 { 1, "0.345", 3 },
1495 { 1, ".345", 3 },
1496 { 1, "-0.345", -3 },
1497 { 1, "-.345", -3 },
1498 { 1, "12.", 120 },
1499 { 1, "-180", -1800 },
1500 { 1, "180", 1800 },
1501 { 1, "360", 3600 },
1502 { 1, "123.4567890123", 1234 },
1503 { 1, "123.4567890123456789012345", 1234 },
1504 { 1, "922337203685477580.7", 9223372036854775807LL },
1505 { 1, "-922337203685477580.7", -9223372036854775807LL },
1506 { 1, "-922337203685477580.8", .expect_err = -ERANGE },
1507 { 1, "922337203685477580.8", .expect_err = -ERANGE },
1508 { 1, "-922337203685477580.9", .expect_err = -ERANGE },
1509 { 1, "100000000000000000000", .expect_err = -ERANGE },
1510 { 1, "-100000000000000000000", .expect_err = -ERANGE },
1511 { 1, "999999999999999999999999999.99", .expect_err = -ERANGE },
1512 { 1, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1513 { 1, "1.2.3", .expect_err = -EINVAL },
1514 { 1, "foo", .expect_err = -EINVAL },
1515 { 1, "1.foo", .expect_err = -EINVAL },
1516 { 1, "1.foo", .expect_err = -EINVAL },
1517 { 1, "12.-345", .expect_err = -EINVAL },
1518 { 1, "-12.-345", .expect_err = -EINVAL },
1519 { 1, "12.+345", .expect_err = -EINVAL },
1520 { 1, "+12.+345", .expect_err = -EINVAL },
1521 { 1, "", .expect_err = -EINVAL },
1522 { 1, NULL, .expect_err = -EINVAL },
1523
1524 { 6, "0", 0 },
1525 { 6, "1", 1000000 },
1526 { 6, "12.345", 12345000 },
1527 { 6, "+12.345", 12345000 },
1528 { 6, "-12.345", -12345000 },
1529 { 6, "0.345", 345000 },
1530 { 6, ".345", 345000 },
1531 { 6, "-0.345", -345000 },
1532 { 6, "-.345", -345000 },
1533 { 6, "12.", 12000000 },
1534 { 6, "-180", -180000000 },
1535 { 6, "180", 180000000 },
1536 { 6, "360", 360000000 },
1537 { 6, "123.4567890123", 123456789 },
1538 { 6, "123.4567890123456789012345", 123456789 },
1539 { 6, "9223372036854.775807", 9223372036854775807LL },
1540 { 6, "-9223372036854.775807", -9223372036854775807LL },
1541 { 6, "-9223372036854.775808", .expect_err = -ERANGE },
1542 { 6, "9223372036854.775808", .expect_err = -ERANGE },
1543 { 6, "-9223372036854.775809", .expect_err = -ERANGE },
1544 { 6, "100000000000000000000", .expect_err = -ERANGE },
1545 { 6, "-100000000000000000000", .expect_err = -ERANGE },
1546 { 6, "999999999999999999999999999.99", .expect_err = -ERANGE },
1547 { 6, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1548 { 6, "1.2.3", .expect_err = -EINVAL },
1549 { 6, "foo", .expect_err = -EINVAL },
1550 { 6, "1.foo", .expect_err = -EINVAL },
1551 { 6, "1.foo", .expect_err = -EINVAL },
1552 { 6, "12.-345", .expect_err = -EINVAL },
1553 { 6, "-12.-345", .expect_err = -EINVAL },
1554 { 6, "12.+345", .expect_err = -EINVAL },
1555 { 6, "+12.+345", .expect_err = -EINVAL },
1556 { 6, "", .expect_err = -EINVAL },
1557 { 6, NULL, .expect_err = -EINVAL },
1558
1559 { 18, "0", 0 },
1560 { 18, "1", 1000000000000000000LL },
1561 { 18, "1.2345", 1234500000000000000LL },
1562 { 18, "+1.2345", 1234500000000000000LL },
1563 { 18, "-1.2345", -1234500000000000000LL },
1564 { 18, "0.345", 345000000000000000LL },
1565 { 18, ".345", 345000000000000000LL },
1566 { 18, "-0.345", -345000000000000000LL },
1567 { 18, "-.345", -345000000000000000LL },
1568 { 18, "2.", 2000000000000000000LL },
1569 { 18, "-8", -8000000000000000000LL },
1570 { 18, "1.234567890123", 1234567890123000000LL },
1571 { 18, "1.234567890123456789012345", 1234567890123456789LL },
1572 { 18, "123.4567890123", .expect_err = -ERANGE },
1573 { 18, "9.223372036854775807", 9223372036854775807LL },
1574 { 18, "-9.223372036854775807", -9223372036854775807LL },
1575 { 18, "-9.223372036854775808", .expect_err = -ERANGE },
1576 { 18, "9.223372036854775808", .expect_err = -ERANGE },
1577 { 18, "-9.223372036854775809", .expect_err = -ERANGE },
1578 { 18, "100000000000000000000", .expect_err = -ERANGE },
1579 { 18, "-100000000000000000000", .expect_err = -ERANGE },
1580 { 18, "999999999999999999999999999.99", .expect_err = -ERANGE },
1581 { 18, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1582 { 18, "1.2.3", .expect_err = -EINVAL },
1583 { 18, "foo", .expect_err = -EINVAL },
1584 { 18, "1.foo", .expect_err = -EINVAL },
1585 { 18, "1.foo", .expect_err = -EINVAL },
1586 { 18, "12.-345", .expect_err = -EINVAL },
1587 { 18, "-12.-345", .expect_err = -EINVAL },
1588 { 18, "12.+345", .expect_err = -EINVAL },
1589 { 18, "+12.+345", .expect_err = -EINVAL },
1590 { 18, "", .expect_err = -EINVAL },
1591 { 18, NULL, .expect_err = -EINVAL },
1592
1593 { 19, "0", 0 },
1594 { 19, ".1", 1000000000000000000LL },
1595 { 19, ".12345", 1234500000000000000LL },
1596 { 19, "+.12345", 1234500000000000000LL },
1597 { 19, "-.12345", -1234500000000000000LL },
1598 { 19, "0.0345", 345000000000000000LL },
1599 { 19, ".0345", 345000000000000000LL },
1600 { 19, "-0.0345", -345000000000000000LL },
1601 { 19, "-.0345", -345000000000000000LL },
1602 { 19, ".2", 2000000000000000000LL },
1603 { 19, "-.8", -8000000000000000000LL },
1604 { 19, ".1234567890123", 1234567890123000000LL },
1605 { 19, ".1234567890123456789012345", 1234567890123456789LL },
1606 { 19, "123.4567890123", .expect_err = -ERANGE },
1607 { 19, ".9223372036854775807", 9223372036854775807LL },
1608 { 19, "-.9223372036854775807", -9223372036854775807LL },
1609 { 19, "-.9223372036854775808", .expect_err = -ERANGE },
1610 { 19, ".9223372036854775808", .expect_err = -ERANGE },
1611 { 19, "-.9223372036854775809", .expect_err = -ERANGE },
1612 { 19, "100000000000000000000", .expect_err = -ERANGE },
1613 { 19, "-100000000000000000000", .expect_err = -ERANGE },
1614 { 19, "999999999999999999999999999.99", .expect_err = -ERANGE },
1615 { 19, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1616 { 19, "1.2.3", .expect_err = -EINVAL },
1617 { 19, "foo", .expect_err = -EINVAL },
1618 { 19, "1.foo", .expect_err = -EINVAL },
1619 { 19, "1.foo", .expect_err = -EINVAL },
1620 { 19, "12.-345", .expect_err = -EINVAL },
1621 { 19, "-12.-345", .expect_err = -EINVAL },
1622 { 19, "12.+345", .expect_err = -EINVAL },
1623 { 19, "+12.+345", .expect_err = -EINVAL },
1624 { 19, "", .expect_err = -EINVAL },
1625 { 19, NULL, .expect_err = -EINVAL },
1626
1627 { 20, "0", 0 },
1628 { 20, ".01", 1000000000000000000LL },
1629 { 20, ".012345", 1234500000000000000LL },
1630 { 20, "+.012345", 1234500000000000000LL },
1631 { 20, "-.012345", -1234500000000000000LL },
1632 { 20, "0.00345", 345000000000000000LL },
1633 { 20, ".00345", 345000000000000000LL },
1634 { 20, "-0.00345", -345000000000000000LL },
1635 { 20, "-.00345", -345000000000000000LL },
1636 { 20, ".02", 2000000000000000000LL },
1637 { 20, "-.08", -8000000000000000000LL },
1638 { 20, ".01234567890123", 1234567890123000000LL },
1639 { 20, ".01234567890123456789012345", 1234567890123456789LL },
1640 { 20, "12.34567890123", .expect_err = -ERANGE },
1641 { 20, ".09223372036854775807", 9223372036854775807LL },
1642 { 20, "-.09223372036854775807", -9223372036854775807LL },
1643 { 20, "-.09223372036854775808", .expect_err = -ERANGE },
1644 { 20, ".09223372036854775808", .expect_err = -ERANGE },
1645 { 20, "-.09223372036854775809", .expect_err = -ERANGE },
1646 { 20, ".1", .expect_err = -ERANGE },
1647 { 20, "-.1", .expect_err = -ERANGE },
1648 { 20, "999999999999999999999999999.99", .expect_err = -ERANGE },
1649 { 20, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1650 { 20, "1.2.3", .expect_err = -EINVAL },
1651 { 20, "foo", .expect_err = -EINVAL },
1652 { 20, "1.foo", .expect_err = -EINVAL },
1653 { 20, "1.foo", .expect_err = -EINVAL },
1654 { 20, "12.-345", .expect_err = -EINVAL },
1655 { 20, "-12.-345", .expect_err = -EINVAL },
1656 { 20, "12.+345", .expect_err = -EINVAL },
1657 { 20, "+12.+345", .expect_err = -EINVAL },
1658 { 20, "", .expect_err = -EINVAL },
1659 { 20, NULL, .expect_err = -EINVAL },
1660
1661 { 25, "0", 0 },
1662 { 25, ".0000001", 1000000000000000000LL },
1663 { 25, ".00000012345", 1234500000000000000LL },
1664 { 25, "+.00000012345", 1234500000000000000LL },
1665 { 25, "-.00000012345", -1234500000000000000LL },
1666 { 25, "0.0000000345", 345000000000000000LL },
1667 { 25, ".0000000345", 345000000000000000LL },
1668 { 25, "-0.0000000345", -345000000000000000LL },
1669 { 25, "-.0000000345", -345000000000000000LL },
1670 { 25, ".0000002", 2000000000000000000LL },
1671 { 25, "-.0000008", -8000000000000000000LL },
1672 { 25, ".0000001234567890123", 1234567890123000000LL },
1673 { 25, ".0000001234567890123456789012345", 1234567890123456789LL },
1674 { 25, ".0001234567890123", .expect_err = -ERANGE },
1675 { 25, ".0000009223372036854775807", 9223372036854775807LL },
1676 { 25, "-.0000009223372036854775807", -9223372036854775807LL },
1677 { 25, "-.0000009223372036854775808", .expect_err = -ERANGE },
1678 { 25, ".0000009223372036854775808", .expect_err = -ERANGE },
1679 { 25, "-.0000009223372036854775809", .expect_err = -ERANGE },
1680 { 25, ".000001", .expect_err = -ERANGE },
1681 { 25, "-.000001", .expect_err = -ERANGE },
1682 { 25, "999999999999999999999999999.99", .expect_err = -ERANGE },
1683 { 25, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1684 { 25, "1.2.3", .expect_err = -EINVAL },
1685 { 25, "foo", .expect_err = -EINVAL },
1686 { 25, "1.foo", .expect_err = -EINVAL },
1687 { 25, "1.foo", .expect_err = -EINVAL },
1688 { 25, "12.-345", .expect_err = -EINVAL },
1689 { 25, "-12.-345", .expect_err = -EINVAL },
1690 { 25, "12.+345", .expect_err = -EINVAL },
1691 { 25, "+12.+345", .expect_err = -EINVAL },
1692 { 25, "", .expect_err = -EINVAL },
1693 { 25, NULL, .expect_err = -EINVAL },
1694};
1695const char *errno_str(int rc)
1696{
Neels Hofmeyr47773342021-09-05 18:48:31 +02001697 switch (rc) {
1698 case -EINVAL:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001699 return "=-EINVAL";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001700 case -ERANGE:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001701 return "=-ERANGE";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001702 case -E2BIG:
1703 return "=-E2BIG";
1704 case -EOVERFLOW:
1705 return "=-EOVERFLOW";
1706 default:
1707 return "";
1708 }
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001709}
1710void test_float_str_to_int()
1711{
1712 const struct float_str_to_int_test *t;
1713 printf("--- %s\n", __func__);
1714 for (t = float_str_to_int_tests; (t - float_str_to_int_tests) < ARRAY_SIZE(float_str_to_int_tests); t++) {
1715 int rc;
1716 int64_t val;
1717 rc = osmo_float_str_to_int(&val, t->str, t->precision);
1718 printf("osmo_float_str_to_int(%s, %u) -> rc=%d%s val=%" PRId64 "\n",
1719 osmo_quote_str(t->str, -1), t->precision, rc, errno_str(rc), val);
1720
1721 if (rc != t->expect_err)
1722 printf(" ERROR: expected rc=%d%s\n", t->expect_err, errno_str(t->expect_err));
1723 if (val != t->expect_val)
1724 printf(" ERROR: expected val=%" PRId64 "\n", t->expect_val);
1725 if (rc != t->expect_err||val != t->expect_val)
1726 exit(0);
1727 }
1728}
1729
1730struct int_to_float_str_test {
1731 unsigned int precision;
1732 int64_t val;
1733 const char *expect_str;
1734};
1735struct int_to_float_str_test int_to_float_str_tests[] = {
1736 { 0, 0, "0" },
1737 { 0, 1, "1" },
1738 { 0, 1000000, "1000000" },
1739 { 0, -1000000, "-1000000" },
1740 { 0, 1000001, "1000001" },
1741 { 0, -1000001, "-1000001" },
1742 { 0, 1000100, "1000100" },
1743 { 0, -1010000, "-1010000" },
1744 { 0, 1100000, "1100000" },
1745 { 0, 10000000, "10000000" },
1746 { 0, -10000000, "-10000000" },
1747 { 0, 100000000, "100000000" },
1748 { 0, -100000000, "-100000000" },
1749 { 0, 9223372036854775807, "9223372036854775807" },
1750 { 0, -9223372036854775807, "-9223372036854775807" },
1751 { 0, INT64_MIN, "-ERR" },
1752
1753 { 1, 0, "0" },
1754 { 1, 1, "0.1" },
1755 { 1, 1000000, "100000" },
1756 { 1, -1000000, "-100000" },
1757 { 1, 1000001, "100000.1" },
1758 { 1, -1000001, "-100000.1" },
1759 { 1, 1000100, "100010" },
1760 { 1, -1010000, "-101000" },
1761 { 1, 1100000, "110000" },
1762 { 1, 10000000, "1000000" },
1763 { 1, -10000000, "-1000000" },
1764 { 1, 100000000, "10000000" },
1765 { 1, -100000000, "-10000000" },
1766 { 1, 9223372036854775807, "922337203685477580.7" },
1767 { 1, -9223372036854775807, "-922337203685477580.7" },
1768 { 1, INT64_MIN, "-ERR" },
1769
1770 { 3, 0, "0" },
1771 { 3, 1, "0.001" },
1772 { 3, 1000000, "1000" },
1773 { 3, -1000000, "-1000" },
1774 { 3, 1000001, "1000.001" },
1775 { 3, -1000001, "-1000.001" },
1776 { 3, 1000100, "1000.1" },
1777 { 3, -1010000, "-1010" },
1778 { 3, 1100000, "1100" },
1779 { 3, 10000000, "10000" },
1780 { 3, -10000000, "-10000" },
1781 { 3, 100000000, "100000" },
1782 { 3, -100000000, "-100000" },
1783 { 3, 9223372036854775807, "9223372036854775.807" },
1784 { 3, -9223372036854775807, "-9223372036854775.807" },
1785 { 3, INT64_MIN, "-ERR" },
1786
1787 { 6, 0, "0" },
1788 { 6, 1, "0.000001" },
1789 { 6, 1000000, "1" },
1790 { 6, -1000000, "-1" },
1791 { 6, 1000001, "1.000001" },
1792 { 6, -1000001, "-1.000001" },
1793 { 6, 1000100, "1.0001" },
1794 { 6, -1010000, "-1.01" },
1795 { 6, 1100000, "1.1" },
1796 { 6, 10000000, "10" },
1797 { 6, -10000000, "-10" },
1798 { 6, 100000000, "100" },
1799 { 6, -100000000, "-100" },
1800 { 6, 9223372036854775807, "9223372036854.775807" },
1801 { 6, -9223372036854775807, "-9223372036854.775807" },
1802 { 6, INT64_MIN, "-ERR" },
1803
1804 { 17, 0, "0" },
1805 { 17, 1, "0.00000000000000001" },
1806 { 17, 1000000, "0.00000000001" },
1807 { 17, -1000000, "-0.00000000001" },
1808 { 17, 1000001, "0.00000000001000001" },
1809 { 17, -1000001, "-0.00000000001000001" },
1810 { 17, 1000100, "0.000000000010001" },
1811 { 17, -1010000, "-0.0000000000101" },
1812 { 17, 1100000, "0.000000000011" },
1813 { 17, 10000000, "0.0000000001" },
1814 { 17, -10000000, "-0.0000000001" },
1815 { 17, 100000000, "0.000000001" },
1816 { 17, -100000000, "-0.000000001" },
1817 { 17, 9223372036854775807, "92.23372036854775807" },
1818 { 17, -9223372036854775807, "-92.23372036854775807" },
1819 { 17, INT64_MIN, "-ERR" },
1820
1821 { 18, 0, "0" },
1822 { 18, 1, "0.000000000000000001" },
1823 { 18, 1000000, "0.000000000001" },
1824 { 18, -1000000, "-0.000000000001" },
1825 { 18, 1000001, "0.000000000001000001" },
1826 { 18, -1000001, "-0.000000000001000001" },
1827 { 18, 1000100, "0.0000000000010001" },
1828 { 18, -1010000, "-0.00000000000101" },
1829 { 18, 1100000, "0.0000000000011" },
1830 { 18, 10000000, "0.00000000001" },
1831 { 18, -10000000, "-0.00000000001" },
1832 { 18, 100000000, "0.0000000001" },
1833 { 18, -100000000, "-0.0000000001" },
1834 { 18, 9223372036854775807, "9.223372036854775807" },
1835 { 18, -9223372036854775807, "-9.223372036854775807" },
1836 { 18, INT64_MIN, "-ERR" },
1837
1838 { 19, 0, "0" },
1839 { 19, 1, "0.0000000000000000001" },
1840 { 19, 1000000, "0.0000000000001" },
1841 { 19, -1000000, "-0.0000000000001" },
1842 { 19, 1000001, "0.0000000000001000001" },
1843 { 19, -1000001, "-0.0000000000001000001" },
1844 { 19, 1000100, "0.00000000000010001" },
1845 { 19, -1010000, "-0.000000000000101" },
1846 { 19, 1100000, "0.00000000000011" },
1847 { 19, 10000000, "0.000000000001" },
1848 { 19, -10000000, "-0.000000000001" },
1849 { 19, 100000000, "0.00000000001" },
1850 { 19, -100000000, "-0.00000000001" },
1851 { 19, 9223372036854775807, "0.9223372036854775807" },
1852 { 19, -9223372036854775807, "-0.9223372036854775807" },
1853 { 19, INT64_MIN, "-ERR" },
1854
1855 { 23, 0, "0" },
1856 { 23, 1, "0.00000000000000000000001" },
1857 { 23, 1000000, "0.00000000000000001" },
1858 { 23, -1000000, "-0.00000000000000001" },
1859 { 23, 1000001, "0.00000000000000001000001" },
1860 { 23, -1000001, "-0.00000000000000001000001" },
1861 { 23, 1000100, "0.000000000000000010001" },
1862 { 23, -1010000, "-0.0000000000000000101" },
1863 { 23, 1100000, "0.000000000000000011" },
1864 { 23, 10000000, "0.0000000000000001" },
1865 { 23, -10000000, "-0.0000000000000001" },
1866 { 23, 100000000, "0.000000000000001" },
1867 { 23, -100000000, "-0.000000000000001" },
1868 { 23, 9223372036854775807, "0.00009223372036854775807" },
1869 { 23, -9223372036854775807, "-0.00009223372036854775807" },
1870 { 23, INT64_MIN, "-ERR" },
1871};
1872void test_int_to_float_str()
1873{
1874 const struct int_to_float_str_test *t;
1875 printf("--- %s\n", __func__);
1876 for (t = int_to_float_str_tests;
1877 (t - int_to_float_str_tests) < ARRAY_SIZE(int_to_float_str_tests);
1878 t++) {
1879 char buf[128];
1880 int rc;
1881 rc = osmo_int_to_float_str_buf(buf, sizeof(buf), t->val, t->precision);
1882 printf("osmo_int_to_float_str_buf(%" PRId64 ", %u) -> rc=%d str=%s\n", t->val, t->precision, rc,
1883 osmo_quote_str(buf, -1));
1884
1885 if (rc != strlen(buf))
1886 printf(" ERROR: expected rc=%zu\n", strlen(buf));
1887 if (strcmp(buf, t->expect_str))
1888 printf(" ERROR: expected str=%s\n", osmo_quote_str(t->expect_str, -1));
1889 if (rc != strlen(buf) || strcmp(buf, t->expect_str))
1890 exit(0);
1891 }
1892}
1893
Neels Hofmeyr47773342021-09-05 18:48:31 +02001894struct str_to_int_test {
1895 const char *str;
1896 int base;
1897 int min_val;
1898 int max_val;
1899 int expect_rc;
1900 int expect_val;
1901};
1902/* Avoid using INT_MAX and INT_MIN because that would produce different test output on different architectures */
1903struct str_to_int_test str_to_int_tests[] = {
1904 { NULL, 10, -1000, 1000, -EINVAL, 0 },
1905 { "", 10, -1000, 1000, -EINVAL, 0 },
1906 { " ", 10, -1000, 1000, -EINVAL, 0 },
1907 { "-", 10, -1000, 1000, -EINVAL, 0 },
1908 { "--", 10, -1000, 1000, -EINVAL, 0 },
1909 { "+", 10, -1000, 1000, -EINVAL, 0 },
1910 { "++", 10, -1000, 1000, -EINVAL, 0 },
1911
1912 { "0", 10, -1000, 1000, 0, 0 },
1913 { "1", 10, -1000, 1000, 0, 1 },
1914 { "+1", 10, -1000, 1000, 0, 1 },
1915 { "-1", 10, -1000, 1000, 0, -1 },
1916 { "1000", 10, -1000, 1000, 0, 1000 },
1917 { "+1000", 10, -1000, 1000, 0, 1000 },
1918 { "-1000", 10, -1000, 1000, 0, -1000 },
1919 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
1920 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
1921 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
1922
1923 { "0", 16, -1000, 1000, 0, 0 },
1924 { "1", 16, -1000, 1000, 0, 1 },
1925 { "0x1", 16, -1000, 1000, 0, 1 },
1926 { "+1", 16, -1000, 1000, 0, 1 },
1927 { "-1", 16, -1000, 1000, 0, -1 },
1928 { "+0x1", 16, -1000, 1000, 0, 1 },
1929 { "-0x1", 16, -1000, 1000, 0, -1 },
1930 { "3e8", 16, -1000, 1000, 0, 1000 },
1931 { "3E8", 16, -1000, 1000, 0, 1000 },
1932 { "0x3e8", 16, -1000, 1000, 0, 1000 },
1933 { "0x3E8", 16, -1000, 1000, 0, 1000 },
1934 { "+3e8", 16, -1000, 1000, 0, 1000 },
1935 { "+3E8", 16, -1000, 1000, 0, 1000 },
1936 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
1937 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
1938 { "-3e8", 16, -1000, 1000, 0, -1000 },
1939 { "-3E8", 16, -1000, 1000, 0, -1000 },
1940 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
1941 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
1942 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
1943 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
1944 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
1945 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
1946 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
1947 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
1948 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
1949 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
1950 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
1951 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
1952 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
1953 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
1954
1955 { "garble", 10, -1000, 1000, -EINVAL, 0 },
1956 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
1957 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
1958 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
1959 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
1960 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
1961 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
1962};
1963void test_str_to_int()
1964{
1965 const struct str_to_int_test *t;
1966 printf("--- %s\n", __func__);
1967 for (t = str_to_int_tests; (t - str_to_int_tests) < ARRAY_SIZE(str_to_int_tests); t++) {
1968 int rc;
1969 int val;
1970 rc = osmo_str_to_int(&val, t->str, t->base, t->min_val, t->max_val);
1971 printf("osmo_str_to_int(%s, %d, %d, %d) -> rc=%d%s val=%d\n",
1972 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
1973
1974 if (rc != t->expect_rc)
1975 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
1976 if (val != t->expect_val)
1977 printf(" ERROR: expected val=%d\n", t->expect_val);
1978 }
1979}
1980
1981struct str_to_int64_test {
1982 const char *str;
1983 int base;
1984 int64_t min_val;
1985 int64_t max_val;
1986 int expect_rc;
1987 int64_t expect_val;
1988};
1989struct str_to_int64_test str_to_int64_tests[] = {
1990 { NULL, 10, -1000, 1000, -EINVAL, 0 },
1991 { "", 10, -1000, 1000, -EINVAL, 0 },
1992 { " ", 10, -1000, 1000, -EINVAL, 0 },
1993 { "-", 10, -1000, 1000, -EINVAL, 0 },
1994 { "--", 10, -1000, 1000, -EINVAL, 0 },
1995 { "+", 10, -1000, 1000, -EINVAL, 0 },
1996 { "++", 10, -1000, 1000, -EINVAL, 0 },
1997
1998 { "0", 10, -1000, 1000, 0, 0 },
1999 { "1", 10, -1000, 1000, 0, 1 },
2000 { "+1", 10, -1000, 1000, 0, 1 },
2001 { "-1", 10, -1000, 1000, 0, -1 },
2002 { "1000", 10, -1000, 1000, 0, 1000 },
2003 { "+1000", 10, -1000, 1000, 0, 1000 },
2004 { "-1000", 10, -1000, 1000, 0, -1000 },
2005 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
2006 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
2007 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
2008
2009 { "0", 16, -1000, 1000, 0, 0 },
2010 { "1", 16, -1000, 1000, 0, 1 },
2011 { "0x1", 16, -1000, 1000, 0, 1 },
2012 { "+1", 16, -1000, 1000, 0, 1 },
2013 { "-1", 16, -1000, 1000, 0, -1 },
2014 { "+0x1", 16, -1000, 1000, 0, 1 },
2015 { "-0x1", 16, -1000, 1000, 0, -1 },
2016 { "3e8", 16, -1000, 1000, 0, 1000 },
2017 { "3E8", 16, -1000, 1000, 0, 1000 },
2018 { "0x3e8", 16, -1000, 1000, 0, 1000 },
2019 { "0x3E8", 16, -1000, 1000, 0, 1000 },
2020 { "+3e8", 16, -1000, 1000, 0, 1000 },
2021 { "+3E8", 16, -1000, 1000, 0, 1000 },
2022 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
2023 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
2024 { "-3e8", 16, -1000, 1000, 0, -1000 },
2025 { "-3E8", 16, -1000, 1000, 0, -1000 },
2026 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
2027 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
2028 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
2029 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
2030 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2031 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2032 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2033 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2034 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2035 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2036 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2037 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2038 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2039 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2040
2041 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2042 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2043 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2044 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2045 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2046 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2047 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2048
2049 { "-9223372036854775808", 10, INT64_MIN, INT64_MAX, 0, INT64_MIN },
2050 { "9223372036854775807", 10, INT64_MIN, INT64_MAX, 0, INT64_MAX },
2051
2052 { "-9223372036854775809", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MIN },
2053 { "9223372036854775808", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MAX },
2054
2055 { "-9223372036854775808", 10, -1000, 1000, -ERANGE, INT64_MIN },
2056 { "9223372036854775807", 10, -1000, 1000, -ERANGE, INT64_MAX },
2057 { "-9223372036854775809", 10, -1000, 1000, -EOVERFLOW, INT64_MIN },
2058 { "9223372036854775808", 10, -1000, 1000, -EOVERFLOW, INT64_MAX },
2059};
2060void test_str_to_int64()
2061{
2062 const struct str_to_int64_test *t;
2063 printf("--- %s\n", __func__);
2064 for (t = str_to_int64_tests; (t - str_to_int64_tests) < ARRAY_SIZE(str_to_int64_tests); t++) {
2065 int rc;
2066 int64_t val;
2067 rc = osmo_str_to_int64(&val, t->str, t->base, t->min_val, t->max_val);
2068 printf("osmo_str_to_int64(%s, %d, %"PRId64", %"PRId64") -> rc=%d%s val=%"PRId64"\n",
2069 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2070
2071 if (rc != t->expect_rc)
2072 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2073 if (val != t->expect_val)
2074 printf(" ERROR: expected val=%"PRId64"\n", t->expect_val);
2075 }
2076}
2077
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002078int main(int argc, char **argv)
2079{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02002080 static const struct log_info log_info = {};
2081 log_init(&log_info, NULL);
2082
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002083 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01002084 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02002085 test_ipa_ccm_id_get_parsing();
2086 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02002087 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02002088 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01002089 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01002090 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02002091 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01002092 str_escape3_test();
2093 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02002094 isqrt_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02002095 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02002096 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01002097 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02002098 strbuf_test_nolen();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01002099 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01002100 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01002101 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01002102 osmo_strnchr_test();
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00002103 test_float_str_to_int();
2104 test_int_to_float_str();
Neels Hofmeyr47773342021-09-05 18:48:31 +02002105 test_str_to_int();
2106 test_str_to_int64();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002107 return 0;
2108}