dte test coverage


Directory: ./
File: test/init.c
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 101 107 94.4%
Functions: 5 5 100.0%
Branches: 2 4 50.0%

Line Branch Exec Source
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include "test.h"
9 #include "editor.h"
10 #include "terminal/color.h"
11 #include "terminal/terminal.h"
12 #include "util/fd.h"
13 #include "util/log.h"
14 #include "util/path.h"
15 #include "util/xreadwrite.h"
16 #include "version.h"
17
18 1 static void test_process_sanity(TestContext *ctx)
19 {
20 // Note that if this fails, there'll only be (at best) an "aborted"
21 // message, since there's no stderr for test_fail() to use
22 1 ASSERT_TRUE(fd_is_valid(STDERR_FILENO));
23
24 1 ASSERT_NONNULL(freopen("/dev/null", "r", stdin));
25 1 ASSERT_NONNULL(freopen("/dev/null", "w", stdout));
26 1 }
27
28 1 static void test_posix_sanity(TestContext *ctx)
29 {
30 // This is not guaranteed by ISO C99, but it is required by POSIX
31 // and is relied upon by this codebase:
32 1 ASSERT_EQ(CHAR_BIT, 8);
33 1 ASSERT_TRUE(sizeof(int) >= 4);
34
35 IGNORE_WARNING("-Wformat-truncation")
36
37 // Some snprintf(3) implementations historically returned -1 in case of
38 // truncation. C99 and POSIX 2001 both require that it return the full
39 // size of the formatted string, as if there had been enough space.
40 1 char buf[8] = "........";
41 1 ASSERT_EQ(snprintf(buf, 8, "0123456789"), 10);
42 1 ASSERT_EQ(buf[7], '\0');
43 1 EXPECT_STREQ(buf, "0123456");
44
45 // C99 and POSIX 2001 also require the same behavior as above when the
46 // size argument is 0 (and allow the buffer argument to be NULL).
47 1 ASSERT_EQ(snprintf(NULL, 0, "987654321"), 9);
48
49 UNIGNORE_WARNINGS
50 1 }
51
52 // Note: this must be ordered before a successful call to log_open()
53 // (i.e. the one in test_init()), so as not to trigger the BUG_ON()
54 // assertions at the top of log_open()
55 1 static void test_log_open_errors(TestContext *ctx)
56 {
57 1 const LogLevel none = LOG_LEVEL_NONE;
58 1 const LogLevel info = LOG_LEVEL_INFO;
59 1 errno = 0;
60 1 ASSERT_EQ(log_open("/dev/null", none, false), none);
61 1 EXPECT_EQ(errno, 0);
62 1 ASSERT_EQ(log_open("build/test/non-existent-dir/x", info, false), none);
63 1 EXPECT_EQ(errno, ENOENT);
64
65
1/2
✓ Branch 0 (9→10) taken 1 times.
✗ Branch 1 (9→13) not taken.
1 if (access("/dev/full", W_OK) == 0) {
66 1 errno = 0;
67 1 ASSERT_EQ(log_open("/dev/full", info, false), none);
68 1 EXPECT_EQ(errno, ENOSPC);
69 }
70
71 1 int tty = open("/dev/tty", O_WRONLY | O_CLOEXEC | O_NOCTTY);
72
1/2
✗ Branch 0 (14→15) not taken.
✓ Branch 1 (14→23) taken 1 times.
1 if (tty >= 0) {
73 ASSERT_TRUE(tty > STDERR_FILENO);
74 ASSERT_TRUE(is_controlling_tty(tty));
75 EXPECT_EQ(xclose(tty), 0);
76 errno = 0;
77 ASSERT_EQ(log_open("/dev/tty", info, false), none);
78 EXPECT_EQ(errno, EINVAL);
79 }
80 1 }
81
82 1 static void test_init(TestContext *ctx)
83 {
84 1 char *home = path_absolute("build/test/HOME");
85 1 char *dte_home = path_absolute("build/test/DTE_HOME");
86 1 ASSERT_NONNULL(home);
87 1 ASSERT_NONNULL(dte_home);
88
89 1 ASSERT_TRUE(mkdir(home, 0755) == 0 || errno == EEXIST);
90 1 ASSERT_TRUE(mkdir(dte_home, 0755) == 0 || errno == EEXIST);
91
92 1 ASSERT_EQ(setenv("HOME", home, 1), 0);
93 1 ASSERT_EQ(setenv("DTE_HOME", dte_home, 1), 0);
94 1 ASSERT_EQ(setenv("XDG_RUNTIME_DIR", dte_home, 1), 0);
95 1 ASSERT_EQ(setenv("TZ", "UTC", 1), 0);
96
97 1 free(home);
98 1 free(dte_home);
99
100 1 ASSERT_EQ(unsetenv("TERM"), 0);
101 1 ASSERT_EQ(unsetenv("COLORTERM"), 0);
102
103 1 LogLevel lvl = LOG_LEVEL_WARNING;
104 1 ASSERT_EQ(log_open("build/test/log.txt", lvl, false), lvl);
105 1 LOG_CRITICAL("%s: testing LOG_CRITICAL()", __func__);
106 1 LOG_ERROR("%s: testing LOG_ERROR()", __func__);
107 1 LOG_WARNING("%s: testing LOG_WARNING()", __func__);
108 1 LOG_NOTICE("%s: testing LOG_NOTICE()", __func__);
109 1 LOG_INFO("%s: testing LOG_INFO()", __func__);
110 1 LOG_DEBUG("%s: testing LOG_DEBUG()", __func__);
111 1 LOG_TRACE("%s: testing LOG_TRACE()", __func__);
112 1 log_write(LOG_LEVEL_WARNING, STRN("testing log_write()"));
113 1 log_write(LOG_LEVEL_INFO, STRN("testing log_write()"));
114
115 1 EditorState *e = init_editor_state(EFLAG_HEADLESS);
116 1 ctx->userdata = e;
117 1 ASSERT_NONNULL(e);
118 1 ASSERT_NONNULL(e->user_config_dir);
119 1 ASSERT_NONNULL(e->home_dir.data);
120 1 EXPECT_NONNULL(e->terminal.obuf.buf);
121 1 EXPECT_NONNULL(e->terminal.ibuf.buf);
122
123 1 const char *ver = getenv("DTE_VERSION");
124 1 EXPECT_NONNULL(ver);
125 1 EXPECT_STREQ(ver, VERSION);
126 1 }
127
128 1 static void test_deinit(TestContext *ctx)
129 {
130 // Make sure default Terminal state wasn't changed
131 1 EditorState *e = ctx->userdata;
132 1 const Terminal *term = &e->terminal;
133 1 EXPECT_EQ(term->width, 80);
134 1 EXPECT_EQ(term->height, 24);
135 1 EXPECT_EQ(term->ncv_attributes, 0);
136 1 EXPECT_EQ(term->features, TFLAG_8_COLOR);
137 1 EXPECT_EQ(term->ibuf.len, 0);
138 1 EXPECT_NONNULL(term->ibuf.buf);
139
140 // Make sure no terminal output was buffered
141 1 const TermOutputBuffer *obuf = &term->obuf;
142 1 EXPECT_NONNULL(obuf->buf);
143 1 EXPECT_EQ(obuf->count, 0);
144 1 EXPECT_EQ(obuf->scroll_x, 0);
145 1 EXPECT_EQ(obuf->x, 0);
146 1 EXPECT_EQ(obuf->width, 0);
147 1 EXPECT_EQ(obuf->style.fg, COLOR_DEFAULT);
148 1 EXPECT_EQ(obuf->style.bg, COLOR_DEFAULT);
149 1 EXPECT_EQ(obuf->style.attr, 0);
150 1 EXPECT_EQ(obuf->cursor_style.type, CURSOR_DEFAULT);
151 1 EXPECT_EQ(obuf->cursor_style.color, COLOR_DEFAULT);
152
153 1 ASSERT_NONNULL(e->view);
154 1 ASSERT_NONNULL(e->buffer);
155 1 EXPECT_EQ(e->buffers.count, 1);
156 1 EXPECT_NULL(e->buffer->abs_filename);
157 1 EXPECT_PTREQ(e->buffer, e->buffers.ptrs[0]);
158 1 EXPECT_FALSE(e->child_controls_terminal);
159 1 EXPECT_EQ(e->flags, EFLAG_HEADLESS);
160 1 EXPECT_EQ(e->include_recursion_count, 0);
161
162 1 frame_remove(e, e->root_frame);
163 1 EXPECT_NULL(e->view);
164 1 EXPECT_NULL(e->buffer);
165 1 EXPECT_EQ(e->buffers.count, 0);
166
167 1 free_editor_state(e);
168 1 EXPECT_TRUE(log_close());
169 1 }
170
171 static const TestEntry itests[] = {
172 TEST(test_process_sanity),
173 TEST(test_posix_sanity),
174 TEST(test_log_open_errors),
175 TEST(test_init),
176 };
177
178 static const TestEntry dtests[] = {
179 TEST(test_deinit),
180 };
181
182 const TestGroup init_tests = TEST_GROUP(itests);
183 const TestGroup deinit_tests = TEST_GROUP(dtests);
184