#include #include #include #include #include "engine.h" #include #include "tui.h" // 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"); } 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(); printf("\nAll TUI tests passed!\n"); return 0; }