Browse code

test_options_parse: Add test for read_config_string

The <inlineopt> test discovered the issue
fixed by commit "buffer: Fix buf_parse eating input".

Change-Id: Icb91d9c560b6f78f16571ac3052cc566d94afe99
Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1247
Message-Id: <20251008100222.4610-1-gert@greenie.muc.de>
URL: https://sourceforge.net/p/openvpn/mailman/message/59243809/
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Frank Lichtenheld authored on 2025/10/08 19:02:16
Showing 1 changed files
... ...
@@ -43,6 +43,9 @@ __wrap_add_option(struct options *options, char *p[], bool is_inline, const char
43 43
                   const unsigned int permission_mask, unsigned int *option_types_found,
44 44
                   struct env_set *es)
45 45
 {
46
+    function_called();
47
+    check_expected(p);
48
+    check_expected(is_inline);
46 49
 }
47 50
 
48 51
 void
... ...
@@ -185,11 +188,117 @@ test_parse_line(void **state)
185 185
     gc_free(&gc);
186 186
 }
187 187
 
188
+static void
189
+read_single_config(struct options *options, const char *config)
190
+{
191
+    unsigned int option_types_found = 0;
192
+    struct env_set es;
193
+    CLEAR(es);
194
+    read_config_string("test_options_parse", options, config, M_INFO, OPT_P_DEFAULT,
195
+                       &option_types_found, &es);
196
+}
197
+
198
+union tokens_parameter
199
+{
200
+    uintmax_t as_int;
201
+    void *as_pointer;
202
+};
203
+
204
+static int
205
+check_tokens(const uintmax_t value, const uintmax_t expected)
206
+{
207
+    union tokens_parameter temp;
208
+    temp.as_int = value;
209
+    const char **p = (const char **)temp.as_pointer;
210
+    temp.as_int = expected;
211
+    const char **expected_p = (const char **)temp.as_pointer;
212
+    for (int i = 0; i < MAX_PARMS; i++)
213
+    {
214
+        if (!p[i] && !expected_p[i])
215
+        {
216
+            return true;
217
+        }
218
+        if ((p[i] && !expected_p[i])
219
+            || (!p[i] && expected_p[i]))
220
+        {
221
+            fprintf(stderr, "diff at i=%d\n", i);
222
+            return false;
223
+        }
224
+        if (strcmp(p[i], expected_p[i]))
225
+        {
226
+            fprintf(stderr, "diff at i=%d, p=<%s> ep=<%s>\n", i, p[i], expected_p[i]);
227
+            return false;
228
+        }
229
+    }
230
+    fprintf(stderr, "fallthrough");
231
+    return false;
232
+}
233
+
234
+static void
235
+test_read_config(void **state)
236
+{
237
+    struct options o;
238
+    CLEAR(o); /* NB: avoiding init_options to limit dependencies */
239
+    gc_init(&o.gc);
240
+    gc_init(&o.dns_options.gc);
241
+    o.gc_owned = true;
242
+
243
+    char *p_expect_someopt[MAX_PARMS];
244
+    char *p_expect_otheropt[MAX_PARMS];
245
+    char *p_expect_inlineopt[MAX_PARMS];
246
+    CLEAR(p_expect_someopt);
247
+    CLEAR(p_expect_otheropt);
248
+    CLEAR(p_expect_inlineopt);
249
+    p_expect_someopt[0] = "someopt";
250
+    p_expect_someopt[1] = "parm1";
251
+    p_expect_someopt[2] = "parm2";
252
+    p_expect_otheropt[0] = "otheropt";
253
+    p_expect_otheropt[1] = "1";
254
+    p_expect_otheropt[2] = "2";
255
+    p_expect_inlineopt[0] = "inlineopt";
256
+    p_expect_inlineopt[1] = "some text\nother text\n";
257
+
258
+    /* basic test */
259
+    expect_function_call(__wrap_add_option);
260
+    expect_check(__wrap_add_option, p, check_tokens, p_expect_someopt);
261
+    expect_value(__wrap_add_option, is_inline, 0);
262
+    expect_function_call(__wrap_add_option);
263
+    expect_check(__wrap_add_option, p, check_tokens, p_expect_otheropt);
264
+    expect_value(__wrap_add_option, is_inline, 0);
265
+    read_single_config(&o, "someopt parm1 parm2\n  otheropt 1 2");
266
+
267
+    /* -- gets stripped */
268
+    expect_function_call(__wrap_add_option);
269
+    expect_check(__wrap_add_option, p, check_tokens, p_expect_someopt);
270
+    expect_value(__wrap_add_option, is_inline, 0);
271
+    expect_function_call(__wrap_add_option);
272
+    expect_check(__wrap_add_option, p, check_tokens, p_expect_otheropt);
273
+    expect_value(__wrap_add_option, is_inline, 0);
274
+    read_single_config(&o, "someopt parm1 parm2\n\t--otheropt 1 2");
275
+
276
+    /* inline options */
277
+    expect_function_call(__wrap_add_option);
278
+    expect_check(__wrap_add_option, p, check_tokens, p_expect_inlineopt);
279
+    expect_value(__wrap_add_option, is_inline, 1);
280
+    read_single_config(&o, "<inlineopt>\nsome text\nother text\n</inlineopt>");
281
+
282
+    p_expect_inlineopt[0] = "inlineopt";
283
+    p_expect_inlineopt[1] = A_TIMES_256 A_TIMES_256 A_TIMES_256 A_TIMES_256 A_TIMES_256 "\n";
284
+    expect_function_call(__wrap_add_option);
285
+    expect_check(__wrap_add_option, p, check_tokens, p_expect_inlineopt);
286
+    expect_value(__wrap_add_option, is_inline, 1);
287
+    read_single_config(&o, "<inlineopt>\n" A_TIMES_256 A_TIMES_256 A_TIMES_256 A_TIMES_256 A_TIMES_256 "\n</inlineopt>");
288
+
289
+    gc_free(&o.gc);
290
+    gc_free(&o.dns_options.gc);
291
+}
292
+
188 293
 int
189 294
 main(void)
190 295
 {
191 296
     const struct CMUnitTest tests[] = {
192 297
         cmocka_unit_test(test_parse_line),
298
+        cmocka_unit_test(test_read_config),
193 299
     };
194 300
 
195 301
     return cmocka_run_group_tests_name("options_parse", tests, NULL, NULL);