/src/freeradius-server/src/lib/util/dict_test.c
Line | Count | Source |
1 | | /* |
2 | | * This program is free software; you can redistribute it and/or modify |
3 | | * it under the terms of the GNU General Public License as published by |
4 | | * the Free Software Foundation; either version 2 of the License, or |
5 | | * (at your option) any later version. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
15 | | */ |
16 | | |
17 | | /** Common functions for test files which need to programmatically create test dictionaries |
18 | | * |
19 | | * @file src/lib/util/dict_test.c |
20 | | * |
21 | | * @copyright 2021 The FreeRADIUS server project |
22 | | */ |
23 | | |
24 | | #include <freeradius-devel/util/dict.h> |
25 | | #include <freeradius-devel/util/dict_priv.h> |
26 | | #include "dict_test.h" |
27 | | |
28 | | fr_dict_t *fr_dict_test; |
29 | | |
30 | | fr_dict_attr_t const *fr_dict_attr_test_string; |
31 | | fr_dict_attr_t const *fr_dict_attr_test_octets; |
32 | | |
33 | | fr_dict_attr_t const *fr_dict_attr_test_ipv4_addr; |
34 | | fr_dict_attr_t const *fr_dict_attr_test_ipv4_prefix; |
35 | | |
36 | | fr_dict_attr_t const *fr_dict_attr_test_ipv6_addr; |
37 | | fr_dict_attr_t const *fr_dict_attr_test_ipv6_prefix; |
38 | | |
39 | | fr_dict_attr_t const *fr_dict_attr_test_ifid; |
40 | | fr_dict_attr_t const *fr_dict_attr_test_combo_ip_addr; |
41 | | fr_dict_attr_t const *fr_dict_attr_test_combo_ip_prefix; |
42 | | fr_dict_attr_t const *fr_dict_attr_test_ethernet; |
43 | | fr_dict_attr_t const *fr_dict_attr_test_bool; |
44 | | |
45 | | fr_dict_attr_t const *fr_dict_attr_test_uint8; |
46 | | fr_dict_attr_t const *fr_dict_attr_test_uint16; |
47 | | fr_dict_attr_t const *fr_dict_attr_test_uint32; |
48 | | fr_dict_attr_t const *fr_dict_attr_test_uint64; |
49 | | |
50 | | fr_dict_attr_t const *fr_dict_attr_test_int8; |
51 | | fr_dict_attr_t const *fr_dict_attr_test_int16; |
52 | | fr_dict_attr_t const *fr_dict_attr_test_int32; |
53 | | fr_dict_attr_t const *fr_dict_attr_test_int64; |
54 | | |
55 | | fr_dict_attr_t const *fr_dict_attr_test_float32; |
56 | | fr_dict_attr_t const *fr_dict_attr_test_float64; |
57 | | |
58 | | fr_dict_attr_t const *fr_dict_attr_test_date; |
59 | | |
60 | | fr_dict_attr_t const *fr_dict_attr_test_time_delta; |
61 | | |
62 | | fr_dict_attr_t const *fr_dict_attr_test_size; |
63 | | |
64 | | fr_dict_attr_t const *fr_dict_attr_test_tlv; |
65 | | fr_dict_attr_t const *fr_dict_attr_test_tlv_string; |
66 | | |
67 | | fr_dict_attr_t const *fr_dict_attr_test_struct; |
68 | | fr_dict_attr_t const *fr_dict_attr_test_struct_uint32; |
69 | | |
70 | | fr_dict_attr_t const *fr_dict_attr_test_vsa; |
71 | | fr_dict_attr_t const *fr_dict_attr_test_vendor; |
72 | | fr_dict_attr_t const *fr_dict_attr_test_vendor_string; |
73 | | |
74 | | fr_dict_attr_t const *fr_dict_attr_test_group; |
75 | | |
76 | | fr_dict_attr_t const *fr_dict_attr_test_nested_top_tlv; |
77 | | fr_dict_attr_t const *fr_dict_attr_test_nested_child_tlv; |
78 | | fr_dict_attr_t const *fr_dict_attr_test_nested_leaf_string; |
79 | | fr_dict_attr_t const *fr_dict_attr_test_nested_leaf_int32; |
80 | | |
81 | | fr_dict_attr_t const *fr_dict_attr_test_enum; |
82 | | |
83 | | static fr_value_box_t enum_test_0 = FR_VALUE_BOX_INITIALISER(enum_test_0, FR_TYPE_UINT32, .uint32, 123); |
84 | | static fr_value_box_t enum_test_1 = FR_VALUE_BOX_INITIALISER(enum_test_1, FR_TYPE_UINT32, .uint32, 321); |
85 | | |
86 | | fr_dict_test_attr_t const fr_dict_test_attrs[] = { |
87 | | /* |
88 | | * Variable length |
89 | | */ |
90 | | { .attr = FR_TEST_ATTR_STRING, .da = &fr_dict_attr_test_string, .name = "Test-String", .type = FR_TYPE_STRING }, |
91 | | { .attr = FR_TEST_ATTR_OCTETS, .da = &fr_dict_attr_test_octets, .name = "Test-Octets", .type = FR_TYPE_OCTETS }, |
92 | | |
93 | | /* |
94 | | * Networking |
95 | | */ |
96 | | { .attr = FR_TEST_ATTR_IPV4_ADDR, .da = &fr_dict_attr_test_ipv4_addr, .name = "Test-IPv4-Addr", .type = FR_TYPE_IPV4_ADDR }, |
97 | | { .attr = FR_TEST_ATTR_IPV4_PREFIX, .da = &fr_dict_attr_test_ipv4_prefix, .name = "Test-IPv4-Prefix", .type = FR_TYPE_IPV4_PREFIX }, |
98 | | |
99 | | { .attr = FR_TEST_ATTR_IPV6_ADDR, .da = &fr_dict_attr_test_ipv6_addr, .name = "Test-IPv6-Addr", .type = FR_TYPE_IPV6_ADDR }, |
100 | | { .attr = FR_TEST_ATTR_IPV6_PREFIX, .da = &fr_dict_attr_test_ipv6_prefix, .name = "Test-IPv6-Prefix", .type = FR_TYPE_IPV6_PREFIX }, |
101 | | |
102 | | { .attr = FR_TEST_ATTR_IFID, .da = &fr_dict_attr_test_ifid, .name = "Test-IFID", .type = FR_TYPE_IFID }, |
103 | | { .attr = FR_TEST_ATTR_ETHERNET, .da = &fr_dict_attr_test_ethernet, .name = "Test-Ethernet", .type = FR_TYPE_ETHERNET }, |
104 | | |
105 | | /* |
106 | | * Numeric |
107 | | */ |
108 | | { .attr = FR_TEST_ATTR_UINT8, .da = &fr_dict_attr_test_uint8, .name = "Test-Uint8", .type = FR_TYPE_UINT8 }, |
109 | | { .attr = FR_TEST_ATTR_UINT16, .da = &fr_dict_attr_test_uint16, .name = "Test-Uint16", .type = FR_TYPE_UINT16 }, |
110 | | { .attr = FR_TEST_ATTR_UINT32, .da = &fr_dict_attr_test_uint32, .name = "Test-Uint32", .type = FR_TYPE_UINT32 }, |
111 | | { .attr = FR_TEST_ATTR_UINT64, .da = &fr_dict_attr_test_uint64, .name = "Test-Uint64", .type = FR_TYPE_UINT64 }, |
112 | | |
113 | | { .attr = FR_TEST_ATTR_INT8, .da = &fr_dict_attr_test_int8, .name = "Test-Int8", .type = FR_TYPE_INT8 }, |
114 | | { .attr = FR_TEST_ATTR_INT16, .da = &fr_dict_attr_test_int16, .name = "Test-Int16", .type = FR_TYPE_INT16 }, |
115 | | { .attr = FR_TEST_ATTR_INT32, .da = &fr_dict_attr_test_int32, .name = "Test-Int32", .type = FR_TYPE_INT32 }, |
116 | | { .attr = FR_TEST_ATTR_INT64, .da = &fr_dict_attr_test_int64, .name = "Test-Int64", .type = FR_TYPE_INT64 }, |
117 | | |
118 | | { .attr = FR_TEST_ATTR_FLOAT32, .da = &fr_dict_attr_test_float32, .name = "Test-Float32", .type = FR_TYPE_FLOAT32 }, |
119 | | { .attr = FR_TEST_ATTR_FLOAT64, .da = &fr_dict_attr_test_float64, .name = "Test-Float64", .type = FR_TYPE_FLOAT64 }, |
120 | | |
121 | | { .attr = FR_TEST_ATTR_DATE, .da = &fr_dict_attr_test_date, .name = "Test-Date", .type = FR_TYPE_DATE }, |
122 | | |
123 | | { .attr = FR_TEST_ATTR_TIME_DELTA, .da = &fr_dict_attr_test_date, .name = "Test-Time-Delta", .type = FR_TYPE_TIME_DELTA }, |
124 | | |
125 | | { .attr = FR_TEST_ATTR_SIZE, .da = &fr_dict_attr_test_size, .name = "Test-Time-Size", .type = FR_TYPE_SIZE }, |
126 | | |
127 | | /* |
128 | | * Grouping |
129 | | */ |
130 | | { .attr = FR_TEST_ATTR_TLV, .da = &fr_dict_attr_test_tlv, .name = "Test-TLV", .type = FR_TYPE_TLV }, |
131 | | { .attr = FR_TEST_ATTR_TLV_STRING, .parent = &fr_dict_attr_test_tlv, .da = &fr_dict_attr_test_tlv_string, .name = "String", .type = FR_TYPE_STRING }, |
132 | | |
133 | | { .attr = FR_TEST_ATTR_STRUCT, .da = &fr_dict_attr_test_struct, .name = "Test-Struct", .type = FR_TYPE_STRUCT }, |
134 | | { .attr = 1, .parent = &fr_dict_attr_test_struct, .da = &fr_dict_attr_test_struct_uint32, .name = "uint32", .type = FR_TYPE_UINT32 }, |
135 | | |
136 | | { .attr = FR_TEST_ATTR_VSA, .da = &fr_dict_attr_test_vsa, .name = "Test-VSA", .type = FR_TYPE_VSA }, |
137 | | { .attr = FR_TEST_ATTR_VENDOR, .parent = &fr_dict_attr_test_vsa, .da = &fr_dict_attr_test_vendor, .name = "Test-Vendor", .type = FR_TYPE_VENDOR }, |
138 | | { .attr = FR_TEST_ATTR_VENDOR_STRING, .parent = &fr_dict_attr_test_vendor, .da = &fr_dict_attr_test_vendor_string, .name = "String", .type = FR_TYPE_STRING }, |
139 | | |
140 | | { .attr = FR_TEST_ATTR_GROUP, .da = &fr_dict_attr_test_group, .name = "Test-Group", .type = FR_TYPE_GROUP }, |
141 | | |
142 | | /* |
143 | | * Deeper nesting |
144 | | */ |
145 | | { .attr = FR_TEST_ATTR_NESTED_TOP_TLV, .da = &fr_dict_attr_test_nested_top_tlv, .name = "Test-Nested-Top-TLV", .type = FR_TYPE_TLV }, |
146 | | { .attr = FR_TEST_ATTR_NESTED_CHILD_TLV, .parent = &fr_dict_attr_test_nested_top_tlv, .da = &fr_dict_attr_test_nested_child_tlv, .name = "Child-TLV", .type = FR_TYPE_TLV }, |
147 | | { .attr = FR_TEST_ATTR_NESTED_LEAF_STRING, .parent = &fr_dict_attr_test_nested_child_tlv, .da = &fr_dict_attr_test_nested_leaf_string, .name = "Leaf-String", .type = FR_TYPE_STRING }, |
148 | | { .attr = FR_TEST_ATTR_NESTED_LEAF_INT32, .parent = &fr_dict_attr_test_nested_child_tlv, .da = &fr_dict_attr_test_nested_leaf_int32, .name = "Leaf-Int32", .type = FR_TYPE_INT32 }, |
149 | | |
150 | | /* |
151 | | * Enumeration |
152 | | */ |
153 | | { .attr = FR_TEST_ATTR_ENUM, .da = &fr_dict_attr_test_enum, .name = "Test-Enum", .type = FR_TYPE_UINT32, |
154 | | .values = (fr_dict_test_attr_value_t[]){ |
155 | | { .key = "test123", .val = &enum_test_0}, |
156 | | { .key = "test321", .val = &enum_test_1}, |
157 | | { .key = NULL, }, |
158 | | } |
159 | | }, |
160 | | { .attr = FR_TEST_ATTR_INVALID } |
161 | | }; |
162 | | |
163 | | /** Add our test attributes to our test dictionary |
164 | | * |
165 | | * @param[in] dict Test dictionary to add. |
166 | | * @param[in] test_defs Test attribute definitions to add. |
167 | | * @param[in] base to add to all attribute numbers. |
168 | | * @param[in] inst number to add to test attribute. |
169 | | * i.e. if the attribute name is "Foo" |
170 | | * the instance number will be appended |
171 | | * to create "Foo-<inst>" |
172 | | * @return |
173 | | * - 0 on success. |
174 | | * - -1 on failure. |
175 | | */ |
176 | | int fr_dict_test_attrs_init(fr_dict_t *dict, fr_dict_test_attr_t const *test_defs, |
177 | | unsigned int base, int inst) |
178 | 0 | { |
179 | 0 | fr_dict_test_attr_t const *p; |
180 | 0 | fr_dict_attr_flags_t dict_flags = {}; |
181 | |
|
182 | 0 | for (p = test_defs; p->attr != FR_TEST_ATTR_INVALID; p++) { |
183 | 0 | fr_dict_attr_t const *parent = p->parent ? *p->parent : fr_dict_root(dict); |
184 | 0 | fr_dict_attr_t const *attr; |
185 | | |
186 | | /* |
187 | | * We only mangle top level attributes |
188 | | */ |
189 | 0 | if (!p->parent) { |
190 | 0 | char const *name; |
191 | 0 | char *buff = NULL; |
192 | |
|
193 | 0 | if (inst >= 0) { |
194 | 0 | name = buff = talloc_asprintf(NULL, "%s-%u", p->name, (unsigned int)inst); |
195 | 0 | } else { |
196 | 0 | name = p->name; |
197 | 0 | } |
198 | |
|
199 | 0 | if (fr_dict_attr_add(dict, parent, name, p->attr + base, p->type, &dict_flags) < 0) { |
200 | 0 | talloc_free(buff); |
201 | 0 | return -1; |
202 | 0 | } |
203 | | |
204 | 0 | attr = fr_dict_attr_by_name(NULL, parent, name); |
205 | 0 | if (!attr) { |
206 | 0 | fr_strerror_printf("Failed adding test attribute \"%s\"", name); |
207 | 0 | talloc_free(buff); |
208 | 0 | return -1; |
209 | 0 | } |
210 | | |
211 | 0 | talloc_free(buff); |
212 | 0 | } else { |
213 | 0 | if (fr_dict_attr_add(dict, parent, p->name, p->attr, p->type, &dict_flags) < 0) return -1; |
214 | | |
215 | 0 | attr = fr_dict_attr_by_name(NULL, parent, p->name); |
216 | 0 | if (!attr) { |
217 | 0 | fr_strerror_printf("Failed adding test attribute \"%s\"", p->name); |
218 | 0 | return -1; |
219 | 0 | } |
220 | 0 | } |
221 | | |
222 | | /* Add the enumeration values */ |
223 | 0 | if (p->values) { |
224 | 0 | fr_dict_test_attr_value_t *v; |
225 | |
|
226 | 0 | for (v = p->values; |
227 | 0 | v->key != NULL; |
228 | 0 | v++) fr_dict_enum_add_name(fr_dict_attr_unconst(attr), v->key, v->val, false, false); |
229 | 0 | } |
230 | |
|
231 | 0 | *p->da = attr; |
232 | 0 | } |
233 | | |
234 | 0 | return 0; |
235 | 0 | } |
236 | | |
237 | | /** Initialise a test dictionary and add our test_defs to it |
238 | | * |
239 | | * @param[in] ctx to bind the global dictionary ctx lifetim to. |
240 | | * @param[out] dict_p Where to write a pointer to our test dictionary. |
241 | | * May be NULL. |
242 | | * @param[in] test_defs Test attributes. If NULL will default to the |
243 | | * default test attributes. |
244 | | * @return |
245 | | * - 0 on success. |
246 | | * - -1 on failure. |
247 | | */ |
248 | | int fr_dict_test_init(TALLOC_CTX *ctx, fr_dict_t **dict_p, fr_dict_test_attr_t const *test_defs) |
249 | 0 | { |
250 | 0 | fr_dict_gctx_t const *our_dict_gctx; |
251 | 0 | fr_dict_t *dict; |
252 | |
|
253 | 0 | our_dict_gctx = fr_dict_global_ctx_init(ctx, false, "share/dictionary"); |
254 | 0 | if (!our_dict_gctx) return -1; |
255 | | |
256 | 0 | if (!test_defs) test_defs = fr_dict_test_attrs; |
257 | | |
258 | | /* |
259 | | * Set the root name of the dictionary |
260 | | */ |
261 | 0 | dict = fr_dict_alloc("test", 42); |
262 | 0 | if (!dict) { |
263 | 0 | error: |
264 | 0 | fr_dict_global_ctx_free(our_dict_gctx); |
265 | 0 | return -1; |
266 | 0 | } |
267 | | |
268 | 0 | if (fr_dict_test_attrs_init(dict, test_defs, 0, 0) < 0) goto error; |
269 | | |
270 | 0 | fr_dict_test = dict; |
271 | |
|
272 | 0 | if (dict_p) *dict_p = dict; |
273 | |
|
274 | 0 | return 0; |
275 | 0 | } |