blob: 0b7bfe446c3fedaa0d5ddfd30067740e1abf0250 [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
Philipp Maier94705d02023-01-11 10:55:47 +0100769static void mod_test_mod(int x, int y, int expected_result)
770{
771 int result;
772 result = x % y;
773 printf(" %d mod %d = %d = %d\n", x, y, result, expected_result);
774 OSMO_ASSERT(result == expected_result);
775}
776
777static void mod_test_mod_flr(int x, int y, int expected_result)
778{
779 int result;
780 result = OSMO_MOD_FLR(x, y);
781 printf(" %d mod_flr %d = %d = %d\n", x, y, result, expected_result);
782 OSMO_ASSERT(result == expected_result);
783}
784
785static void mod_test_mod_euc(int x, int y, int expected_result)
786{
787 int result;
788 result = OSMO_MOD_EUC(x, y);
789 printf(" %d mod_euc %d = %d = %d\n", x, y, result, expected_result);
790 OSMO_ASSERT(result == expected_result);
791}
792
793static void mod_test(void)
794{
795 /* See also: Daan Leijen, Division and Modulus for Computer
796 * Scientists, section 1.3 */
797
798 printf("\nTesting built in truncated modulo for comparison:\n");
799 mod_test_mod(8, 3, 2);
800 mod_test_mod(8, -3, 2);
801 mod_test_mod(-8, 3, -2);
802 mod_test_mod(-8, -3, -2);
803 mod_test_mod(1, 2, 1);
804 mod_test_mod(1, -2, 1);
805 mod_test_mod(-1, 2, -1);
806 mod_test_mod(-1, -2, -1);
807
808 printf("\nTesting OSMO_MOD_FLR():\n");
809 mod_test_mod_flr(8, 3, 2);
810 mod_test_mod_flr(8, -3, -1);
811 mod_test_mod_flr(-8, 3, 1);
812 mod_test_mod_flr(-8, -3, -2);
813 mod_test_mod_flr(1, 2, 1);
814 mod_test_mod_flr(1, -2, -1);
815 mod_test_mod_flr(-1, 2, 1);
816 mod_test_mod_flr(-1, -2, -1);
817
818 printf("\nTesting OSMO_MOD_EUC():\n");
819 mod_test_mod_euc(8, 3, 2);
820 mod_test_mod_euc(8, -3, 2);
821 mod_test_mod_euc(-8, 3, 1);
822 mod_test_mod_euc(-8, -3, 1);
823 mod_test_mod_euc(1, 2, 1);
824 mod_test_mod_euc(1, -2, 1);
825 mod_test_mod_euc(-1, 2, 1);
826 mod_test_mod_euc(-1, -2, 1);
827}
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200828
829struct osmo_sockaddr_to_str_and_uint_test_case {
830 uint16_t port;
831 bool omit_port;
832 const char *addr;
833 unsigned int addr_len;
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200834 int address_family; /* AF_INET / AF_INET6 */
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200835 bool omit_addr;
836 unsigned int expect_rc;
837 const char *expect_returned_addr;
838};
839
840struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
841 {
842 .port = 0,
843 .addr = "0.0.0.0",
844 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200845 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200846 .expect_rc = 7,
847 },
848 {
849 .port = 65535,
850 .addr = "255.255.255.255",
851 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200852 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200853 .expect_rc = 15,
854 },
855 {
856 .port = 1234,
857 .addr = "234.23.42.123",
858 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200859 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200860 .expect_rc = 13,
861 },
862 {
863 .port = 1234,
864 .addr = "234.23.42.123",
865 .addr_len = 10,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200866 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200867 .expect_rc = 13,
868 .expect_returned_addr = "234.23.42",
869 },
870 {
871 .port = 1234,
872 .omit_port = true,
873 .addr = "234.23.42.123",
874 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200875 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200876 .expect_rc = 13,
877 },
878 {
879 .port = 1234,
880 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200881 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200882 .omit_addr = true,
883 .expect_rc = 0,
884 .expect_returned_addr = "",
885 },
886 {
887 .port = 1234,
888 .addr = "234.23.42.123",
889 .addr_len = 0,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200890 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200891 .expect_rc = 13,
892 .expect_returned_addr = "",
893 },
894 {
895 .port = 1234,
896 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200897 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200898 .omit_port = true,
899 .omit_addr = true,
900 .expect_rc = 0,
901 .expect_returned_addr = "",
902 },
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200903 {
904 .port = 1234,
905 .addr = "::",
906 .addr_len = 20,
907 .address_family = AF_INET6,
908 .expect_rc = 2,
909 },
910 {
911 .port = 1234,
912 .addr = "::1",
913 .addr_len = 20,
914 .address_family = AF_INET6,
915 .expect_rc = 3,
916 },
917 {
918 .port = 1234,
919 .addr = "::1",
920 .addr_len = 20,
921 .address_family = AF_INET6,
922 .omit_port = true,
923 .omit_addr = false,
924 .expect_rc = 3,
925 },
926 {
927 .port = 1234,
928 .addr = "::1",
929 .addr_len = 20,
930 .address_family = AF_INET6,
931 .omit_port = false,
932 .omit_addr = true,
933 .expect_rc = 0,
934 .expect_returned_addr = "",
935 },
936 {
937 .port = 1234,
938 .addr = "fd02:db8:1::1",
939 .addr_len = 20,
940 .address_family = AF_INET6,
941 .expect_rc = 13,
942 },
943 {
944 .port = 1234,
945 .addr = "2001:db8:1::ab9:C0A8:102",
946 .addr_len = 40,
947 .address_family = AF_INET6,
948 .expect_rc = 24,
949 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
950 },
951 {
952 .port = 1234,
953 .addr = "2001:0db8:0001:0000:0000:0ab9:C0A8:0102",
954 .addr_len = 32,
955 .address_family = AF_INET6,
956 .expect_rc = 24,
957 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
958 },
959 {
960 .port = 1234,
961 .addr = "::ffff:192.168.20.34",
962 .addr_len = 32,
963 .address_family = AF_INET6,
964 .expect_rc = 20,
965 .expect_returned_addr = "::ffff:192.168.20.34",
966 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200967};
968
969static void osmo_sockaddr_to_str_and_uint_test(void)
970{
971 int i;
972 printf("\n%s\n", __func__);
973
974 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
975 struct osmo_sockaddr_to_str_and_uint_test_case *t =
976 &osmo_sockaddr_to_str_and_uint_test_data[i];
977
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200978 struct sockaddr_storage sa;
979 struct sockaddr_in *sin;
980 struct sockaddr_in6 *sin6;
981 sa.ss_family = t->address_family;
982 switch (t->address_family) {
983 case AF_INET:
984 sin = (struct sockaddr_in *)&sa;
985 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin->sin_addr) == 1);
986 sin->sin_port = htons(t->port);
987 break;
988 case AF_INET6:
989 sin6 = (struct sockaddr_in6 *)&sa;
990 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin6->sin6_addr) == 1);
991 sin6->sin6_port = htons(t->port);
992 break;
993 default:
994 OSMO_ASSERT(0);
995 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200996
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200997 char addr[INET6_ADDRSTRLEN] = {};
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200998 uint16_t port = 0;
999 unsigned int rc;
1000
1001 rc = osmo_sockaddr_to_str_and_uint(
1002 t->omit_addr? NULL : addr, t->addr_len,
1003 t->omit_port? NULL : &port,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +02001004 (const struct sockaddr *)&sa);
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001005
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +02001006 printf("[%d] [%s]:%u%s%s addr_len=%u --> [%s]:%u rc=%u\n",
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001007 i,
1008 t->addr ? : "-",
1009 t->port,
1010 t->omit_addr ? " (omit addr)" : "",
1011 t->omit_port ? " (omit port)" : "",
1012 t->addr_len,
1013 addr, port, rc);
1014 if (rc != t->expect_rc)
1015 printf("ERROR: Expected rc = %u\n", t->expect_rc);
1016 if (!t->expect_returned_addr)
1017 t->expect_returned_addr = t->addr;
1018 if (strcmp(t->expect_returned_addr, addr))
1019 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
1020 if (!t->omit_port && port != t->port)
1021 printf("ERROR: Expected port = %u\n", t->port);
1022 }
1023}
1024
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001025struct osmo_str_tolowupper_test_data {
1026 const char *in;
1027 bool use_static_buf;
1028 size_t buflen;
1029 const char *expect_lower;
1030 const char *expect_upper;
1031 size_t expect_rc;
1032 size_t expect_rc_inplace;
1033};
1034
1035struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
1036 {
1037 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1038 .use_static_buf = true,
1039 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
1040 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1041 },
1042 {
1043 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1044 .buflen = 99,
1045 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
1046 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1047 .expect_rc = 62,
1048 .expect_rc_inplace = 62,
1049 },
1050 {
1051 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1052 .buflen = 0,
1053 .expect_lower = "Unset",
1054 .expect_upper = "Unset",
1055 .expect_rc = 62,
1056 .expect_rc_inplace = 0,
1057 },
1058 {
1059 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1060 .buflen = 1,
1061 .expect_lower = "",
1062 .expect_upper = "",
1063 .expect_rc = 62,
1064 .expect_rc_inplace = 0,
1065 },
1066 {
1067 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1068 .buflen = 2,
1069 .expect_lower = "a",
1070 .expect_upper = "A",
1071 .expect_rc = 62,
1072 .expect_rc_inplace = 1,
1073 },
1074 {
1075 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1076 .buflen = 28,
1077 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
1078 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
1079 .expect_rc = 62,
1080 .expect_rc_inplace = 27,
1081 },
1082};
1083
1084
Harald Weltee61d4592022-11-03 11:05:58 +01001085static void osmo_str_tolowupper_test(void)
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001086{
1087 int i;
1088 char buf[128];
1089 bool ok = true;
1090 printf("\n%s\n", __func__);
1091
1092 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
1093 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
1094 size_t rc = 0;
1095 const char *res;
1096
1097 /* tolower */
1098 if (d->use_static_buf) {
1099 res = osmo_str_tolower(d->in);
1100 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
1101 printf(" = %s\n", osmo_quote_str(res, -1));
1102 } else {
1103 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1104 osmo_strlcpy(buf, "Unset", sizeof(buf));
1105 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
1106 res = buf;
1107 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1108 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1109 }
1110
1111 if (strcmp(res, d->expect_lower)) {
1112 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1113 " got %s\n", i, osmo_quote_str(res, -1));
1114 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1115 ok = false;
1116 }
1117
1118 if (!d->use_static_buf && d->expect_rc != rc) {
1119 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1120 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1121 ok = false;
1122 }
1123
1124 /* tolower, in-place */
1125 if (!d->use_static_buf) {
1126 osmo_strlcpy(buf,
1127 d->buflen ? d->in : "Unset",
1128 sizeof(buf));
1129 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
1130 res = buf;
1131 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
1132 d->buflen, osmo_quote_str(d->in, -1));
1133 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1134
1135 if (strcmp(res, d->expect_lower)) {
1136 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1137 " got %s\n", i, osmo_quote_str(res, -1));
1138 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1139 ok = false;
1140 }
1141
1142 if (d->expect_rc_inplace != rc) {
1143 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1144 " got rc=%zu, expected rc=%zu\n",
1145 i, rc, d->expect_rc_inplace);
1146 ok = false;
1147 }
1148 }
1149
1150 /* toupper */
1151 if (d->use_static_buf) {
1152 res = osmo_str_toupper(d->in);
1153 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
1154 printf(" = %s\n", osmo_quote_str(res, -1));
1155 } else {
1156 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1157 osmo_strlcpy(buf, "Unset", sizeof(buf));
1158 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
1159 res = buf;
1160 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1161 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1162 }
1163
1164 if (strcmp(res, d->expect_upper)) {
1165 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1166 " got %s\n", i, osmo_quote_str(res, -1));
1167 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1168 ok = false;
1169 }
1170
1171 if (!d->use_static_buf && d->expect_rc != rc) {
1172 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1173 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1174 ok = false;
1175 }
1176
1177 /* toupper, in-place */
1178 if (!d->use_static_buf) {
1179 osmo_strlcpy(buf,
1180 d->buflen ? d->in : "Unset",
1181 sizeof(buf));
1182 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
1183 res = buf;
1184 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
1185 d->buflen, osmo_quote_str(d->in, -1));
1186 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1187
1188 if (strcmp(res, d->expect_upper)) {
1189 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1190 " got %s\n", i, osmo_quote_str(res, -1));
1191 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1192 ok = false;
1193 }
1194
1195 if (d->expect_rc_inplace != rc) {
1196 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1197 " got rc=%zu, expected rc=%zu\n",
1198 i, rc, d->expect_rc_inplace);
1199 ok = false;
1200 }
1201 }
1202 }
1203
1204 OSMO_ASSERT(ok);
1205}
1206
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001207/* Copy of the examples from OSMO_STRBUF_APPEND() */
1208int print_spaces(char *dst, size_t dst_len, int argument)
1209{
1210 int i;
1211 if (argument < 0)
1212 return -EINVAL;
1213 for (i = 0; i < argument && i < dst_len; i++)
1214 dst[i] = ' ';
1215 if (dst_len)
1216 dst[OSMO_MIN(dst_len - 1, argument)] = '\0';
1217 return argument;
1218}
1219
1220void strbuf_example(char *buf, size_t buflen)
1221{
1222 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1223
1224 OSMO_STRBUF_APPEND(sb, print_spaces, 5);
1225 OSMO_STRBUF_APPEND(sb, snprintf, "The answer is %d but what is the question?", 42);
1226 OSMO_STRBUF_APPEND(sb, print_spaces, 423423);
1227
1228 printf("%s\n", buf);
1229 printf("would have needed %zu bytes\n", sb.chars_needed);
1230}
1231
1232/* Copy of the examples from OSMO_STRBUF_PRINTF() */
1233int strbuf_example2(char *buf, size_t buflen)
1234{
1235 int i;
1236 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1237
1238 OSMO_STRBUF_PRINTF(sb, "T minus");
1239 for (i = 10; i; i--)
1240 OSMO_STRBUF_PRINTF(sb, " %d", i);
1241 OSMO_STRBUF_PRINTF(sb, " ... Lift off!");
1242
1243 return sb.chars_needed;
1244}
1245
1246int strbuf_cascade(char *buf, size_t buflen)
1247{
1248 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1249
1250 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1251 OSMO_STRBUF_PRINTF(sb, " -- ");
1252 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1253 OSMO_STRBUF_PRINTF(sb, " -- ");
1254 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1255
1256 return sb.chars_needed;
1257}
1258
Harald Weltee61d4592022-11-03 11:05:58 +01001259void strbuf_test(void)
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001260{
1261 char buf[256];
1262 int rc;
1263 printf("\n%s\n", __func__);
1264
1265 printf("OSMO_STRBUF_APPEND():\n");
1266 strbuf_example(buf, 23);
1267
1268 printf("\nOSMO_STRBUF_PRINTF():\n");
1269 rc = strbuf_example2(buf, 23);
1270 printf("1: (need %d chars, had size=23) %s\n", rc, buf);
1271
1272 rc = strbuf_example2(buf, rc);
1273 printf("2: (need %d chars, had size=%d) %s\n", rc, rc, buf);
1274
1275 rc = strbuf_example2(buf, rc + 1);
1276 printf("3: (need %d chars, had size=%d+1) %s\n", rc, rc, buf);
1277
1278 rc = strbuf_example2(buf, 0);
1279 snprintf(buf, sizeof(buf), "0x2b 0x2b 0x2b...");
1280 printf("4: (need %d chars, had size=0) %s\n", rc, buf);
1281
1282 rc = strbuf_example2(NULL, 99);
1283 printf("5: (need %d chars, had NULL buffer)\n", rc);
1284
1285 printf("\ncascade:\n");
1286 rc = strbuf_cascade(buf, sizeof(buf));
1287 printf("(need %d chars)\n%s\n", rc, buf);
1288 rc = strbuf_cascade(buf, 63);
1289 printf("(need %d chars, had size=63) %s\n", rc, buf);
1290}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001291
Harald Weltee61d4592022-11-03 11:05:58 +01001292void strbuf_test_nolen(void)
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001293{
1294 char buf[20];
1295 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1296 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1297 printf("\n%s\n", __func__);
1298
1299 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1300 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1301 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1302 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1303
1304 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1305 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1306 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1307}
1308
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001309static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1310{
1311 bool rc = osmo_str_startswith(str, startswith_str);
1312 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1313 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1314 if (rc != expect_rc)
1315 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1316}
1317
Harald Weltee61d4592022-11-03 11:05:58 +01001318static void startswith_test(void)
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001319{
1320 printf("\n%s()\n", __func__);
1321 startswith_test_str(NULL, NULL, true);
1322 startswith_test_str("", NULL, true);
1323 startswith_test_str(NULL, "", true);
1324 startswith_test_str("", "", true);
1325 startswith_test_str("abc", NULL, true);
1326 startswith_test_str("abc", "", true);
1327 startswith_test_str(NULL, "abc", false);
1328 startswith_test_str("", "abc", false);
1329 startswith_test_str("abc", "a", true);
1330 startswith_test_str("abc", "ab", true);
1331 startswith_test_str("abc", "abc", true);
1332 startswith_test_str("abc", "abcd", false);
1333 startswith_test_str("abc", "xyz", false);
1334}
1335
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001336static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1337{
1338 if (!arg)
1339 return -EINVAL;
1340 return snprintf(buf, buflen, "%s", arg);
1341}
1342
1343static char *foo_name_c(void *ctx, const char *arg)
1344{
1345 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1346}
1347
1348static char *foo_name_c_null(void *ctx, const char *arg)
1349{
1350 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1351}
1352
1353static char *foo_name_c_zero(void *ctx, const char *arg)
1354{
1355 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1356}
1357
1358static char *foo_name_c_zero_null(void *ctx, const char *arg)
1359{
1360 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1361}
1362
Harald Weltee61d4592022-11-03 11:05:58 +01001363static void name_c_impl_test(void)
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001364{
1365 char *test_strs[] = {
1366 "test",
1367 "longer than 10 chars",
1368 NULL,
1369 };
1370 struct {
1371 const char *label;
1372 char *(*func)(void *, const char*);
1373 } funcs[] = {
1374 {
1375 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1376 foo_name_c,
1377 },
1378 {
1379 "OSMO_NAME_C_IMPL(10, NULL)",
1380 foo_name_c_null,
1381 },
1382 {
1383 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1384 foo_name_c_zero,
1385 },
1386 {
1387 "OSMO_NAME_C_IMPL(0, NULL)",
1388 foo_name_c_zero_null,
1389 },
1390 };
1391
1392 int i;
1393 void *ctx = talloc_named_const(NULL, 0, __func__);
1394 int allocs = talloc_total_blocks(ctx);
1395
1396 printf("\n%s\n", __func__);
1397 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1398 char *test_str = test_strs[i];
1399 int j;
1400 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1401
1402 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1403 char *str = funcs[j].func(ctx, test_str);
1404 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1405 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1406 if (str) {
1407 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1408 talloc_free(str);
1409 }
1410 printf("\n");
1411 }
1412 }
1413 talloc_free(ctx);
1414}
1415
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001416static void osmo_print_n_test(void)
1417{
1418 struct token_test {
1419 const char *src;
1420 size_t token_len;
1421 size_t buf_size;
1422 const char *expect_token;
1423 int expect_rc;
1424 };
1425 struct token_test tests[] = {
1426 { "foo=bar", 3, 100, "foo", 3 },
1427 { "foo", 10, 100, "foo", 3 },
1428 { "foo", 3, 100, "foo", 3 },
1429 { NULL, 10, 100, "", 0 },
1430 { "", 10, 100, "", 0 },
1431 { "foo=bar", 0, 100, "", 0 },
1432
1433 { "foo=bar", 3, 2, "f", 3 },
1434 { "foo", 10, 2, "f", 3 },
1435 { "foo", 3, 2, "f", 3 },
1436 { NULL, 10, 2, "", 0 },
1437 { "", 10, 2, "", 0 },
1438 { "foo=bar", 0, 2, "", 0 },
1439
1440 { "foo=bar", 3, 1, "", 3 },
1441 { "foo", 10, 1, "", 3 },
1442 { "foo", 3, 1, "", 3 },
1443 { NULL, 10, 1, "", 0 },
1444 { "", 10, 1, "", 0 },
1445 { "foo=bar", 0, 1, "", 0 },
1446
1447 { "foo=bar", 3, 0, "unchanged", 3 },
1448 { "foo", 10, 0, "unchanged", 3 },
1449 { "foo", 3, 0, "unchanged", 3 },
1450 { NULL, 10, 0, "unchanged", 0 },
1451 { "", 10, 0, "unchanged", 0 },
1452 { "foo=bar", 0, 0, "unchanged", 0 },
1453 };
1454 struct token_test *t;
1455 printf("\n%s()\n", __func__);
1456 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1457 char buf[100] = "unchanged";
1458 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1459 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1460 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1461 if (strcmp(buf, t->expect_token))
1462 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1463 if (rc != t->expect_rc)
1464 printf(" ERROR: expected rc %d", t->expect_rc);
1465 printf("\n");
1466 }
1467}
1468
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001469static void osmo_strnchr_test(void)
1470{
1471 struct test {
1472 const char *haystack;
1473 size_t haystack_len;
1474 const char *needle;
1475 int expect_offset;
1476 };
1477 struct test tests[] = {
1478 { "foo=bar", 8, "=", 3 },
1479 { "foo=bar", 4, "=", 3 },
1480 { "foo=bar", 3, "=", -1 },
1481 { "foo=bar", 0, "=", -1 },
1482 { "foo\0=bar", 9, "=", -1 },
1483 { "foo\0=bar", 9, "\0", 3 },
1484 };
1485 struct test *t;
1486 printf("\n%s()\n", __func__);
1487 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1488 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1489 int offset = -1;
1490 if (r)
1491 offset = r - t->haystack;
1492 printf("osmo_strnchr(%s, %zu, ",
1493 osmo_quote_str(t->haystack, -1), t->haystack_len);
1494 printf("'%s') -> %d",
1495 osmo_escape_str(t->needle, 1), offset);
1496 if (offset != t->expect_offset)
1497 printf(" ERROR expected %d", t->expect_offset);
1498 printf("\n");
1499 }
1500}
1501
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001502struct float_str_to_int_test {
1503 unsigned int precision;
1504 const char *str;
1505 int64_t expect_val;
1506 int expect_err;
1507};
1508struct float_str_to_int_test float_str_to_int_tests[] = {
1509 { 0, "0", 0 },
1510 { 0, "1", 1 },
1511 { 0, "12.345", 12 },
1512 { 0, "+12.345", 12 },
1513 { 0, "-12.345", -12 },
1514 { 0, "0.345", 0 },
1515 { 0, ".345", 0 },
1516 { 0, "-0.345", 0 },
1517 { 0, "-.345", 0 },
1518 { 0, "12.", 12 },
1519 { 0, "-180", -180 },
1520 { 0, "180", 180 },
1521 { 0, "360", 360 },
1522 { 0, "123.4567890123", 123 },
1523 { 0, "123.4567890123456789012345", 123 },
1524 { 0, "9223372036854775807", 9223372036854775807LL },
1525 { 0, "-9223372036854775807", -9223372036854775807LL },
1526 { 0, "-9223372036854775808", .expect_err = -ERANGE },
1527 { 0, "9223372036854775808", .expect_err = -ERANGE },
1528 { 0, "-9223372036854775809", .expect_err = -ERANGE },
1529 { 0, "100000000000000000000", .expect_err = -ERANGE },
1530 { 0, "-100000000000000000000", .expect_err = -ERANGE },
1531 { 0, "999999999999999999999999999.99", .expect_err = -ERANGE },
1532 { 0, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1533 { 0, "1.2.3", .expect_err = -EINVAL },
1534 { 0, "foo", .expect_err = -EINVAL },
1535 { 0, "1.foo", .expect_err = -EINVAL },
1536 { 0, "1.foo", .expect_err = -EINVAL },
1537 { 0, "12.-345", .expect_err = -EINVAL },
1538 { 0, "-12.-345", .expect_err = -EINVAL },
1539 { 0, "12.+345", .expect_err = -EINVAL },
1540 { 0, "+12.+345", .expect_err = -EINVAL },
1541 { 0, "", .expect_err = -EINVAL },
1542 { 0, NULL, .expect_err = -EINVAL },
1543
1544 { 1, "0", 0 },
1545 { 1, "1", 10 },
1546 { 1, "12.345", 123 },
1547 { 1, "+12.345", 123 },
1548 { 1, "-12.345", -123 },
1549 { 1, "0.345", 3 },
1550 { 1, ".345", 3 },
1551 { 1, "-0.345", -3 },
1552 { 1, "-.345", -3 },
1553 { 1, "12.", 120 },
1554 { 1, "-180", -1800 },
1555 { 1, "180", 1800 },
1556 { 1, "360", 3600 },
1557 { 1, "123.4567890123", 1234 },
1558 { 1, "123.4567890123456789012345", 1234 },
1559 { 1, "922337203685477580.7", 9223372036854775807LL },
1560 { 1, "-922337203685477580.7", -9223372036854775807LL },
1561 { 1, "-922337203685477580.8", .expect_err = -ERANGE },
1562 { 1, "922337203685477580.8", .expect_err = -ERANGE },
1563 { 1, "-922337203685477580.9", .expect_err = -ERANGE },
1564 { 1, "100000000000000000000", .expect_err = -ERANGE },
1565 { 1, "-100000000000000000000", .expect_err = -ERANGE },
1566 { 1, "999999999999999999999999999.99", .expect_err = -ERANGE },
1567 { 1, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1568 { 1, "1.2.3", .expect_err = -EINVAL },
1569 { 1, "foo", .expect_err = -EINVAL },
1570 { 1, "1.foo", .expect_err = -EINVAL },
1571 { 1, "1.foo", .expect_err = -EINVAL },
1572 { 1, "12.-345", .expect_err = -EINVAL },
1573 { 1, "-12.-345", .expect_err = -EINVAL },
1574 { 1, "12.+345", .expect_err = -EINVAL },
1575 { 1, "+12.+345", .expect_err = -EINVAL },
1576 { 1, "", .expect_err = -EINVAL },
1577 { 1, NULL, .expect_err = -EINVAL },
1578
1579 { 6, "0", 0 },
1580 { 6, "1", 1000000 },
1581 { 6, "12.345", 12345000 },
1582 { 6, "+12.345", 12345000 },
1583 { 6, "-12.345", -12345000 },
1584 { 6, "0.345", 345000 },
1585 { 6, ".345", 345000 },
1586 { 6, "-0.345", -345000 },
1587 { 6, "-.345", -345000 },
1588 { 6, "12.", 12000000 },
1589 { 6, "-180", -180000000 },
1590 { 6, "180", 180000000 },
1591 { 6, "360", 360000000 },
1592 { 6, "123.4567890123", 123456789 },
1593 { 6, "123.4567890123456789012345", 123456789 },
1594 { 6, "9223372036854.775807", 9223372036854775807LL },
1595 { 6, "-9223372036854.775807", -9223372036854775807LL },
1596 { 6, "-9223372036854.775808", .expect_err = -ERANGE },
1597 { 6, "9223372036854.775808", .expect_err = -ERANGE },
1598 { 6, "-9223372036854.775809", .expect_err = -ERANGE },
1599 { 6, "100000000000000000000", .expect_err = -ERANGE },
1600 { 6, "-100000000000000000000", .expect_err = -ERANGE },
1601 { 6, "999999999999999999999999999.99", .expect_err = -ERANGE },
1602 { 6, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1603 { 6, "1.2.3", .expect_err = -EINVAL },
1604 { 6, "foo", .expect_err = -EINVAL },
1605 { 6, "1.foo", .expect_err = -EINVAL },
1606 { 6, "1.foo", .expect_err = -EINVAL },
1607 { 6, "12.-345", .expect_err = -EINVAL },
1608 { 6, "-12.-345", .expect_err = -EINVAL },
1609 { 6, "12.+345", .expect_err = -EINVAL },
1610 { 6, "+12.+345", .expect_err = -EINVAL },
1611 { 6, "", .expect_err = -EINVAL },
1612 { 6, NULL, .expect_err = -EINVAL },
1613
1614 { 18, "0", 0 },
1615 { 18, "1", 1000000000000000000LL },
1616 { 18, "1.2345", 1234500000000000000LL },
1617 { 18, "+1.2345", 1234500000000000000LL },
1618 { 18, "-1.2345", -1234500000000000000LL },
1619 { 18, "0.345", 345000000000000000LL },
1620 { 18, ".345", 345000000000000000LL },
1621 { 18, "-0.345", -345000000000000000LL },
1622 { 18, "-.345", -345000000000000000LL },
1623 { 18, "2.", 2000000000000000000LL },
1624 { 18, "-8", -8000000000000000000LL },
1625 { 18, "1.234567890123", 1234567890123000000LL },
1626 { 18, "1.234567890123456789012345", 1234567890123456789LL },
1627 { 18, "123.4567890123", .expect_err = -ERANGE },
1628 { 18, "9.223372036854775807", 9223372036854775807LL },
1629 { 18, "-9.223372036854775807", -9223372036854775807LL },
1630 { 18, "-9.223372036854775808", .expect_err = -ERANGE },
1631 { 18, "9.223372036854775808", .expect_err = -ERANGE },
1632 { 18, "-9.223372036854775809", .expect_err = -ERANGE },
1633 { 18, "100000000000000000000", .expect_err = -ERANGE },
1634 { 18, "-100000000000000000000", .expect_err = -ERANGE },
1635 { 18, "999999999999999999999999999.99", .expect_err = -ERANGE },
1636 { 18, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1637 { 18, "1.2.3", .expect_err = -EINVAL },
1638 { 18, "foo", .expect_err = -EINVAL },
1639 { 18, "1.foo", .expect_err = -EINVAL },
1640 { 18, "1.foo", .expect_err = -EINVAL },
1641 { 18, "12.-345", .expect_err = -EINVAL },
1642 { 18, "-12.-345", .expect_err = -EINVAL },
1643 { 18, "12.+345", .expect_err = -EINVAL },
1644 { 18, "+12.+345", .expect_err = -EINVAL },
1645 { 18, "", .expect_err = -EINVAL },
1646 { 18, NULL, .expect_err = -EINVAL },
1647
1648 { 19, "0", 0 },
1649 { 19, ".1", 1000000000000000000LL },
1650 { 19, ".12345", 1234500000000000000LL },
1651 { 19, "+.12345", 1234500000000000000LL },
1652 { 19, "-.12345", -1234500000000000000LL },
1653 { 19, "0.0345", 345000000000000000LL },
1654 { 19, ".0345", 345000000000000000LL },
1655 { 19, "-0.0345", -345000000000000000LL },
1656 { 19, "-.0345", -345000000000000000LL },
1657 { 19, ".2", 2000000000000000000LL },
1658 { 19, "-.8", -8000000000000000000LL },
1659 { 19, ".1234567890123", 1234567890123000000LL },
1660 { 19, ".1234567890123456789012345", 1234567890123456789LL },
1661 { 19, "123.4567890123", .expect_err = -ERANGE },
1662 { 19, ".9223372036854775807", 9223372036854775807LL },
1663 { 19, "-.9223372036854775807", -9223372036854775807LL },
1664 { 19, "-.9223372036854775808", .expect_err = -ERANGE },
1665 { 19, ".9223372036854775808", .expect_err = -ERANGE },
1666 { 19, "-.9223372036854775809", .expect_err = -ERANGE },
1667 { 19, "100000000000000000000", .expect_err = -ERANGE },
1668 { 19, "-100000000000000000000", .expect_err = -ERANGE },
1669 { 19, "999999999999999999999999999.99", .expect_err = -ERANGE },
1670 { 19, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1671 { 19, "1.2.3", .expect_err = -EINVAL },
1672 { 19, "foo", .expect_err = -EINVAL },
1673 { 19, "1.foo", .expect_err = -EINVAL },
1674 { 19, "1.foo", .expect_err = -EINVAL },
1675 { 19, "12.-345", .expect_err = -EINVAL },
1676 { 19, "-12.-345", .expect_err = -EINVAL },
1677 { 19, "12.+345", .expect_err = -EINVAL },
1678 { 19, "+12.+345", .expect_err = -EINVAL },
1679 { 19, "", .expect_err = -EINVAL },
1680 { 19, NULL, .expect_err = -EINVAL },
1681
1682 { 20, "0", 0 },
1683 { 20, ".01", 1000000000000000000LL },
1684 { 20, ".012345", 1234500000000000000LL },
1685 { 20, "+.012345", 1234500000000000000LL },
1686 { 20, "-.012345", -1234500000000000000LL },
1687 { 20, "0.00345", 345000000000000000LL },
1688 { 20, ".00345", 345000000000000000LL },
1689 { 20, "-0.00345", -345000000000000000LL },
1690 { 20, "-.00345", -345000000000000000LL },
1691 { 20, ".02", 2000000000000000000LL },
1692 { 20, "-.08", -8000000000000000000LL },
1693 { 20, ".01234567890123", 1234567890123000000LL },
1694 { 20, ".01234567890123456789012345", 1234567890123456789LL },
1695 { 20, "12.34567890123", .expect_err = -ERANGE },
1696 { 20, ".09223372036854775807", 9223372036854775807LL },
1697 { 20, "-.09223372036854775807", -9223372036854775807LL },
1698 { 20, "-.09223372036854775808", .expect_err = -ERANGE },
1699 { 20, ".09223372036854775808", .expect_err = -ERANGE },
1700 { 20, "-.09223372036854775809", .expect_err = -ERANGE },
1701 { 20, ".1", .expect_err = -ERANGE },
1702 { 20, "-.1", .expect_err = -ERANGE },
1703 { 20, "999999999999999999999999999.99", .expect_err = -ERANGE },
1704 { 20, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1705 { 20, "1.2.3", .expect_err = -EINVAL },
1706 { 20, "foo", .expect_err = -EINVAL },
1707 { 20, "1.foo", .expect_err = -EINVAL },
1708 { 20, "1.foo", .expect_err = -EINVAL },
1709 { 20, "12.-345", .expect_err = -EINVAL },
1710 { 20, "-12.-345", .expect_err = -EINVAL },
1711 { 20, "12.+345", .expect_err = -EINVAL },
1712 { 20, "+12.+345", .expect_err = -EINVAL },
1713 { 20, "", .expect_err = -EINVAL },
1714 { 20, NULL, .expect_err = -EINVAL },
1715
1716 { 25, "0", 0 },
1717 { 25, ".0000001", 1000000000000000000LL },
1718 { 25, ".00000012345", 1234500000000000000LL },
1719 { 25, "+.00000012345", 1234500000000000000LL },
1720 { 25, "-.00000012345", -1234500000000000000LL },
1721 { 25, "0.0000000345", 345000000000000000LL },
1722 { 25, ".0000000345", 345000000000000000LL },
1723 { 25, "-0.0000000345", -345000000000000000LL },
1724 { 25, "-.0000000345", -345000000000000000LL },
1725 { 25, ".0000002", 2000000000000000000LL },
1726 { 25, "-.0000008", -8000000000000000000LL },
1727 { 25, ".0000001234567890123", 1234567890123000000LL },
1728 { 25, ".0000001234567890123456789012345", 1234567890123456789LL },
1729 { 25, ".0001234567890123", .expect_err = -ERANGE },
1730 { 25, ".0000009223372036854775807", 9223372036854775807LL },
1731 { 25, "-.0000009223372036854775807", -9223372036854775807LL },
1732 { 25, "-.0000009223372036854775808", .expect_err = -ERANGE },
1733 { 25, ".0000009223372036854775808", .expect_err = -ERANGE },
1734 { 25, "-.0000009223372036854775809", .expect_err = -ERANGE },
1735 { 25, ".000001", .expect_err = -ERANGE },
1736 { 25, "-.000001", .expect_err = -ERANGE },
1737 { 25, "999999999999999999999999999.99", .expect_err = -ERANGE },
1738 { 25, "-999999999999999999999999999.99", .expect_err = -ERANGE },
1739 { 25, "1.2.3", .expect_err = -EINVAL },
1740 { 25, "foo", .expect_err = -EINVAL },
1741 { 25, "1.foo", .expect_err = -EINVAL },
1742 { 25, "1.foo", .expect_err = -EINVAL },
1743 { 25, "12.-345", .expect_err = -EINVAL },
1744 { 25, "-12.-345", .expect_err = -EINVAL },
1745 { 25, "12.+345", .expect_err = -EINVAL },
1746 { 25, "+12.+345", .expect_err = -EINVAL },
1747 { 25, "", .expect_err = -EINVAL },
1748 { 25, NULL, .expect_err = -EINVAL },
1749};
1750const char *errno_str(int rc)
1751{
Neels Hofmeyr47773342021-09-05 18:48:31 +02001752 switch (rc) {
1753 case -EINVAL:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001754 return "=-EINVAL";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001755 case -ERANGE:
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001756 return "=-ERANGE";
Neels Hofmeyr47773342021-09-05 18:48:31 +02001757 case -E2BIG:
1758 return "=-E2BIG";
1759 case -EOVERFLOW:
1760 return "=-EOVERFLOW";
1761 default:
1762 return "";
1763 }
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001764}
Harald Weltee61d4592022-11-03 11:05:58 +01001765void test_float_str_to_int(void)
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001766{
1767 const struct float_str_to_int_test *t;
1768 printf("--- %s\n", __func__);
1769 for (t = float_str_to_int_tests; (t - float_str_to_int_tests) < ARRAY_SIZE(float_str_to_int_tests); t++) {
1770 int rc;
1771 int64_t val;
1772 rc = osmo_float_str_to_int(&val, t->str, t->precision);
1773 printf("osmo_float_str_to_int(%s, %u) -> rc=%d%s val=%" PRId64 "\n",
1774 osmo_quote_str(t->str, -1), t->precision, rc, errno_str(rc), val);
1775
1776 if (rc != t->expect_err)
1777 printf(" ERROR: expected rc=%d%s\n", t->expect_err, errno_str(t->expect_err));
1778 if (val != t->expect_val)
1779 printf(" ERROR: expected val=%" PRId64 "\n", t->expect_val);
1780 if (rc != t->expect_err||val != t->expect_val)
1781 exit(0);
1782 }
1783}
1784
1785struct int_to_float_str_test {
1786 unsigned int precision;
1787 int64_t val;
1788 const char *expect_str;
1789};
1790struct int_to_float_str_test int_to_float_str_tests[] = {
1791 { 0, 0, "0" },
1792 { 0, 1, "1" },
1793 { 0, 1000000, "1000000" },
1794 { 0, -1000000, "-1000000" },
1795 { 0, 1000001, "1000001" },
1796 { 0, -1000001, "-1000001" },
1797 { 0, 1000100, "1000100" },
1798 { 0, -1010000, "-1010000" },
1799 { 0, 1100000, "1100000" },
1800 { 0, 10000000, "10000000" },
1801 { 0, -10000000, "-10000000" },
1802 { 0, 100000000, "100000000" },
1803 { 0, -100000000, "-100000000" },
1804 { 0, 9223372036854775807, "9223372036854775807" },
1805 { 0, -9223372036854775807, "-9223372036854775807" },
1806 { 0, INT64_MIN, "-ERR" },
1807
1808 { 1, 0, "0" },
1809 { 1, 1, "0.1" },
1810 { 1, 1000000, "100000" },
1811 { 1, -1000000, "-100000" },
1812 { 1, 1000001, "100000.1" },
1813 { 1, -1000001, "-100000.1" },
1814 { 1, 1000100, "100010" },
1815 { 1, -1010000, "-101000" },
1816 { 1, 1100000, "110000" },
1817 { 1, 10000000, "1000000" },
1818 { 1, -10000000, "-1000000" },
1819 { 1, 100000000, "10000000" },
1820 { 1, -100000000, "-10000000" },
1821 { 1, 9223372036854775807, "922337203685477580.7" },
1822 { 1, -9223372036854775807, "-922337203685477580.7" },
1823 { 1, INT64_MIN, "-ERR" },
1824
1825 { 3, 0, "0" },
1826 { 3, 1, "0.001" },
1827 { 3, 1000000, "1000" },
1828 { 3, -1000000, "-1000" },
1829 { 3, 1000001, "1000.001" },
1830 { 3, -1000001, "-1000.001" },
1831 { 3, 1000100, "1000.1" },
1832 { 3, -1010000, "-1010" },
1833 { 3, 1100000, "1100" },
1834 { 3, 10000000, "10000" },
1835 { 3, -10000000, "-10000" },
1836 { 3, 100000000, "100000" },
1837 { 3, -100000000, "-100000" },
1838 { 3, 9223372036854775807, "9223372036854775.807" },
1839 { 3, -9223372036854775807, "-9223372036854775.807" },
1840 { 3, INT64_MIN, "-ERR" },
1841
1842 { 6, 0, "0" },
1843 { 6, 1, "0.000001" },
1844 { 6, 1000000, "1" },
1845 { 6, -1000000, "-1" },
1846 { 6, 1000001, "1.000001" },
1847 { 6, -1000001, "-1.000001" },
1848 { 6, 1000100, "1.0001" },
1849 { 6, -1010000, "-1.01" },
1850 { 6, 1100000, "1.1" },
1851 { 6, 10000000, "10" },
1852 { 6, -10000000, "-10" },
1853 { 6, 100000000, "100" },
1854 { 6, -100000000, "-100" },
1855 { 6, 9223372036854775807, "9223372036854.775807" },
1856 { 6, -9223372036854775807, "-9223372036854.775807" },
1857 { 6, INT64_MIN, "-ERR" },
1858
1859 { 17, 0, "0" },
1860 { 17, 1, "0.00000000000000001" },
1861 { 17, 1000000, "0.00000000001" },
1862 { 17, -1000000, "-0.00000000001" },
1863 { 17, 1000001, "0.00000000001000001" },
1864 { 17, -1000001, "-0.00000000001000001" },
1865 { 17, 1000100, "0.000000000010001" },
1866 { 17, -1010000, "-0.0000000000101" },
1867 { 17, 1100000, "0.000000000011" },
1868 { 17, 10000000, "0.0000000001" },
1869 { 17, -10000000, "-0.0000000001" },
1870 { 17, 100000000, "0.000000001" },
1871 { 17, -100000000, "-0.000000001" },
1872 { 17, 9223372036854775807, "92.23372036854775807" },
1873 { 17, -9223372036854775807, "-92.23372036854775807" },
1874 { 17, INT64_MIN, "-ERR" },
1875
1876 { 18, 0, "0" },
1877 { 18, 1, "0.000000000000000001" },
1878 { 18, 1000000, "0.000000000001" },
1879 { 18, -1000000, "-0.000000000001" },
1880 { 18, 1000001, "0.000000000001000001" },
1881 { 18, -1000001, "-0.000000000001000001" },
1882 { 18, 1000100, "0.0000000000010001" },
1883 { 18, -1010000, "-0.00000000000101" },
1884 { 18, 1100000, "0.0000000000011" },
1885 { 18, 10000000, "0.00000000001" },
1886 { 18, -10000000, "-0.00000000001" },
1887 { 18, 100000000, "0.0000000001" },
1888 { 18, -100000000, "-0.0000000001" },
1889 { 18, 9223372036854775807, "9.223372036854775807" },
1890 { 18, -9223372036854775807, "-9.223372036854775807" },
1891 { 18, INT64_MIN, "-ERR" },
1892
1893 { 19, 0, "0" },
1894 { 19, 1, "0.0000000000000000001" },
1895 { 19, 1000000, "0.0000000000001" },
1896 { 19, -1000000, "-0.0000000000001" },
1897 { 19, 1000001, "0.0000000000001000001" },
1898 { 19, -1000001, "-0.0000000000001000001" },
1899 { 19, 1000100, "0.00000000000010001" },
1900 { 19, -1010000, "-0.000000000000101" },
1901 { 19, 1100000, "0.00000000000011" },
1902 { 19, 10000000, "0.000000000001" },
1903 { 19, -10000000, "-0.000000000001" },
1904 { 19, 100000000, "0.00000000001" },
1905 { 19, -100000000, "-0.00000000001" },
1906 { 19, 9223372036854775807, "0.9223372036854775807" },
1907 { 19, -9223372036854775807, "-0.9223372036854775807" },
1908 { 19, INT64_MIN, "-ERR" },
1909
1910 { 23, 0, "0" },
1911 { 23, 1, "0.00000000000000000000001" },
1912 { 23, 1000000, "0.00000000000000001" },
1913 { 23, -1000000, "-0.00000000000000001" },
1914 { 23, 1000001, "0.00000000000000001000001" },
1915 { 23, -1000001, "-0.00000000000000001000001" },
1916 { 23, 1000100, "0.000000000000000010001" },
1917 { 23, -1010000, "-0.0000000000000000101" },
1918 { 23, 1100000, "0.000000000000000011" },
1919 { 23, 10000000, "0.0000000000000001" },
1920 { 23, -10000000, "-0.0000000000000001" },
1921 { 23, 100000000, "0.000000000000001" },
1922 { 23, -100000000, "-0.000000000000001" },
1923 { 23, 9223372036854775807, "0.00009223372036854775807" },
1924 { 23, -9223372036854775807, "-0.00009223372036854775807" },
1925 { 23, INT64_MIN, "-ERR" },
1926};
Harald Weltee61d4592022-11-03 11:05:58 +01001927void test_int_to_float_str(void)
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00001928{
1929 const struct int_to_float_str_test *t;
1930 printf("--- %s\n", __func__);
1931 for (t = int_to_float_str_tests;
1932 (t - int_to_float_str_tests) < ARRAY_SIZE(int_to_float_str_tests);
1933 t++) {
1934 char buf[128];
1935 int rc;
1936 rc = osmo_int_to_float_str_buf(buf, sizeof(buf), t->val, t->precision);
1937 printf("osmo_int_to_float_str_buf(%" PRId64 ", %u) -> rc=%d str=%s\n", t->val, t->precision, rc,
1938 osmo_quote_str(buf, -1));
1939
1940 if (rc != strlen(buf))
1941 printf(" ERROR: expected rc=%zu\n", strlen(buf));
1942 if (strcmp(buf, t->expect_str))
1943 printf(" ERROR: expected str=%s\n", osmo_quote_str(t->expect_str, -1));
1944 if (rc != strlen(buf) || strcmp(buf, t->expect_str))
1945 exit(0);
1946 }
1947}
1948
Neels Hofmeyr47773342021-09-05 18:48:31 +02001949struct str_to_int_test {
1950 const char *str;
1951 int base;
1952 int min_val;
1953 int max_val;
1954 int expect_rc;
1955 int expect_val;
1956};
1957/* Avoid using INT_MAX and INT_MIN because that would produce different test output on different architectures */
1958struct str_to_int_test str_to_int_tests[] = {
1959 { NULL, 10, -1000, 1000, -EINVAL, 0 },
1960 { "", 10, -1000, 1000, -EINVAL, 0 },
1961 { " ", 10, -1000, 1000, -EINVAL, 0 },
1962 { "-", 10, -1000, 1000, -EINVAL, 0 },
1963 { "--", 10, -1000, 1000, -EINVAL, 0 },
1964 { "+", 10, -1000, 1000, -EINVAL, 0 },
1965 { "++", 10, -1000, 1000, -EINVAL, 0 },
1966
1967 { "0", 10, -1000, 1000, 0, 0 },
1968 { "1", 10, -1000, 1000, 0, 1 },
1969 { "+1", 10, -1000, 1000, 0, 1 },
1970 { "-1", 10, -1000, 1000, 0, -1 },
1971 { "1000", 10, -1000, 1000, 0, 1000 },
1972 { "+1000", 10, -1000, 1000, 0, 1000 },
1973 { "-1000", 10, -1000, 1000, 0, -1000 },
1974 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
1975 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
1976 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
1977
1978 { "0", 16, -1000, 1000, 0, 0 },
1979 { "1", 16, -1000, 1000, 0, 1 },
1980 { "0x1", 16, -1000, 1000, 0, 1 },
1981 { "+1", 16, -1000, 1000, 0, 1 },
1982 { "-1", 16, -1000, 1000, 0, -1 },
1983 { "+0x1", 16, -1000, 1000, 0, 1 },
1984 { "-0x1", 16, -1000, 1000, 0, -1 },
1985 { "3e8", 16, -1000, 1000, 0, 1000 },
1986 { "3E8", 16, -1000, 1000, 0, 1000 },
1987 { "0x3e8", 16, -1000, 1000, 0, 1000 },
1988 { "0x3E8", 16, -1000, 1000, 0, 1000 },
1989 { "+3e8", 16, -1000, 1000, 0, 1000 },
1990 { "+3E8", 16, -1000, 1000, 0, 1000 },
1991 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
1992 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
1993 { "-3e8", 16, -1000, 1000, 0, -1000 },
1994 { "-3E8", 16, -1000, 1000, 0, -1000 },
1995 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
1996 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
1997 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
1998 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
1999 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2000 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2001 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2002 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2003 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2004 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2005 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2006 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2007 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2008 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2009
2010 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2011 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2012 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2013 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2014 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2015 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2016 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2017};
Harald Weltee61d4592022-11-03 11:05:58 +01002018void test_str_to_int(void)
Neels Hofmeyr47773342021-09-05 18:48:31 +02002019{
2020 const struct str_to_int_test *t;
2021 printf("--- %s\n", __func__);
2022 for (t = str_to_int_tests; (t - str_to_int_tests) < ARRAY_SIZE(str_to_int_tests); t++) {
2023 int rc;
2024 int val;
2025 rc = osmo_str_to_int(&val, t->str, t->base, t->min_val, t->max_val);
2026 printf("osmo_str_to_int(%s, %d, %d, %d) -> rc=%d%s val=%d\n",
2027 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2028
2029 if (rc != t->expect_rc)
2030 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2031 if (val != t->expect_val)
2032 printf(" ERROR: expected val=%d\n", t->expect_val);
2033 }
2034}
2035
2036struct str_to_int64_test {
2037 const char *str;
2038 int base;
2039 int64_t min_val;
2040 int64_t max_val;
2041 int expect_rc;
2042 int64_t expect_val;
2043};
2044struct str_to_int64_test str_to_int64_tests[] = {
2045 { NULL, 10, -1000, 1000, -EINVAL, 0 },
2046 { "", 10, -1000, 1000, -EINVAL, 0 },
2047 { " ", 10, -1000, 1000, -EINVAL, 0 },
2048 { "-", 10, -1000, 1000, -EINVAL, 0 },
2049 { "--", 10, -1000, 1000, -EINVAL, 0 },
2050 { "+", 10, -1000, 1000, -EINVAL, 0 },
2051 { "++", 10, -1000, 1000, -EINVAL, 0 },
2052
2053 { "0", 10, -1000, 1000, 0, 0 },
2054 { "1", 10, -1000, 1000, 0, 1 },
2055 { "+1", 10, -1000, 1000, 0, 1 },
2056 { "-1", 10, -1000, 1000, 0, -1 },
2057 { "1000", 10, -1000, 1000, 0, 1000 },
2058 { "+1000", 10, -1000, 1000, 0, 1000 },
2059 { "-1000", 10, -1000, 1000, 0, -1000 },
2060 { "1001", 10, -1000, 1000, -ERANGE, 1001 },
2061 { "+1001", 10, -1000, 1000, -ERANGE, 1001 },
2062 { "-1001", 10, -1000, 1000, -ERANGE, -1001 },
2063
2064 { "0", 16, -1000, 1000, 0, 0 },
2065 { "1", 16, -1000, 1000, 0, 1 },
2066 { "0x1", 16, -1000, 1000, 0, 1 },
2067 { "+1", 16, -1000, 1000, 0, 1 },
2068 { "-1", 16, -1000, 1000, 0, -1 },
2069 { "+0x1", 16, -1000, 1000, 0, 1 },
2070 { "-0x1", 16, -1000, 1000, 0, -1 },
2071 { "3e8", 16, -1000, 1000, 0, 1000 },
2072 { "3E8", 16, -1000, 1000, 0, 1000 },
2073 { "0x3e8", 16, -1000, 1000, 0, 1000 },
2074 { "0x3E8", 16, -1000, 1000, 0, 1000 },
2075 { "+3e8", 16, -1000, 1000, 0, 1000 },
2076 { "+3E8", 16, -1000, 1000, 0, 1000 },
2077 { "+0x3e8", 16, -1000, 1000, 0, 1000 },
2078 { "+0x3E8", 16, -1000, 1000, 0, 1000 },
2079 { "-3e8", 16, -1000, 1000, 0, -1000 },
2080 { "-3E8", 16, -1000, 1000, 0, -1000 },
2081 { "-0x3e8", 16, -1000, 1000, 0, -1000 },
2082 { "-0x3E8", 16, -1000, 1000, 0, -1000 },
2083 { "3e9", 16, -1000, 1000, -ERANGE, 1001 },
2084 { "3E9", 16, -1000, 1000, -ERANGE, 1001 },
2085 { "0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2086 { "0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2087 { "+3e9", 16, -1000, 1000, -ERANGE, 1001 },
2088 { "+3E9", 16, -1000, 1000, -ERANGE, 1001 },
2089 { "+0x3e9", 16, -1000, 1000, -ERANGE, 1001 },
2090 { "+0x3E9", 16, -1000, 1000, -ERANGE, 1001 },
2091 { "-3e9", 16, -1000, 1000, -ERANGE, -1001 },
2092 { "-3E9", 16, -1000, 1000, -ERANGE, -1001 },
2093 { "-0x3e9", 16, -1000, 1000, -ERANGE, -1001 },
2094 { "-0x3E9", 16, -1000, 1000, -ERANGE, -1001 },
2095
2096 { "garble", 10, -1000, 1000, -EINVAL, 0 },
2097 { "-garble", 10, -1000, 1000, -EINVAL, 0 },
2098 { "0x123", 10, -1000, 1000, -E2BIG, 0 },
2099 { "123potatoes", 10, -1000, 1000, -E2BIG, 123 },
2100 { "123 potatoes", 10, -1000, 1000, -E2BIG, 123 },
2101 { "123 ", 10, -1000, 1000, -E2BIG, 123 },
2102 { "123.4", 10, -1000, 1000, -E2BIG, 123 },
2103
2104 { "-9223372036854775808", 10, INT64_MIN, INT64_MAX, 0, INT64_MIN },
2105 { "9223372036854775807", 10, INT64_MIN, INT64_MAX, 0, INT64_MAX },
2106
2107 { "-9223372036854775809", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MIN },
2108 { "9223372036854775808", 10, INT64_MIN, INT64_MAX, -EOVERFLOW, INT64_MAX },
2109
2110 { "-9223372036854775808", 10, -1000, 1000, -ERANGE, INT64_MIN },
2111 { "9223372036854775807", 10, -1000, 1000, -ERANGE, INT64_MAX },
2112 { "-9223372036854775809", 10, -1000, 1000, -EOVERFLOW, INT64_MIN },
2113 { "9223372036854775808", 10, -1000, 1000, -EOVERFLOW, INT64_MAX },
2114};
Harald Weltee61d4592022-11-03 11:05:58 +01002115void test_str_to_int64(void)
Neels Hofmeyr47773342021-09-05 18:48:31 +02002116{
2117 const struct str_to_int64_test *t;
2118 printf("--- %s\n", __func__);
2119 for (t = str_to_int64_tests; (t - str_to_int64_tests) < ARRAY_SIZE(str_to_int64_tests); t++) {
2120 int rc;
2121 int64_t val;
2122 rc = osmo_str_to_int64(&val, t->str, t->base, t->min_val, t->max_val);
2123 printf("osmo_str_to_int64(%s, %d, %"PRId64", %"PRId64") -> rc=%d%s val=%"PRId64"\n",
2124 osmo_quote_str(t->str, -1), t->base, t->min_val, t->max_val, rc, errno_str(rc), val);
2125
2126 if (rc != t->expect_rc)
2127 printf(" ERROR: expected rc=%d%s\n", t->expect_rc, errno_str(t->expect_rc));
2128 if (val != t->expect_val)
2129 printf(" ERROR: expected val=%"PRId64"\n", t->expect_val);
2130 }
2131}
2132
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002133int main(int argc, char **argv)
2134{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02002135 static const struct log_info log_info = {};
2136 log_init(&log_info, NULL);
2137
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002138 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01002139 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02002140 test_ipa_ccm_id_get_parsing();
2141 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02002142 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02002143 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01002144 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01002145 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02002146 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01002147 str_escape3_test();
2148 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02002149 isqrt_test();
Philipp Maier94705d02023-01-11 10:55:47 +01002150 mod_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02002151 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02002152 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01002153 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02002154 strbuf_test_nolen();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01002155 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01002156 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01002157 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01002158 osmo_strnchr_test();
Neels Hofmeyr87c3afb2020-09-30 21:47:47 +00002159 test_float_str_to_int();
2160 test_int_to_float_str();
Neels Hofmeyr47773342021-09-05 18:48:31 +02002161 test_str_to_int();
2162 test_str_to_int64();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01002163 return 0;
2164}