Add native C tests (make test-io)

For the moment these are functionally equivalent the end-to-end python tests
(make test) without spinning up and exercising the daemon. Eventually they
should extend or complement them.
master
Raheman Vaiya 4 years ago
parent b1fdaa4d01
commit ad2aecf022
  1. 13
      Makefile
  2. 10
      t/overload_2-2.t
  3. 31
      t/overload_2.t
  4. 246
      t/test-io.c

@ -95,3 +95,16 @@ test:
for f in *.sh; do \
./$$f; \
done
test-io:
-mkdir bin
$(CC) -o bin/test-io \
t/test-io.c \
src/keyboard.c \
src/string.c \
src/macro.c \
src/config.c \
src/error.c \
src/ini.c \
src/keys.c \
src/unicode.c && \
./bin/test-io t/test.conf t/*.t

@ -0,0 +1,10 @@
o down
; down
11ms
o up
; up
control down
shift down
control up
shift up

@ -0,0 +1,31 @@
o down
o up
o down
9ms
o up
o down
11ms
o up
o down
x down
x up
o up
o down
x down
o up
x up
a down
a up
a down
a up
control down
control up
control down
x down
x up
control up
a down
a up
x down
x up

@ -0,0 +1,246 @@
#include <stdio.h>
#include <stdlib.h>
#include "../src/keyd.h"
#define MAX_EVENTS 1024
struct key_event output[MAX_EVENTS];
size_t noutput = 0;
static uint8_t lookup_code(const char *name)
{
size_t i;
if (!strcmp(name, "control"))
return KEYD_LEFTCTRL;
if (!strcmp(name, "shift"))
return KEYD_LEFTSHIFT;
if (!strcmp(name, "meta"))
return KEYD_LEFTMETA;
if (!strcmp(name, "alt"))
return KEYD_LEFTALT;
for (i = 0; i < ARRAY_SIZE(keycode_table); i++)
if (keycode_table[i].name && !strcmp(keycode_table[i].name, name))
return i;
return 0;
}
static void test_sink(uint8_t code, uint8_t pressed)
{
output[noutput].code = code;
output[noutput].pressed = pressed;
noutput++;
}
static char *read_file(const char *path)
{
int fd = open(path, O_RDONLY);
static char buf[4096];
size_t sz = 0;
ssize_t n;
if (fd < 0) {
perror("open");
exit(-1);
}
while ((n = read(fd, buf, sizeof(buf) - sz)) > 0) {
sz += n;
assert(sz < sizeof buf);
}
buf[sz] = 0;
return buf;
}
static int cmp_events(struct key_event *input, size_t nin,
struct key_event *output, size_t nout)
{
size_t i;
if (nin != nout)
return -1;
for (i = 0; i < nin; i++) {
if (input[i].code != output[i].code
|| input[i].pressed != output[i].pressed)
return -1;
}
return 0;
}
static int print_diff(struct key_event *expected, size_t nexp,
struct key_event *output, size_t nout)
{
int i;
int n = nout > nexp ? nout : nexp;
int ret = 0;
printf("\n%-30s%s\n\n", "Expected", "Output");
for (i = 0; i < n; i++) {
int np = 0;
int match = i < nexp &&
i < nout &&
output[i].code == expected[i].code &&
output[i].pressed == expected[i].pressed;
if (!match)
ret = -1;
if (!match)
printf("\033[32;1m");
np = 0;
if (i < nexp)
np = printf("%s %s",
keycode_table[expected[i].code].name,
expected[i].pressed ? "down" : "up");
while (np++ < 30)
printf(" ");
if (!match)
printf("\033[0m\033[31;1m");
if (i < nout)
printf("%s %s",
keycode_table[output[i].code].name,
output[i].pressed ? "down" : "up");
if (!match)
printf("\033[0m");
printf("\n");
}
return ret;
}
static int parse_events(char *s, struct key_event in[MAX_EVENTS], size_t *nin,
struct key_event out[MAX_EVENTS], size_t *nout)
{
int ret;
int time = 0;
int ln = 0;
int n = 0;
struct key_event *events = in;
char *line = s;
*nin = 0;
*nout = 0;
while (1) {
int len;
char *end = strchr(line, '\n');
if (!end)
break;
*end = 0;
len = strlen(line);
ln++;
if (line[0] == '#')
goto next;
while (line[0] == ' ')
line++;
if (!line[0]) {
*nin = n;
events = out;
n = 0;
goto next;
}
if (len >= 2 && line[len - 1] == 's' && line[len - 2] == 'm') {
time += atoi(line);
} else {
uint8_t code;
char *k = strtok(line, " ");
char *v = strtok(NULL, " \n");
if (!v || (strcmp(v, "up") && strcmp(v, "down"))) {
printf("%d: Invalid line\n", ln);
goto next;
}
if (!(code = lookup_code(k))) {
printf("%d: %s is not a valid key\n", ln,
k);
goto next;
}
assert(n < MAX_EVENTS);
events[n].code = code;
events[n].pressed = !strcmp(v, "down");
events[n].timestamp = time;
n++;
}
next:
line = end + 1;
}
*nout = n;
return 0;
}
void run_test(struct keyboard *kbd, const char *path)
{
char *data = read_file(path);
struct key_event input[MAX_EVENTS];
size_t ninput;
struct key_event expected[MAX_EVENTS];
size_t nexpected;
if (parse_events(data, input, &ninput, expected, &nexpected) < 0) {
fprintf(stderr, "Failed to parse input\n");
exit(-1);
}
noutput = 0;
kbd_process_events(kbd, input, ninput);
if (cmp_events(output, noutput, expected, nexpected)) {
printf("%s \033[31;1mFAILED\033[0m\n", path);
print_diff(expected, nexpected, output, noutput);
exit(-1);
} else {
printf("%s \033[32;1mPASSED\033[0m\n", path);
}
}
int main(int argc, char *argv[])
{
size_t i;
struct config config;
struct keyboard *kbd;
if (argc < 2) {
printf
("usage: %s <test config> <test file> [<test file>...]\n",
argv[0]);
return -1;
}
if (config_parse(&config, argv[1])) {
printf("Failed to parse config %s\n", argv[1]);
return -1;
}
kbd = new_keyboard(&config, test_sink, NULL);
for (i = 2; i < argc; i++)
run_test(kbd, argv[i]);
return 0;
}
Loading…
Cancel
Save