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