dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 100.0% 73 / 0 / 73
Functions: 100.0% 3 / 0 / 3
Branches: 97.1% 33 / 18 / 52

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