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 8031 static bool run_command(CommandRunner *runner, char **av)
18 {
19 8031 const CommandSet *cmds = runner->cmds;
20 8031 struct EditorState *e = runner->e;
21 8031 ErrorBuffer *ebuf = runner->ebuf;
22 8031 BUG_ON(!cmds);
23 8031 BUG_ON(!e);
24 8031 BUG_ON(!ebuf);
25
26 8031 const Command *cmd = cmds->lookup(av[0]);
27
2/2
✓ Branch 9 → 10 taken 35 times.
✓ Branch 9 → 30 taken 7996 times.
8031 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 7346 times.
✓ Branch 30 → 33 taken 650 times.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 33 taken 7345 times.
7996 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 7990 times.
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 36 not taken.
7995 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 7995 begin_change(CHANGE_MERGE_NONE);
72
73 7995 CommandArgs a = cmdargs_new(av + 1);
74
4/4
✓ Branch 38 → 39 taken 7988 times.
✓ Branch 38 → 42 taken 7 times.
✓ Branch 40 → 41 taken 137 times.
✓ Branch 40 → 42 taken 7851 times.
7995 bool r = likely(parse_args(cmd, &a, ebuf)) && command_func_call(e, ebuf, cmd, &a);
75
76 7995 end_change();
77 7995 return r;
78 }
79
80 // Recursion is limited by MAX_RECURSION_DEPTH
81 // NOLINTNEXTLINE(misc-no-recursion)
82 9464 static bool run_commands(CommandRunner *runner, const PointerArray *array)
83 {
84
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 9463 times.
9464 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 9463 bool stop_at_first_err = (runner->flags & CMDRUNNER_STOP_AT_FIRST_ERROR);
89 9463 void **ptrs = array->ptrs;
90 9463 size_t len = array->count;
91 9463 size_t nfailed = 0;
92 9463 BUG_ON(len == 0);
93 9463 BUG_ON(ptrs[len - 1] != NULL);
94 9463 runner->recursion_count++;
95
96
2/2
✓ Branch 18 → 11 taken 9560 times.
✓ Branch 18 → 19 taken 9461 times.
19021 for (size_t s = 0, e = 0; s < len; ) {
97 // Iterate over strings, until a terminating NULL is encountered
98 37696 while (ptrs[e]) {
99 28136 e++;
100 37696 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 8031 times.
✓ Branch 12 → 17 taken 1529 times.
9560 if (e != s) {
106
2/2
✓ Branch 14 → 15 taken 167 times.
✓ Branch 14 → 17 taken 7864 times.
8031 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 9558 s = ++e;
116 }
117
118 9461 out:
119 9463 runner->recursion_count--;
120 9463 return (nfailed == 0);
121 }
122
123 9439 bool handle_command(CommandRunner *runner, const char *cmd)
124 {
125 9439 BUG_ON(runner->recursion_count != 0);
126 9439 PointerArray array = PTR_ARRAY_INIT;
127 9439 CommandParseError err = parse_commands(runner, &array, cmd);
128 9439 bool r;
129
2/2
✓ Branch 5 → 6 taken 9434 times.
✓ Branch 5 → 9 taken 5 times.
9439 if (likely(err == CMDERR_NONE)) {
130 9434 r = run_commands(runner, &array);
131 9434 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 9439 ptr_array_free(&array);
138 9439 return r;
139 }
140