#include #include #include #include #include "engine.h" #include #include #include "tui.h" // Mode definitions (mirrored from tui.c) typedef enum { MODE_NORMAL, MODE_VISUAL, MODE_MOVE } UIMode; // Test helper static Engine *create_test_engine(void) { Engine *engine = (Engine *)calloc(1, sizeof(Engine)); assert(engine != NULL); engine->control_channel = 0; engine->sample_rate = 48000; engine->quantize_mode = QUANTIZE_OFF; engine->quantize_threshold = 0; engine->queued_triggers = NULL; // Initialize command queue command_queue_init(&engine->command_queue); // Initialize atomic state mirrors atomic_store(&engine->transport_rolling, 0); atomic_store(&engine->transport_clock_count, 0); atomic_store(&engine->transport_beat_position, 0); atomic_store(&engine->transport_bar_position, 0); atomic_store(&engine->transport_sample_position, 0); atomic_store(&engine->quantize_mode_atomic, (int)QUANTIZE_OFF); atomic_store(&engine->quantize_threshold_atomic, 0); // Initialize transport engine->transport.rolling = false; engine->transport.clock_count = 0; engine->transport.beat_position = 0; engine->transport.bar_position = 0; engine->transport.sample_position = 0; for (int i = 0; i < MAX_CLIPS; i++) { engine->clips[i].state = CLIP_EMPTY; engine->clips[i].buffer = (float *)calloc(MAX_BUFFER_SIZE, sizeof(float)); assert(engine->clips[i].buffer != NULL); engine->clips[i].buffer_size = 0; engine->clips[i].write_position = 0; engine->clips[i].read_position = 0; } return engine; } static void destroy_test_engine(Engine *engine) { if (engine) { QueuedTrigger *qt = engine->queued_triggers; while (qt) { QueuedTrigger *next = qt->next; free(qt); qt = next; } for (int i = 0; i < MAX_CLIPS; i++) { free(engine->clips[i].buffer); } free(engine); } } // Test 1: Grid to clip index mapping void test_grid_to_clip_index(void) { printf("Test 1: Grid to clip index mapping... "); // 8x8 grid should map to 64 clips assert(0 * 8 + 0 == 0); // Top-left assert(0 * 8 + 7 == 7); // Top-right assert(7 * 8 + 0 == 56); // Bottom-left assert(7 * 8 + 7 == 63); // Bottom-right assert(3 * 8 + 4 == 28); // Middle printf("PASSED\n"); } // Test 2: Trigger clip via grid position void test_trigger_via_grid(void) { printf("Test 2: Trigger clip via grid position... "); Engine *engine = create_test_engine(); // Simulate pressing 't' on grid position (3, 4) = clip 28 int clip_idx = 3 * 8 + 4; engine_trigger_clip(engine, clip_idx); engine_process_commands(engine); assert(engine->clips[clip_idx].state == CLIP_RECORDING); destroy_test_engine(engine); printf("PASSED\n"); } // Test 3: Reset clip via grid position void test_reset_via_grid(void) { printf("Test 3: Reset clip via grid position... "); Engine *engine = create_test_engine(); // Set up a clip at grid position (1, 2) = clip 10 int clip_idx = 1 * 8 + 2; engine->clips[clip_idx].state = CLIP_LOOPING; engine->clips[clip_idx].buffer_size = 100; // Simulate pressing 'r' engine_reset_clip(engine, clip_idx); engine_process_commands(engine); assert(engine->clips[clip_idx].state == CLIP_EMPTY); assert(engine->clips[clip_idx].buffer_size == 0); destroy_test_engine(engine); printf("PASSED\n"); } // Test 4: Scene trigger via grid row void test_scene_via_grid(void) { printf("Test 4: Scene trigger via grid row... "); Engine *engine = create_test_engine(); // Simulate pressing 's' on row 3 int scene_index = 3; engine_trigger_scene(engine, scene_index); engine_process_commands(engine); // All clips in scene 3 should be recording for (int ch = 0; ch < MAX_CHANNELS; ch++) { int clip_idx = CLIP_INDEX(scene_index, ch); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 5: Quantize mode cycling void test_quantize_cycling(void) { printf("Test 5: Quantize mode cycling... "); Engine *engine = create_test_engine(); // Simulate pressing 'q' to cycle through modes assert(engine->quantize_mode == QUANTIZE_OFF); // Cycle: OFF -> BEAT engine_set_quantize_mode(engine, QUANTIZE_BEAT); engine_process_commands(engine); assert(engine->quantize_mode == QUANTIZE_BEAT); // Cycle: BEAT -> BAR engine_set_quantize_mode(engine, QUANTIZE_BAR); engine_process_commands(engine); assert(engine->quantize_mode == QUANTIZE_BAR); // Cycle: BAR -> OFF engine_set_quantize_mode(engine, QUANTIZE_OFF); engine_process_commands(engine); assert(engine->quantize_mode == QUANTIZE_OFF); destroy_test_engine(engine); printf("PASSED\n"); } // Test 6: Threshold toggling void test_threshold_toggle(void) { printf("Test 6: Threshold toggling... "); Engine *engine = create_test_engine(); // Simulate pressing 'T' to toggle threshold assert(engine->quantize_threshold == 0); // Toggle to 1000 engine_set_quantize_threshold(engine, 1000); engine_process_commands(engine); assert(engine->quantize_threshold == 1000); // Toggle back to 0 engine_set_quantize_threshold(engine, 0); engine_process_commands(engine); assert(engine->quantize_threshold == 0); destroy_test_engine(engine); printf("PASSED\n"); } // Test 7: Transport reset void test_transport_reset_via_tui(void) { printf("Test 7: Transport reset via TUI... "); Engine *engine = create_test_engine(); // Set up transport state engine->transport.rolling = true; engine->transport.clock_count = 100; engine->transport.beat_position = 2; engine->transport.bar_position = 5; engine->transport.sample_position = 10000; // Simulate pressing 'x' engine_reset_transport(engine); engine_process_commands(engine); assert(engine->transport.rolling == false); assert(engine->transport.clock_count == 0); assert(engine->transport.beat_position == 0); assert(engine->transport.bar_position == 0); assert(engine->transport.sample_position == 0); destroy_test_engine(engine); printf("PASSED\n"); } // Test 8: Navigation wrapping void test_navigation_wrapping(void) { printf("Test 8: Navigation wrapping... "); // Test that navigation wraps around the grid // Left from column 0 should go to column 7 int col = 0; col = (col - 1 + 8) % 8; assert(col == 7); // Right from column 7 should go to column 0 col = 7; col = (col + 1) % 8; assert(col == 0); // Up from row 0 should go to row 7 int row = 0; row = (row - 1 + 8) % 8; assert(row == 7); // Down from row 7 should go to row 0 row = 7; row = (row + 1) % 8; assert(row == 0); printf("PASSED\n"); } // Test 9: Multiple clips in different states void test_multiple_clip_states(void) { printf("Test 9: Multiple clips in different states... "); Engine *engine = create_test_engine(); // Set up clips in various states engine->clips[0].state = CLIP_EMPTY; engine->clips[1].state = CLIP_RECORDING; engine->clips[2].state = CLIP_LOOPING; engine->clips[3].state = CLIP_STOPPED; // Verify states assert(engine->clips[0].state == CLIP_EMPTY); assert(engine->clips[1].state == CLIP_RECORDING); assert(engine->clips[2].state == CLIP_LOOPING); assert(engine->clips[3].state == CLIP_STOPPED); destroy_test_engine(engine); printf("PASSED\n"); } // Test 10: Buffer size display void test_buffer_size_display(void) { printf("Test 10: Buffer size display... "); Engine *engine = create_test_engine(); // Set up a clip with known buffer size engine->clips[5].state = CLIP_LOOPING; engine->clips[5].buffer_size = 48000; // 1 second at 48kHz // Verify buffer size assert(engine->clips[5].buffer_size == 48000); destroy_test_engine(engine); printf("PASSED\n"); } // Test 11: Help toggle void test_help_toggle(void) { printf("Test 11: Help toggle... "); // Test that help flag toggles correctly bool show_help = false; show_help = !show_help; assert(show_help == true); show_help = !show_help; assert(show_help == false); printf("PASSED\n"); } // Test 12: Escape key handling void test_escape_handling(void) { printf("Test 12: Escape key handling... "); // Test that escape key (27) is handled int ch = 27; assert(ch == 27); // Escape // Test that 'Q' is handled ch = 'Q'; assert(ch == 'Q'); printf("PASSED\n"); } // Test 13: TUI init and cleanup (without ncurses) void test_tui_init_cleanup(void) { printf("Test 13: TUI init and cleanup... "); Engine *engine = create_test_engine(); // We can't actually call tui_init/tui_cleanup in test environment // but we can verify the engine is valid assert(engine != NULL); assert(engine->sample_rate == 48000); destroy_test_engine(engine); printf("PASSED (skipped ncurses init)\n"); } // Test 14: State to color mapping void test_state_to_color_mapping(void) { printf("Test 14: State to color mapping... "); // Verify state values match expected color indices assert(CLIP_EMPTY == 0); assert(CLIP_RECORDING == 1); assert(CLIP_LOOPING == 2); assert(CLIP_STOPPED == 3); printf("PASSED\n"); } // Test 15: Full grid coverage void test_full_grid_coverage(void) { printf("Test 15: Full grid coverage... "); Engine *engine = create_test_engine(); // Trigger all 64 clips via grid positions for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { int clip_idx = row * 8 + col; engine_trigger_clip(engine, clip_idx); engine_process_commands(engine); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } } // Verify all clips are recording for (int i = 0; i < MAX_CLIPS; i++) { assert(engine->clips[i].state == CLIP_RECORDING); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 16: Scene trigger from each row void test_scene_from_each_row(void) { printf("Test 16: Scene trigger from each row... "); Engine *engine = create_test_engine(); // Trigger scene from each row for (int row = 0; row < 8; row++) { engine_trigger_scene(engine, row); engine_process_commands(engine); // Verify all clips in this scene are recording for (int ch = 0; ch < MAX_CHANNELS; ch++) { int clip_idx = CLIP_INDEX(row, ch); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } } destroy_test_engine(engine); printf("PASSED\n"); } // Test 17: Quantize mode cycle through all modes void test_quantize_full_cycle(void) { printf("Test 17: Quantize mode full cycle... "); Engine *engine = create_test_engine(); // Cycle through all modes twice for (int cycle = 0; cycle < 2; cycle++) { engine_set_quantize_mode(engine, QUANTIZE_OFF); engine_process_commands(engine); assert(engine->quantize_mode == QUANTIZE_OFF); engine_set_quantize_mode(engine, QUANTIZE_BEAT); engine_process_commands(engine); assert(engine->quantize_mode == QUANTIZE_BEAT); engine_set_quantize_mode(engine, QUANTIZE_BAR); engine_process_commands(engine); assert(engine->quantize_mode == QUANTIZE_BAR); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 18: Multiple threshold toggles void test_multiple_threshold_toggles(void) { printf("Test 18: Multiple threshold toggles... "); Engine *engine = create_test_engine(); // Toggle threshold multiple times for (int i = 0; i < 5; i++) { if (engine->quantize_threshold == 0) { engine_set_quantize_threshold(engine, 1000); engine_process_commands(engine); assert(engine->quantize_threshold == 1000); } else { engine_set_quantize_threshold(engine, 0); engine_process_commands(engine); assert(engine->quantize_threshold == 0); } } destroy_test_engine(engine); printf("PASSED\n"); } // Test 19: Transport reset multiple times void test_multiple_transport_resets(void) { printf("Test 19: Multiple transport resets... "); Engine *engine = create_test_engine(); // Reset transport multiple times for (int i = 0; i < 5; i++) { engine->transport.rolling = true; engine->transport.clock_count = 100 + i; engine->transport.beat_position = i % 4; engine->transport.bar_position = i; engine->transport.sample_position = 10000 * i; engine_reset_transport(engine); engine_process_commands(engine); assert(engine->transport.rolling == false); assert(engine->transport.clock_count == 0); assert(engine->transport.beat_position == 0); assert(engine->transport.bar_position == 0); assert(engine->transport.sample_position == 0); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 20: Navigation with arrow keys void test_arrow_key_navigation(void) { printf("Test 20: Arrow key navigation... "); // Test that arrow keys produce same results as hjkl int row = 3, col = 4; // KEY_LEFT (same as 'h') col = (col - 1 + 8) % 8; assert(col == 3); // KEY_DOWN (same as 'j') row = (row + 1) % 8; assert(row == 4); // KEY_UP (same as 'k') row = (row - 1 + 8) % 8; assert(row == 3); // KEY_RIGHT (same as 'l') col = (col + 1) % 8; assert(col == 4); printf("PASSED\n"); } // Test 21: Command mode parsing - quit command void test_command_mode_quit(void) { printf("Test 21: Command mode quit command... "); // Test that ":q" command is recognized const char *cmd = "q"; assert(strcmp(cmd, "q") == 0); printf("PASSED\n"); } // Test 22: Command mode parsing - empty command void test_command_mode_empty(void) { printf("Test 22: Command mode empty command... "); // Test that empty command doesn't quit const char *cmd = ""; assert(strcmp(cmd, "q") != 0); printf("PASSED\n"); } // Test 23: Command mode parsing - unknown command void test_command_mode_unknown(void) { printf("Test 23: Command mode unknown command... "); // Test that unknown commands don't quit const char *cmd = "unknown"; assert(strcmp(cmd, "q") != 0); printf("PASSED\n"); } // Test 24: Command mode buffer overflow protection void test_command_mode_buffer_overflow(void) { printf("Test 24: Command mode buffer overflow protection... "); // Test that buffer doesn't overflow with long input char cmd_buffer[256]; int cmd_pos = 0; memset(cmd_buffer, 0, sizeof(cmd_buffer)); // Simulate typing more characters than buffer can hold for (int i = 0; i < 300; i++) { if (cmd_pos < (int)sizeof(cmd_buffer) - 1) { cmd_buffer[cmd_pos++] = 'a'; } } cmd_buffer[cmd_pos] = '\0'; // Buffer should not overflow assert(strlen(cmd_buffer) < sizeof(cmd_buffer)); assert(cmd_pos <= (int)sizeof(cmd_buffer) - 1); printf("PASSED\n"); } // Test 25: Command mode backspace handling void test_command_mode_backspace(void) { printf("Test 25: Command mode backspace handling... "); // Test backspace removes characters char cmd_buffer[256]; int cmd_pos = 0; memset(cmd_buffer, 0, sizeof(cmd_buffer)); // Type "test" cmd_buffer[cmd_pos++] = 't'; cmd_buffer[cmd_pos++] = 'e'; cmd_buffer[cmd_pos++] = 's'; cmd_buffer[cmd_pos++] = 't'; cmd_buffer[cmd_pos] = '\0'; assert(strcmp(cmd_buffer, "test") == 0); // Backspace twice cmd_pos--; cmd_buffer[cmd_pos] = '\0'; cmd_pos--; cmd_buffer[cmd_pos] = '\0'; assert(strcmp(cmd_buffer, "te") == 0); printf("PASSED\n"); } // Test 26: Command mode escape cancels void test_command_mode_escape(void) { printf("Test 26: Command mode escape cancels... "); // Test that escape key (27) cancels command mode int ch = 27; assert(ch == 27); // Escape printf("PASSED\n"); } // Test 27: Command mode enter executes void test_command_mode_enter(void) { printf("Test 27: Command mode enter executes... "); // Test that enter key executes command int ch = '\n'; assert(ch == '\n'); ch = '\r'; assert(ch == '\r'); printf("PASSED\n"); } // Test 28: Command mode colon triggers mode void test_command_mode_colon(void) { printf("Test 28: Command mode colon triggers mode... "); // Test that ':' character triggers command mode char ch = ':'; assert(ch == ':'); printf("PASSED\n"); } // Test 29: Visual mode entry void test_visual_mode_entry(void) { printf("Test 29: Visual mode entry... "); // Simulate pressing 'v' to enter visual mode UIMode current_mode = MODE_NORMAL; int selected_row = 3, selected_col = 4; int visual_start_row = 0, visual_start_col = 0; int visual_end_row = 0, visual_end_col = 0; // Press 'v' current_mode = MODE_VISUAL; visual_start_row = selected_row; visual_start_col = selected_col; visual_end_row = selected_row; visual_end_col = selected_col; assert(current_mode == MODE_VISUAL); assert(visual_start_row == 3); assert(visual_start_col == 4); assert(visual_end_row == 3); assert(visual_end_col == 4); printf("PASSED\n"); } // Test 30: Visual mode selection expansion void test_visual_mode_selection(void) { printf("Test 30: Visual mode selection expansion... "); int visual_start_row = 2, visual_start_col = 2; int visual_end_row = 2, visual_end_col = 2; // Move right visual_end_col = (visual_end_col + 1) % 8; assert(visual_end_col == 3); // Move down visual_end_row = (visual_end_row + 1) % 8; assert(visual_end_row == 3); // Check selection bounds int min_row = (visual_start_row < visual_end_row) ? visual_start_row : visual_end_row; int max_row = (visual_start_row > visual_end_row) ? visual_start_row : visual_end_row; int min_col = (visual_start_col < visual_end_col) ? visual_start_col : visual_end_col; int max_col = (visual_start_col > visual_end_col) ? visual_start_col : visual_end_col; assert(min_row == 2); assert(max_row == 3); assert(min_col == 2); assert(max_col == 3); printf("PASSED\n"); } // Test 31: Visual mode escape returns to normal void test_visual_mode_escape(void) { printf("Test 31: Visual mode escape returns to normal... "); UIMode current_mode = MODE_VISUAL; // Press Escape current_mode = MODE_NORMAL; assert(current_mode == MODE_NORMAL); printf("PASSED\n"); } // Test 32: Visual line selection void test_visual_line_selection(void) { printf("Test 32: Visual line selection... "); int selected_row = 3; UIMode current_mode = MODE_NORMAL; int visual_start_row = 0, visual_start_col = 0; int visual_end_row = 0, visual_end_col = 0; // Press 'V' current_mode = MODE_VISUAL; visual_start_row = selected_row; visual_start_col = 0; visual_end_row = selected_row; visual_end_col = 7; // GRID_COLS - 1 assert(current_mode == MODE_VISUAL); assert(visual_start_row == 3); assert(visual_start_col == 0); assert(visual_end_row == 3); assert(visual_end_col == 7); printf("PASSED\n"); } // Test 33: Move mode entry and navigation void test_move_mode_navigation(void) { printf("Test 33: Move mode navigation... "); UIMode current_mode = MODE_NORMAL; int selected_row = 3, selected_col = 4; // Enter move mode current_mode = MODE_MOVE; assert(current_mode == MODE_MOVE); // Move left selected_col = (selected_col - 1 + 8) % 8; assert(selected_col == 3); // Move down selected_row = (selected_row + 1) % 8; assert(selected_row == 4); // Move up selected_row = (selected_row - 1 + 8) % 8; assert(selected_row == 3); // Move right selected_col = (selected_col + 1) % 8; assert(selected_col == 4); printf("PASSED\n"); } // Test 34: Move mode returns to normal on enter void test_move_mode_enter(void) { printf("Test 34: Move mode returns to normal on enter... "); UIMode current_mode = MODE_MOVE; // Press Enter current_mode = MODE_NORMAL; assert(current_mode == MODE_NORMAL); printf("PASSED\n"); } // Test 35: Move mode returns to normal on escape void test_move_mode_escape(void) { printf("Test 35: Move mode returns to normal on escape... "); UIMode current_mode = MODE_MOVE; // Press Escape current_mode = MODE_NORMAL; assert(current_mode == MODE_NORMAL); printf("PASSED\n"); } // Test 36: Delete (reset) single clip void test_delete_single_clip(void) { printf("Test 36: Delete (reset) single clip... "); Engine *engine = create_test_engine(); // Set up a looping clip int clip_idx = 10; engine->clips[clip_idx].state = CLIP_LOOPING; engine->clips[clip_idx].buffer_size = 100; engine->clips[clip_idx].write_position = 100; engine->clips[clip_idx].read_position = 50; // Simulate pressing 'd' on selected clip engine_reset_clip(engine, clip_idx); engine_process_commands(engine); assert(engine->clips[clip_idx].state == CLIP_EMPTY); assert(engine->clips[clip_idx].buffer_size == 0); assert(engine->clips[clip_idx].write_position == 0); assert(engine->clips[clip_idx].read_position == 0); destroy_test_engine(engine); printf("PASSED\n"); } // Test 37: Delete (reset) multiple clips via visual selection void test_delete_visual_selection(void) { printf("Test 37: Delete visual selection... "); Engine *engine = create_test_engine(); // Set up clips in a 2x2 selection area int clips[] = {18, 19, 26, 27}; // rows 2-3, cols 2-3 for (int i = 0; i < 4; i++) { engine->clips[clips[i]].state = CLIP_LOOPING; engine->clips[clips[i]].buffer_size = 100; engine->clips[clips[i]].write_position = 100; engine->clips[clips[i]].read_position = 50; } // Simulate deleting the selection for (int i = 0; i < 4; i++) { engine_reset_clip(engine, clips[i]); } engine_process_commands(engine); for (int i = 0; i < 4; i++) { assert(engine->clips[clips[i]].state == CLIP_EMPTY); assert(engine->clips[clips[i]].buffer_size == 0); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 38: Yank single clip void test_yank_single_clip(void) { printf("Test 38: Yank single clip... "); Engine *engine = create_test_engine(); // Set up a clip int clip_idx = 15; engine->clips[clip_idx].state = CLIP_LOOPING; engine->clips[clip_idx].buffer_size = 100; // Simulate yanking the clip - should stop it engine_trigger_clip(engine, clip_idx); // Toggle to stop engine_process_commands(engine); assert(engine->clips[clip_idx].state == CLIP_STOPPED); destroy_test_engine(engine); printf("PASSED\n"); } // Test 39: Yank multiple clips via visual selection void test_yank_visual_selection(void) { printf("Test 39: Yank visual selection... "); Engine *engine = create_test_engine(); // Set up clips in a 2x2 selection int clips[] = {18, 19, 26, 27}; for (int i = 0; i < 4; i++) { engine->clips[clips[i]].state = CLIP_LOOPING; engine->clips[clips[i]].buffer_size = 100; } // Simulate yanking the selection - should stop all clips for (int i = 0; i < 4; i++) { engine_trigger_clip(engine, clips[i]); // Toggle to stop } engine_process_commands(engine); for (int i = 0; i < 4; i++) { assert(engine->clips[clips[i]].state == CLIP_STOPPED); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 40: Paste clips void test_paste_clips(void) { printf("Test 40: Paste clips... "); Engine *engine = create_test_engine(); // Simulate yanking clip at position (1, 1) = clip 9 int yank_buffer[] = {9}; int selected_row = 3, selected_col = 3; // Paste at position (3, 3) = clip 27 // Calculate offset int first_yanked_row = yank_buffer[0] / 8; int first_yanked_col = yank_buffer[0] % 8; int row_offset = selected_row - first_yanked_row; int col_offset = selected_col - first_yanked_col; assert(first_yanked_row == 1); assert(first_yanked_col == 1); assert(row_offset == 2); assert(col_offset == 2); // Simulate paste: trigger clip three times to go empty -> recording -> looping -> stopped int new_row = first_yanked_row + row_offset; int new_col = first_yanked_col + col_offset; int new_clip_idx = new_row * 8 + new_col; assert(new_row == 3); assert(new_col == 3); assert(new_clip_idx == 27); engine_trigger_clip(engine, new_clip_idx); engine_trigger_clip(engine, new_clip_idx); engine_trigger_clip(engine, new_clip_idx); engine_process_commands(engine); assert(engine->clips[27].state == CLIP_STOPPED); destroy_test_engine(engine); printf("PASSED\n"); } // Test 41: Paste with bounds checking void test_paste_bounds_checking(void) { printf("Test 41: Paste bounds checking... "); Engine *engine = create_test_engine(); // Yank clip at position (7, 7) = clip 63 (bottom-right) int yank_buffer[] = {63}; int selected_row = 0, selected_col = 0; // Paste at top-left // Calculate offset int first_yanked_row = yank_buffer[0] / 8; int first_yanked_col = yank_buffer[0] % 8; int row_offset = selected_row - first_yanked_row; int col_offset = selected_col - first_yanked_col; assert(row_offset == -7); assert(col_offset == -7); // Simulate paste: new position should be (0, 0) = clip 0 int new_row = first_yanked_row + row_offset; int new_col = first_yanked_col + col_offset; assert(new_row == 0); assert(new_col == 0); // Test out-of-bounds paste (should be clipped) selected_row = 0; selected_col = 0; row_offset = selected_row - 0; col_offset = selected_col - 0; // Yank clip at (0, 0) and try to paste at (0, 0) - should work new_row = 0 + row_offset; new_col = 0 + col_offset; assert(new_row >= 0 && new_row < 8 && new_col >= 0 && new_col < 8); destroy_test_engine(engine); printf("PASSED\n"); } // Test 42: Mark setting void test_mark_setting(void) { printf("Test 42: Mark setting... "); int marks[26]; for (int i = 0; i < 26; i++) { marks[i] = -1; } int selected_row = 3, selected_col = 4; int clip_idx = selected_row * 8 + selected_col; // Set mark 'a' char mark_char = 'a'; int idx = mark_char - 'a'; marks[idx] = clip_idx; assert(marks[0] == 28); // 3 * 8 + 4 = 28 // Set mark 'z' mark_char = 'z'; idx = mark_char - 'a'; marks[idx] = clip_idx; assert(marks[25] == 28); printf("PASSED\n"); } // Test 43: Go to mark void test_go_to_mark(void) { printf("Test 43: Go to mark... "); int marks[26]; for (int i = 0; i < 26; i++) { marks[i] = -1; } // Set mark 'b' to clip 42 marks[1] = 42; // 'b' - 'a' = 1 // Go to mark 'b' char mark_char = 'b'; int idx = mark_char - 'a'; int clip_idx = marks[idx]; assert(clip_idx == 42); // Calculate row and col int row = clip_idx / 8; int col = clip_idx % 8; assert(row == 5); assert(col == 2); printf("PASSED\n"); } // Test 44: Go to unset mark void test_go_to_unset_mark(void) { printf("Test 44: Go to unset mark... "); int marks[26]; for (int i = 0; i < 26; i++) { marks[i] = -1; } // Try to go to unset mark 'c' char mark_char = 'c'; int idx = mark_char - 'a'; int clip_idx = marks[idx]; assert(clip_idx == -1); // Mark not set printf("PASSED\n"); } // Test 45: Play next scene void test_play_next_scene(void) { printf("Test 45: Play next scene... "); Engine *engine = create_test_engine(); int selected_row = 3; // Play next scene int next_row = (selected_row + 1) % 8; engine_trigger_scene(engine, next_row); engine_process_commands(engine); assert(next_row == 4); // Verify clips in scene 4 are recording for (int ch = 0; ch < MAX_CHANNELS; ch++) { int clip_idx = CLIP_INDEX(4, ch); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 46: Play previous scene void test_play_prev_scene(void) { printf("Test 46: Play previous scene... "); Engine *engine = create_test_engine(); int selected_row = 3; // Play previous scene int prev_row = (selected_row - 1 + 8) % 8; engine_trigger_scene(engine, prev_row); engine_process_commands(engine); assert(prev_row == 2); // Verify clips in scene 2 are recording for (int ch = 0; ch < MAX_CHANNELS; ch++) { int clip_idx = CLIP_INDEX(2, ch); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 47: Play next scene wraps around void test_play_next_scene_wrap(void) { printf("Test 47: Play next scene wraps around... "); Engine *engine = create_test_engine(); int selected_row = 7; // Last row // Play next scene should wrap to row 0 int next_row = (selected_row + 1) % 8; assert(next_row == 0); engine_trigger_scene(engine, next_row); engine_process_commands(engine); for (int ch = 0; ch < MAX_CHANNELS; ch++) { int clip_idx = CLIP_INDEX(0, ch); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 48: Play previous scene wraps around void test_play_prev_scene_wrap(void) { printf("Test 48: Play previous scene wraps around... "); Engine *engine = create_test_engine(); int selected_row = 0; // First row // Play previous scene should wrap to row 7 int prev_row = (selected_row - 1 + 8) % 8; assert(prev_row == 7); engine_trigger_scene(engine, prev_row); engine_process_commands(engine); for (int ch = 0; ch < MAX_CHANNELS; ch++) { int clip_idx = CLIP_INDEX(7, ch); assert(engine->clips[clip_idx].state == CLIP_RECORDING); } destroy_test_engine(engine); printf("PASSED\n"); } // Test 49: Visual mode delete then escape void test_visual_delete_then_escape(void) { printf("Test 49: Visual mode delete then escape... "); Engine *engine = create_test_engine(); // Set up clips in visual selection int clips[] = {18, 19, 26, 27}; for (int i = 0; i < 4; i++) { engine->clips[clips[i]].state = CLIP_LOOPING; engine->clips[clips[i]].buffer_size = 100; } // Simulate visual mode delete for (int i = 0; i < 4; i++) { engine_reset_clip(engine, clips[i]); } engine_process_commands(engine); // Verify clips are reset for (int i = 0; i < 4; i++) { assert(engine->clips[clips[i]].state == CLIP_EMPTY); } // Simulate returning to normal mode UIMode current_mode = MODE_NORMAL; assert(current_mode == MODE_NORMAL); destroy_test_engine(engine); printf("PASSED\n"); } // Test 50: Visual mode yank then escape void test_visual_yank_then_escape(void) { printf("Test 50: Visual mode yank then escape... "); Engine *engine = create_test_engine(); // Set up clips in visual selection int clips[] = {18, 19, 26, 27}; for (int i = 0; i < 4; i++) { engine->clips[clips[i]].state = CLIP_LOOPING; engine->clips[clips[i]].buffer_size = 100; } // Simulate yanking the selection - should stop all clips for (int i = 0; i < 4; i++) { engine_trigger_clip(engine, clips[i]); // Toggle to stop } engine_process_commands(engine); // Verify clips are stopped for (int i = 0; i < 4; i++) { assert(engine->clips[clips[i]].state == CLIP_STOPPED); } // Simulate returning to normal mode UIMode current_mode = MODE_NORMAL; assert(current_mode == MODE_NORMAL); destroy_test_engine(engine); printf("PASSED\n"); } // Test 51: Multiple marks void test_multiple_marks(void) { printf("Test 51: Multiple marks... "); int marks[26]; for (int i = 0; i < 26; i++) { marks[i] = -1; } // Set multiple marks marks[0] = 0; // 'a' = clip 0 marks[1] = 63; // 'b' = clip 63 marks[2] = 28; // 'c' = clip 28 assert(marks[0] == 0); assert(marks[1] == 63); assert(marks[2] == 28); // Go to mark 'b' int clip_idx = marks[1]; int row = clip_idx / 8; int col = clip_idx % 8; assert(row == 7); assert(col == 7); printf("PASSED\n"); } // Test 52: Re-mark existing mark void test_remark_existing_mark(void) { printf("Test 52: Re-mark existing mark... "); int marks[26]; for (int i = 0; i < 26; i++) { marks[i] = -1; } // Set mark 'a' to clip 10 marks[0] = 10; assert(marks[0] == 10); // Re-mark 'a' to clip 42 marks[0] = 42; assert(marks[0] == 42); printf("PASSED\n"); } int main(void) { printf("Running TUI tests...\n\n"); test_grid_to_clip_index(); test_trigger_via_grid(); test_reset_via_grid(); test_scene_via_grid(); test_quantize_cycling(); test_threshold_toggle(); test_transport_reset_via_tui(); test_navigation_wrapping(); test_multiple_clip_states(); test_buffer_size_display(); test_help_toggle(); test_escape_handling(); test_tui_init_cleanup(); test_state_to_color_mapping(); test_full_grid_coverage(); test_scene_from_each_row(); test_quantize_full_cycle(); test_multiple_threshold_toggles(); test_multiple_transport_resets(); test_arrow_key_navigation(); test_command_mode_quit(); test_command_mode_empty(); test_command_mode_unknown(); test_command_mode_buffer_overflow(); test_command_mode_backspace(); test_command_mode_escape(); test_command_mode_enter(); test_command_mode_colon(); test_visual_mode_entry(); test_visual_mode_selection(); test_visual_mode_escape(); test_visual_line_selection(); test_move_mode_navigation(); test_move_mode_enter(); test_move_mode_escape(); test_delete_single_clip(); test_delete_visual_selection(); test_yank_single_clip(); test_yank_visual_selection(); test_paste_clips(); test_paste_bounds_checking(); test_mark_setting(); test_go_to_mark(); test_go_to_unset_mark(); test_play_next_scene(); test_play_prev_scene(); test_play_next_scene_wrap(); test_play_prev_scene_wrap(); test_visual_delete_then_escape(); test_visual_yank_then_escape(); test_multiple_marks(); test_remark_existing_mark(); printf("\nAll TUI tests passed!\n"); return 0; }