END_TEST static bool check_adjusted_tstamp(Streader* sr, int32_t index, void* userdata) { fail_if(sr == NULL, "Callback did not get a Streader"); fail_if(Streader_is_error_set(sr), "Callback was called with Streader error set: %s", Streader_get_error_desc(sr)); fail_if(index < 0, "Callback got a negative item index (%" PRId32 ")", index); fail_if(index >= item_count, "Callback got too large an index (%" PRId32 ")", index); fail_if(userdata != NULL, "Callback got unexpected userdata"); Tstamp* ts = TSTAMP_AUTO; fail_if(!Streader_read_tstamp(sr, ts), "Could not read timestamp from list index %" PRId32 ": %s", index, Streader_get_error_desc(sr)); fail_if((Tstamp_get_beats(ts) != index + 10) || (Tstamp_get_rem(ts) != index + 100), "Unexpected list item " PRIts " (expected (%d, %d))", PRIVALts(*ts), (int)index + 10, (int)index + 100); return true; }
END_TEST static bool fill_array_index(Streader* sr, const char* key, void* userdata) { fail_if(sr == NULL, "Callback did not get a Streader"); fail_if(Streader_is_error_set(sr), "Callback was called with Streader error set: %s", Streader_get_error_desc(sr)); fail_if(key == NULL, "Callback did not get a key"); fail_if(strlen(key) != 1 || strchr("0123", key[0]) == NULL, "Callback got an unexpected key `%s`", key); fail_if(userdata == NULL, "Callback did not get userdata"); int arr_index = key[0] - '0'; assert(arr_index >= 0); assert(arr_index < 4); int* array = userdata; int64_t num = 0; fail_if(!Streader_read_int(sr, &num), "Could not read integer from dictionary: %s", Streader_get_error_desc(sr)); fail_if(num != arr_index + 10, "Unexpected value %" PRId64 " (expected %d)", num, arr_index + 10); array[arr_index] = (int)num; return true; }
END_TEST START_TEST(Whitespace_terminates_decimal_number) { Streader* sr = init_with_cstr("- 1"); double num = NAN; fail_if(Streader_read_float(sr, &num), "Streader accepted \"- 1\" as a float"); sr = init_with_cstr("-1 .5"); num = NAN; fail_if(!Streader_read_float(sr, &num), "Could not read float from \"-1 .5\": %s", Streader_get_error_desc(sr)); fail_if(num != -1, "Streader read %f instead of -1 from \"-1 .5\"", num); sr = init_with_cstr("-1. 5"); num = NAN; fail_if(Streader_read_float(sr, &num), "Streader accepted \"-1.\" as a float"); sr = init_with_cstr("-1 e5"); num = NAN; fail_if(!Streader_read_float(sr, &num), "Could not read float from \"-1 e5\": %s", Streader_get_error_desc(sr)); fail_if(num != -1, "Streader read %f instead of -1 from \"-1 e5\"", num); sr = init_with_cstr("-1e 5"); num = NAN; fail_if(Streader_read_float(sr, &num), "Streader accepted \"-1e\" as a float"); }
END_TEST #define item_count 4 static bool inc_doubled_int(Streader* sr, int32_t index, void* userdata) { fail_if(sr == NULL, "Callback did not get a Streader"); fail_if(Streader_is_error_set(sr), "Callback was called with Streader error set: %s", Streader_get_error_desc(sr)); fail_if(index < 0, "Callback got a negative item index (%" PRId32 ")", index); fail_if(index >= item_count, "Callback got too large an index (%" PRId32 ")", index); fail_if(userdata == NULL, "Callback did not get userdata"); int64_t num = 0; fail_if(!Streader_read_int(sr, &num), "Could not read integer from list index %" PRId32 ": %s", index, Streader_get_error_desc(sr)); fail_if(num != index * 2, "Unexpected list item %" PRId64 " (expected %" PRId32 ")", num, index * 2); int* nums = userdata; nums[index] = (int)num + 1; return true; }
END_TEST START_TEST(Read_zero_float) { const char* zeros[] = { "0 x", "0.0 x", "0e0 x", "0.0e0 x", "0.0e+0 x", "0.0e-0 x", }; for (size_t i = 0; i < arr_size(zeros); ++i) { Streader* sr = init_with_cstr(zeros[i]); double num = NAN; fail_if(!Streader_read_float(sr, &num), "Could not read 0 from \"%s\": %s", zeros[i], Streader_get_error_desc(sr)); fail_if(num != 0, "Streader stored %f instead of 0 from \"%s\"", num, zeros[i]); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume 0 from \"%s\" correctly: %s", zeros[i], Streader_get_error_desc(sr)); } // TODO: The code below does not test the sign of negative zero // as C99 doesn't guarantee it. // Revisit when migrating to emulated floats. const char* neg_zeros[] = { "-0 x", "-0.0 x", "-0e0 x", "-0.0e0 x", "-0.0e+0 x", "-0.0e-0 x", }; for (size_t i = 0; i < arr_size(neg_zeros); ++i) { Streader* sr = init_with_cstr(neg_zeros[i]); double num = NAN; fail_if(!Streader_read_float(sr, &num), "Could not read -0 from \"%s\": %s", neg_zeros[i], Streader_get_error_desc(sr)); fail_if(num != 0, "Streader stored %f instead of -0 from \"%s\"", num, neg_zeros[i]); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume -0 from \"%s\" correctly", neg_zeros[i]); } }
END_TEST #undef make_str START_TEST(Read_empty_list) { static const char* lists[] = { "[] x", "[ ]x", "[ ] x", }; for (size_t i = 0; i < arr_size(lists); ++i) { Streader* sr = init_with_cstr(lists[i]); fail_if(!Streader_read_list(sr, NULL, NULL), "Could not read empty list from `%s`: %s", lists[i], Streader_get_error_desc(sr)); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume empty list from `%s` correctly", lists[i]); } }
END_TEST START_TEST(Read_nonzero_float) { const double nums[] = { 0.5, 1.0, 1.5, -0.5, -1.0, -1.5, 0.0625, 10.0, }; const char* formats[] = { "%.4f x", "%f x", "%e x", }; for (size_t i = 0; i < arr_size(nums); ++i) { for (size_t k = 0; k < arr_size(formats); ++k) { char data[128] = ""; sprintf(data, formats[k], nums[i]); Streader* sr = init_with_cstr(data); double num = NAN; fail_if(!Streader_read_float(sr, &num), "Could not read float from \"%s\": %s", data, Streader_get_error_desc(sr)); fail_if(num != nums[i], "Streader stored %f instead of %.6f from \"%s\"", num, nums[i]); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume float from \"%s\" correctly", data); } } }
END_TEST START_TEST(Read_valid_piref) { static const struct { const char* data; const Pat_inst_ref expected; } pirefs[] = { { "[0, 0]", { 0, 0 } }, { "[2,5]", { 2, 5 } }, { " [2,5]", { 2, 5 } }, { "[ 2,5]", { 2, 5 } }, { "[2 ,5]", { 2, 5 } }, { "[2, 5]", { 2, 5 } }, { "[2,5 ]", { 2, 5 } }, { "[0, 1023]", { 0, KQT_PAT_INSTANCES_MAX - 1 } }, { "[1023, 0]", { KQT_PATTERNS_MAX - 1, 0 } }, { "[1023, 1023]", { KQT_PATTERNS_MAX - 1, KQT_PAT_INSTANCES_MAX - 1 } }, }; for (size_t i = 0; i < arr_size(pirefs); ++i) { char data[128] = ""; sprintf(data, "%s x", pirefs[i].data); Streader* sr = init_with_cstr(data); Pat_inst_ref* result = PAT_INST_REF_AUTO; fail_if(!Streader_read_piref(sr, result), "Could not read pattern instance refernce " PRIpi " from `%s`: %s", PRIVALpi(pirefs[i].expected), data, Streader_get_error_desc(sr)); fail_if(Pat_inst_ref_cmp(result, &pirefs[i].expected) != 0, "Streader stored " PRIpi " instead of " PRIpi " when reading `%s`", PRIVALpi(*result), PRIVALpi(pirefs[i].expected), data); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume pattern instance from `%s` correctly", data); } }
END_TEST START_TEST(Fire_with_complex_bind_can_be_processed_with_multiple_receives) { set_mix_volume(0); setup_debug_instrument(); setup_debug_single_pulse(); const int event_count = 2048; setup_complex_bind(event_count); pause(); kqt_Handle_fire_event(handle, 0, "[\"#\", \"\"]"); check_unexpected_error(); // Receive and make sure all events are found const char* events = kqt_Handle_receive_events(handle); int32_t expected = 0; int loop_count = 0; while (strcmp("[]", events) != 0) { Streader* sr = Streader_init(STREADER_AUTO, events, (int64_t)strlen(events)); fail_if(!Streader_read_list(sr, read_received_events_bind, &expected), "Event list reading failed: %s", Streader_get_error_desc(sr)); events = kqt_Handle_receive_events(handle); ++loop_count; } fail_if(loop_count <= 1, "Test did not fill the event buffer, increase event count!"); fail_if(expected != event_count, "Read %" PRId32 " instead of %d events", expected, event_count); // Continue playing kqt_Handle_play(handle, 10); fail_if(kqt_Handle_get_frames_available(handle) != 10, "Kunquat handle rendered %ld instead of 10 frames", kqt_Handle_get_frames_available(handle)); // FIXME: We can only check for 512 notes as we run out of voices :-P const float expected_buf[10] = { min((float)event_count, 512) }; const float* actual_buf = kqt_Handle_get_audio(handle, 0); check_buffers_equal(expected_buf, actual_buf, 10, 0.0f); }
END_TEST START_TEST(Read_valid_string) { static const struct { const char* data; const char* expected; } strings[] = { { "\"\"", "" }, { "\" \"", " " }, { "\" \"", " " }, { "\"\\\"\"", "\"" }, { "\"\\\\\"", "\\" }, { "\"\\/\"", "/" }, { "\"/\"", "/" }, /* { "\"\\b\"", "\b" }, { "\"\\f\"", "\f" }, { "\"\\n\"", "\n" }, { "\"\\r\"", "\r" }, { "\"\\t\"", "\t" }, */ { "\"abc def\"", "abc def" }, }; for (size_t i = 0; i < arr_size(strings); ++i) { char data[128] = ""; sprintf(data, "%s x", strings[i].data); Streader* sr = init_with_cstr(data); char result[128] = "zzz"; fail_if(!Streader_read_string(sr, 128, result), "Could not read string `%s`: %s", data, Streader_get_error_desc(sr)); fail_if(strcmp(result, strings[i].expected) != 0, "Streader stored `%s` instead of `%s`", result, strings[i].expected); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume string `%s` correctly"); } }
END_TEST START_TEST(Read_valid_tstamp) { static const struct { const char* data; const Tstamp expected; } tstamps[] = { { "[0, 0]", { 0, 0 } }, { "[2,5]", { 2, 5 } }, { " [2,5]", { 2, 5 } }, { "[ 2,5]", { 2, 5 } }, { "[2 ,5]", { 2, 5 } }, { "[2, 5]", { 2, 5 } }, { "[2,5 ]", { 2, 5 } }, { "[-1, 3]", { -1, 3 } }, { "[0, 882161279]", { 0, KQT_TSTAMP_BEAT - 1 } }, }; for (size_t i = 0; i < arr_size(tstamps); ++i) { char data[128] = ""; sprintf(data, "%s x", tstamps[i].data); Streader* sr = init_with_cstr(data); Tstamp* result = Tstamp_set(TSTAMP_AUTO, 99, 99); fail_if(!Streader_read_tstamp(sr, result), "Could not read timestamp " PRIts " from `%s`: %s", PRIVALts(tstamps[i].expected), data, Streader_get_error_desc(sr)); fail_if(Tstamp_cmp(result, &tstamps[i].expected) != 0, "Streader stored " PRIts " instead of " PRIts " when reading `%s`", PRIVALts(*result), PRIVALts(tstamps[i].expected), data); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume timestamp from `%s` correctly", data); } }
END_TEST static bool fail_at_index_2(Streader* sr, int32_t index, void* userdata) { (void)sr; (void)userdata; fail_if(index > 2, "List processing continued after failure"); if (index == 2) return false; fail_if(!Streader_read_int(sr, NULL), "Could not read an integer from list: %s", Streader_get_error_desc(sr)); return true; }
END_TEST static bool fail_at_key_2(Streader* sr, const char* key, void* userdata) { (void)sr; (void)userdata; fail_if(strcmp(key, "2") > 0, "Dictionary processing continued after failure"); if (strcmp(key, "2") == 0) return false; fail_if(!Streader_read_float(sr, NULL), "Could not read a float from dictionary: %s", Streader_get_error_desc(sr)); return true; }
int kqt_Handle_fire_event(kqt_Handle handle, int channel, const char* event) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); check_data_is_validated(h, 0); if (channel < 0 || channel >= KQT_COLUMNS_MAX) { Handle_set_error(h, ERROR_ARGUMENT, "Invalid channel number: %d", channel); return 0; } if (event == NULL) { Handle_set_error(h, ERROR_ARGUMENT, "No event description given"); return 0; } const size_t length = strlen(event); if (length > 4096) { Handle_set_error(h, ERROR_ARGUMENT, "Event description is too long"); return 0; } Streader* sr = Streader_init(STREADER_AUTO, event, (int64_t)length); if (!Player_fire(h->player, channel, sr)) { rassert(Streader_is_error_set(sr)); Handle_set_error( h, ERROR_ARGUMENT, "Invalid event description `%s`: %s", event, Streader_get_error_desc(sr)); return 0; } return 1; }
END_TEST START_TEST(Read_empty_dict) { static const char* dicts[] = { "{} x", "{ }x", "{ } x", }; for (size_t i = 0; i < arr_size(dicts); ++i) { Streader* sr = init_with_cstr(dicts[i]); fail_if(!Streader_read_dict(sr, NULL, NULL), "Could not read empty dictionary from `%s`: %s", dicts[i], Streader_get_error_desc(sr)); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume empty dictionary from `%s` correctly", dicts[i]); } }