dte test coverage


Directory: ./
File: src/command/args.c
Date: 2025-11-12 12:04:10
Coverage Exec Excl Total
Lines: 100.0% 75 1 76
Functions: 100.0% 3 0 3
Branches: 93.0% 40 0 43

Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3 #include "args.h"
4 #include "util/str-array.h"
5 #include "util/xstring.h"
6
7 /*
8 * Flags and first "--" are removed.
9 * Flag arguments are moved to beginning.
10 * Other arguments come right after flag arguments.
11 *
12 * a->args field should be set before calling.
13 * If parsing succeeds, the other fields are set and 0 is returned.
14 */
15 10781 ArgParseError do_parse_args(const Command *cmd, CommandArgs *a)
16 {
17 10781 char **args = a->args;
18 10781 BUG_ON(!args);
19
20 10781 const char *flag_desc = cmd->flags;
21 10781 bool flags_after_arg = !(cmd->cmdopts & CMDOPT_NO_FLAGS_AFTER_ARGS);
22 10781 size_t argc = string_array_length(args);
23 10781 size_t nr_flags = 0;
24 10781 size_t nr_flag_args = 0;
25
26
2/2
✓ Branch 29 → 5 taken 17492 times.
✓ Branch 29 → 30 taken 7411 times.
24903 for (size_t i = 0; args[i]; ) {
27 17492 char *arg = args[i];
28
2/2
✓ Branch 5 → 6 taken 44 times.
✓ Branch 5 → 7 taken 17448 times.
17492 if (unlikely(streq(arg, "--"))) {
29 // Move the NULL too
30 44 memmove(args + i, args + i + 1, (argc - i) * sizeof(*args));
31 44 free(arg);
32 44 argc--;
33 44 break;
34 }
35
36
4/4
✓ Branch 7 → 8 taken 2176 times.
✓ Branch 7 → 9 taken 15272 times.
✓ Branch 8 → 9 taken 7 times.
✓ Branch 8 → 26 taken 2169 times.
17448 if (arg[0] != '-' || arg[1] == '\0') {
37
2/2
✓ Branch 9 → 10 taken 11964 times.
✓ Branch 9 → 30 taken 3315 times.
15279 if (!flags_after_arg) {
38 break;
39 }
40 11964 i++;
41 11964 continue;
42 }
43
44
2/2
✓ Branch 26 → 11 taken 2707 times.
✓ Branch 26 → 27 taken 2158 times.
4865 for (size_t j = 1; arg[j]; j++) {
45 2707 unsigned char flag = arg[j];
46 2707 const char *flagp = strchr(flag_desc, flag);
47
2/2
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 13 taken 2704 times.
2707 if (unlikely(!flagp || flag == '=')) {
48 3 a->flags[0] = flag;
49 3 return ARGERR_INVALID_OPTION;
50 }
51
52 2704 a->flag_set |= cmdargs_flagset_bit(flag);
53 2704 a->flags[nr_flags++] = flag;
54
2/2
✓ Branch 14 → 15 taken 2703 times.
✓ Branch 14 → 34 taken 1 time.
2704 if (unlikely(nr_flags == ARRAYLEN(a->flags))) {
55 return ARGERR_TOO_MANY_OPTIONS;
56 }
57
58
2/2
✓ Branch 15 → 16 taken 2665 times.
✓ Branch 15 → 17 taken 38 times.
2703 if (likely(flagp[1] != '=')) {
59 2665 continue;
60 }
61
62
3/4
✓ Branch 17 → 18 taken 38 times.
✗ Branch 17 → 19 not taken.
✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 20 taken 36 times.
38 if (unlikely(j > 1 || arg[j + 1])) {
63 2 a->flags[0] = flag;
64 2 return ARGERR_OPTION_ARGUMENT_NOT_SEPARATE;
65 }
66
67 36 char *flag_arg = args[i + 1];
68
2/2
✓ Branch 20 → 21 taken 5 times.
✓ Branch 20 → 22 taken 31 times.
36 if (unlikely(!flag_arg)) {
69 5 a->flags[0] = flag;
70 5 return ARGERR_OPTION_ARGUMENT_MISSING;
71 }
72
73 // Move flag argument before any other arguments
74
2/2
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 30 times.
31 if (i != nr_flag_args) {
75 // farg1 arg1 arg2 -f farg2 arg3
76 // farg1 farg2 arg1 arg2 arg3
77 1 size_t count = i - nr_flag_args;
78 1 char **ptr = args + nr_flag_args;
79 1 memmove(ptr + 1, ptr, count * sizeof(*args));
80 }
81 31 args[nr_flag_args++] = flag_arg;
82 31 i++;
83 }
84
85 2158 memmove(args + i, args + i + 1, (argc - i) * sizeof(*args));
86 2158 free(arg);
87 2158 argc--;
88 }
89
90 10770 a->flags[nr_flags] = '\0';
91 10770 a->nr_flags = nr_flags;
92 10770 a->nr_args = argc - nr_flag_args;
93 10770 a->nr_flag_args = nr_flag_args;
94
95
2/2
✓ Branch 30 → 31 taken 10734 times.
✓ Branch 30 → 34 taken 36 times.
10770 if (unlikely(a->nr_args < cmd->min_args)) {
96 return ARGERR_TOO_FEW_ARGUMENTS;
97 }
98
99 10734 static_assert_compatible_types(cmd->max_args, uint8_t);
100
4/4
✓ Branch 31 → 32 taken 6 times.
✓ Branch 31 → 34 taken 10728 times.
✓ Branch 32 → 33 taken 4 times.
✓ Branch 32 → 34 taken 2 times.
10734 if (unlikely(a->nr_args > cmd->max_args && cmd->max_args != 0xFF)) {
101 4 return ARGERR_TOO_MANY_ARGUMENTS;
102 }
103
104 return 0;
105 }
106
107 7 static bool arg_parse_error_msg (
108 const Command *cmd,
109 const CommandArgs *a,
110 ArgParseError err,
111 ErrorBuffer *ebuf
112 ) {
113 7 const char *name = cmd->name;
114
6/7
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 2 → 5 taken 1 time.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 2 → 7 taken 2 times.
✓ Branch 2 → 8 taken 1 time.
✗ Branch 2 → 9 not taken.
7 switch (err) {
115 1 case ARGERR_INVALID_OPTION:
116 1 return error_msg_for_cmd(ebuf, name, "Invalid option -%c", a->flags[0]);
117 1 case ARGERR_TOO_MANY_OPTIONS:
118 1 return error_msg_for_cmd(ebuf, name, "Too many options given");
119 1 case ARGERR_OPTION_ARGUMENT_MISSING:
120 1 return error_msg_for_cmd(ebuf, name, "Option -%c requires an argument", a->flags[0]);
121 1 case ARGERR_OPTION_ARGUMENT_NOT_SEPARATE:
122 1 return error_msg_for_cmd (
123 ebuf, name,
124 "Option -%c must be given separately because it requires an argument",
125 1 a->flags[0]
126 );
127 2 case ARGERR_TOO_FEW_ARGUMENTS:
128 2 return error_msg_for_cmd (
129 ebuf, name,
130 "Too few arguments (got: %zu, minimum: %u)",
131 2 a->nr_args, (unsigned int)cmd->min_args
132 );
133 1 case ARGERR_TOO_MANY_ARGUMENTS:
134 1 return error_msg_for_cmd (
135 ebuf, name,
136 "Too many arguments (got: %zu, maximum: %u)",
137 1 a->nr_args, (unsigned int)cmd->max_args
138 );
139 case ARGERR_NONE:
140 break;
141 }
142
143 BUG("unhandled error type");
144 return false;
145 }
146
147 7882 bool parse_args(const Command *cmd, CommandArgs *a, ErrorBuffer *ebuf)
148 {
149 7882 ArgParseError err = do_parse_args(cmd, a);
150
3/4
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 7 taken 7875 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 7 times.
7882 return likely(err == ARGERR_NONE) || arg_parse_error_msg(cmd, a, err, ebuf);
151 }
152