| Daniel Osawa | 51c1813 | 2025-11-26 09:21:20 -0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 |
| 2 | // SPDX-FileCopyrightText: Copyright OpenBMC Authors |
| 3 | |
| 4 | #include <libcper/cper-utils.h> |
| 5 | |
| 6 | #include <stdio.h> |
| 7 | #include <stdlib.h> |
| 8 | #include <assert.h> |
| 9 | #include <string.h> |
| 10 | #include <json.h> |
| 11 | |
| 12 | // Test vectors: input bytes and expected hex strings |
| 13 | static const UINT8 test_bytes_1[] = { 0x00 }; |
| 14 | static const char *test_hex_1 = "00"; |
| 15 | |
| 16 | static const UINT8 test_bytes_2[] = { 0xff }; |
| 17 | static const char *test_hex_2 = "ff"; |
| 18 | |
| 19 | static const UINT8 test_bytes_3[] = { 0xde, 0xad, 0xbe, 0xef }; |
| 20 | static const char *test_hex_3 = "deadbeef"; |
| 21 | |
| 22 | static const UINT8 test_bytes_4[] = { 0x01, 0x23, 0x45, 0x67, |
| 23 | 0x89, 0xab, 0xcd, 0xef }; |
| 24 | static const char *test_hex_4 = "0123456789abcdef"; |
| 25 | |
| 26 | static const UINT8 test_bytes_5[] = { 0x00, 0x00, 0x00, 0x00 }; |
| 27 | static const char *test_hex_5 = "00000000"; |
| 28 | |
| 29 | // Test encoding: bytes -> hex string |
| 30 | void test_hex_encode_good(void) |
| 31 | { |
| 32 | printf("Testing hex encoding...\n"); |
| 33 | |
| 34 | // Test 1: Single zero byte |
| 35 | { |
| 36 | json_object *obj = json_object_new_object(); |
| 37 | add_bytes_hex(obj, "data", test_bytes_1, sizeof(test_bytes_1)); |
| 38 | json_object *field = json_object_object_get(obj, "data"); |
| 39 | assert(field != NULL); |
| 40 | const char *hex = json_object_get_string(field); |
| 41 | assert(strcmp(hex, test_hex_1) == 0); |
| 42 | json_object_put(obj); |
| 43 | } |
| 44 | |
| 45 | // Test 2: Single 0xFF byte |
| 46 | { |
| 47 | json_object *obj = json_object_new_object(); |
| 48 | add_bytes_hex(obj, "data", test_bytes_2, sizeof(test_bytes_2)); |
| 49 | json_object *field = json_object_object_get(obj, "data"); |
| 50 | assert(field != NULL); |
| 51 | const char *hex = json_object_get_string(field); |
| 52 | assert(strcmp(hex, test_hex_2) == 0); |
| 53 | json_object_put(obj); |
| 54 | } |
| 55 | |
| 56 | // Test 3: "deadbeef" |
| 57 | { |
| 58 | json_object *obj = json_object_new_object(); |
| 59 | add_bytes_hex(obj, "data", test_bytes_3, sizeof(test_bytes_3)); |
| 60 | json_object *field = json_object_object_get(obj, "data"); |
| 61 | assert(field != NULL); |
| 62 | const char *hex = json_object_get_string(field); |
| 63 | assert(strcmp(hex, test_hex_3) == 0); |
| 64 | json_object_put(obj); |
| 65 | } |
| 66 | |
| 67 | // Test 4: Full range 0-9, a-f |
| 68 | { |
| 69 | json_object *obj = json_object_new_object(); |
| 70 | add_bytes_hex(obj, "data", test_bytes_4, sizeof(test_bytes_4)); |
| 71 | json_object *field = json_object_object_get(obj, "data"); |
| 72 | assert(field != NULL); |
| 73 | const char *hex = json_object_get_string(field); |
| 74 | assert(strcmp(hex, test_hex_4) == 0); |
| 75 | json_object_put(obj); |
| 76 | } |
| 77 | |
| 78 | // Test 5: All zeros |
| 79 | { |
| 80 | json_object *obj = json_object_new_object(); |
| 81 | add_bytes_hex(obj, "data", test_bytes_5, sizeof(test_bytes_5)); |
| 82 | json_object *field = json_object_object_get(obj, "data"); |
| 83 | assert(field != NULL); |
| 84 | const char *hex = json_object_get_string(field); |
| 85 | assert(strcmp(hex, test_hex_5) == 0); |
| 86 | json_object_put(obj); |
| 87 | } |
| 88 | |
| 89 | printf("Hex encoding tests passed.\n"); |
| 90 | } |
| 91 | |
| 92 | // Test decoding: hex string -> bytes |
| 93 | void test_hex_decode_good(void) |
| 94 | { |
| 95 | printf("Testing hex decoding...\n"); |
| 96 | |
| 97 | // Test 1: Single zero byte |
| 98 | { |
| 99 | json_object *obj = json_object_new_object(); |
| 100 | json_object_object_add(obj, "data", |
| 101 | json_object_new_string(test_hex_1)); |
| 102 | size_t out_len = 0; |
| 103 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 104 | assert(bytes != NULL); |
| 105 | assert(out_len == sizeof(test_bytes_1)); |
| 106 | assert(memcmp(bytes, test_bytes_1, out_len) == 0); |
| 107 | free(bytes); |
| 108 | json_object_put(obj); |
| 109 | } |
| 110 | |
| 111 | // Test 2: Single 0xFF byte |
| 112 | { |
| 113 | json_object *obj = json_object_new_object(); |
| 114 | json_object_object_add(obj, "data", |
| 115 | json_object_new_string(test_hex_2)); |
| 116 | size_t out_len = 0; |
| 117 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 118 | assert(bytes != NULL); |
| 119 | assert(out_len == sizeof(test_bytes_2)); |
| 120 | assert(memcmp(bytes, test_bytes_2, out_len) == 0); |
| 121 | free(bytes); |
| 122 | json_object_put(obj); |
| 123 | } |
| 124 | |
| 125 | // Test 3: "deadbeef" |
| 126 | { |
| 127 | json_object *obj = json_object_new_object(); |
| 128 | json_object_object_add(obj, "data", |
| 129 | json_object_new_string(test_hex_3)); |
| 130 | size_t out_len = 0; |
| 131 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 132 | assert(bytes != NULL); |
| 133 | assert(out_len == sizeof(test_bytes_3)); |
| 134 | assert(memcmp(bytes, test_bytes_3, out_len) == 0); |
| 135 | free(bytes); |
| 136 | json_object_put(obj); |
| 137 | } |
| 138 | |
| 139 | // Test 4: Full range with uppercase hex |
| 140 | { |
| 141 | json_object *obj = json_object_new_object(); |
| 142 | json_object_object_add( |
| 143 | obj, "data", |
| 144 | json_object_new_string("0123456789ABCDEF")); |
| 145 | size_t out_len = 0; |
| 146 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 147 | assert(bytes != NULL); |
| 148 | assert(out_len == sizeof(test_bytes_4)); |
| 149 | assert(memcmp(bytes, test_bytes_4, out_len) == 0); |
| 150 | free(bytes); |
| 151 | json_object_put(obj); |
| 152 | } |
| 153 | |
| 154 | // Test 5: Mixed case hex |
| 155 | { |
| 156 | json_object *obj = json_object_new_object(); |
| 157 | json_object_object_add(obj, "data", |
| 158 | json_object_new_string("DeAdBeEf")); |
| 159 | size_t out_len = 0; |
| 160 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 161 | assert(bytes != NULL); |
| 162 | assert(out_len == sizeof(test_bytes_3)); |
| 163 | assert(memcmp(bytes, test_bytes_3, out_len) == 0); |
| 164 | free(bytes); |
| 165 | json_object_put(obj); |
| 166 | } |
| 167 | |
| 168 | printf("Hex decoding tests passed.\n"); |
| 169 | } |
| 170 | |
| 171 | // Test error handling |
| 172 | void test_hex_error_cases(void) |
| 173 | { |
| 174 | printf("Testing hex error handling...\n"); |
| 175 | |
| 176 | // Test encode with NULL object |
| 177 | { |
| 178 | add_bytes_hex(NULL, "data", test_bytes_1, sizeof(test_bytes_1)); |
| 179 | // Should not crash |
| 180 | } |
| 181 | |
| 182 | // Test encode with NULL bytes |
| 183 | { |
| 184 | json_object *obj = json_object_new_object(); |
| 185 | add_bytes_hex(obj, "data", NULL, 4); |
| 186 | json_object *field = json_object_object_get(obj, "data"); |
| 187 | assert(field == NULL); // Should not add field |
| 188 | json_object_put(obj); |
| 189 | } |
| 190 | |
| 191 | // Test encode with zero length |
| 192 | { |
| 193 | json_object *obj = json_object_new_object(); |
| 194 | add_bytes_hex(obj, "data", test_bytes_1, 0); |
| 195 | json_object *field = json_object_object_get(obj, "data"); |
| 196 | assert(field == NULL); // Should not add field |
| 197 | json_object_put(obj); |
| 198 | } |
| 199 | |
| 200 | // Test decode with NULL object |
| 201 | { |
| 202 | size_t out_len = 0; |
| 203 | UINT8 *bytes = get_bytes_hex(NULL, "data", &out_len); |
| 204 | assert(bytes == NULL); |
| 205 | } |
| 206 | |
| 207 | // Test decode with NULL out_len |
| 208 | { |
| 209 | json_object *obj = json_object_new_object(); |
| 210 | json_object_object_add(obj, "data", |
| 211 | json_object_new_string("deadbeef")); |
| 212 | UINT8 *bytes = get_bytes_hex(obj, "data", NULL); |
| 213 | assert(bytes == NULL); |
| 214 | json_object_put(obj); |
| 215 | } |
| 216 | |
| 217 | // Test decode with missing field |
| 218 | { |
| 219 | json_object *obj = json_object_new_object(); |
| 220 | size_t out_len = 0; |
| 221 | UINT8 *bytes = get_bytes_hex(obj, "nonexistent", &out_len); |
| 222 | assert(bytes == NULL); |
| 223 | json_object_put(obj); |
| 224 | } |
| 225 | |
| 226 | // Test decode with non-string field |
| 227 | { |
| 228 | json_object *obj = json_object_new_object(); |
| 229 | json_object_object_add(obj, "data", json_object_new_int(12345)); |
| 230 | size_t out_len = 0; |
| 231 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 232 | assert(bytes == NULL); |
| 233 | json_object_put(obj); |
| 234 | } |
| 235 | |
| 236 | // Test decode with odd-length hex string |
| 237 | { |
| 238 | json_object *obj = json_object_new_object(); |
| 239 | json_object_object_add(obj, "data", |
| 240 | json_object_new_string("abc")); |
| 241 | size_t out_len = 0; |
| 242 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 243 | assert(bytes == NULL); // Should fail - odd length |
| 244 | json_object_put(obj); |
| 245 | } |
| 246 | |
| 247 | // Test decode with invalid hex character |
| 248 | { |
| 249 | json_object *obj = json_object_new_object(); |
| 250 | json_object_object_add(obj, "data", |
| 251 | json_object_new_string("deadbXef")); |
| 252 | size_t out_len = 0; |
| 253 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 254 | assert(bytes == NULL); // Should fail - 'X' is invalid |
| 255 | json_object_put(obj); |
| 256 | } |
| 257 | |
| 258 | // Test decode with empty string |
| 259 | { |
| 260 | json_object *obj = json_object_new_object(); |
| 261 | json_object_object_add(obj, "data", json_object_new_string("")); |
| 262 | size_t out_len = 0; |
| 263 | UINT8 *bytes = get_bytes_hex(obj, "data", &out_len); |
| 264 | // Empty string has even length (0), so it might succeed with 0 bytes |
| 265 | // Or fail - depends on implementation. Current impl should return empty buf |
| 266 | if (bytes != NULL) { |
| 267 | assert(out_len == 0); |
| 268 | free(bytes); |
| 269 | } |
| 270 | json_object_put(obj); |
| 271 | } |
| 272 | |
| 273 | printf("Hex error handling tests passed.\n"); |
| 274 | } |
| 275 | |
| 276 | // Test round-trip: bytes -> hex -> bytes |
| 277 | void test_hex_roundtrip(void) |
| 278 | { |
| 279 | printf("Testing hex round-trip...\n"); |
| 280 | |
| 281 | // Test with various byte patterns |
| 282 | UINT8 test_data[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
| 283 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; |
| 284 | |
| 285 | json_object *obj = json_object_new_object(); |
| 286 | add_bytes_hex(obj, "roundtrip", test_data, sizeof(test_data)); |
| 287 | |
| 288 | size_t out_len = 0; |
| 289 | UINT8 *decoded = get_bytes_hex(obj, "roundtrip", &out_len); |
| 290 | assert(decoded != NULL); |
| 291 | assert(out_len == sizeof(test_data)); |
| 292 | assert(memcmp(decoded, test_data, out_len) == 0); |
| 293 | |
| 294 | free(decoded); |
| 295 | json_object_put(obj); |
| 296 | |
| 297 | printf("Hex round-trip tests passed.\n"); |
| 298 | } |