Files

149 lines
4.1 KiB
C

#include "test_motd.h"
#include "motd.h"
#include "protocol.h"
#include "test_utils.h"
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
/* Write `body` (len bytes) to a fresh temp file; returns its heap path. */
static int write_file(const char* body, size_t len, char** out_path) {
char tmpl[] = "/tmp/fastsync_motd_XXXXXX";
int fd = mkstemp(tmpl);
if (fd < 0)
return -1;
if (write(fd, body, len) != (ssize_t)len) {
close(fd);
unlink(tmpl);
return -1;
}
close(fd);
*out_path = strdup(tmpl);
return *out_path ? 0 : -1;
}
static void test_motd_read_present() {
char* path;
char body[] = "Welcome to FastSync\nBe excellent to each other.\n";
EXPECT_EQ_INT(write_file(body, strlen(body), &path), 0);
char* motd = motd_read_file(path);
unlink(path);
free(path);
EXPECT_NOT_NULL(motd);
EXPECT_EQ_STR(motd, body);
free(motd);
}
static void test_motd_read_absent() {
EXPECT_NULL(motd_read_file("/nonexistent/fastsync_motd_zzz"));
EXPECT_NULL(motd_read_file(""));
EXPECT_NULL(motd_read_file(NULL));
}
static void test_motd_read_unreadable() {
/* Reading a directory through fopen succeeds for the open but fread fails
* with EISDIR, which is a reliable "unreadable" probe even for root. */
const char* dir = "/tmp";
EXPECT_NULL(motd_read_file(dir));
}
static void test_motd_read_large_truncated() {
size_t total = MOTD_MAX_BYTES + 100;
char* body = malloc(total);
EXPECT_NOT_NULL(body);
memset(body, 'x', total);
body[0] = 'h';
char* path;
EXPECT_EQ_INT(write_file(body, total, &path), 0);
char* motd = motd_read_file(path);
unlink(path);
free(path);
EXPECT_NOT_NULL(motd);
EXPECT_EQ_INT((int)strlen(motd), MOTD_MAX_BYTES);
EXPECT_EQ_INT(motd[0], 'h');
EXPECT_EQ_INT(motd[MOTD_MAX_BYTES - 1], 'x');
EXPECT_EQ_STR(motd + MOTD_MAX_BYTES, "");
free(motd);
free(body);
}
static void test_motd_render_escaping() {
/* Newlines/tabs survive; control bytes (ESC included) become \NNN octal. */
char* rendered = motd_render("line1\n\tansi\033[31m", false);
EXPECT_NOT_NULL(rendered);
EXPECT_EQ_STR(rendered, "line1\n\tansi\\#033[31m");
free(rendered);
/* High-bit bytes are escaped without --8-bit-output. */
rendered = motd_render("\xC3\xA9", false);
EXPECT_NOT_NULL(rendered);
EXPECT_EQ_STR(rendered, "\\#303\\#251");
free(rendered);
/* --8-bit-output keeps bytes >= 0x80 verbatim. */
rendered = motd_render("\xC3\xA9", true);
EXPECT_NOT_NULL(rendered);
EXPECT_EQ_STR(rendered, "\xC3\xA9");
free(rendered);
EXPECT_NULL(motd_render(NULL, false));
}
static void test_motd_frame_roundtrip() {
int p[2];
EXPECT_EQ_INT(pipe(p), 0);
io_set_fds(p[0], p[1]);
io_set_bwlimit(0);
const char* motd = "Greetings from the module server.\nEnjoy your stay.\n";
EXPECT_TRUE(motd_send(0, motd));
char* received = motd_receive(0);
EXPECT_NOT_NULL(received);
EXPECT_EQ_STR(received, motd);
free(received);
/* An unset MOTD is an empty (but present) frame, not an error. */
EXPECT_TRUE(motd_send(0, NULL));
received = motd_receive(0);
EXPECT_NOT_NULL(received);
EXPECT_EQ_STR(received, "");
free(received);
close(p[0]);
close(p[1]);
}
static void test_motd_receive_over_bound_rejected() {
int p[2];
EXPECT_EQ_INT(pipe(p), 0);
io_set_fds(p[0], p[1]);
io_set_bwlimit(0);
size_t size = MOTD_MAX_BYTES + 100;
char* big = malloc(size);
EXPECT_NOT_NULL(big);
memset(big, 'a', size);
big[size - 1] = '\0';
/* A (hostile/oversized) peer frame within MAX_STRING_SIZE but above the MOTD
* bound is consumed and discarded: motd_receive returns NULL and the stream
* stays framed for the next message. */
EXPECT_TRUE(send_str(0, big));
EXPECT_NULL(motd_receive(0));
EXPECT_TRUE(send_str(0, "after"));
char* next = receive_str(0);
EXPECT_NOT_NULL(next);
EXPECT_EQ_STR(next, "after");
free(next);
free(big);
close(p[0]);
close(p[1]);
}
void test_motd() {
test_motd_read_present();
test_motd_read_absent();
test_motd_read_unreadable();
test_motd_read_large_truncated();
test_motd_render_escaping();
test_motd_frame_roundtrip();
test_motd_receive_over_bound_rejected();
}