dte test coverage


Directory: ./
File: src/command/run.c
Date: 2025-12-03 13:13:24
Coverage Exec Excl Total
Lines: 100.0% 70 0 70
Functions: 100.0% 3 0 3
Branches: 97.1% 33 0 34

Line Branch Exec Source
1 #include "run.h"
2 #include "args.h"
3 #include "parse.h"
4 #include "change.h"
5 #include "util/debug.h"
6 #include "util/ptr-array.h"
7 #include "util/xmalloc.h"
8
9 enum {
10 MAX_RECURSION_DEPTH = 16, // Maximum number of `alias` expansions
11 };
12
13 static bool run_commands(CommandRunner *runner, const PointerArray *array);
14
15 // Recursion is limited by MAX_RECURSION_DEPTH
16 // NOLINTNEXTLINE(misc-no-recursion)
17 7936 static bool run_command(CommandRunner *runner, char **av)
18 {
19 7936 const CommandSet *cmds = runner->cmds;
20 7936 const Command *cmd = cmds->lookup(av[0]);
21 7936 struct EditorState *e = runner->e;
22 7936 ErrorBuffer *ebuf = runner->ebuf;
23
24
2/2
✓ Branch 3 → 4 taken 35 times.
✓ Branch 3 → 24 taken 7901 times.
7936 if (!cmd) {
25 35 const char *name = av[0];
26
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 33 times.
35 if (!runner->lookup_alias) {
27 2 return error_msg_for_cmd(ebuf, NULL, "No such command: %s", name);
28 }
29
30 33 const char *alias_value = runner->lookup_alias(e, name);
31
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 31 times.
33 if (unlikely(!alias_value)) {
32 2 return error_msg_for_cmd(ebuf, NULL, "No such command or alias: %s", name);
33 }
34
35 31 PointerArray array = PTR_ARRAY_INIT;
36 31 CommandParseError err = parse_commands(runner, &array, alias_value);
37
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 14 taken 30 times.
31 if (unlikely(err != CMDERR_NONE)) {
38 1 const char *err_msg = command_parse_error_to_string(err);
39 1 ptr_array_free(&array);
40 1 return error_msg_for_cmd(ebuf, NULL, "Parsing alias %s: %s", name, err_msg);
41 }
42
43 // Remove NULL
44 30 array.count--;
45
46
2/2
✓ Branch 18 → 15 taken 35 times.
✓ Branch 18 → 19 taken 30 times.
65 for (size_t i = 1; av[i]; i++) {
47 35 ptr_array_append(&array, xstrdup(av[i]));
48 }
49 30 ptr_array_append(&array, NULL);
50
51 30 bool r = run_commands(runner, &array);
52 30 ptr_array_free(&array);
53 30 return r;
54 }
55
56
4/4
✓ Branch 24 → 25 taken 7285 times.
✓ Branch 24 → 27 taken 616 times.
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 27 taken 7284 times.
7901 if (unlikely(ebuf->config_filename && !(cmd->cmdopts & CMDOPT_ALLOW_IN_RC))) {
57 1 return error_msg_for_cmd(ebuf, NULL, "Command %s not allowed in config file", cmd->name);
58 }
59
60 // Record command in macro buffer, if recording (this needs to be done
61 // before parse_args() mutates the array)
62
3/4
✓ Branch 27 → 28 taken 5 times.
✓ Branch 27 → 30 taken 7895 times.
✓ Branch 28 → 29 taken 5 times.
✗ Branch 28 → 30 not taken.
7900 if ((runner->flags & CMDRUNNER_ALLOW_RECORDING) && runner->cmds->macro_record) {
63 5 runner->cmds->macro_record(e, cmd, av + 1);
64 }
65
66 // By default change can't be merged with previous one.
67 // Any command can override this by calling begin_change() again.
68 7900 begin_change(CHANGE_MERGE_NONE);
69
70 7900 CommandArgs a = cmdargs_new(av + 1);
71
4/4
✓ Branch 32 → 33 taken 7893 times.
✓ Branch 32 → 36 taken 7 times.
✓ Branch 34 → 35 taken 138 times.
✓ Branch 34 → 36 taken 7755 times.
7900 bool r = likely(parse_args(cmd, &a, ebuf)) && command_func_call(e, ebuf, cmd, &a);
72
73 7900 end_change();
74 7900 return r;
75 }
76
77 // Recursion is limited by MAX_RECURSION_DEPTH
78 // NOLINTNEXTLINE(misc-no-recursion)
79 9345 static bool run_commands(CommandRunner *runner, const PointerArray *array)
80 {
81
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 9344 times.
9345 if (unlikely(runner->recursion_count > MAX_RECURSION_DEPTH)) {
82 1 return error_msg_for_cmd(runner->ebuf, NULL, "alias recursion limit reached");
83 }
84
85 9344 bool stop_at_first_err = (runner->flags & CMDRUNNER_STOP_AT_FIRST_ERROR);
86 9344 void **ptrs = array->ptrs;
87 9344 size_t len = array->count;
88 9344 size_t nfailed = 0;
89 9344 BUG_ON(len == 0);
90 9344 BUG_ON(ptrs[len - 1] != NULL);
91 9344 runner->recursion_count++;
92
93
2/2
✓ Branch 18 → 11 taken 9441 times.
✓ Branch 18 → 19 taken 9342 times.
18783 for (size_t s = 0, e = 0; s < len; ) {
94 // Iterate over strings, until a terminating NULL is encountered
95 37228 while (ptrs[e]) {
96 27787 e++;
97 37228 BUG_ON(e >= len);
98 }
99
100 // If the value of `e` (end) changed, there's a run of at least
101 // 1 string, which is a command followed by 0 or more arguments
102
2/2
✓ Branch 12 → 13 taken 7936 times.
✓ Branch 12 → 17 taken 1505 times.
9441 if (e != s) {
103
2/2
✓ Branch 14 → 15 taken 168 times.
✓ Branch 14 → 17 taken 7768 times.
7936 if (!run_command(runner, (char**)ptrs + s)) {
104 168 nfailed++;
105
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 17 taken 166 times.
168 if (stop_at_first_err) {
106 2 goto out;
107 }
108 }
109 }
110
111 // Skip past the NULL, onto the next command (if any)
112 9439 s = ++e;
113 }
114
115 9342 out:
116 9344 runner->recursion_count--;
117 9344 return (nfailed == 0);
118 }
119
120 9320 bool handle_command(CommandRunner *runner, const char *cmd)
121 {
122 9320 BUG_ON(runner->recursion_count != 0);
123 9320 PointerArray array = PTR_ARRAY_INIT;
124 9320 CommandParseError err = parse_commands(runner, &array, cmd);
125 9320 bool r;
126
2/2
✓ Branch 5 → 6 taken 9315 times.
✓ Branch 5 → 9 taken 5 times.
9320 if (likely(err == CMDERR_NONE)) {
127 9315 r = run_commands(runner, &array);
128 9315 BUG_ON(runner->recursion_count != 0);
129 } else {
130 5 const char *str = command_parse_error_to_string(err);
131 5 error_msg_for_cmd(runner->ebuf, NULL, "Command syntax error: %s", str);
132 5 r = false;
133 }
134 9320 ptr_array_free(&array);
135 9320 return r;
136 }
137