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