Coverage Report

Created: 2026-02-26 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}