1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2025 Oxide Computer Compnay 14 */ 15 16 /* 17 * Test our favorite things: parsing addresses and turning them back into 18 * strings. 19 */ 20 21 #include <err.h> 22 #include <string.h> 23 #include <sys/sysmacros.h> 24 25 #include "libi2c_test_util.h" 26 27 typedef struct addr_map { 28 const char *am_str; 29 const char *am_comp; 30 uint16_t am_type; 31 uint16_t am_addr; 32 } addr_map_t; 33 34 /* 35 * The system always outputs addresses in hex, so we have an optional second 36 * form that indicates what we expect back. 37 */ 38 static const addr_map_t roundtrip_addrs[] = { 39 { "0x23", NULL, I2C_ADDR_7BIT, 0x23 }, 40 { "0x10", NULL, I2C_ADDR_7BIT, 0x10 }, 41 { "0x7f", NULL, I2C_ADDR_7BIT, 0x7f }, 42 { "30", "0x1e", I2C_ADDR_7BIT, 0x1e }, 43 { "0x9", "0x09", I2C_ADDR_7BIT, 0x09 }, 44 { "10b,0", "10b,0x000", I2C_ADDR_10BIT, 0x0 }, 45 { "10b,0x3ff", NULL, I2C_ADDR_10BIT, 0x3ff }, 46 { "10b,0x169", NULL, I2C_ADDR_10BIT, 0x169 }, 47 { "10b,777", "10b,0x309", I2C_ADDR_10BIT, 0x309 } 48 }; 49 50 typedef struct bad_str { 51 const char *bs_str; 52 i2c_err_t bs_err; 53 } bad_str_t; 54 55 static const bad_str_t bad_strs[] = { 56 { "hello", I2C_ERR_BAD_ADDR }, 57 { "0x", I2C_ERR_BAD_ADDR }, 58 { "0x3456789", I2C_ERR_BAD_ADDR }, 59 { "0x23nope", I2C_ERR_BAD_ADDR }, 60 { "2b", I2C_ERR_BAD_ADDR }, 61 { "0x2bornot2b", I2C_ERR_BAD_ADDR }, 62 { "0x80", I2C_ERR_BAD_ADDR }, 63 { "256", I2C_ERR_BAD_ADDR }, 64 { "-4", I2C_ERR_BAD_ADDR }, 65 { "0x23;0x34", I2C_ERR_BAD_ADDR }, 66 { "10b,its", I2C_ERR_BAD_ADDR }, 67 { "10b,0xa ", I2C_ERR_BAD_ADDR }, 68 { "10b,123\ttrap", I2C_ERR_BAD_ADDR }, 69 { "10b,-23", I2C_ERR_BAD_ADDR }, 70 { "foo,0x12", I2C_ERR_BAD_ADDR_TYPE }, 71 { ",0x12", I2C_ERR_BAD_ADDR_TYPE }, 72 { "10b2,0x12", I2C_ERR_BAD_ADDR_TYPE }, 73 }; 74 75 typedef struct bad_addr { 76 uint16_t ba_type; 77 uint16_t ba_addr; 78 i2c_err_t ba_err; 79 } bad_addr_t; 80 81 /* 82 * Unlike other cases, reserved addresses aren't part of this as we will parse 83 * any address, regardless if it's reserved for some reason. 84 */ 85 static const bad_addr_t bad_addrs[] = { 86 { I2C_ADDR_7BIT, 0x80, I2C_ERR_BAD_ADDR }, 87 { I2C_ADDR_7BIT, 0x7777, I2C_ERR_BAD_ADDR }, 88 { I2C_ADDR_7BIT, INT16_MAX, I2C_ERR_BAD_ADDR }, 89 { I2C_ADDR_10BIT, 0x400, I2C_ERR_BAD_ADDR }, 90 { I2C_ADDR_10BIT, 0x7777, I2C_ERR_BAD_ADDR }, 91 { I2C_ADDR_10BIT, 0x2bb2, I2C_ERR_BAD_ADDR }, 92 { I2C_ADDR_10BIT, UINT16_MAX, I2C_ERR_BAD_ADDR }, 93 { I2C_ADDR_10BIT + 1, 0x0, I2C_ERR_BAD_ADDR_TYPE }, 94 { I2C_ADDR_10BIT + 1, 0x23, I2C_ERR_BAD_ADDR_TYPE }, 95 { 0x42, 0x23, I2C_ERR_BAD_ADDR_TYPE }, 96 { 0x7777, 0x7777, I2C_ERR_BAD_ADDR_TYPE }, 97 { INT16_MAX, UINT16_MAX, I2C_ERR_BAD_ADDR_TYPE }, 98 }; 99 100 static bool 101 valid_addr_roundtrip(i2c_hdl_t *hdl) 102 { 103 bool ret = true; 104 105 for (size_t i = 0; i < ARRAY_SIZE(roundtrip_addrs); i++) { 106 const addr_map_t *map = &roundtrip_addrs[i]; 107 char buf[128]; 108 i2c_addr_t addr; 109 110 if (!i2c_addr_parse(hdl, map->am_str, &addr)) { 111 libi2c_test_warn(hdl, "TEST FAILED: failed to parse " 112 "string %s", map->am_str); 113 ret = false; 114 } else { 115 bool valid = true; 116 if (map->am_type != addr.ia_type) { 117 warnx("TEST FAILED: parsed string %s address " 118 "type as 0x%x, expected 0x%x", map->am_str, 119 addr.ia_type, map->am_type); 120 valid = false; 121 } 122 123 if (map->am_addr != addr.ia_addr) { 124 warnx("TEST FAILED: parsed string %s address " 125 "as 0x%x, expected 0x%x", map->am_str, 126 addr.ia_addr, map->am_addr); 127 valid = false; 128 } 129 130 if (valid) { 131 (void) printf("TEST PASSED: successful " 132 "str->addr of %s\n", map->am_str); 133 } 134 } 135 136 addr.ia_type = map->am_type; 137 addr.ia_addr = map->am_addr; 138 const char *comp = map->am_comp != NULL ? map->am_comp : 139 map->am_str; 140 if (!i2c_addr_to_string(hdl, &addr, buf, sizeof (buf))) { 141 libi2c_test_warn(hdl, "TEST FAILED: failed to " 142 "transform address 0x%x,0x%x to a string", 143 map->am_type, map->am_addr); 144 ret = false; 145 } else if (strcmp(buf, comp) != 0) { 146 libi2c_test_warn(hdl, "TEST FAILED: parsed 0x%x,0x%x " 147 "to %s, but expected %s", map->am_type, 148 map->am_addr, buf, comp); 149 ret = false; 150 } else { 151 (void) printf("TEST PASSED: successful addr->str of " 152 "%s\n", map->am_str); 153 } 154 } 155 156 return (ret); 157 } 158 159 static bool 160 invalid_strings(i2c_hdl_t *hdl) 161 { 162 bool ret = true; 163 164 for (size_t i = 0; i < ARRAY_SIZE(bad_strs); i++) { 165 i2c_addr_t addr; 166 167 if (i2c_addr_parse(hdl, bad_strs[i].bs_str, &addr)) { 168 warnx("TEST FAILED: incorrectly parsed string %s " 169 "as a valid address", bad_strs[i].bs_str); 170 ret = false; 171 continue; 172 } 173 174 i2c_err_t err = i2c_err(hdl); 175 if (err != bad_strs[i].bs_err) { 176 warnx("TEST FAILED: parsing address string %s returned " 177 "%s (0x%x) but expected %s (0x%x)", 178 bad_strs[i].bs_str, i2c_errtostr(hdl, err), err, 179 i2c_errtostr(hdl, bad_strs[i].bs_err), 180 bad_strs[i].bs_err); 181 ret = false; 182 } else { 183 (void) printf("TEST PASSED: failed to parse address %s " 184 "with error %s (0x%x)\n", bad_strs[i].bs_str, 185 i2c_errtostr(hdl, err), err); 186 } 187 } 188 189 return (ret); 190 } 191 192 static bool 193 invalid_addrs(i2c_hdl_t *hdl) 194 { 195 bool ret = true; 196 197 for (size_t i = 0; i < ARRAY_SIZE(bad_addrs); i++) { 198 char buf[128]; 199 i2c_addr_t addr; 200 201 addr.ia_type = bad_addrs[i].ba_type; 202 addr.ia_addr = bad_addrs[i].ba_addr; 203 if (i2c_addr_to_string(hdl, &addr, buf, sizeof (buf))) { 204 warnx("TEST FAILED: unexpectedly parsed 0x%x,0x%x " 205 "as a valid string", addr.ia_type, addr.ia_addr); 206 ret = false; 207 continue; 208 } 209 210 i2c_err_t err = i2c_err(hdl); 211 if (err != bad_addrs[i].ba_err) { 212 warnx("TEST FAILED: parsing address 0x%x,0x%x failed " 213 "with %s (0x%x) but expected %s (0x%x)", 214 addr.ia_type, addr.ia_addr, i2c_errtostr(hdl, err), 215 err, i2c_errtostr(hdl, bad_addrs[i].ba_err), 216 bad_addrs[i].ba_err); 217 ret = false; 218 } else { 219 (void) printf("TEST PASSED: failed to parse address " 220 "0x%x,0x%x with error %s (0x%x)\n", addr.ia_type, 221 addr.ia_addr, i2c_errtostr(hdl, err), err); 222 } 223 } 224 225 return (ret); 226 } 227 228 static bool 229 short_buffers(i2c_hdl_t *hdl) 230 { 231 bool ret = true; 232 char buf[32]; 233 i2c_addr_t addr = { I2C_ADDR_7BIT, 0x23 }; 234 235 if (i2c_addr_to_string(hdl, &addr, buf, 0)) { 236 warnx("TEST FAILED: i2c_addr_to_string() with zero sized " 237 "buffer unexpectedly worked"); 238 ret = false; 239 } else if (i2c_err(hdl) != I2C_ERR_BUF_TOO_SMALL) { 240 warnx("TEST FAILED: i2c_addr_to_string() with zero sized " 241 "buffer failed with wrong code %s (0x%x), expected " 242 "I2C_ERR_BUF_TOO_SMALL (0x%x)", i2c_errtostr(hdl, 243 i2c_err(hdl)), i2c_err(hdl), I2C_ERR_BUF_TOO_SMALL); 244 ret = false; 245 } else { 246 (void) printf("TEST PASSED: i2c_addr_to_string() fails " 247 "correctly with zero sized buffer\n"); 248 } 249 250 if (i2c_addr_to_string(hdl, &addr, buf, 2)) { 251 warnx("TEST FAILED: i2c_addr_to_string() with short buffer " 252 "unexpectedly worked"); 253 ret = false; 254 } else if (i2c_err(hdl) != I2C_ERR_BUF_TOO_SMALL) { 255 warnx("TEST FAILED: i2c_addr_to_string() with short buffer " 256 "failed with wrong code %s (0x%x), expected " 257 "I2C_ERR_BUF_TOO_SMALL (0x%x)", i2c_errtostr(hdl, 258 i2c_err(hdl)), i2c_err(hdl), I2C_ERR_BUF_TOO_SMALL); 259 ret = false; 260 } else { 261 (void) printf("TEST PASSED: i2c_addr_to_string() fails " 262 "correctly with short buffer\n"); 263 } 264 265 return (ret); 266 } 267 268 static bool 269 bad_args(i2c_hdl_t *hdl) 270 { 271 bool ret = true; 272 char buf[32] = { 0 }; 273 i2c_addr_t addr; 274 275 if (i2c_addr_to_string(hdl, NULL, buf, sizeof (buf))) { 276 warnx("TEST FAILED: i2c_addr_to_string() with NULL address " 277 "unexpectedly worked"); 278 ret = false; 279 } else if (i2c_err(hdl) != I2C_ERR_BAD_PTR) { 280 warnx("TEST FAILED: i2c_addr_to_string() with NULL address " 281 "failed with wrong code %s (0x%x), expected " 282 "I2C_ERR_BAD_PTR (0x%x)", i2c_errtostr(hdl, i2c_err(hdl)), 283 i2c_err(hdl), I2C_ERR_BAD_PTR); 284 ret = false; 285 } else { 286 (void) printf("TEST PASSED: i2c_addr_to_string() handles " 287 "NULL address correctly\n"); 288 } 289 290 if (i2c_addr_to_string(hdl, &addr, NULL, 0)) { 291 warnx("TEST FAILED: i2c_addr_to_string() with NULL buffer " 292 "unexpectedly worked"); 293 ret = false; 294 } else if (i2c_err(hdl) != I2C_ERR_BAD_PTR) { 295 warnx("TEST FAILED: i2c_addr_to_string() with NULL buffer " 296 "failed with wrong code %s (0x%x), expected " 297 "I2C_ERR_BAD_PTR (0x%x)", i2c_errtostr(hdl, i2c_err(hdl)), 298 i2c_err(hdl), I2C_ERR_BAD_PTR); 299 ret = false; 300 } else { 301 (void) printf("TEST PASSED: i2c_addr_to_string() handles " 302 "NULL buffer correctly\n"); 303 } 304 305 if (i2c_addr_parse(hdl, buf, NULL)) { 306 warnx("TEST FAILED: i2c_addr_parse() with NULL address " 307 "unexpectedly worked"); 308 ret = false; 309 } else if (i2c_err(hdl) != I2C_ERR_BAD_PTR) { 310 warnx("TEST FAILED: i2c_addr_parse() with NULL address " 311 "failed with wrong code %s (0x%x), expected " 312 "I2C_ERR_BAD_PTR (0x%x)", i2c_errtostr(hdl, i2c_err(hdl)), 313 i2c_err(hdl), I2C_ERR_BAD_PTR); 314 ret = false; 315 } else { 316 (void) printf("TEST PASSED: i2c_addr_parse() handles " 317 "NULL address correctly\n"); 318 } 319 320 if (i2c_addr_parse(hdl, NULL, &addr)) { 321 warnx("TEST FAILED: i2c_addr_parse() with NULL string " 322 "unexpectedly worked"); 323 ret = false; 324 } else if (i2c_err(hdl) != I2C_ERR_BAD_PTR) { 325 warnx("TEST FAILED: i2c_addr_parse() with NULL string " 326 "failed with wrong code %s (0x%x), expected " 327 "I2C_ERR_BAD_PTR (0x%x)", i2c_errtostr(hdl, i2c_err(hdl)), 328 i2c_err(hdl), I2C_ERR_BAD_PTR); 329 ret = false; 330 } else { 331 (void) printf("TEST PASSED: i2c_addr_parse() handles " 332 "NULL string correctly\n"); 333 } 334 335 return (ret); 336 } 337 338 static bool 339 reserved_addrs(i2c_hdl_t *hdl) 340 { 341 bool ret = true; 342 343 for (i2c_rsvd_addr_t ra = I2C_RSVD_ADDR_GEN_CALL; 344 ra <= I2C_RSVD_ADDR_HS_3; ra++) { 345 i2c_addr_t addr = { I2C_ADDR_7BIT, ra }; 346 if (!i2c_addr_reserved(&addr)) { 347 warnx("TEST FAILED: 7-bit 0x%02x mistakenly thought " 348 "as not reserved", ra); 349 ret = false; 350 } else { 351 (void) printf("TEST PASSED: 7-bit 0x%02x is correctly " 352 "considered a reserved address\n", ra); 353 } 354 355 addr.ia_type = I2C_ADDR_10BIT; 356 if (!i2c_addr_reserved(&addr)) { 357 warnx("TEST FAILED: 10-bit 0x%02x mistakenly thought " 358 "as not reserved", ra); 359 ret = false; 360 } else { 361 (void) printf("TEST PASSED: 10-bit 0x%02x is correctly " 362 "considered a reserved address\n", ra); 363 } 364 } 365 366 for (i2c_rsvd_addr_t ra = I2C_RSVD_ADDR_10B_0; 367 ra <= I2C_RSVD_ADDR_DID_3; ra++) { 368 i2c_addr_t addr = { I2C_ADDR_7BIT, ra }; 369 if (!i2c_addr_reserved(&addr)) { 370 warnx("TEST FAILED: 7-bit 0x%02x mistakenly thought " 371 "as not reserved", ra); 372 ret = false; 373 } else { 374 (void) printf("TEST PASSED: 7-bit 0x%02x is correctly " 375 "considered a reserved address\n", ra); 376 } 377 378 addr.ia_type = I2C_ADDR_10BIT; 379 if (!i2c_addr_reserved(&addr)) { 380 warnx("TEST FAILED: 10-bit 0x%02x mistakenly thought " 381 "as not reserved", ra); 382 ret = false; 383 } else { 384 (void) printf("TEST PASSED: 10-bit 0x%02x is correctly " 385 "considered a reserved address\n", ra); 386 } 387 } 388 389 uint16_t unrsvd_addrs[] = { 0x9, 0x17, 0x23, 0x42, 0x70 }; 390 for (size_t i = 0; i < ARRAY_SIZE(unrsvd_addrs); i++) { 391 i2c_addr_t addr = { I2C_ADDR_7BIT, unrsvd_addrs[i] }; 392 if (i2c_addr_reserved(&addr)) { 393 warnx("TEST FAILED: 7-bit 0x%02x mistakenly thought " 394 "as reserved", unrsvd_addrs[i]); 395 ret = false; 396 } else { 397 (void) printf("TEST PASSED: 7-bit 0x%02x is correctly " 398 "not a reserved address\n", unrsvd_addrs[i]); 399 } 400 401 addr.ia_type = I2C_ADDR_10BIT; 402 if (i2c_addr_reserved(&addr)) { 403 warnx("TEST FAILED: 10-bit 0x%03x mistakenly thought " 404 "as reserved", unrsvd_addrs[i]); 405 ret = false; 406 } else { 407 (void) printf("TEST PASSED: 10-bit 0x%03x is correctly " 408 "not a reserved address\n", unrsvd_addrs[i]); 409 } 410 } 411 412 return (ret); 413 } 414 415 int 416 main(void) 417 { 418 int ret = EXIT_SUCCESS; 419 i2c_hdl_t *hdl = i2c_init(); 420 if (hdl == NULL) { 421 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to create " 422 "libi2c handle"); 423 } 424 425 if (!valid_addr_roundtrip(hdl)) { 426 ret = EXIT_FAILURE; 427 } 428 429 if (!invalid_strings(hdl)) { 430 ret = EXIT_FAILURE; 431 } 432 433 if (!invalid_addrs(hdl)) { 434 ret = EXIT_FAILURE; 435 } 436 437 if (!short_buffers(hdl)) { 438 ret = EXIT_FAILURE; 439 } 440 441 if (!bad_args(hdl)) { 442 ret = EXIT_FAILURE; 443 } 444 445 if (!reserved_addrs(hdl)) { 446 ret = EXIT_FAILURE; 447 } 448 449 if (ret == EXIT_SUCCESS) { 450 (void) printf("All tests passed successfully\n"); 451 } 452 i2c_fini(hdl); 453 return (ret); 454 } 455