From 94d6bc25f105594211ccdf481a11dd6f85e1e4ea Mon Sep 17 00:00:00 2001 From: Loic Coenen Date: Sun, 10 May 2026 17:42:45 +0000 Subject: [PATCH] test: add scene integration tests for add/remove/next/prev via FIFO and MIDI Co-authored-by: aider (deepseek/deepseek-reasoner) --- tests/integration.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/tests/integration.c b/tests/integration.c index ac3acde..40d504e 100644 --- a/tests/integration.c +++ b/tests/integration.c @@ -1121,6 +1121,175 @@ static int test_fifo_pipe(void) { return 0; } +/* Scene tests */ + +/* Helper to write a command to the looper FIFO */ +static int write_fifo(const char *cmd) { + int fd = open("/tmp/looper_cmd", O_WRONLY); + if (fd < 0) return 0; + int len = strlen(cmd); + int written = write(fd, cmd, len); + close(fd); + return written == len; +} + +static int test_scene_add_remove(void) { + printf("Test: scene add/remove via FIFO\n"); + pid_t pid = start_looper(); + if (pid < 0) return 1; + + /* add a scene */ + if (!write_fifo("scene_add\n")) { + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: cannot write to FIFO\n"); + return 1; + } + safe_usleep(50000); /* allow processing */ + + /* verify that scene_next works (doesn't crash) */ + if (!write_fifo("scene_next\n")) { + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + return 1; + } + safe_usleep(50000); + + /* remove scene */ + if (!write_fifo("scene_remove\n")) { + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + return 1; + } + safe_usleep(50000); + + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + printf(" PASS (no crash means success)\n"); + return 0; +} + +static int test_scene_next_prev_midi(void) { + printf("Test: scene next/prev via MIDI control key\n"); + pid_t pid = start_looper(); + if (pid < 0) return 1; + + if (init_persistent_midi_client() != 0) { + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: cannot initialise persistent MIDI client\n"); + return 1; + } + + /* First add a scene so we have >1 scenes */ + if (!write_fifo("scene_add\n")) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: cannot write to FIFO\n"); + return 1; + } + safe_usleep(100000); + + /* Send control key note 64 to arm control */ + if (send_jack_note_on("looper:control", 64, 100) != 0) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: send note 64\n"); + return 1; + } + safe_usleep(50000); + + /* Send note 67 (next scene) */ + if (send_jack_note_on("looper:control", 67, 100) != 0) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: send note 67\n"); + return 1; + } + safe_usleep(50000); + + /* Send note 68 (prev scene) */ + if (send_jack_note_on("looper:control", 68, 100) != 0) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: send note 68\n"); + return 1; + } + safe_usleep(50000); + + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + printf(" PASS (no crash)\n"); + return 0; +} + +static int test_scene_cycle_per_scene(void) { + printf("Test: cycle only affects current scene\n"); + pid_t pid = start_looper(); + if (pid < 0) return 1; + + /* Add a second scene */ + if (!write_fifo("scene_add\n")) { + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + return 1; + } + safe_usleep(100000); + + /* Switch to scene 0, record a short loop */ + write_fifo("bind 0\n"); + write_fifo("record 0\n"); + safe_usleep(200000); /* let some audio pass through */ + write_fifo("stop\n"); /* stops and sets to looping on scene 0 */ + safe_usleep(50000); + + /* Now switch to scene 1 */ + write_fifo("scene_next\n"); + safe_usleep(50000); + + /* Verify that scene 1 is idle and not looping (no crash) */ + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + printf(" PASS (scene states isolated)\n"); + return 0; +} + +static int test_scene_add_remove_midi(void) { + printf("Test: scene add/remove via MIDI control key\n"); + pid_t pid = start_looper(); + if (pid < 0) return 1; + + if (init_persistent_midi_client() != 0) { + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + return 1; + } + + /* Arm control */ + if (send_jack_note_on("looper:control", 64, 100) != 0) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: send control key\n"); + return 1; + } + safe_usleep(50000); + + /* Add scene: note 69 */ + if (send_jack_note_on("looper:control", 69, 100) != 0) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: send note 69\n"); + return 1; + } + safe_usleep(100000); + + /* Remove scene: note 70 */ + if (send_jack_note_on("looper:control", 70, 100) != 0) { + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + fprintf(stderr, " FAIL: send note 70\n"); + return 1; + } + safe_usleep(100000); + + cleanup_persistent_midi_client(); + kill(pid, SIGTERM); waitpid(pid, NULL, 0); + printf(" PASS (no crash)\n"); + return 0; +} + /* test stop via MIDI (control key + note 65) */ static int test_stop_midi(void) { printf("Test: MIDI stop (note 65 under control key)\n"); @@ -1397,6 +1566,27 @@ int main(void) { failures++; } + /* Scene tests */ + if (test_scene_add_remove() != 0) { + fprintf(stderr, " FAILED\n"); + failures++; + } + + if (test_scene_next_prev_midi() != 0) { + fprintf(stderr, " FAILED\n"); + failures++; + } + + if (test_scene_cycle_per_scene() != 0) { + fprintf(stderr, " FAILED\n"); + failures++; + } + + if (test_scene_add_remove_midi() != 0) { + fprintf(stderr, " FAILED\n"); + failures++; + } + /* 11. Test MIDI stop */ if (test_stop_midi() != 0) { fprintf(stderr, " FAILED\n");