Files
looper/tests/integration.c
Loic Coenen bbf560efe2 test: implement full integration test for JACK looper state machine
Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
2026-05-07 20:30:01 +00:00

110 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
/*
* Integration test for the JACK looper.
*
* 1. Start the looper binary (./looper)
* 2. Wait for JACK ports to appear
* 3. Send several noteon messages (MIDI note number 1) to its 'control' port
* using jack_midi_send, testing the state machine:
* IDLE → RECORD → LOOPING → PAUSED → LOOPING → PAUSED (toggle)
* 4. Send a MIDI clock Start (0xFA) to force IDLE → RECORD.
* 5. Send a MIDI clock Stop (0xFC) to force RECORD → IDLE.
* 6. Send a MIDI clock Continue (0xFB) to resume LOOPING from PAUSED.
* 7. Kill the process and check that it exits cleanly.
*/
#define WAIT_SECONDS 1
static int run_cmd(const char *fmt, ...) {
char buf[512];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return system(buf);
}
int main(void) {
/* 1. binary must exist */
if (system("test -x ./looper") != 0) {
fprintf(stderr, "FATAL: looper binary not found\n");
return 1;
}
/* 2. start the looper */
pid_t pid = fork();
if (pid == 0) {
execl("./looper", "looper", NULL);
perror("execl");
_exit(1);
}
printf("Waiting for looper (pid %d) to register ports...\n", (int)pid);
sleep(3); /* generous, JACK ports must be visible */
/* 3. send noteon messages (toggle state machine) */
printf("Sending first noteon → IDLE → RECORD\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending second noteon → RECORD → LOOPING\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending third noteon → LOOPING → PAUSED\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending fourth noteon → PAUSED → LOOPING\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending fifth noteon → LOOPING → PAUSED (toggle)\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
/* 4. MIDI clock start (0xFA) IDLE → RECORD */
printf("Sending MIDI clock Start (0xFA)\n");
run_cmd("jack_midi_send -c looper:clock -m 'FA' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
/* 5. MIDI clock stop (0xFC) RECORD → IDLE */
printf("Sending MIDI clock Stop (0xFC)\n");
run_cmd("jack_midi_send -c looper:clock -m 'FC' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
/* bring back to PAUSED via control port */
printf("Sending noteon to reach PAUSED again\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'"); // now PAUSED
sleep(1);
/* 6. MIDI clock Continue (0xFB) PAUSED → LOOPING */
printf("Sending MIDI clock Continue (0xFB)\n");
run_cmd("jack_midi_send -c looper:clock -m 'FB' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
/* cleanup */
printf("Terminating looper...\n");
kill(pid, SIGTERM);
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("Looper exited with status %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Looper terminated by signal %d\n", WTERMSIG(status));
}
printf("Integration test finished (manual verification recommended)\n");
return 0;
}