xref: /freebsd/contrib/pkgconf/tests/api/test-serialize.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1 /*
2  * test-serialize.c
3  * Tests for spdxtool's JSON serialization value model.
4  *
5  * SPDX-License-Identifier: pkgconf
6  *
7  * Copyright (c) 2026 pkgconf authors (see AUTHORS).
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * This software is provided 'as is' and without any warranty, express or
14  * implied.  In no event shall the authors be liable for any damages arising
15  * from the use of this software.
16  */
17 
18 #include <libpkgconf/stdinc.h>
19 #include <libpkgconf/libpkgconf.h>
20 #include "test-api.h"
21 #include "serialize.h"
22 
23 // Render a value to a freshly-allocated C string (caller frees)
24 static char *
render(spdxtool_serialize_value_t * value)25 render(spdxtool_serialize_value_t *value)
26 {
27 	pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
28 	TEST_ASSERT_TRUE(spdxtool_serialize_value_to_buf(&buf, value, 0));
29 	char *s = strdup(pkgconf_buffer_str_or_empty(&buf));
30 	pkgconf_buffer_finalize(&buf);
31 	return s;
32 }
33 
34 // Render a container without taking ownership of it
35 static char *
render_object(spdxtool_serialize_object_list_t * o)36 render_object(spdxtool_serialize_object_list_t *o)
37 {
38 	spdxtool_serialize_value_t wrap = { .type = SPDXTOOL_SERIALIZE_TYPE_OBJECT, .value = { .o = o } };
39 	return render(&wrap);
40 }
41 
42 static char *
render_array(spdxtool_serialize_array_t * a)43 render_array(spdxtool_serialize_array_t *a)
44 {
45 	spdxtool_serialize_value_t wrap = { .type = SPDXTOOL_SERIALIZE_TYPE_ARRAY, .value = { .a = a } };
46 	return render(&wrap);
47 }
48 
49 // Scalar value types: string / int / bool / null
50 static void
test_serialize_value_string(void)51 test_serialize_value_string(void)
52 {
53 	spdxtool_serialize_value_t *v = spdxtool_serialize_value_string("hi");
54 	TEST_ASSERT_NONNULL(v);
55 	char *s = render(v);
56 	TEST_ASSERT_STRCMP_EQ(s, "\"hi\"");
57 	free(s);
58 	spdxtool_serialize_value_free(v);
59 }
60 
61 static void
test_serialize_value_int(void)62 test_serialize_value_int(void)
63 {
64 	spdxtool_serialize_value_t *v = spdxtool_serialize_value_int(123);
65 	TEST_ASSERT_NONNULL(v);
66 	char *s = render(v);
67 	TEST_ASSERT_STRCMP_EQ(s, "123");
68 	free(s);
69 	spdxtool_serialize_value_free(v);
70 }
71 
72 static void
test_serialize_value_bool(void)73 test_serialize_value_bool(void)
74 {
75 	spdxtool_serialize_value_t *t = spdxtool_serialize_value_bool(true);
76 	spdxtool_serialize_value_t *f = spdxtool_serialize_value_bool(false);
77 	char *st = render(t);
78 	char *sf = render(f);
79 	TEST_ASSERT_STRCMP_EQ(st, "true");
80 	TEST_ASSERT_STRCMP_EQ(sf, "false");
81 	free(st);
82 	free(sf);
83 	spdxtool_serialize_value_free(t);
84 	spdxtool_serialize_value_free(f);
85 }
86 
87 static void
test_serialize_value_null(void)88 test_serialize_value_null(void)
89 {
90 	spdxtool_serialize_value_t *v = spdxtool_serialize_value_null();
91 	TEST_ASSERT_NONNULL(v);
92 	char *s = render(v);
93 	TEST_ASSERT_STRCMP_EQ(s, "null");
94 	free(s);
95 	spdxtool_serialize_value_free(v);
96 }
97 
98 // All JSON string escape sequences, including control characters
99 static void
test_serialize_escape_sequences(void)100 test_serialize_escape_sequences(void)
101 {
102 	spdxtool_serialize_value_t *v = spdxtool_serialize_value_string("\"\\\b\f\n\r\t\x01" "Z");
103 	char *s = render(v);
104 
105 	TEST_ASSERT_STRSTR(s, "\\\"");     // quote
106 	TEST_ASSERT_STRSTR(s, "\\\\");     // backslash
107 	TEST_ASSERT_STRSTR(s, "\\b");      // backspace
108 	TEST_ASSERT_STRSTR(s, "\\f");      // form feed
109 	TEST_ASSERT_STRSTR(s, "\\n");      // newline
110 	TEST_ASSERT_STRSTR(s, "\\r");      // carriage return
111 	TEST_ASSERT_STRSTR(s, "\\t");      // tab
112 	TEST_ASSERT_STRSTR(s, "\\u0001");  // other ctrl
113 	TEST_ASSERT_STRSTR(s, "Z");        // printable passthrough
114 
115 	free(s);
116 	spdxtool_serialize_value_free(v);
117 }
118 
119 // Mixed-type object exercises the int/bool/null add helpers
120 static void
test_serialize_object_mixed_types(void)121 test_serialize_object_mixed_types(void)
122 {
123 	spdxtool_serialize_object_list_t *o = spdxtool_serialize_object_list_new();
124 	TEST_ASSERT_NONNULL(o);
125 
126 	TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_string(o, "s", "x"));
127 	TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_int(o, "i", 42));
128 	TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_bool(o, "b", true));
129 	TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_null(o, "n"));
130 
131 	char *s = render_object(o);
132 	TEST_ASSERT_STRSTR(s, "\"s\": \"x\"");
133 	TEST_ASSERT_STRSTR(s, "\"i\": 42");
134 	TEST_ASSERT_STRSTR(s, "\"b\": true");
135 	TEST_ASSERT_STRSTR(s, "\"n\": null");
136 
137 	free(s);
138 	spdxtool_serialize_object_list_free(o);
139 }
140 
141 // Mixed-type array exercises the int/bool/null array helpers
142 static void
test_serialize_array_mixed_types(void)143 test_serialize_array_mixed_types(void)
144 {
145 	spdxtool_serialize_array_t *a = spdxtool_serialize_array_new();
146 	TEST_ASSERT_NONNULL(a);
147 
148 	TEST_ASSERT_NONNULL(spdxtool_serialize_array_add_int(a, 7));
149 	TEST_ASSERT_NONNULL(spdxtool_serialize_array_add_bool(a, false));
150 	TEST_ASSERT_NONNULL(spdxtool_serialize_array_add_null(a));
151 
152 	char *s = render_array(a);
153 	TEST_ASSERT_STRSTR(s, "7");
154 	TEST_ASSERT_STRSTR(s, "false");
155 	TEST_ASSERT_STRSTR(s, "null");
156 
157 	free(s);
158 	spdxtool_serialize_array_free(a);
159 }
160 
161 // Defensive NULL handling that the CLI path never reaches
162 static void
test_serialize_null_guards(void)163 test_serialize_null_guards(void)
164 {
165 	pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
166 	spdxtool_serialize_value_t *v = spdxtool_serialize_value_null();
167 
168 	// value_to_buf rejects NULL buffer or NULL value
169 	TEST_ASSERT_FALSE(spdxtool_serialize_value_to_buf(NULL, v, 0));
170 	TEST_ASSERT_FALSE(spdxtool_serialize_value_to_buf(&buf, NULL, 0));
171 	pkgconf_buffer_finalize(&buf);
172 
173 	// value_string(NULL) yields NULL
174 	TEST_ASSERT_NULL(spdxtool_serialize_value_string(NULL));
175 
176 	// add_take with a NULL container frees the value and returns NULL
177 	TEST_ASSERT_NULL(spdxtool_serialize_object_add_take(NULL, "k", v));
178 	TEST_ASSERT_NULL(spdxtool_serialize_array_add_take(NULL, spdxtool_serialize_value_null()));
179 
180 	// free routines are NULL-safe
181 	spdxtool_serialize_value_free(NULL);
182 	spdxtool_serialize_object_free(NULL);
183 	spdxtool_serialize_object_list_free(NULL);
184 	spdxtool_serialize_array_free(NULL);
185 }
186 
187 int
main(int argc,const char ** argv)188 main(int argc, const char **argv)
189 {
190 	(void) argc;
191 	const char *basename = pkgconf_path_find_basename(argv[0]);
192 
193 	TEST_RUN(basename, test_serialize_value_string);
194 	TEST_RUN(basename, test_serialize_value_int);
195 	TEST_RUN(basename, test_serialize_value_bool);
196 	TEST_RUN(basename, test_serialize_value_null);
197 	TEST_RUN(basename, test_serialize_escape_sequences);
198 	TEST_RUN(basename, test_serialize_object_mixed_types);
199 	TEST_RUN(basename, test_serialize_array_mixed_types);
200 	TEST_RUN(basename, test_serialize_null_guards);
201 
202 	return EXIT_SUCCESS;
203 }
204