blob: 9ff023bff3a64d390770656e938b4cb55c854849 [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;
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200778 int address_family; /* AF_INET / AF_INET6 */
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200779 bool omit_addr;
780 unsigned int expect_rc;
781 const char *expect_returned_addr;
782};
783
784struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
785 {
786 .port = 0,
787 .addr = "0.0.0.0",
788 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200789 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200790 .expect_rc = 7,
791 },
792 {
793 .port = 65535,
794 .addr = "255.255.255.255",
795 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200796 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200797 .expect_rc = 15,
798 },
799 {
800 .port = 1234,
801 .addr = "234.23.42.123",
802 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200803 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200804 .expect_rc = 13,
805 },
806 {
807 .port = 1234,
808 .addr = "234.23.42.123",
809 .addr_len = 10,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200810 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200811 .expect_rc = 13,
812 .expect_returned_addr = "234.23.42",
813 },
814 {
815 .port = 1234,
816 .omit_port = true,
817 .addr = "234.23.42.123",
818 .addr_len = 20,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200819 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200820 .expect_rc = 13,
821 },
822 {
823 .port = 1234,
824 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200825 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200826 .omit_addr = true,
827 .expect_rc = 0,
828 .expect_returned_addr = "",
829 },
830 {
831 .port = 1234,
832 .addr = "234.23.42.123",
833 .addr_len = 0,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200834 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200835 .expect_rc = 13,
836 .expect_returned_addr = "",
837 },
838 {
839 .port = 1234,
840 .addr = "234.23.42.123",
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200841 .address_family = AF_INET,
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200842 .omit_port = true,
843 .omit_addr = true,
844 .expect_rc = 0,
845 .expect_returned_addr = "",
846 },
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200847 {
848 .port = 1234,
849 .addr = "::",
850 .addr_len = 20,
851 .address_family = AF_INET6,
852 .expect_rc = 2,
853 },
854 {
855 .port = 1234,
856 .addr = "::1",
857 .addr_len = 20,
858 .address_family = AF_INET6,
859 .expect_rc = 3,
860 },
861 {
862 .port = 1234,
863 .addr = "::1",
864 .addr_len = 20,
865 .address_family = AF_INET6,
866 .omit_port = true,
867 .omit_addr = false,
868 .expect_rc = 3,
869 },
870 {
871 .port = 1234,
872 .addr = "::1",
873 .addr_len = 20,
874 .address_family = AF_INET6,
875 .omit_port = false,
876 .omit_addr = true,
877 .expect_rc = 0,
878 .expect_returned_addr = "",
879 },
880 {
881 .port = 1234,
882 .addr = "fd02:db8:1::1",
883 .addr_len = 20,
884 .address_family = AF_INET6,
885 .expect_rc = 13,
886 },
887 {
888 .port = 1234,
889 .addr = "2001:db8:1::ab9:C0A8:102",
890 .addr_len = 40,
891 .address_family = AF_INET6,
892 .expect_rc = 24,
893 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
894 },
895 {
896 .port = 1234,
897 .addr = "2001:0db8:0001:0000:0000:0ab9:C0A8:0102",
898 .addr_len = 32,
899 .address_family = AF_INET6,
900 .expect_rc = 24,
901 .expect_returned_addr = "2001:db8:1::ab9:c0a8:102",
902 },
903 {
904 .port = 1234,
905 .addr = "::ffff:192.168.20.34",
906 .addr_len = 32,
907 .address_family = AF_INET6,
908 .expect_rc = 20,
909 .expect_returned_addr = "::ffff:192.168.20.34",
910 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200911};
912
913static void osmo_sockaddr_to_str_and_uint_test(void)
914{
915 int i;
916 printf("\n%s\n", __func__);
917
918 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
919 struct osmo_sockaddr_to_str_and_uint_test_case *t =
920 &osmo_sockaddr_to_str_and_uint_test_data[i];
921
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200922 struct sockaddr_storage sa;
923 struct sockaddr_in *sin;
924 struct sockaddr_in6 *sin6;
925 sa.ss_family = t->address_family;
926 switch (t->address_family) {
927 case AF_INET:
928 sin = (struct sockaddr_in *)&sa;
929 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin->sin_addr) == 1);
930 sin->sin_port = htons(t->port);
931 break;
932 case AF_INET6:
933 sin6 = (struct sockaddr_in6 *)&sa;
934 OSMO_ASSERT(inet_pton(t->address_family, t->addr, &sin6->sin6_addr) == 1);
935 sin6->sin6_port = htons(t->port);
936 break;
937 default:
938 OSMO_ASSERT(0);
939 }
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200940
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200941 char addr[INET6_ADDRSTRLEN] = {};
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200942 uint16_t port = 0;
943 unsigned int rc;
944
945 rc = osmo_sockaddr_to_str_and_uint(
946 t->omit_addr? NULL : addr, t->addr_len,
947 t->omit_port? NULL : &port,
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200948 (const struct sockaddr *)&sa);
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200949
Pau Espin Pedrol1a3d24e2020-08-28 18:31:32 +0200950 printf("[%d] [%s]:%u%s%s addr_len=%u --> [%s]:%u rc=%u\n",
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200951 i,
952 t->addr ? : "-",
953 t->port,
954 t->omit_addr ? " (omit addr)" : "",
955 t->omit_port ? " (omit port)" : "",
956 t->addr_len,
957 addr, port, rc);
958 if (rc != t->expect_rc)
959 printf("ERROR: Expected rc = %u\n", t->expect_rc);
960 if (!t->expect_returned_addr)
961 t->expect_returned_addr = t->addr;
962 if (strcmp(t->expect_returned_addr, addr))
963 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
964 if (!t->omit_port && port != t->port)
965 printf("ERROR: Expected port = %u\n", t->port);
966 }
967}
968
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200969struct osmo_str_tolowupper_test_data {
970 const char *in;
971 bool use_static_buf;
972 size_t buflen;
973 const char *expect_lower;
974 const char *expect_upper;
975 size_t expect_rc;
976 size_t expect_rc_inplace;
977};
978
979struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
980 {
981 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
982 .use_static_buf = true,
983 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
984 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
985 },
986 {
987 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
988 .buflen = 99,
989 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
990 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
991 .expect_rc = 62,
992 .expect_rc_inplace = 62,
993 },
994 {
995 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
996 .buflen = 0,
997 .expect_lower = "Unset",
998 .expect_upper = "Unset",
999 .expect_rc = 62,
1000 .expect_rc_inplace = 0,
1001 },
1002 {
1003 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1004 .buflen = 1,
1005 .expect_lower = "",
1006 .expect_upper = "",
1007 .expect_rc = 62,
1008 .expect_rc_inplace = 0,
1009 },
1010 {
1011 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1012 .buflen = 2,
1013 .expect_lower = "a",
1014 .expect_upper = "A",
1015 .expect_rc = 62,
1016 .expect_rc_inplace = 1,
1017 },
1018 {
1019 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
1020 .buflen = 28,
1021 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
1022 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
1023 .expect_rc = 62,
1024 .expect_rc_inplace = 27,
1025 },
1026};
1027
1028
1029static void osmo_str_tolowupper_test()
1030{
1031 int i;
1032 char buf[128];
1033 bool ok = true;
1034 printf("\n%s\n", __func__);
1035
1036 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
1037 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
1038 size_t rc = 0;
1039 const char *res;
1040
1041 /* tolower */
1042 if (d->use_static_buf) {
1043 res = osmo_str_tolower(d->in);
1044 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
1045 printf(" = %s\n", osmo_quote_str(res, -1));
1046 } else {
1047 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1048 osmo_strlcpy(buf, "Unset", sizeof(buf));
1049 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
1050 res = buf;
1051 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1052 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1053 }
1054
1055 if (strcmp(res, d->expect_lower)) {
1056 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1057 " got %s\n", i, osmo_quote_str(res, -1));
1058 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1059 ok = false;
1060 }
1061
1062 if (!d->use_static_buf && d->expect_rc != rc) {
1063 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
1064 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1065 ok = false;
1066 }
1067
1068 /* tolower, in-place */
1069 if (!d->use_static_buf) {
1070 osmo_strlcpy(buf,
1071 d->buflen ? d->in : "Unset",
1072 sizeof(buf));
1073 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
1074 res = buf;
1075 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
1076 d->buflen, osmo_quote_str(d->in, -1));
1077 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1078
1079 if (strcmp(res, d->expect_lower)) {
1080 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1081 " got %s\n", i, osmo_quote_str(res, -1));
1082 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
1083 ok = false;
1084 }
1085
1086 if (d->expect_rc_inplace != rc) {
1087 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
1088 " got rc=%zu, expected rc=%zu\n",
1089 i, rc, d->expect_rc_inplace);
1090 ok = false;
1091 }
1092 }
1093
1094 /* toupper */
1095 if (d->use_static_buf) {
1096 res = osmo_str_toupper(d->in);
1097 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
1098 printf(" = %s\n", osmo_quote_str(res, -1));
1099 } else {
1100 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1101 osmo_strlcpy(buf, "Unset", sizeof(buf));
1102 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
1103 res = buf;
1104 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1105 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1106 }
1107
1108 if (strcmp(res, d->expect_upper)) {
1109 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1110 " got %s\n", i, osmo_quote_str(res, -1));
1111 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1112 ok = false;
1113 }
1114
1115 if (!d->use_static_buf && d->expect_rc != rc) {
1116 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1117 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1118 ok = false;
1119 }
1120
1121 /* toupper, in-place */
1122 if (!d->use_static_buf) {
1123 osmo_strlcpy(buf,
1124 d->buflen ? d->in : "Unset",
1125 sizeof(buf));
1126 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
1127 res = buf;
1128 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
1129 d->buflen, osmo_quote_str(d->in, -1));
1130 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1131
1132 if (strcmp(res, d->expect_upper)) {
1133 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1134 " got %s\n", i, osmo_quote_str(res, -1));
1135 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1136 ok = false;
1137 }
1138
1139 if (d->expect_rc_inplace != rc) {
1140 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1141 " got rc=%zu, expected rc=%zu\n",
1142 i, rc, d->expect_rc_inplace);
1143 ok = false;
1144 }
1145 }
1146 }
1147
1148 OSMO_ASSERT(ok);
1149}
1150
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001151/* Copy of the examples from OSMO_STRBUF_APPEND() */
1152int print_spaces(char *dst, size_t dst_len, int argument)
1153{
1154 int i;
1155 if (argument < 0)
1156 return -EINVAL;
1157 for (i = 0; i < argument && i < dst_len; i++)
1158 dst[i] = ' ';
1159 if (dst_len)
1160 dst[OSMO_MIN(dst_len - 1, argument)] = '\0';
1161 return argument;
1162}
1163
1164void strbuf_example(char *buf, size_t buflen)
1165{
1166 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1167
1168 OSMO_STRBUF_APPEND(sb, print_spaces, 5);
1169 OSMO_STRBUF_APPEND(sb, snprintf, "The answer is %d but what is the question?", 42);
1170 OSMO_STRBUF_APPEND(sb, print_spaces, 423423);
1171
1172 printf("%s\n", buf);
1173 printf("would have needed %zu bytes\n", sb.chars_needed);
1174}
1175
1176/* Copy of the examples from OSMO_STRBUF_PRINTF() */
1177int strbuf_example2(char *buf, size_t buflen)
1178{
1179 int i;
1180 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1181
1182 OSMO_STRBUF_PRINTF(sb, "T minus");
1183 for (i = 10; i; i--)
1184 OSMO_STRBUF_PRINTF(sb, " %d", i);
1185 OSMO_STRBUF_PRINTF(sb, " ... Lift off!");
1186
1187 return sb.chars_needed;
1188}
1189
1190int strbuf_cascade(char *buf, size_t buflen)
1191{
1192 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1193
1194 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1195 OSMO_STRBUF_PRINTF(sb, " -- ");
1196 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1197 OSMO_STRBUF_PRINTF(sb, " -- ");
1198 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1199
1200 return sb.chars_needed;
1201}
1202
1203void strbuf_test()
1204{
1205 char buf[256];
1206 int rc;
1207 printf("\n%s\n", __func__);
1208
1209 printf("OSMO_STRBUF_APPEND():\n");
1210 strbuf_example(buf, 23);
1211
1212 printf("\nOSMO_STRBUF_PRINTF():\n");
1213 rc = strbuf_example2(buf, 23);
1214 printf("1: (need %d chars, had size=23) %s\n", rc, buf);
1215
1216 rc = strbuf_example2(buf, rc);
1217 printf("2: (need %d chars, had size=%d) %s\n", rc, rc, buf);
1218
1219 rc = strbuf_example2(buf, rc + 1);
1220 printf("3: (need %d chars, had size=%d+1) %s\n", rc, rc, buf);
1221
1222 rc = strbuf_example2(buf, 0);
1223 snprintf(buf, sizeof(buf), "0x2b 0x2b 0x2b...");
1224 printf("4: (need %d chars, had size=0) %s\n", rc, buf);
1225
1226 rc = strbuf_example2(NULL, 99);
1227 printf("5: (need %d chars, had NULL buffer)\n", rc);
1228
1229 printf("\ncascade:\n");
1230 rc = strbuf_cascade(buf, sizeof(buf));
1231 printf("(need %d chars)\n%s\n", rc, buf);
1232 rc = strbuf_cascade(buf, 63);
1233 printf("(need %d chars, had size=63) %s\n", rc, buf);
1234}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001235
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001236void strbuf_test_nolen()
1237{
1238 char buf[20];
1239 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1240 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1241 printf("\n%s\n", __func__);
1242
1243 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1244 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1245 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1246 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1247
1248 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1249 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1250 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1251}
1252
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001253static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1254{
1255 bool rc = osmo_str_startswith(str, startswith_str);
1256 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1257 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1258 if (rc != expect_rc)
1259 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1260}
1261
1262static void startswith_test()
1263{
1264 printf("\n%s()\n", __func__);
1265 startswith_test_str(NULL, NULL, true);
1266 startswith_test_str("", NULL, true);
1267 startswith_test_str(NULL, "", true);
1268 startswith_test_str("", "", true);
1269 startswith_test_str("abc", NULL, true);
1270 startswith_test_str("abc", "", true);
1271 startswith_test_str(NULL, "abc", false);
1272 startswith_test_str("", "abc", false);
1273 startswith_test_str("abc", "a", true);
1274 startswith_test_str("abc", "ab", true);
1275 startswith_test_str("abc", "abc", true);
1276 startswith_test_str("abc", "abcd", false);
1277 startswith_test_str("abc", "xyz", false);
1278}
1279
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001280static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1281{
1282 if (!arg)
1283 return -EINVAL;
1284 return snprintf(buf, buflen, "%s", arg);
1285}
1286
1287static char *foo_name_c(void *ctx, const char *arg)
1288{
1289 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1290}
1291
1292static char *foo_name_c_null(void *ctx, const char *arg)
1293{
1294 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1295}
1296
1297static char *foo_name_c_zero(void *ctx, const char *arg)
1298{
1299 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1300}
1301
1302static char *foo_name_c_zero_null(void *ctx, const char *arg)
1303{
1304 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1305}
1306
1307static void name_c_impl_test()
1308{
1309 char *test_strs[] = {
1310 "test",
1311 "longer than 10 chars",
1312 NULL,
1313 };
1314 struct {
1315 const char *label;
1316 char *(*func)(void *, const char*);
1317 } funcs[] = {
1318 {
1319 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1320 foo_name_c,
1321 },
1322 {
1323 "OSMO_NAME_C_IMPL(10, NULL)",
1324 foo_name_c_null,
1325 },
1326 {
1327 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1328 foo_name_c_zero,
1329 },
1330 {
1331 "OSMO_NAME_C_IMPL(0, NULL)",
1332 foo_name_c_zero_null,
1333 },
1334 };
1335
1336 int i;
1337 void *ctx = talloc_named_const(NULL, 0, __func__);
1338 int allocs = talloc_total_blocks(ctx);
1339
1340 printf("\n%s\n", __func__);
1341 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1342 char *test_str = test_strs[i];
1343 int j;
1344 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1345
1346 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1347 char *str = funcs[j].func(ctx, test_str);
1348 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1349 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1350 if (str) {
1351 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1352 talloc_free(str);
1353 }
1354 printf("\n");
1355 }
1356 }
1357 talloc_free(ctx);
1358}
1359
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001360static void osmo_print_n_test(void)
1361{
1362 struct token_test {
1363 const char *src;
1364 size_t token_len;
1365 size_t buf_size;
1366 const char *expect_token;
1367 int expect_rc;
1368 };
1369 struct token_test tests[] = {
1370 { "foo=bar", 3, 100, "foo", 3 },
1371 { "foo", 10, 100, "foo", 3 },
1372 { "foo", 3, 100, "foo", 3 },
1373 { NULL, 10, 100, "", 0 },
1374 { "", 10, 100, "", 0 },
1375 { "foo=bar", 0, 100, "", 0 },
1376
1377 { "foo=bar", 3, 2, "f", 3 },
1378 { "foo", 10, 2, "f", 3 },
1379 { "foo", 3, 2, "f", 3 },
1380 { NULL, 10, 2, "", 0 },
1381 { "", 10, 2, "", 0 },
1382 { "foo=bar", 0, 2, "", 0 },
1383
1384 { "foo=bar", 3, 1, "", 3 },
1385 { "foo", 10, 1, "", 3 },
1386 { "foo", 3, 1, "", 3 },
1387 { NULL, 10, 1, "", 0 },
1388 { "", 10, 1, "", 0 },
1389 { "foo=bar", 0, 1, "", 0 },
1390
1391 { "foo=bar", 3, 0, "unchanged", 3 },
1392 { "foo", 10, 0, "unchanged", 3 },
1393 { "foo", 3, 0, "unchanged", 3 },
1394 { NULL, 10, 0, "unchanged", 0 },
1395 { "", 10, 0, "unchanged", 0 },
1396 { "foo=bar", 0, 0, "unchanged", 0 },
1397 };
1398 struct token_test *t;
1399 printf("\n%s()\n", __func__);
1400 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1401 char buf[100] = "unchanged";
1402 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1403 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1404 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1405 if (strcmp(buf, t->expect_token))
1406 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1407 if (rc != t->expect_rc)
1408 printf(" ERROR: expected rc %d", t->expect_rc);
1409 printf("\n");
1410 }
1411}
1412
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001413static void osmo_strnchr_test(void)
1414{
1415 struct test {
1416 const char *haystack;
1417 size_t haystack_len;
1418 const char *needle;
1419 int expect_offset;
1420 };
1421 struct test tests[] = {
1422 { "foo=bar", 8, "=", 3 },
1423 { "foo=bar", 4, "=", 3 },
1424 { "foo=bar", 3, "=", -1 },
1425 { "foo=bar", 0, "=", -1 },
1426 { "foo\0=bar", 9, "=", -1 },
1427 { "foo\0=bar", 9, "\0", 3 },
1428 };
1429 struct test *t;
1430 printf("\n%s()\n", __func__);
1431 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1432 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1433 int offset = -1;
1434 if (r)
1435 offset = r - t->haystack;
1436 printf("osmo_strnchr(%s, %zu, ",
1437 osmo_quote_str(t->haystack, -1), t->haystack_len);
1438 printf("'%s') -> %d",
1439 osmo_escape_str(t->needle, 1), offset);
1440 if (offset != t->expect_offset)
1441 printf(" ERROR expected %d", t->expect_offset);
1442 printf("\n");
1443 }
1444}
1445
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001446int main(int argc, char **argv)
1447{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02001448 static const struct log_info log_info = {};
1449 log_init(&log_info, NULL);
1450
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001451 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01001452 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02001453 test_ipa_ccm_id_get_parsing();
1454 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02001455 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02001456 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01001457 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01001458 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02001459 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01001460 str_escape3_test();
1461 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02001462 isqrt_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001463 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001464 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001465 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001466 strbuf_test_nolen();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001467 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001468 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001469 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001470 osmo_strnchr_test();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001471 return 0;
1472}