dte test coverage


Directory: ./
File: test/error.c
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 53 53 100.0%
Functions: 2 2 100.0%
Branches: 3 4 75.0%

Line Branch Exec Source
1 #include "test.h"
2 #include "commands.h"
3 #include "editor.h"
4 #include "error.h"
5 #include "util/ascii.h"
6 #include "util/debug.h"
7 #include "window.h"
8
9 1 static const char *dummy_lookup_alias(const EditorState *e, const char *name)
10 {
11 1 BUG_ON(!e);
12 1 BUG_ON(!name);
13 1 return "insert \"...";
14 }
15
16 1 static void test_normal_command_errors(TestContext *ctx)
17 {
18 1 static const struct {
19 const char *cmd_str;
20 const char *expected_error_substr;
21 } tests[] = {
22 // Note: do not include error substrings produced by strerror(3)
23 {"non__existent__command", "no such command or alias"},
24 {"alias '' up", "empty alias name"},
25 {"alias -- -name up", "alias name cannot begin with '-'"},
26 {"alias 'x y' up", "invalid byte in alias name"},
27 {"alias open close", "can't replace existing command"},
28 {"bind C-C-C", "invalid key string"},
29 {"bind -T invalid-mode C-k eol", "can't bind key in unknown mode"},
30 {"cd", "too few arguments"},
31 {"cd ''", "directory argument cannot be empty"},
32 {"cd /non-existent/dir/_x_29_", "changing directory failed"},
33 {"compile dfa34dazzdf2 echo", "no such error parser"},
34 {"cursor xyz bar #f40", "invalid mode argument"},
35 {"cursor insert _ #f40", "invalid cursor type"},
36 {"cursor insert bar blue", "invalid cursor color"},
37 {"def-mode normal", "mode 'normal' already exists"},
38 {"def-mode command", "mode 'command' already exists"},
39 {"def-mode search", "mode 'search' already exists"},
40 {"def-mode _m; def-mode _m", "mode '_m' already exists"},
41 {"errorfmt x (re) zz", "unknown substring name"},
42 {"errorfmt x (re) file line", "invalid substring count"},
43 {"exec -s sh -c 'kill -s USR1 $$'", "child received signal"},
44 {"exec -s sh -c 'exit 44'", "child returned 44"},
45 {"exec -s _z9kjdf_2dmm_92:j-a3d_xzkw::", "unable to exec"},
46 {"exec -s -e errmsg sh -c 'echo X >&2; exit 9'", "child returned 9: \"X\""},
47 {"ft -- -name ext", "invalid filetype name"},
48 {"hi xyz red green blue", "too many colors"},
49 {"hi xyz _invalid_", "invalid color or attribute"},
50 {"line 0", "invalid line number"},
51 {"line _", "invalid line number"},
52 {"line 1:x", "invalid line number"},
53 {"macro xyz", "unknown action"},
54 {"match-bracket", "no character under cursor"},
55 {"move-tab 0", "invalid tab position"},
56 {"msg -np", "mutually exclusive"},
57 {"msg -p 12", "mutually exclusive"},
58 {"open -t filename", "can't be used with filename arguments"},
59 {"open /non/exi/ste/nt/file_Name", "error opening"},
60 {"open /dev/null", "not a regular file"},
61 {"option c auto-indent true syntax", "missing option value"},
62 {"option c filetype c", "filetype cannot be set via option command"},
63 {"option , auto-indent true", "invalid filetype"},
64 {"option -r '' auto-indent true", "empty pattern"},
65 {"quit xyz", "not a valid integer"},
66 {"quit 9000", "exit code should be between"},
67 {"redo 8", "nothing to redo"},
68 {"repeat x up", "not a valid repeat count"},
69 {"repeat 2 invalid-cmd", "no such command: invalid-cmd"},
70 {"replace '' x", "must contain at least 1 character"},
71 {"replace e5fwHgHuCFVZd x", "not found"},
72 {"replace -c a b", "-c flag unavailable in headless mode"},
73 {"save ''", "empty filename"},
74 {"save", "no filename"},
75 {"search -nw", "mutually exclusive"},
76 {"search -p str", "mutually exclusive"},
77 {"search e5fwHgHuCFVZd", "not found"},
78 {"set filetype", "not boolean"},
79 {"set filetype ' '", "invalid filetype name"},
80 {"set tab-width s", "integer value for tab-width expected"},
81 {"set indent-width 9", "must be in 1-8 range"},
82 {"set emulate-tab x", "invalid value"},
83 {"set case-sensitive-search z", "invalid value"},
84 {"set ws-error A", "invalid flag"},
85 {"set non-existent 1", "no such option"},
86 {"set -g filetype c", "not global"},
87 {"set -l statusline-right _", "not local"},
88 {"set 1 2 3", "one or even number of arguments expected"},
89 {"set statusline-left %", "format character expected"},
90 {"set statusline-left %!", "invalid format character"},
91 {"setenv DTE_VERSION 0.1", "cannot be changed"},
92 {"shift x", "invalid number"},
93 {"shift 0", "must be non-zero"},
94 {"show -c alias", "requires 2 arguments"},
95 {"show zzz", "invalid argument"},
96 {"show bind M-M-M---", "invalid key string"},
97 {"show buffer x", "doesn't take extra arguments"},
98 {"show builtin a78sd8623d7k", "no built-in config"},
99 {"show cursor xyz", "no cursor entry"},
100 {"show option 31ldx92kjsd8", "invalid option name"},
101 {"show wsplit m2wz9u263t8a", "invalid window"},
102 {"suspend", "unavailable in headless mode"},
103 {"toggle ws-error", "requires arguments"},
104 {"view z", "invalid view index"},
105 {"view 0", "invalid view index"},
106 {"wrap-paragraph _", "invalid paragraph width"},
107 {"wrap-paragraph 90000", "width must be between"},
108 {"wsplit -t file", "flags -n and -t can't be used with filename"},
109
110 // Error strings produced by arg_parse_error_msg():
111 {"bind -nnnnnnnnnn C-k eol", "too many options given"},
112 {"bind -Z C-k eol", "invalid option -Z"},
113 {"bind -Tsearch C-k eol", "option -T must be given separately"},
114 {"bind -T ", "option -T requires an argument"},
115 {"bind 1 2 3", "too many arguments"},
116 {"bind", "too few arguments"},
117 };
118
119 1 EditorState *e = ctx->userdata;
120 1 ASSERT_NONNULL(window_open_empty_buffer(e->window));
121
122
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1 times.
93 FOR_EACH_I(i, tests) {
123 92 const char *cmd = tests[i].cmd_str;
124 92 const char *substr = tests[i].expected_error_substr;
125 92 ASSERT_NONNULL(cmd);
126 92 ASSERT_NONNULL(substr);
127 92 ASSERT_TRUE(substr[0] != '\0');
128 92 ASSERT_TRUE(substr[1] != '\0');
129 92 ASSERT_TRUE(!ascii_isupper(substr[0]));
130
131 92 clear_error();
132 92 EXPECT_FALSE(handle_normal_command(e, cmd, false));
133 92 bool is_error = false;
134 92 const char *msg = get_msg(&is_error);
135 92 ASSERT_NONNULL(msg);
136 92 EXPECT_TRUE(is_error);
137
138 // Check for substring in error message (ignoring capitalization)
139 92 const char *found = strstr(msg, substr + 1);
140
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 if (likely(found && found != msg)) {
141 92 test_pass(ctx);
142 92 EXPECT_EQ(ascii_tolower(found[-1]), substr[0]);
143 } else {
144 TEST_FAIL (
145 "Test #%zu: substring \"%s\" not found in message \"%s\"",
146 i + 1, substr, msg
147 );
148 }
149 }
150
151 1 window_close_current_view(e->window);
152 1 set_view(e->window->view);
153
154 // Special case errors produced by run_command():
155 // ----------------------------------------------
156
157 1 CommandRunner runner = normal_mode_cmdrunner(e);
158 1 runner.lookup_alias = NULL;
159 1 clear_error();
160 1 EXPECT_FALSE(handle_command(&runner, "_xyz"));
161 1 bool is_error = false;
162 1 const char *msg = get_msg(&is_error);
163 1 EXPECT_STREQ(msg, "No such command: _xyz");
164 1 EXPECT_TRUE(is_error);
165
166 1 runner.lookup_alias = dummy_lookup_alias;
167 1 clear_error();
168 1 EXPECT_FALSE(handle_command(&runner, "_abc"));
169 1 msg = get_msg(&is_error);
170 1 EXPECT_TRUE(msg && str_has_prefix(msg, "Parsing alias _abc:"));
171 1 EXPECT_TRUE(is_error);
172
173 1 EXPECT_NULL(current_config.file);
174 1 current_config.file = "example";
175 1 current_config.line = 1;
176 1 runner.lookup_alias = NULL;
177 1 clear_error();
178 1 EXPECT_FALSE(handle_command(&runner, "quit"));
179 1 msg = get_msg(&is_error);
180 1 EXPECT_STREQ(msg, "example:1: Command quit not allowed in config file");
181 1 EXPECT_TRUE(is_error);
182 1 current_config.file = NULL;
183
184 // TODO: Cover alias recursion overflow check in run_commands()
185 1 }
186
187 static const TestEntry tests[] = {
188 TEST(test_normal_command_errors),
189 };
190
191 const TestGroup error_tests = TEST_GROUP(tests);
192