blob: e15cf5f63442cc0fc291e5b66cc00180ddb8e59f [file] [log] [blame]
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001/* tests for utilities of libmsomcore */
2/*
3 * (C) 2014 Holger Hans Peter Freyther
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020023#include <osmocom/gsm/ipa.h>
Harald Welte7869baf2018-07-31 20:25:48 +020024#include <osmocom/gsm/protocol/ipaccess.h>
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020025
26#include <osmocom/core/logging.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010027#include <osmocom/core/utils.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020028#include <osmocom/core/socket.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010029
30#include <stdio.h>
Harald Welte504caac2017-10-27 17:19:59 +020031#include <ctype.h>
Harald Welte15a5f8d2018-06-06 16:58:17 +020032#include <time.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020033#include <netinet/in.h>
34#include <arpa/inet.h>
Neels Hofmeyr7079e692018-12-05 21:02:36 +010035#include <errno.h>
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +010036#include <limits.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010037
38static void hexdump_test(void)
39{
40 uint8_t data[4098];
Neels Hofmeyr0423b612019-01-14 23:32:53 +010041 char buf[256];
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010042 int i;
43
44 for (i = 0; i < ARRAY_SIZE(data); ++i)
45 data[i] = i & 0xff;
46
47 printf("Plain dump\n");
48 printf("%s\n", osmo_hexdump(data, 4));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010049 printf("%s\n", osmo_hexdump_nospc(data, 4));
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010050
51 printf("Corner case\n");
52 printf("%s\n", osmo_hexdump(data, ARRAY_SIZE(data)));
53 printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data)));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010054
55#define _HEXDUMP_BUF_TEST(SIZE, DELIM, DELIM_AFTER) \
56 buf[0] = '!'; \
57 buf[1] = '\0'; \
58 printf("osmo_hexdump_buf(buf, " #SIZE ", data, 4, %s, " #DELIM_AFTER ")\n = \"%s\"\n", \
59 DELIM ? #DELIM : "NULL", \
60 osmo_hexdump_buf(buf, SIZE, data, 4, DELIM, DELIM_AFTER))
61#define HEXDUMP_BUF_TEST(DELIM) \
62 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, false); \
63 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, true); \
64 _HEXDUMP_BUF_TEST(6, DELIM, false); \
65 _HEXDUMP_BUF_TEST(7, DELIM, false); \
66 _HEXDUMP_BUF_TEST(8, DELIM, false); \
67 _HEXDUMP_BUF_TEST(6, DELIM, true); \
68 _HEXDUMP_BUF_TEST(7, DELIM, true); \
69 _HEXDUMP_BUF_TEST(8, DELIM, true)
70
71 HEXDUMP_BUF_TEST("[delim]");
72 HEXDUMP_BUF_TEST(" ");
73 HEXDUMP_BUF_TEST(":");
74 HEXDUMP_BUF_TEST("::");
75 HEXDUMP_BUF_TEST("");
76 HEXDUMP_BUF_TEST(NULL);
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010077}
78
Neels Hofmeyr7adb5672017-02-14 15:48:19 +010079static void hexparse_test(void)
80{
81 int i;
82 int rc;
83 uint8_t data[256];
84
85 printf("\nHexparse 0..255 in lower case\n");
86 memset(data, 0, sizeof(data));
87 rc = osmo_hexparse(
88 "000102030405060708090a0b0c0d0e0f"
89 "101112131415161718191a1b1c1d1e1f"
90 "202122232425262728292a2b2c2d2e2f"
91 "303132333435363738393a3b3c3d3e3f"
92 "404142434445464748494a4b4c4d4e4f"
93 "505152535455565758595a5b5c5d5e5f"
94 "606162636465666768696a6b6c6d6e6f"
95 "707172737475767778797a7b7c7d7e7f"
96 "808182838485868788898a8b8c8d8e8f"
97 "909192939495969798999a9b9c9d9e9f"
98 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
99 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
100 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
101 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
102 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
103 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
104 , data, sizeof(data));
105 printf("rc = %d\n", rc);
106 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
107 for (i = 0; i < sizeof(data); i++)
108 OSMO_ASSERT(data[i] == i);
109
110 printf("Hexparse 0..255 in upper case\n");
111 memset(data, 0, sizeof(data));
112 rc = osmo_hexparse(
113 "000102030405060708090A0B0C0D0E0F"
114 "101112131415161718191A1B1C1D1E1F"
115 "202122232425262728292A2B2C2D2E2F"
116 "303132333435363738393A3B3C3D3E3F"
117 "404142434445464748494A4B4C4D4E4F"
118 "505152535455565758595A5B5C5D5E5F"
119 "606162636465666768696A6B6C6D6E6F"
120 "707172737475767778797A7B7C7D7E7F"
121 "808182838485868788898A8B8C8D8E8F"
122 "909192939495969798999A9B9C9D9E9F"
123 "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
124 "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
125 "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
126 "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
127 "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
128 "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
129 , data, sizeof(data));
130 printf("rc = %d\n", rc);
131 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
132 for (i = 0; i < sizeof(data); i++)
133 OSMO_ASSERT(data[i] == i);
134
135 printf("Hexparse 0..255 in mixed case\n");
136 memset(data, 0, sizeof(data));
137 rc = osmo_hexparse(
138 "000102030405060708090A0B0C0D0E0F"
139 "101112131415161718191A1B1C1D1E1F"
140 "202122232425262728292A2B2C2D2E2F"
141 "303132333435363738393a3b3c3d3e3f"
142 "404142434445464748494A4B4C4D4E4F"
143 "505152535455565758595a5b5c5d5e5f"
144 "606162636465666768696A6B6C6D6E6F"
145 "707172737475767778797A7B7C7D7E7F"
146 "808182838485868788898A8B8C8D8E8F"
147 "909192939495969798999A9B9C9D9E9F"
148 "A0A1A2A3a4a5a6a7a8a9AAABACADAEAF"
149 "B0B1B2B3b4b5b6b7b8b9BABBBCBDBEBF"
150 "C0C1C2C3c4c5c6c7c8c9CACBCCCDCECF"
151 "D0D1D2D3d4d5d6d7d8d9DADBDCDDDEDF"
152 "E0E1E2E3e4e5e6e7e8e9EAEBECEDEEEF"
153 "F0F1F2F3f4f5f6f7f8f9FAFBFCFDFEFF"
154 , data, sizeof(data));
155 printf("rc = %d\n", rc);
156 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
157 for (i = 0; i < sizeof(data); i++)
158 OSMO_ASSERT(data[i] == i);
159
Neels Hofmeyr437ed4a2017-02-14 15:54:31 +0100160 printf("Hexparse 0..255 with whitespace\n");
161 memset(data, 0, sizeof(data));
162 rc = osmo_hexparse(
163 "00 01\t02\r030405060708090A0B0C0D0 E 0 F\n"
164 "10 11\t12\r131415161718191A1B1C1D1 E 1 F\n"
165 "20 21\t22\r232425262728292A2B2C2D2 E 2 F\n"
166 "30 31\t32\r333435363738393a3b3c3d3 e 3 f\n"
167 "40 41\t42\r434445464748494A4B4C4D4 E 4 F\n"
168 "50 51\t52\r535455565758595a5b5c5d5 e 5 f\n"
169 "60 61\t62\r636465666768696A6B6C6D6 E 6 F\n"
170 "70 71\t72\r737475767778797A7B7C7D7 E 7 F\n"
171 "80 81\t82\r838485868788898A8B8C8D8 E 8 F\n"
172 "90 91\t92\r939495969798999A9B9C9D9 E 9 F\n"
173 "A0 A1\tA2\rA3a4a5a6a7a8a9AAABACADA E A F\n"
174 "B0 B1\tB2\rB3b4b5b6b7b8b9BABBBCBDB E B F\n"
175 "C0 C1\tC2\rC3c4c5c6c7c8c9CACBCCCDC E C F \n"
176 "D0 D1\tD2\rD3d4d5d6d7d8d9DADBDCDDD E D F\t\n"
177 "E0 E1\tE2\rE3e4e5e6e7e8e9EAEBECEDE E E F \t\n"
178 "F0 F1\tF2\rF3f4f5f6f7f8f9FAFBFCFDF E F F \t\r\n"
179 , data, sizeof(data));
180 printf("rc = %d\n", rc);
181 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
182 for (i = 0; i < sizeof(data); i++)
183 OSMO_ASSERT(data[i] == i);
184
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100185 printf("Hexparse with buffer too short\n");
186 memset(data, 0, sizeof(data));
187 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0f", data, 15);
188 printf("rc = %d\n", rc);
189
190 printf("Hexparse with uneven amount of digits\n");
191 memset(data, 0, sizeof(data));
192 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0", data, 16);
193 printf("rc = %d\n", rc);
194
195 printf("Hexparse with invalid char\n");
196 memset(data, 0, sizeof(data));
197 rc = osmo_hexparse("0001020304050X0708090a0b0c0d0e0f", data, 16);
198 printf("rc = %d\n", rc);
199}
200
Harald Welte7869baf2018-07-31 20:25:48 +0200201static void test_ipa_ccm_id_resp_parsing(void)
202{
203 struct tlv_parsed tvp;
204 int rc;
205
206 static const uint8_t id_resp_data[] = {
207 0x00, 0x13, IPAC_IDTAG_MACADDR,
208 '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0',
209 0x00, 0x11, IPAC_IDTAG_IPADDR,
210 '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0',
211 0x00, 0x0a, IPAC_IDTAG_UNIT,
212 '1','2','3','4','/','0','/','0','\0',
213 0x00, 0x02, IPAC_IDTAG_LOCATION1,
214 '\0',
215 0x00, 0x0d, IPAC_IDTAG_LOCATION2,
216 'B','T','S','_','N','B','T','1','3','1','G','\0',
217 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS,
218 '1','6','5','a','0','2','9','_','5','5','\0',
219 0x00, 0x14, IPAC_IDTAG_SWVERSION,
220 '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0',
221 0x00, 0x18, IPAC_IDTAG_UNITNAME,
222 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0',
223 0x00, 0x0a, IPAC_IDTAG_SERNR,
224 '0','0','1','1','0','7','8','1','\0'
225 };
226
227 printf("\nTesting IPA CCM ID RESP parsing\n");
228
229 rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data));
230 OSMO_ASSERT(rc == 0);
231
232 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR));
233 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12);
234 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR));
235 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10);
236 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT));
237 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09);
238 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1));
239 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01);
240 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2));
241 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c);
242 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS));
243 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
244 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION));
245 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
246 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13);
247 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME));
248 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17);
249 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR));
250 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09);
251}
252
253static void test_ipa_ccm_id_get_parsing(void)
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200254{
255 struct tlv_parsed tvp;
256 int rc;
257
Harald Welte48fd0192018-07-31 20:19:49 +0200258 /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */
Harald Welte7869baf2018-07-31 20:25:48 +0200259 static const uint8_t id_get_data[] = {
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200260 0x01, 0x08,
261 0x01, 0x07,
262 0x01, 0x02,
263 0x01, 0x03,
264 0x01, 0x04,
265 0x01, 0x05,
266 0x01, 0x01,
267 0x01, 0x00,
268 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30,
269 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
270 };
271
Harald Welte7869baf2018-07-31 20:25:48 +0200272 printf("\nTesting IPA CCM ID GET parsing\n");
273
274 rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data));
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200275 OSMO_ASSERT(rc == 0);
276
277 OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
278 OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0);
279
280 OSMO_ASSERT(TLVP_PRESENT(&tvp, 7));
281 OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0);
282
283 OSMO_ASSERT(TLVP_PRESENT(&tvp, 2));
284 OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0);
285
286 OSMO_ASSERT(TLVP_PRESENT(&tvp, 3));
287 OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0);
288
289 OSMO_ASSERT(TLVP_PRESENT(&tvp, 4));
290 OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0);
291
292 OSMO_ASSERT(TLVP_PRESENT(&tvp, 5));
293 OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0);
294
295 OSMO_ASSERT(TLVP_PRESENT(&tvp, 1));
296 OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0);
297
298 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0));
299 OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0);
300
301 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23));
302 OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16);
303
304 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24));
305 OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16);
306
307 OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
308}
309
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200310static struct {
311 const char *str;
312 int min_digits;
313 int max_digits;
314 bool require_even;
315 bool expect_ok;
316} test_hexstrs[] = {
317 { NULL, 0, 10, false, true },
318 { NULL, 1, 10, false, false },
319 { "", 0, 10, false, true },
320 { "", 1, 10, false, false },
321 { " ", 0, 10, false, false },
322 { "1", 0, 10, false, true },
323 { "1", 1, 10, false, true },
324 { "1", 1, 10, true, false },
325 { "1", 2, 10, false, false },
326 { "123", 1, 10, false, true },
327 { "123", 1, 10, true, false },
328 { "123", 4, 10, false, false },
329 { "1234", 4, 10, true, true },
330 { "12345", 4, 10, true, false },
331 { "123456", 4, 10, true, true },
332 { "1234567", 4, 10, true, false },
333 { "12345678", 4, 10, true, true },
334 { "123456789", 4, 10, true, false },
335 { "123456789a", 4, 10, true, true },
336 { "123456789ab", 4, 10, true, false },
337 { "123456789abc", 4, 10, true, false },
338 { "123456789ab", 4, 10, false, false },
339 { "123456789abc", 4, 10, false, false },
340 { "0123456789abcdefABCDEF", 0, 100, false, true },
341 { "0123456789 abcdef ABCDEF", 0, 100, false, false },
342 { "foobar", 0, 100, false, false },
343 { "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
344 { "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
345 { "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
346};
347
348bool test_is_hexstr()
349{
350 int i;
351 bool pass = true;
352 bool ok = true;
353 printf("\n----- %s\n", __func__);
354
355 for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
356 ok = osmo_is_hexstr(test_hexstrs[i].str,
357 test_hexstrs[i].min_digits,
358 test_hexstrs[i].max_digits,
359 test_hexstrs[i].require_even);
360 pass = pass && (ok == test_hexstrs[i].expect_ok);
361 printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
362 i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
363 test_hexstrs[i].str,
364 test_hexstrs[i].min_digits,
365 test_hexstrs[i].max_digits,
366 test_hexstrs[i].require_even,
367 test_hexstrs[i].expect_ok ? "valid" : "invalid");
368 }
369 return pass;
370}
371
Harald Welte504caac2017-10-27 17:19:59 +0200372struct bcdcheck {
373 uint8_t bcd;
374 char ch;
375};
376
377static const struct bcdcheck bcdchecks[] = {
378 { 0, '0' },
379 { 1, '1' },
380 { 2, '2' },
381 { 3, '3' },
382 { 4, '4' },
383 { 5, '5' },
384 { 6, '6' },
385 { 7, '7' },
386 { 8, '8' },
387 { 9, '9' },
388 { 0xA, 'A' },
389 { 0xB, 'B' },
390 { 0xC, 'C' },
391 { 0xD, 'D' },
392 { 0xE, 'E' },
393 { 0xF, 'F' },
394};
395
396static void bcd_test(void)
397{
398 int i;
399
400 printf("\nTesting BCD conversion\n");
401 for (i = 0; i < ARRAY_SIZE(bcdchecks); i++) {
402 const struct bcdcheck *check = &bcdchecks[i];
403 char ch = osmo_bcd2char(check->bcd);
404 printf("\tval=0x%x, expected=%c, found=%c\n", check->bcd, check->ch, ch);
405 OSMO_ASSERT(osmo_bcd2char(check->bcd) == check->ch);
406 /* test char -> bcd back-coversion */
407 OSMO_ASSERT(osmo_char2bcd(ch) == check->bcd);
408 /* test for lowercase hex char */
409 OSMO_ASSERT(osmo_char2bcd(tolower(ch)) == check->bcd);
410 }
411}
412
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100413struct bcd2str_test {
414 const char *bcd_hex;
415 int start_nibble;
416 int end_nibble;
417 bool allow_hex;
418 size_t str_size;
419 const char *expect_str;
420 int expect_rc;
421};
422
423static const struct bcd2str_test bcd2str_tests[] = {
424 {
425 .bcd_hex = "1a 32 54 76 98 f0",
426 .start_nibble = 1,
427 .end_nibble = 11,
428 .expect_str = "1234567890",
429 .expect_rc = 10,
430 },
431 {
432 .bcd_hex = "1a 32 a4 cb 9d f0",
433 .start_nibble = 1,
434 .end_nibble = 11,
435 .expect_str = "1234ABCD90",
436 .expect_rc = -EINVAL,
437 },
438 {
439 .bcd_hex = "1a 32 a4 cb 9d f0",
440 .start_nibble = 1,
441 .end_nibble = 11,
442 .allow_hex = true,
443 .expect_str = "1234ABCD90",
444 .expect_rc = 10,
445 },
446 {
447 .bcd_hex = "1a 32 54 76 98 f0",
448 .start_nibble = 1,
449 .end_nibble = 12,
450 .expect_str = "1234567890F",
451 .expect_rc = -EINVAL,
452 },
453 {
454 .bcd_hex = "1a 32 54 76 98 f0",
455 .start_nibble = 1,
456 .end_nibble = 12,
457 .allow_hex = true,
458 .expect_str = "1234567890F",
459 .expect_rc = 11,
460 },
461 {
462 .bcd_hex = "1a 32 54 76 98 f0",
463 .start_nibble = 0,
464 .end_nibble = 12,
465 .allow_hex = true,
466 .expect_str = "A1234567890F",
467 .expect_rc = 12,
468 },
469 {
470 .bcd_hex = "1a 32 54 76 98 f0",
471 .start_nibble = 1,
472 .end_nibble = 12,
473 .str_size = 5,
474 .expect_str = "1234",
475 .expect_rc = 11,
476 },
477 {
478 .bcd_hex = "",
479 .start_nibble = 1,
480 .end_nibble = 1,
481 .expect_str = "",
482 .expect_rc = 0,
483 },
484};
485
486static void bcd2str_test(void)
487{
488 int i;
489 uint8_t bcd[64];
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200490 uint8_t bcd2[64];
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100491 int rc;
492
493 printf("\nTesting bcd to string conversion\n");
494
495 for (i = 0; i < ARRAY_SIZE(bcd2str_tests); i++) {
496 const struct bcd2str_test *t = &bcd2str_tests[i];
497 char str[64] = {};
498 size_t str_size = t->str_size ? : sizeof(str);
499
500 osmo_hexparse(t->bcd_hex, bcd, sizeof(bcd));
501
502 printf("- BCD-input='%s' nibbles=[%d..%d[ str_size=%zu\n", t->bcd_hex,
503 t->start_nibble, t->end_nibble, str_size);
504 rc = osmo_bcd2str(str, str_size, bcd, t->start_nibble, t->end_nibble, t->allow_hex);
505
506 printf(" rc=%d\n", rc);
507
508 OSMO_ASSERT(str[str_size-1] == '\0');
509 printf(" -> %s\n", osmo_quote_str(str, -1));
510
511 if (rc != t->expect_rc)
512 printf(" ERROR: expected rc=%d\n", t->expect_rc);
513 if (strcmp(str, t->expect_str))
514 printf(" ERROR: expected result %s\n", osmo_quote_str(t->expect_str, -1));
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200515
516 memset(bcd2, 0xff, sizeof(bcd2));
517 rc = osmo_str2bcd(bcd2, sizeof(bcd2), str, t->start_nibble, -1, t->allow_hex);
518 printf("osmo_str2bcd(start_nibble=%d) -> rc=%d\n", t->start_nibble, rc);
519 if (rc > 0)
520 printf(" = %s\n", osmo_hexdump(bcd2, rc));
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100521 }
522
523 printf("- zero output buffer\n");
524 rc = osmo_bcd2str(NULL, 100, bcd, 1, 2, false);
525 printf(" bcd2str(NULL, ...) -> %d\n", rc);
526 OSMO_ASSERT(rc < 0);
527 rc = osmo_bcd2str((char*)23, 0, bcd, 1, 2, false);
528 printf(" bcd2str(dst, 0, ...) -> %d\n", rc);
529 OSMO_ASSERT(rc < 0);
530}
531
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100532static void str_escape_test(void)
533{
534 int i;
535 int j;
536 uint8_t in_buf[32];
537 char out_buf[11];
538 const char *printable = "printable";
539 const char *res;
540
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100541 printf("\nTesting string escaping: osmo_escape_str()\n");
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100542 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100543 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100544 for (j = 0; j < 16; j++) {
545 for (i = 0; i < 16; i++)
546 in_buf[i] = (j << 4) | i;
547 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
548 }
549
550 printf("- nul terminated:\n");
551 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
552
553 printf("- passthru:\n");
554 res = osmo_escape_str(printable, -1);
Harald Welte98ed3392019-03-28 13:26:53 +0100555 if (strcmp(res, printable))
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100556 printf("NOT passed through! \"%s\"\n", res);
557 else
558 printf("passed through unchanged \"%s\"\n", res);
559
560 printf("- zero length:\n");
561 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
562
563 printf("- truncation when too long:\n");
564 memset(in_buf, 'x', sizeof(in_buf));
565 in_buf[0] = '\a';
566 in_buf[7] = 'E';
567 memset(out_buf, 0x7f, sizeof(out_buf));
568 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
569 OSMO_ASSERT(out_buf[10] == 0x7f);
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100570}
571
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200572static void str_quote_test(void)
573{
574 int i;
575 int j;
576 uint8_t in_buf[32];
577 char out_buf[11];
578 const char *printable = "printable";
579 const char *res;
580
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100581 printf("\nTesting string quoting: osmo_quote_str()\n");
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200582 printf("- all chars from 0 to 255 in batches of 16:\n");
583 in_buf[16] = '\0';
584 for (j = 0; j < 16; j++) {
585 for (i = 0; i < 16; i++)
586 in_buf[i] = (j << 4) | i;
587 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
588 }
589
590 printf("- nul terminated:\n");
591 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
592
593 printf("- never passthru:\n");
594 res = osmo_quote_str(printable, -1);
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100595 if (strcmp(res, printable))
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200596 printf("NOT passed through. '%s'\n", res);
597 else
598 printf("passed through unchanged '%s'\n", res);
599
600 printf("- zero length:\n");
601 printf("'%s'\n", osmo_quote_str("omitted", 0));
602
603 printf("- truncation when too long:\n");
604 memset(in_buf, 'x', sizeof(in_buf));
605 in_buf[0] = '\a';
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100606 in_buf[6] = 'E';
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200607 memset(out_buf, 0x7f, sizeof(out_buf));
608 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
609 OSMO_ASSERT(out_buf[10] == 0x7f);
610
611 printf("- always truncation, even when no escaping needed:\n");
612 memset(in_buf, 'x', sizeof(in_buf));
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100613 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 +0200614 in_buf[20] = '\0';
615 memset(out_buf, 0x7f, sizeof(out_buf));
616 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
617 OSMO_ASSERT(out_buf[0] == '"');
618
619 printf("- try to feed too little buf for quoting:\n");
620 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
621
622 printf("- NULL string becomes a \"NULL\" literal:\n");
623 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
624}
625
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100626static void str_escape3_test(void)
627{
628 int i;
629 int j;
630 uint8_t in_buf[32];
631 char out_buf[11];
632 const char *printable = "printable";
633 const char *res;
634 void *ctx = talloc_named_const(NULL, 0, __func__);
635
636 printf("\nTesting string escaping: osmo_escape_cstr_buf()\n");
637 printf("- all chars from 0 to 255 in batches of 16:\n");
638 in_buf[16] = '\0';
639 for (j = 0; j < 16; j++) {
640 for (i = 0; i < 16; i++)
641 in_buf[i] = (j << 4) | i;
642 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, (const char*)in_buf, 16));
643 }
644
645 printf("- nul terminated:\n");
646 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "termi\nated", -1));
647
648 printf("- passthru:\n");
649 res = osmo_escape_cstr_c(ctx, printable, -1);
650 if (strcmp(res, printable))
651 printf("NOT passed through! \"%s\"\n", res);
652 else
653 printf("passed through unchanged \"%s\"\n", res);
654
655 printf("- zero length:\n");
656 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "omitted", 0));
657
658 printf("- truncation when too long:\n");
659 memset(in_buf, 'x', sizeof(in_buf));
660 in_buf[0] = '\a';
661 in_buf[7] = 'E';
662 memset(out_buf, 0x7f, sizeof(out_buf));
663 osmo_escape_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
664 printf("\"%s\"\n", out_buf);
665 OSMO_ASSERT(out_buf[10] == 0x7f);
666
667 printf("- Test escaping an escaped string:\n");
668 res = "\x02\x03\n";
669 for (i = 0; i <= 3; i++) {
670 res = osmo_escape_cstr_c(ctx, res, -1);
671 printf("%d: '%s'\n", i, res);
672 }
673
674 talloc_free(ctx);
675}
676
677static void str_quote3_test(void)
678{
679 int i;
680 int j;
681 uint8_t in_buf[32];
682 char out_buf[11];
683 const char *printable = "printable";
684 const char *res;
685 void *ctx = talloc_named_const(NULL, 0, __func__);
686
687 printf("\nTesting string quoting: osmo_quote_cstr_buf()\n");
688 printf("- all chars from 0 to 255 in batches of 16:\n");
689 in_buf[16] = '\0';
690 for (j = 0; j < 16; j++) {
691 for (i = 0; i < 16; i++)
692 in_buf[i] = (j << 4) | i;
693 printf("%s\n", osmo_quote_cstr_c(ctx, (const char*)in_buf, 16));
694 }
695
696 printf("- nul terminated:\n");
697 printf("'%s'\n", osmo_quote_cstr_c(ctx, "termi\nated", -1));
698
699 printf("- never passthru:\n");
700 res = osmo_quote_cstr_c(ctx, printable, -1);
701 if (strcmp(res, printable))
702 printf("NOT passed through. '%s'\n", res);
703 else
704 printf("passed through unchanged '%s'\n", res);
705
706 printf("- zero length:\n");
707 printf("'%s'\n", osmo_quote_cstr_c(ctx, "omitted", 0));
708
709 printf("- truncation when too long:\n");
710 memset(in_buf, 'x', sizeof(in_buf));
711 in_buf[0] = '\a';
712 in_buf[6] = 'E';
713 memset(out_buf, 0x7f, sizeof(out_buf));
714 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
715 printf("'%s'\n", out_buf);
716 OSMO_ASSERT(out_buf[10] == 0x7f);
717
718 printf("- always truncation, even when no escaping needed:\n");
719 memset(in_buf, 'x', sizeof(in_buf));
720 in_buf[7] = 'E'; /* dst has 10, less 1 quote and nul, leaves 8, i.e. in[7] is last */
721 in_buf[20] = '\0';
722 memset(out_buf, 0x7f, sizeof(out_buf));
723 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, -1);
724 printf("'%s'\n", out_buf);
725 OSMO_ASSERT(out_buf[0] == '"');
726 OSMO_ASSERT(out_buf[10] == 0x7f);
727
728 printf("- try to feed too little buf for quoting:\n");
729 osmo_quote_cstr_buf(out_buf, 2, "", -1);
730 printf("'%s'\n", out_buf);
731
732 printf("- Test quoting a quoted+escaped string:\n");
733 res = "\x02\x03\n";
734 for (i = 0; i <= 3; i++) {
735 res = osmo_quote_cstr_c(ctx, res, -1);
736 printf("%d: %s\n", i, res);
737 }
738
739 printf("- Test C-string equivalence:\n");
740#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"
741#define EMPTY_STR ""
742 printf("strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)) == %d\n",
743 strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)));
744 printf("strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)) == %d\n",
745 strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)));
746 printf("strcmp(\"NULL\", osmo_quote_cstr_c(ctx, NULL, -1)) == %d\n",
747 strcmp("NULL", osmo_quote_cstr_c(ctx, NULL, -1)));
748
749 talloc_free(ctx);
750}
751
Harald Welte15a5f8d2018-06-06 16:58:17 +0200752static void isqrt_test(void)
753{
754 int i;
755
756 printf("\nTesting integer square-root\n");
757 srand(time(NULL));
758 for (i = 0; i < 1024; i++) {
759 uint16_t x;
760 uint32_t r = rand();
761 if (RAND_MAX < UINT16_MAX)
762 x = r * (UINT16_MAX/RAND_MAX);
763 else
764 x = r;
Neels Hofmeyr6979c542018-07-19 22:05:21 +0200765 uint32_t sq = (uint32_t)x*x;
Harald Welte15a5f8d2018-06-06 16:58:17 +0200766 uint32_t y = osmo_isqrt32(sq);
767 if (y != x)
768 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
769 }
770}
771
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200772
773struct osmo_sockaddr_to_str_and_uint_test_case {
774 uint16_t port;
775 bool omit_port;
776 const char *addr;
777 unsigned int addr_len;
778 bool omit_addr;
779 unsigned int expect_rc;
780 const char *expect_returned_addr;
781};
782
783struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
784 {
785 .port = 0,
786 .addr = "0.0.0.0",
787 .addr_len = 20,
788 .expect_rc = 7,
789 },
790 {
791 .port = 65535,
792 .addr = "255.255.255.255",
793 .addr_len = 20,
794 .expect_rc = 15,
795 },
796 {
797 .port = 1234,
798 .addr = "234.23.42.123",
799 .addr_len = 20,
800 .expect_rc = 13,
801 },
802 {
803 .port = 1234,
804 .addr = "234.23.42.123",
805 .addr_len = 10,
806 .expect_rc = 13,
807 .expect_returned_addr = "234.23.42",
808 },
809 {
810 .port = 1234,
811 .omit_port = true,
812 .addr = "234.23.42.123",
813 .addr_len = 20,
814 .expect_rc = 13,
815 },
816 {
817 .port = 1234,
818 .addr = "234.23.42.123",
819 .omit_addr = true,
820 .expect_rc = 0,
821 .expect_returned_addr = "",
822 },
823 {
824 .port = 1234,
825 .addr = "234.23.42.123",
826 .addr_len = 0,
827 .expect_rc = 13,
828 .expect_returned_addr = "",
829 },
830 {
831 .port = 1234,
832 .addr = "234.23.42.123",
833 .omit_port = true,
834 .omit_addr = true,
835 .expect_rc = 0,
836 .expect_returned_addr = "",
837 },
838};
839
840static void osmo_sockaddr_to_str_and_uint_test(void)
841{
842 int i;
843 printf("\n%s\n", __func__);
844
845 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
846 struct osmo_sockaddr_to_str_and_uint_test_case *t =
847 &osmo_sockaddr_to_str_and_uint_test_data[i];
848
849 struct sockaddr_in sin = {
850 .sin_family = AF_INET,
851 .sin_port = htons(t->port),
852 };
853 inet_aton(t->addr, &sin.sin_addr);
854
855 char addr[20] = {};
856 uint16_t port = 0;
857 unsigned int rc;
858
859 rc = osmo_sockaddr_to_str_and_uint(
860 t->omit_addr? NULL : addr, t->addr_len,
861 t->omit_port? NULL : &port,
862 (const struct sockaddr*)&sin);
863
864 printf("[%d] %s:%u%s%s addr_len=%u --> %s:%u rc=%u\n",
865 i,
866 t->addr ? : "-",
867 t->port,
868 t->omit_addr ? " (omit addr)" : "",
869 t->omit_port ? " (omit port)" : "",
870 t->addr_len,
871 addr, port, rc);
872 if (rc != t->expect_rc)
873 printf("ERROR: Expected rc = %u\n", t->expect_rc);
874 if (!t->expect_returned_addr)
875 t->expect_returned_addr = t->addr;
876 if (strcmp(t->expect_returned_addr, addr))
877 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
878 if (!t->omit_port && port != t->port)
879 printf("ERROR: Expected port = %u\n", t->port);
880 }
881}
882
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200883struct osmo_str_tolowupper_test_data {
884 const char *in;
885 bool use_static_buf;
886 size_t buflen;
887 const char *expect_lower;
888 const char *expect_upper;
889 size_t expect_rc;
890 size_t expect_rc_inplace;
891};
892
893struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
894 {
895 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
896 .use_static_buf = true,
897 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
898 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
899 },
900 {
901 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
902 .buflen = 99,
903 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
904 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
905 .expect_rc = 62,
906 .expect_rc_inplace = 62,
907 },
908 {
909 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
910 .buflen = 0,
911 .expect_lower = "Unset",
912 .expect_upper = "Unset",
913 .expect_rc = 62,
914 .expect_rc_inplace = 0,
915 },
916 {
917 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
918 .buflen = 1,
919 .expect_lower = "",
920 .expect_upper = "",
921 .expect_rc = 62,
922 .expect_rc_inplace = 0,
923 },
924 {
925 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
926 .buflen = 2,
927 .expect_lower = "a",
928 .expect_upper = "A",
929 .expect_rc = 62,
930 .expect_rc_inplace = 1,
931 },
932 {
933 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
934 .buflen = 28,
935 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
936 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
937 .expect_rc = 62,
938 .expect_rc_inplace = 27,
939 },
940};
941
942
943static void osmo_str_tolowupper_test()
944{
945 int i;
946 char buf[128];
947 bool ok = true;
948 printf("\n%s\n", __func__);
949
950 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
951 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
952 size_t rc = 0;
953 const char *res;
954
955 /* tolower */
956 if (d->use_static_buf) {
957 res = osmo_str_tolower(d->in);
958 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
959 printf(" = %s\n", osmo_quote_str(res, -1));
960 } else {
961 OSMO_ASSERT(sizeof(buf) >= d->buflen);
962 osmo_strlcpy(buf, "Unset", sizeof(buf));
963 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
964 res = buf;
965 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
966 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
967 }
968
969 if (strcmp(res, d->expect_lower)) {
970 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
971 " got %s\n", i, osmo_quote_str(res, -1));
972 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
973 ok = false;
974 }
975
976 if (!d->use_static_buf && d->expect_rc != rc) {
977 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
978 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
979 ok = false;
980 }
981
982 /* tolower, in-place */
983 if (!d->use_static_buf) {
984 osmo_strlcpy(buf,
985 d->buflen ? d->in : "Unset",
986 sizeof(buf));
987 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
988 res = buf;
989 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
990 d->buflen, osmo_quote_str(d->in, -1));
991 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
992
993 if (strcmp(res, d->expect_lower)) {
994 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
995 " got %s\n", i, osmo_quote_str(res, -1));
996 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
997 ok = false;
998 }
999
1000 if (d->expect_rc_inplace != rc) {
1001 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1002 " got rc=%zu, expected rc=%zu\n",
1003 i, rc, d->expect_rc_inplace);
1004 ok = false;
1005 }
1006 }
1007
1008 /* toupper */
1009 if (d->use_static_buf) {
1010 res = osmo_str_toupper(d->in);
1011 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
1012 printf(" = %s\n", osmo_quote_str(res, -1));
1013 } else {
1014 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1015 osmo_strlcpy(buf, "Unset", sizeof(buf));
1016 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
1017 res = buf;
1018 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1019 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1020 }
1021
1022 if (strcmp(res, d->expect_upper)) {
1023 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1024 " got %s\n", i, osmo_quote_str(res, -1));
1025 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1026 ok = false;
1027 }
1028
1029 if (!d->use_static_buf && d->expect_rc != rc) {
1030 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1031 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1032 ok = false;
1033 }
1034
1035 /* toupper, in-place */
1036 if (!d->use_static_buf) {
1037 osmo_strlcpy(buf,
1038 d->buflen ? d->in : "Unset",
1039 sizeof(buf));
1040 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
1041 res = buf;
1042 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
1043 d->buflen, osmo_quote_str(d->in, -1));
1044 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1045
1046 if (strcmp(res, d->expect_upper)) {
1047 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1048 " got %s\n", i, osmo_quote_str(res, -1));
1049 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1050 ok = false;
1051 }
1052
1053 if (d->expect_rc_inplace != rc) {
1054 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1055 " got rc=%zu, expected rc=%zu\n",
1056 i, rc, d->expect_rc_inplace);
1057 ok = false;
1058 }
1059 }
1060 }
1061
1062 OSMO_ASSERT(ok);
1063}
1064
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001065/* Copy of the examples from OSMO_STRBUF_APPEND() */
1066int print_spaces(char *dst, size_t dst_len, int argument)
1067{
1068 int i;
1069 if (argument < 0)
1070 return -EINVAL;
1071 for (i = 0; i < argument && i < dst_len; i++)
1072 dst[i] = ' ';
1073 if (dst_len)
1074 dst[OSMO_MIN(dst_len - 1, argument)] = '\0';
1075 return argument;
1076}
1077
1078void strbuf_example(char *buf, size_t buflen)
1079{
1080 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1081
1082 OSMO_STRBUF_APPEND(sb, print_spaces, 5);
1083 OSMO_STRBUF_APPEND(sb, snprintf, "The answer is %d but what is the question?", 42);
1084 OSMO_STRBUF_APPEND(sb, print_spaces, 423423);
1085
1086 printf("%s\n", buf);
1087 printf("would have needed %zu bytes\n", sb.chars_needed);
1088}
1089
1090/* Copy of the examples from OSMO_STRBUF_PRINTF() */
1091int strbuf_example2(char *buf, size_t buflen)
1092{
1093 int i;
1094 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1095
1096 OSMO_STRBUF_PRINTF(sb, "T minus");
1097 for (i = 10; i; i--)
1098 OSMO_STRBUF_PRINTF(sb, " %d", i);
1099 OSMO_STRBUF_PRINTF(sb, " ... Lift off!");
1100
1101 return sb.chars_needed;
1102}
1103
1104int strbuf_cascade(char *buf, size_t buflen)
1105{
1106 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1107
1108 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1109 OSMO_STRBUF_PRINTF(sb, " -- ");
1110 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1111 OSMO_STRBUF_PRINTF(sb, " -- ");
1112 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1113
1114 return sb.chars_needed;
1115}
1116
1117void strbuf_test()
1118{
1119 char buf[256];
1120 int rc;
1121 printf("\n%s\n", __func__);
1122
1123 printf("OSMO_STRBUF_APPEND():\n");
1124 strbuf_example(buf, 23);
1125
1126 printf("\nOSMO_STRBUF_PRINTF():\n");
1127 rc = strbuf_example2(buf, 23);
1128 printf("1: (need %d chars, had size=23) %s\n", rc, buf);
1129
1130 rc = strbuf_example2(buf, rc);
1131 printf("2: (need %d chars, had size=%d) %s\n", rc, rc, buf);
1132
1133 rc = strbuf_example2(buf, rc + 1);
1134 printf("3: (need %d chars, had size=%d+1) %s\n", rc, rc, buf);
1135
1136 rc = strbuf_example2(buf, 0);
1137 snprintf(buf, sizeof(buf), "0x2b 0x2b 0x2b...");
1138 printf("4: (need %d chars, had size=0) %s\n", rc, buf);
1139
1140 rc = strbuf_example2(NULL, 99);
1141 printf("5: (need %d chars, had NULL buffer)\n", rc);
1142
1143 printf("\ncascade:\n");
1144 rc = strbuf_cascade(buf, sizeof(buf));
1145 printf("(need %d chars)\n%s\n", rc, buf);
1146 rc = strbuf_cascade(buf, 63);
1147 printf("(need %d chars, had size=63) %s\n", rc, buf);
1148}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001149
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001150void strbuf_test_nolen()
1151{
1152 char buf[20];
1153 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1154 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1155 printf("\n%s\n", __func__);
1156
1157 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1158 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1159 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1160 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1161
1162 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1163 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1164 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1165}
1166
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001167static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1168{
1169 bool rc = osmo_str_startswith(str, startswith_str);
1170 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1171 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1172 if (rc != expect_rc)
1173 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1174}
1175
1176static void startswith_test()
1177{
1178 printf("\n%s()\n", __func__);
1179 startswith_test_str(NULL, NULL, true);
1180 startswith_test_str("", NULL, true);
1181 startswith_test_str(NULL, "", true);
1182 startswith_test_str("", "", true);
1183 startswith_test_str("abc", NULL, true);
1184 startswith_test_str("abc", "", true);
1185 startswith_test_str(NULL, "abc", false);
1186 startswith_test_str("", "abc", false);
1187 startswith_test_str("abc", "a", true);
1188 startswith_test_str("abc", "ab", true);
1189 startswith_test_str("abc", "abc", true);
1190 startswith_test_str("abc", "abcd", false);
1191 startswith_test_str("abc", "xyz", false);
1192}
1193
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001194static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1195{
1196 if (!arg)
1197 return -EINVAL;
1198 return snprintf(buf, buflen, "%s", arg);
1199}
1200
1201static char *foo_name_c(void *ctx, const char *arg)
1202{
1203 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1204}
1205
1206static char *foo_name_c_null(void *ctx, const char *arg)
1207{
1208 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1209}
1210
1211static char *foo_name_c_zero(void *ctx, const char *arg)
1212{
1213 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1214}
1215
1216static char *foo_name_c_zero_null(void *ctx, const char *arg)
1217{
1218 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1219}
1220
1221static void name_c_impl_test()
1222{
1223 char *test_strs[] = {
1224 "test",
1225 "longer than 10 chars",
1226 NULL,
1227 };
1228 struct {
1229 const char *label;
1230 char *(*func)(void *, const char*);
1231 } funcs[] = {
1232 {
1233 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1234 foo_name_c,
1235 },
1236 {
1237 "OSMO_NAME_C_IMPL(10, NULL)",
1238 foo_name_c_null,
1239 },
1240 {
1241 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1242 foo_name_c_zero,
1243 },
1244 {
1245 "OSMO_NAME_C_IMPL(0, NULL)",
1246 foo_name_c_zero_null,
1247 },
1248 };
1249
1250 int i;
1251 void *ctx = talloc_named_const(NULL, 0, __func__);
1252 int allocs = talloc_total_blocks(ctx);
1253
1254 printf("\n%s\n", __func__);
1255 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1256 char *test_str = test_strs[i];
1257 int j;
1258 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1259
1260 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1261 char *str = funcs[j].func(ctx, test_str);
1262 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1263 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1264 if (str) {
1265 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1266 talloc_free(str);
1267 }
1268 printf("\n");
1269 }
1270 }
1271 talloc_free(ctx);
1272}
1273
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001274static void osmo_print_n_test(void)
1275{
1276 struct token_test {
1277 const char *src;
1278 size_t token_len;
1279 size_t buf_size;
1280 const char *expect_token;
1281 int expect_rc;
1282 };
1283 struct token_test tests[] = {
1284 { "foo=bar", 3, 100, "foo", 3 },
1285 { "foo", 10, 100, "foo", 3 },
1286 { "foo", 3, 100, "foo", 3 },
1287 { NULL, 10, 100, "", 0 },
1288 { "", 10, 100, "", 0 },
1289 { "foo=bar", 0, 100, "", 0 },
1290
1291 { "foo=bar", 3, 2, "f", 3 },
1292 { "foo", 10, 2, "f", 3 },
1293 { "foo", 3, 2, "f", 3 },
1294 { NULL, 10, 2, "", 0 },
1295 { "", 10, 2, "", 0 },
1296 { "foo=bar", 0, 2, "", 0 },
1297
1298 { "foo=bar", 3, 1, "", 3 },
1299 { "foo", 10, 1, "", 3 },
1300 { "foo", 3, 1, "", 3 },
1301 { NULL, 10, 1, "", 0 },
1302 { "", 10, 1, "", 0 },
1303 { "foo=bar", 0, 1, "", 0 },
1304
1305 { "foo=bar", 3, 0, "unchanged", 3 },
1306 { "foo", 10, 0, "unchanged", 3 },
1307 { "foo", 3, 0, "unchanged", 3 },
1308 { NULL, 10, 0, "unchanged", 0 },
1309 { "", 10, 0, "unchanged", 0 },
1310 { "foo=bar", 0, 0, "unchanged", 0 },
1311 };
1312 struct token_test *t;
1313 printf("\n%s()\n", __func__);
1314 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1315 char buf[100] = "unchanged";
1316 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1317 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1318 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1319 if (strcmp(buf, t->expect_token))
1320 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1321 if (rc != t->expect_rc)
1322 printf(" ERROR: expected rc %d", t->expect_rc);
1323 printf("\n");
1324 }
1325}
1326
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001327static void osmo_strnchr_test(void)
1328{
1329 struct test {
1330 const char *haystack;
1331 size_t haystack_len;
1332 const char *needle;
1333 int expect_offset;
1334 };
1335 struct test tests[] = {
1336 { "foo=bar", 8, "=", 3 },
1337 { "foo=bar", 4, "=", 3 },
1338 { "foo=bar", 3, "=", -1 },
1339 { "foo=bar", 0, "=", -1 },
1340 { "foo\0=bar", 9, "=", -1 },
1341 { "foo\0=bar", 9, "\0", 3 },
1342 };
1343 struct test *t;
1344 printf("\n%s()\n", __func__);
1345 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1346 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1347 int offset = -1;
1348 if (r)
1349 offset = r - t->haystack;
1350 printf("osmo_strnchr(%s, %zu, ",
1351 osmo_quote_str(t->haystack, -1), t->haystack_len);
1352 printf("'%s') -> %d",
1353 osmo_escape_str(t->needle, 1), offset);
1354 if (offset != t->expect_offset)
1355 printf(" ERROR expected %d", t->expect_offset);
1356 printf("\n");
1357 }
1358}
1359
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001360int main(int argc, char **argv)
1361{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02001362 static const struct log_info log_info = {};
1363 log_init(&log_info, NULL);
1364
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001365 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01001366 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02001367 test_ipa_ccm_id_get_parsing();
1368 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02001369 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02001370 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01001371 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01001372 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02001373 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01001374 str_escape3_test();
1375 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02001376 isqrt_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001377 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001378 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001379 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001380 strbuf_test_nolen();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001381 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001382 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001383 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001384 osmo_strnchr_test();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001385 return 0;
1386}