Reject non-hex workspace colors

9dcf7d3a276e43eecf8c0a17872ec1f927741a95
Alexis Sellier committed ago 1 parent f9d5f530
Makefile +12 -2
189 189
	@echo "cc   test/unit.c => $@"
190 190
	@$(CC) $(TEST_CPPFLAGS) $(TEST_CFLAGS) test/unit.c util.c \
191 191
		ext-workspace-v1-protocol.c swm-toplevel-v1-protocol.c \
192 192
		swm-workspace-v1-protocol.c $(LDLIBS) -o $@
193 193
194 +
$(TEST_BIN)/ctl-unit: test/ctl_unit.c swmctl.c \
195 +
		ext-foreign-toplevel-list-v1-client-protocol.h \
196 +
		swm-toplevel-v1-client-protocol.h swm-workspace-v1-client-protocol.h \
197 +
		ext-foreign-toplevel-list-v1-protocol.c swm-toplevel-v1-protocol.c \
198 +
		swm-workspace-v1-protocol.c | $(TEST_BIN)
199 +
	@echo "cc   test/ctl_unit.c => $@"
200 +
	@$(CC) -I. $(CTL_CPPFLAGS) $(TEST_CFLAGS) test/ctl_unit.c \
201 +
		ext-foreign-toplevel-list-v1-protocol.c swm-toplevel-v1-protocol.c \
202 +
		swm-workspace-v1-protocol.c $(CTL_LDLIBS) -o $@
203 +
194 204
$(TEST_BIN)/swm: $(TEST_COMMON) | $(TEST_BIN)
195 205
	@echo "cc   swm.c => $@"
196 206
	@$(CC) $(TEST_CPPFLAGS) $(TEST_CFLAGS) $(TEST_SRC)/swm.c util.c \
197 207
		ext-workspace-v1-protocol.c swm-toplevel-v1-protocol.c \
198 208
		swm-workspace-v1-protocol.c $(LDLIBS) -o $@
204 214
	@echo "cc   swmctl.c => $@"
205 215
	@$(CC) $(CTL_CPPFLAGS) $(TEST_CFLAGS) swmctl.c \
206 216
		ext-foreign-toplevel-list-v1-protocol.c swm-toplevel-v1-protocol.c \
207 217
		swm-workspace-v1-protocol.c $(CTL_LDLIBS) -o $@
208 218
209 -
test-build: $(TEST_BIN)/unit $(TEST_BIN)/swm $(TEST_BIN)/swmctl
219 +
test-build: $(TEST_BIN)/unit $(TEST_BIN)/ctl-unit $(TEST_BIN)/swm $(TEST_BIN)/swmctl
210 220
211 221
test: test-build
212 222
	@SWM_TEST_BUILD=$(abspath $(TEST_BUILD)) PKG_CONFIG=$(PKG_CONFIG) $(PYTHON) test/run.py
213 223
214 -
test-unit: $(TEST_BIN)/unit
224 +
test-unit: $(TEST_BIN)/unit $(TEST_BIN)/ctl-unit
215 225
	@SWM_TEST_BUILD=$(abspath $(TEST_BUILD)) PKG_CONFIG=$(PKG_CONFIG) $(PYTHON) test/run.py unit
216 226
217 227
test-integration: $(TEST_BIN)/swm $(TEST_BIN)/swmctl
218 228
	@SWM_TEST_BUILD=$(abspath $(TEST_BUILD)) PKG_CONFIG=$(PKG_CONFIG) $(PYTHON) test/run.py integration
219 229
swmctl.c +2 -1
376 376
static uint32_t parse_color(const char *value) {
377 377
    char         *end;
378 378
    unsigned long color;
379 379
    size_t        length = strlen(value);
380 380
381 -
    if ((length != 7 && length != 9) || value[0] != '#')
381 +
    if ((length != 7 && length != 9) || value[0] != '#' ||
382 +
        strspn(value + 1, "0123456789abcdefABCDEF") != length - 1)
382 383
        usage();
383 384
    errno = 0;
384 385
    color = strtoul(value + 1, &end, 16);
385 386
    if (errno || *end || color > 0xffffffff)
386 387
        usage();
test/ctl_unit.c added +35 -0
1 +
#include <assert.h>
2 +
#include <fcntl.h>
3 +
#include <sys/wait.h>
4 +
#include <unistd.h>
5 +
6 +
#define main swmctl_program_main
7 +
#include "swmctl.c"
8 +
#undef main
9 +
10 +
static void expect_invalid_color(const char *value) {
11 +
    pid_t child = fork();
12 +
    int status;
13 +
14 +
    assert(child >= 0);
15 +
    if (!child) {
16 +
        int nullfd = open("/dev/null", O_WRONLY);
17 +
18 +
        assert(nullfd >= 0);
19 +
        assert(dup2(nullfd, STDERR_FILENO) >= 0);
20 +
        close(nullfd);
21 +
        parse_color(value);
22 +
        _exit(EXIT_SUCCESS);
23 +
    }
24 +
    assert(waitpid(child, &status, 0) == child);
25 +
    assert(WIFEXITED(status));
26 +
    assert(WEXITSTATUS(status) == EXIT_FAILURE);
27 +
}
28 +
29 +
int main(void) {
30 +
    assert(parse_color("#012345") == 0x012345ff);
31 +
    assert(parse_color("#01234567") == 0x01234567);
32 +
    expect_invalid_color("# 12345");
33 +
    expect_invalid_color("#+12345");
34 +
    return EXIT_SUCCESS;
35 +
}
test/run.py +7 -1
198 198
def prepare_suite(unit: bool, integration: bool) -> None:
199 199
    """Prepare runtime files for the selected tests."""
200 200
201 201
    binaries = [
202 202
        BIN / name
203 -
        for name, selected in (("unit", unit), ("swm", integration), ("swmctl", integration))
203 +
        for name, selected in (
204 +
            ("unit", unit),
205 +
            ("ctl-unit", unit),
206 +
            ("swm", integration),
207 +
            ("swmctl", integration),
208 +
        )
204 209
        if selected
205 210
    ]
206 211
    missing = [binary for binary in binaries if not binary.exists()]
207 212
    if missing:
208 213
        raise Failure(f"test binary not built: {missing[0]}; run tests through make")
253 258
    env["LLVM_PROFILE_FILE"] = str(PROFILES / "unit-%m-%p.profraw")
254 259
    env["SWM_TEST_STUB_PATH"] = str(BUILD / "stubs")
255 260
    env["SWM_TEST_DIR"] = str(runtime)
256 261
    for name in run(BIN / "unit", "--list", env=env).splitlines():
257 262
        test(name, lambda name=name: run(BIN / "unit", name, env=env))
263 +
    test("control-client-parsing", lambda: run(BIN / "ctl-unit", env=env))
258 264
    shutil.rmtree(runtime)
259 265
260 266
261 267
def current_title() -> str:
262 268
    """Return the compositor's published title."""