blob: e87cb22f8b1776e77b38828dd3e372aa30d3b271 [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];
490 int rc;
491
492 printf("\nTesting bcd to string conversion\n");
493
494 for (i = 0; i < ARRAY_SIZE(bcd2str_tests); i++) {
495 const struct bcd2str_test *t = &bcd2str_tests[i];
496 char str[64] = {};
497 size_t str_size = t->str_size ? : sizeof(str);
498
499 osmo_hexparse(t->bcd_hex, bcd, sizeof(bcd));
500
501 printf("- BCD-input='%s' nibbles=[%d..%d[ str_size=%zu\n", t->bcd_hex,
502 t->start_nibble, t->end_nibble, str_size);
503 rc = osmo_bcd2str(str, str_size, bcd, t->start_nibble, t->end_nibble, t->allow_hex);
504
505 printf(" rc=%d\n", rc);
506
507 OSMO_ASSERT(str[str_size-1] == '\0');
508 printf(" -> %s\n", osmo_quote_str(str, -1));
509
510 if (rc != t->expect_rc)
511 printf(" ERROR: expected rc=%d\n", t->expect_rc);
512 if (strcmp(str, t->expect_str))
513 printf(" ERROR: expected result %s\n", osmo_quote_str(t->expect_str, -1));
514 }
515
516 printf("- zero output buffer\n");
517 rc = osmo_bcd2str(NULL, 100, bcd, 1, 2, false);
518 printf(" bcd2str(NULL, ...) -> %d\n", rc);
519 OSMO_ASSERT(rc < 0);
520 rc = osmo_bcd2str((char*)23, 0, bcd, 1, 2, false);
521 printf(" bcd2str(dst, 0, ...) -> %d\n", rc);
522 OSMO_ASSERT(rc < 0);
523}
524
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100525static void str_escape_test(void)
526{
527 int i;
528 int j;
529 uint8_t in_buf[32];
530 char out_buf[11];
531 const char *printable = "printable";
532 const char *res;
533
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100534 printf("\nTesting string escaping: osmo_escape_str()\n");
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100535 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100536 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100537 for (j = 0; j < 16; j++) {
538 for (i = 0; i < 16; i++)
539 in_buf[i] = (j << 4) | i;
540 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
541 }
542
543 printf("- nul terminated:\n");
544 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
545
546 printf("- passthru:\n");
547 res = osmo_escape_str(printable, -1);
Harald Welte98ed3392019-03-28 13:26:53 +0100548 if (strcmp(res, printable))
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100549 printf("NOT passed through! \"%s\"\n", res);
550 else
551 printf("passed through unchanged \"%s\"\n", res);
552
553 printf("- zero length:\n");
554 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
555
556 printf("- truncation when too long:\n");
557 memset(in_buf, 'x', sizeof(in_buf));
558 in_buf[0] = '\a';
559 in_buf[7] = 'E';
560 memset(out_buf, 0x7f, sizeof(out_buf));
561 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
562 OSMO_ASSERT(out_buf[10] == 0x7f);
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100563}
564
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200565static void str_quote_test(void)
566{
567 int i;
568 int j;
569 uint8_t in_buf[32];
570 char out_buf[11];
571 const char *printable = "printable";
572 const char *res;
573
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100574 printf("\nTesting string quoting: osmo_quote_str()\n");
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200575 printf("- all chars from 0 to 255 in batches of 16:\n");
576 in_buf[16] = '\0';
577 for (j = 0; j < 16; j++) {
578 for (i = 0; i < 16; i++)
579 in_buf[i] = (j << 4) | i;
580 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
581 }
582
583 printf("- nul terminated:\n");
584 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
585
586 printf("- never passthru:\n");
587 res = osmo_quote_str(printable, -1);
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100588 if (strcmp(res, printable))
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200589 printf("NOT passed through. '%s'\n", res);
590 else
591 printf("passed through unchanged '%s'\n", res);
592
593 printf("- zero length:\n");
594 printf("'%s'\n", osmo_quote_str("omitted", 0));
595
596 printf("- truncation when too long:\n");
597 memset(in_buf, 'x', sizeof(in_buf));
598 in_buf[0] = '\a';
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100599 in_buf[6] = 'E';
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200600 memset(out_buf, 0x7f, sizeof(out_buf));
601 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
602 OSMO_ASSERT(out_buf[10] == 0x7f);
603
604 printf("- always truncation, even when no escaping needed:\n");
605 memset(in_buf, 'x', sizeof(in_buf));
Neels Hofmeyrecef7ec2019-03-05 16:42:50 +0100606 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 +0200607 in_buf[20] = '\0';
608 memset(out_buf, 0x7f, sizeof(out_buf));
609 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
610 OSMO_ASSERT(out_buf[0] == '"');
611
612 printf("- try to feed too little buf for quoting:\n");
613 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
614
615 printf("- NULL string becomes a \"NULL\" literal:\n");
616 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
617}
618
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +0100619static void str_escape3_test(void)
620{
621 int i;
622 int j;
623 uint8_t in_buf[32];
624 char out_buf[11];
625 const char *printable = "printable";
626 const char *res;
627 void *ctx = talloc_named_const(NULL, 0, __func__);
628
629 printf("\nTesting string escaping: osmo_escape_cstr_buf()\n");
630 printf("- all chars from 0 to 255 in batches of 16:\n");
631 in_buf[16] = '\0';
632 for (j = 0; j < 16; j++) {
633 for (i = 0; i < 16; i++)
634 in_buf[i] = (j << 4) | i;
635 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, (const char*)in_buf, 16));
636 }
637
638 printf("- nul terminated:\n");
639 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "termi\nated", -1));
640
641 printf("- passthru:\n");
642 res = osmo_escape_cstr_c(ctx, printable, -1);
643 if (strcmp(res, printable))
644 printf("NOT passed through! \"%s\"\n", res);
645 else
646 printf("passed through unchanged \"%s\"\n", res);
647
648 printf("- zero length:\n");
649 printf("\"%s\"\n", osmo_escape_cstr_c(ctx, "omitted", 0));
650
651 printf("- truncation when too long:\n");
652 memset(in_buf, 'x', sizeof(in_buf));
653 in_buf[0] = '\a';
654 in_buf[7] = 'E';
655 memset(out_buf, 0x7f, sizeof(out_buf));
656 osmo_escape_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
657 printf("\"%s\"\n", out_buf);
658 OSMO_ASSERT(out_buf[10] == 0x7f);
659
660 printf("- Test escaping an escaped string:\n");
661 res = "\x02\x03\n";
662 for (i = 0; i <= 3; i++) {
663 res = osmo_escape_cstr_c(ctx, res, -1);
664 printf("%d: '%s'\n", i, res);
665 }
666
667 talloc_free(ctx);
668}
669
670static void str_quote3_test(void)
671{
672 int i;
673 int j;
674 uint8_t in_buf[32];
675 char out_buf[11];
676 const char *printable = "printable";
677 const char *res;
678 void *ctx = talloc_named_const(NULL, 0, __func__);
679
680 printf("\nTesting string quoting: osmo_quote_cstr_buf()\n");
681 printf("- all chars from 0 to 255 in batches of 16:\n");
682 in_buf[16] = '\0';
683 for (j = 0; j < 16; j++) {
684 for (i = 0; i < 16; i++)
685 in_buf[i] = (j << 4) | i;
686 printf("%s\n", osmo_quote_cstr_c(ctx, (const char*)in_buf, 16));
687 }
688
689 printf("- nul terminated:\n");
690 printf("'%s'\n", osmo_quote_cstr_c(ctx, "termi\nated", -1));
691
692 printf("- never passthru:\n");
693 res = osmo_quote_cstr_c(ctx, printable, -1);
694 if (strcmp(res, printable))
695 printf("NOT passed through. '%s'\n", res);
696 else
697 printf("passed through unchanged '%s'\n", res);
698
699 printf("- zero length:\n");
700 printf("'%s'\n", osmo_quote_cstr_c(ctx, "omitted", 0));
701
702 printf("- truncation when too long:\n");
703 memset(in_buf, 'x', sizeof(in_buf));
704 in_buf[0] = '\a';
705 in_buf[6] = 'E';
706 memset(out_buf, 0x7f, sizeof(out_buf));
707 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, sizeof(in_buf));
708 printf("'%s'\n", out_buf);
709 OSMO_ASSERT(out_buf[10] == 0x7f);
710
711 printf("- always truncation, even when no escaping needed:\n");
712 memset(in_buf, 'x', sizeof(in_buf));
713 in_buf[7] = 'E'; /* dst has 10, less 1 quote and nul, leaves 8, i.e. in[7] is last */
714 in_buf[20] = '\0';
715 memset(out_buf, 0x7f, sizeof(out_buf));
716 osmo_quote_cstr_buf(out_buf, 10, (const char *)in_buf, -1);
717 printf("'%s'\n", out_buf);
718 OSMO_ASSERT(out_buf[0] == '"');
719 OSMO_ASSERT(out_buf[10] == 0x7f);
720
721 printf("- try to feed too little buf for quoting:\n");
722 osmo_quote_cstr_buf(out_buf, 2, "", -1);
723 printf("'%s'\n", out_buf);
724
725 printf("- Test quoting a quoted+escaped string:\n");
726 res = "\x02\x03\n";
727 for (i = 0; i <= 3; i++) {
728 res = osmo_quote_cstr_c(ctx, res, -1);
729 printf("%d: %s\n", i, res);
730 }
731
732 printf("- Test C-string equivalence:\n");
733#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"
734#define EMPTY_STR ""
735 printf("strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)) == %d\n",
736 strcmp(OSMO_STRINGIFY_VAL(TEST_STR), osmo_quote_cstr_c(ctx, TEST_STR, 256)));
737 printf("strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)) == %d\n",
738 strcmp(OSMO_STRINGIFY_VAL(EMPTY_STR), osmo_quote_cstr_c(ctx, EMPTY_STR, -1)));
739 printf("strcmp(\"NULL\", osmo_quote_cstr_c(ctx, NULL, -1)) == %d\n",
740 strcmp("NULL", osmo_quote_cstr_c(ctx, NULL, -1)));
741
742 talloc_free(ctx);
743}
744
Harald Welte15a5f8d2018-06-06 16:58:17 +0200745static void isqrt_test(void)
746{
747 int i;
748
749 printf("\nTesting integer square-root\n");
750 srand(time(NULL));
751 for (i = 0; i < 1024; i++) {
752 uint16_t x;
753 uint32_t r = rand();
754 if (RAND_MAX < UINT16_MAX)
755 x = r * (UINT16_MAX/RAND_MAX);
756 else
757 x = r;
Neels Hofmeyr6979c542018-07-19 22:05:21 +0200758 uint32_t sq = (uint32_t)x*x;
Harald Welte15a5f8d2018-06-06 16:58:17 +0200759 uint32_t y = osmo_isqrt32(sq);
760 if (y != x)
761 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
762 }
763}
764
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200765
766struct osmo_sockaddr_to_str_and_uint_test_case {
767 uint16_t port;
768 bool omit_port;
769 const char *addr;
770 unsigned int addr_len;
771 bool omit_addr;
772 unsigned int expect_rc;
773 const char *expect_returned_addr;
774};
775
776struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
777 {
778 .port = 0,
779 .addr = "0.0.0.0",
780 .addr_len = 20,
781 .expect_rc = 7,
782 },
783 {
784 .port = 65535,
785 .addr = "255.255.255.255",
786 .addr_len = 20,
787 .expect_rc = 15,
788 },
789 {
790 .port = 1234,
791 .addr = "234.23.42.123",
792 .addr_len = 20,
793 .expect_rc = 13,
794 },
795 {
796 .port = 1234,
797 .addr = "234.23.42.123",
798 .addr_len = 10,
799 .expect_rc = 13,
800 .expect_returned_addr = "234.23.42",
801 },
802 {
803 .port = 1234,
804 .omit_port = true,
805 .addr = "234.23.42.123",
806 .addr_len = 20,
807 .expect_rc = 13,
808 },
809 {
810 .port = 1234,
811 .addr = "234.23.42.123",
812 .omit_addr = true,
813 .expect_rc = 0,
814 .expect_returned_addr = "",
815 },
816 {
817 .port = 1234,
818 .addr = "234.23.42.123",
819 .addr_len = 0,
820 .expect_rc = 13,
821 .expect_returned_addr = "",
822 },
823 {
824 .port = 1234,
825 .addr = "234.23.42.123",
826 .omit_port = true,
827 .omit_addr = true,
828 .expect_rc = 0,
829 .expect_returned_addr = "",
830 },
831};
832
833static void osmo_sockaddr_to_str_and_uint_test(void)
834{
835 int i;
836 printf("\n%s\n", __func__);
837
838 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
839 struct osmo_sockaddr_to_str_and_uint_test_case *t =
840 &osmo_sockaddr_to_str_and_uint_test_data[i];
841
842 struct sockaddr_in sin = {
843 .sin_family = AF_INET,
844 .sin_port = htons(t->port),
845 };
846 inet_aton(t->addr, &sin.sin_addr);
847
848 char addr[20] = {};
849 uint16_t port = 0;
850 unsigned int rc;
851
852 rc = osmo_sockaddr_to_str_and_uint(
853 t->omit_addr? NULL : addr, t->addr_len,
854 t->omit_port? NULL : &port,
855 (const struct sockaddr*)&sin);
856
857 printf("[%d] %s:%u%s%s addr_len=%u --> %s:%u rc=%u\n",
858 i,
859 t->addr ? : "-",
860 t->port,
861 t->omit_addr ? " (omit addr)" : "",
862 t->omit_port ? " (omit port)" : "",
863 t->addr_len,
864 addr, port, rc);
865 if (rc != t->expect_rc)
866 printf("ERROR: Expected rc = %u\n", t->expect_rc);
867 if (!t->expect_returned_addr)
868 t->expect_returned_addr = t->addr;
869 if (strcmp(t->expect_returned_addr, addr))
870 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
871 if (!t->omit_port && port != t->port)
872 printf("ERROR: Expected port = %u\n", t->port);
873 }
874}
875
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200876struct osmo_str_tolowupper_test_data {
877 const char *in;
878 bool use_static_buf;
879 size_t buflen;
880 const char *expect_lower;
881 const char *expect_upper;
882 size_t expect_rc;
883 size_t expect_rc_inplace;
884};
885
886struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
887 {
888 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
889 .use_static_buf = true,
890 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
891 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
892 },
893 {
894 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
895 .buflen = 99,
896 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
897 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
898 .expect_rc = 62,
899 .expect_rc_inplace = 62,
900 },
901 {
902 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
903 .buflen = 0,
904 .expect_lower = "Unset",
905 .expect_upper = "Unset",
906 .expect_rc = 62,
907 .expect_rc_inplace = 0,
908 },
909 {
910 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
911 .buflen = 1,
912 .expect_lower = "",
913 .expect_upper = "",
914 .expect_rc = 62,
915 .expect_rc_inplace = 0,
916 },
917 {
918 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
919 .buflen = 2,
920 .expect_lower = "a",
921 .expect_upper = "A",
922 .expect_rc = 62,
923 .expect_rc_inplace = 1,
924 },
925 {
926 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
927 .buflen = 28,
928 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
929 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
930 .expect_rc = 62,
931 .expect_rc_inplace = 27,
932 },
933};
934
935
936static void osmo_str_tolowupper_test()
937{
938 int i;
939 char buf[128];
940 bool ok = true;
941 printf("\n%s\n", __func__);
942
943 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
944 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
945 size_t rc = 0;
946 const char *res;
947
948 /* tolower */
949 if (d->use_static_buf) {
950 res = osmo_str_tolower(d->in);
951 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
952 printf(" = %s\n", osmo_quote_str(res, -1));
953 } else {
954 OSMO_ASSERT(sizeof(buf) >= d->buflen);
955 osmo_strlcpy(buf, "Unset", sizeof(buf));
956 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
957 res = buf;
958 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
959 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
960 }
961
962 if (strcmp(res, d->expect_lower)) {
963 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
964 " got %s\n", i, osmo_quote_str(res, -1));
965 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
966 ok = false;
967 }
968
969 if (!d->use_static_buf && d->expect_rc != rc) {
970 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
971 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
972 ok = false;
973 }
974
975 /* tolower, in-place */
976 if (!d->use_static_buf) {
977 osmo_strlcpy(buf,
978 d->buflen ? d->in : "Unset",
979 sizeof(buf));
980 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
981 res = buf;
982 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
983 d->buflen, osmo_quote_str(d->in, -1));
984 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
985
986 if (strcmp(res, d->expect_lower)) {
987 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
988 " got %s\n", i, osmo_quote_str(res, -1));
989 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
990 ok = false;
991 }
992
993 if (d->expect_rc_inplace != rc) {
994 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
995 " got rc=%zu, expected rc=%zu\n",
996 i, rc, d->expect_rc_inplace);
997 ok = false;
998 }
999 }
1000
1001 /* toupper */
1002 if (d->use_static_buf) {
1003 res = osmo_str_toupper(d->in);
1004 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
1005 printf(" = %s\n", osmo_quote_str(res, -1));
1006 } else {
1007 OSMO_ASSERT(sizeof(buf) >= d->buflen);
1008 osmo_strlcpy(buf, "Unset", sizeof(buf));
1009 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
1010 res = buf;
1011 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
1012 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1013 }
1014
1015 if (strcmp(res, d->expect_upper)) {
1016 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1017 " got %s\n", i, osmo_quote_str(res, -1));
1018 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1019 ok = false;
1020 }
1021
1022 if (!d->use_static_buf && d->expect_rc != rc) {
1023 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
1024 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
1025 ok = false;
1026 }
1027
1028 /* toupper, in-place */
1029 if (!d->use_static_buf) {
1030 osmo_strlcpy(buf,
1031 d->buflen ? d->in : "Unset",
1032 sizeof(buf));
1033 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
1034 res = buf;
1035 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
1036 d->buflen, osmo_quote_str(d->in, -1));
1037 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
1038
1039 if (strcmp(res, d->expect_upper)) {
1040 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1041 " got %s\n", i, osmo_quote_str(res, -1));
1042 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
1043 ok = false;
1044 }
1045
1046 if (d->expect_rc_inplace != rc) {
1047 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
1048 " got rc=%zu, expected rc=%zu\n",
1049 i, rc, d->expect_rc_inplace);
1050 ok = false;
1051 }
1052 }
1053 }
1054
1055 OSMO_ASSERT(ok);
1056}
1057
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001058/* Copy of the examples from OSMO_STRBUF_APPEND() */
1059int print_spaces(char *dst, size_t dst_len, int argument)
1060{
1061 int i;
1062 if (argument < 0)
1063 return -EINVAL;
1064 for (i = 0; i < argument && i < dst_len; i++)
1065 dst[i] = ' ';
1066 if (dst_len)
1067 dst[OSMO_MIN(dst_len - 1, argument)] = '\0';
1068 return argument;
1069}
1070
1071void strbuf_example(char *buf, size_t buflen)
1072{
1073 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1074
1075 OSMO_STRBUF_APPEND(sb, print_spaces, 5);
1076 OSMO_STRBUF_APPEND(sb, snprintf, "The answer is %d but what is the question?", 42);
1077 OSMO_STRBUF_APPEND(sb, print_spaces, 423423);
1078
1079 printf("%s\n", buf);
1080 printf("would have needed %zu bytes\n", sb.chars_needed);
1081}
1082
1083/* Copy of the examples from OSMO_STRBUF_PRINTF() */
1084int strbuf_example2(char *buf, size_t buflen)
1085{
1086 int i;
1087 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1088
1089 OSMO_STRBUF_PRINTF(sb, "T minus");
1090 for (i = 10; i; i--)
1091 OSMO_STRBUF_PRINTF(sb, " %d", i);
1092 OSMO_STRBUF_PRINTF(sb, " ... Lift off!");
1093
1094 return sb.chars_needed;
1095}
1096
1097int strbuf_cascade(char *buf, size_t buflen)
1098{
1099 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
1100
1101 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1102 OSMO_STRBUF_PRINTF(sb, " -- ");
1103 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1104 OSMO_STRBUF_PRINTF(sb, " -- ");
1105 OSMO_STRBUF_APPEND(sb, strbuf_example2);
1106
1107 return sb.chars_needed;
1108}
1109
1110void strbuf_test()
1111{
1112 char buf[256];
1113 int rc;
1114 printf("\n%s\n", __func__);
1115
1116 printf("OSMO_STRBUF_APPEND():\n");
1117 strbuf_example(buf, 23);
1118
1119 printf("\nOSMO_STRBUF_PRINTF():\n");
1120 rc = strbuf_example2(buf, 23);
1121 printf("1: (need %d chars, had size=23) %s\n", rc, buf);
1122
1123 rc = strbuf_example2(buf, rc);
1124 printf("2: (need %d chars, had size=%d) %s\n", rc, rc, buf);
1125
1126 rc = strbuf_example2(buf, rc + 1);
1127 printf("3: (need %d chars, had size=%d+1) %s\n", rc, rc, buf);
1128
1129 rc = strbuf_example2(buf, 0);
1130 snprintf(buf, sizeof(buf), "0x2b 0x2b 0x2b...");
1131 printf("4: (need %d chars, had size=0) %s\n", rc, buf);
1132
1133 rc = strbuf_example2(NULL, 99);
1134 printf("5: (need %d chars, had NULL buffer)\n", rc);
1135
1136 printf("\ncascade:\n");
1137 rc = strbuf_cascade(buf, sizeof(buf));
1138 printf("(need %d chars)\n%s\n", rc, buf);
1139 rc = strbuf_cascade(buf, 63);
1140 printf("(need %d chars, had size=63) %s\n", rc, buf);
1141}
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001142
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001143void strbuf_test_nolen()
1144{
1145 char buf[20];
1146 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
1147 uint8_t ubits[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0};
1148 printf("\n%s\n", __func__);
1149
1150 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1151 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1152 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1153 printf("more: %s (need=%zu)\n", buf, sb.chars_needed);
1154
1155 sb = (struct osmo_strbuf){ .buf = buf, .len = 10 };
1156 OSMO_STRBUF_APPEND_NOLEN(sb, osmo_ubit_dump_buf, ubits, sizeof(ubits));
1157 printf("%zu: %s (need=%zu)\n", sb.len, buf, sb.chars_needed);
1158}
1159
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001160static void startswith_test_str(const char *str, const char *startswith_str, bool expect_rc)
1161{
1162 bool rc = osmo_str_startswith(str, startswith_str);
1163 printf("osmo_str_startswith(%s, ", osmo_quote_str(str, -1));
1164 printf("%s) == %s\n", osmo_quote_str(startswith_str, -1), rc ? "true" : "false");
1165 if (rc != expect_rc)
1166 printf(" ERROR: EXPECTED %s\n", expect_rc ? "true" : "false");
1167}
1168
1169static void startswith_test()
1170{
1171 printf("\n%s()\n", __func__);
1172 startswith_test_str(NULL, NULL, true);
1173 startswith_test_str("", NULL, true);
1174 startswith_test_str(NULL, "", true);
1175 startswith_test_str("", "", true);
1176 startswith_test_str("abc", NULL, true);
1177 startswith_test_str("abc", "", true);
1178 startswith_test_str(NULL, "abc", false);
1179 startswith_test_str("", "abc", false);
1180 startswith_test_str("abc", "a", true);
1181 startswith_test_str("abc", "ab", true);
1182 startswith_test_str("abc", "abc", true);
1183 startswith_test_str("abc", "abcd", false);
1184 startswith_test_str("abc", "xyz", false);
1185}
1186
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001187static int foo_name_buf(char *buf, size_t buflen, const char *arg)
1188{
1189 if (!arg)
1190 return -EINVAL;
1191 return snprintf(buf, buflen, "%s", arg);
1192}
1193
1194static char *foo_name_c(void *ctx, const char *arg)
1195{
1196 OSMO_NAME_C_IMPL(ctx, 10, "ERROR", foo_name_buf, arg)
1197}
1198
1199static char *foo_name_c_null(void *ctx, const char *arg)
1200{
1201 OSMO_NAME_C_IMPL(ctx, 10, NULL, foo_name_buf, arg)
1202}
1203
1204static char *foo_name_c_zero(void *ctx, const char *arg)
1205{
1206 OSMO_NAME_C_IMPL(ctx, 0, "ERROR", foo_name_buf, arg)
1207}
1208
1209static char *foo_name_c_zero_null(void *ctx, const char *arg)
1210{
1211 OSMO_NAME_C_IMPL(ctx, 0, NULL, foo_name_buf, arg)
1212}
1213
1214static void name_c_impl_test()
1215{
1216 char *test_strs[] = {
1217 "test",
1218 "longer than 10 chars",
1219 NULL,
1220 };
1221 struct {
1222 const char *label;
1223 char *(*func)(void *, const char*);
1224 } funcs[] = {
1225 {
1226 "OSMO_NAME_C_IMPL(10, \"ERROR\")",
1227 foo_name_c,
1228 },
1229 {
1230 "OSMO_NAME_C_IMPL(10, NULL)",
1231 foo_name_c_null,
1232 },
1233 {
1234 "OSMO_NAME_C_IMPL(0, \"ERROR\")",
1235 foo_name_c_zero,
1236 },
1237 {
1238 "OSMO_NAME_C_IMPL(0, NULL)",
1239 foo_name_c_zero_null,
1240 },
1241 };
1242
1243 int i;
1244 void *ctx = talloc_named_const(NULL, 0, __func__);
1245 int allocs = talloc_total_blocks(ctx);
1246
1247 printf("\n%s\n", __func__);
1248 for (i = 0; i < ARRAY_SIZE(test_strs); i++) {
1249 char *test_str = test_strs[i];
1250 int j;
1251 printf("%2d: %s\n", i, osmo_quote_str(test_str, -1));
1252
1253 for (j = 0; j < ARRAY_SIZE(funcs); j++) {
1254 char *str = funcs[j].func(ctx, test_str);
1255 printf(" %30s -> %s", funcs[j].label, osmo_quote_str(str, -1));
1256 printf(" allocated %d", (int)talloc_total_blocks(ctx) - allocs);
1257 if (str) {
1258 printf(" %zu bytes, name '%s'", talloc_total_size(str), talloc_get_name(str));
1259 talloc_free(str);
1260 }
1261 printf("\n");
1262 }
1263 }
1264 talloc_free(ctx);
1265}
1266
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001267static void osmo_print_n_test(void)
1268{
1269 struct token_test {
1270 const char *src;
1271 size_t token_len;
1272 size_t buf_size;
1273 const char *expect_token;
1274 int expect_rc;
1275 };
1276 struct token_test tests[] = {
1277 { "foo=bar", 3, 100, "foo", 3 },
1278 { "foo", 10, 100, "foo", 3 },
1279 { "foo", 3, 100, "foo", 3 },
1280 { NULL, 10, 100, "", 0 },
1281 { "", 10, 100, "", 0 },
1282 { "foo=bar", 0, 100, "", 0 },
1283
1284 { "foo=bar", 3, 2, "f", 3 },
1285 { "foo", 10, 2, "f", 3 },
1286 { "foo", 3, 2, "f", 3 },
1287 { NULL, 10, 2, "", 0 },
1288 { "", 10, 2, "", 0 },
1289 { "foo=bar", 0, 2, "", 0 },
1290
1291 { "foo=bar", 3, 1, "", 3 },
1292 { "foo", 10, 1, "", 3 },
1293 { "foo", 3, 1, "", 3 },
1294 { NULL, 10, 1, "", 0 },
1295 { "", 10, 1, "", 0 },
1296 { "foo=bar", 0, 1, "", 0 },
1297
1298 { "foo=bar", 3, 0, "unchanged", 3 },
1299 { "foo", 10, 0, "unchanged", 3 },
1300 { "foo", 3, 0, "unchanged", 3 },
1301 { NULL, 10, 0, "unchanged", 0 },
1302 { "", 10, 0, "unchanged", 0 },
1303 { "foo=bar", 0, 0, "unchanged", 0 },
1304 };
1305 struct token_test *t;
1306 printf("\n%s()\n", __func__);
1307 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1308 char buf[100] = "unchanged";
1309 int rc = osmo_print_n(buf, t->buf_size, t->src, t->token_len);
1310 printf("%s token_len=%zu buf_size=%zu", osmo_quote_str(t->src, -1), t->token_len, t->buf_size);
1311 printf(" -> token=%s rc=%d", osmo_quote_str(buf, -1), rc);
1312 if (strcmp(buf, t->expect_token))
1313 printf(" ERROR: expected token %s", osmo_quote_str(t->expect_token, -1));
1314 if (rc != t->expect_rc)
1315 printf(" ERROR: expected rc %d", t->expect_rc);
1316 printf("\n");
1317 }
1318}
1319
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001320static void osmo_strnchr_test(void)
1321{
1322 struct test {
1323 const char *haystack;
1324 size_t haystack_len;
1325 const char *needle;
1326 int expect_offset;
1327 };
1328 struct test tests[] = {
1329 { "foo=bar", 8, "=", 3 },
1330 { "foo=bar", 4, "=", 3 },
1331 { "foo=bar", 3, "=", -1 },
1332 { "foo=bar", 0, "=", -1 },
1333 { "foo\0=bar", 9, "=", -1 },
1334 { "foo\0=bar", 9, "\0", 3 },
1335 };
1336 struct test *t;
1337 printf("\n%s()\n", __func__);
1338 for (t = tests; t - tests < ARRAY_SIZE(tests); t++) {
1339 const char *r = osmo_strnchr(t->haystack, t->haystack_len, t->needle[0]);
1340 int offset = -1;
1341 if (r)
1342 offset = r - t->haystack;
1343 printf("osmo_strnchr(%s, %zu, ",
1344 osmo_quote_str(t->haystack, -1), t->haystack_len);
1345 printf("'%s') -> %d",
1346 osmo_escape_str(t->needle, 1), offset);
1347 if (offset != t->expect_offset)
1348 printf(" ERROR expected %d", t->expect_offset);
1349 printf("\n");
1350 }
1351}
1352
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001353int main(int argc, char **argv)
1354{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +02001355 static const struct log_info log_info = {};
1356 log_init(&log_info, NULL);
1357
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001358 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +01001359 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +02001360 test_ipa_ccm_id_get_parsing();
1361 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +02001362 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +02001363 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +01001364 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +01001365 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +02001366 str_quote_test();
Neels Hofmeyr8a7eed52019-11-21 00:12:10 +01001367 str_escape3_test();
1368 str_quote3_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +02001369 isqrt_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +02001370 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +02001371 osmo_str_tolowupper_test();
Neels Hofmeyr2cbe25f2019-02-11 20:32:06 +01001372 strbuf_test();
Neels Hofmeyr8531d662019-04-11 07:16:02 +02001373 strbuf_test_nolen();
Neels Hofmeyrd79ccc62019-03-07 23:08:40 +01001374 startswith_test();
Neels Hofmeyr823073a2019-10-28 04:58:04 +01001375 name_c_impl_test();
Neels Hofmeyrff65d242019-11-19 00:21:14 +01001376 osmo_print_n_test();
Neels Hofmeyr06356fd2019-11-19 01:38:10 +01001377 osmo_strnchr_test();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001378 return 0;
1379}