#include #include #include static DWORD WINAPI message_queue_consumer_thread(LPVOID arg) { wMessage message = WINPR_C_ARRAY_INIT; wMessageQueue* queue = (wMessageQueue*)arg; while (MessageQueue_Wait(queue)) { if (MessageQueue_Peek(queue, &message, TRUE)) { if (message.id == WMQ_QUIT) break; printf("Message.Type: %" PRIu32 "\n", message.id); } } return 0; } static bool wrap_test(bool (*fkt)(wMessageQueue* queue)) { wMessageQueue* queue = MessageQueue_New(nullptr); if (!queue) return false; WINPR_ASSERT(fkt); const bool rc = fkt(queue); MessageQueue_Free(queue); return rc; } static bool check(const wMessage* message, size_t pos) { if (!message) return false; if (message->context != (void*)13) return false; if (message->id != pos) return false; if (message->wParam != (void*)23) return false; if (message->lParam != (void*)42) return false; if (message->Free != nullptr) return false; return true; } static bool append(wMessageQueue* queue, size_t pos) { const wMessage message = { .context = (void*)13, .id = WINPR_ASSERTING_INT_CAST(DWORD, pos), .wParam = (void*)23, .lParam = (void*)42, .Free = nullptr }; return MessageQueue_Dispatch(queue, &message); } static bool fill_capcity(wMessageQueue* queue, size_t* pos) { WINPR_ASSERT(pos); size_t cpos = *pos; const size_t capacity = MessageQueue_Capacity(queue); while (MessageQueue_Size(queue) < capacity) { if (!append(queue, cpos++)) return false; } *pos = cpos; return true; } static bool drain(wMessageQueue* queue, size_t expect) { wMessage message = WINPR_C_ARRAY_INIT; if (MessageQueue_Get(queue, &message) < 0) return false; if (!check(&message, expect)) return false; return true; } static bool drain_capcity(wMessageQueue* queue, size_t remain, size_t* pos) { WINPR_ASSERT(pos); size_t cpos = *pos; while (MessageQueue_Size(queue) > remain) { if (!drain(queue, cpos++)) return false; } *pos = cpos; return true; } static bool test_growth_move(wMessageQueue* queue, bool big) { WINPR_ASSERT(queue); const size_t cap = MessageQueue_Capacity(queue); if (cap < 4) return false; size_t wpos = 0; size_t rpos = 0; if (!fill_capcity(queue, &wpos)) return false; if (big) { if (!append(queue, wpos++)) return false; } if (!drain_capcity(queue, 3, &rpos)) return false; if (!fill_capcity(queue, &wpos)) return false; if (!append(queue, wpos++)) return false; return drain_capcity(queue, 0, &rpos); } static bool test_growth_big_move(wMessageQueue* queue) { return test_growth_move(queue, true); } static bool test_growth_small_move(wMessageQueue* queue) { return test_growth_move(queue, false); } static bool test_operation_run(wMessageQueue* queue, HANDLE thread) { WINPR_ASSERT(queue); WINPR_ASSERT(thread); if (!MessageQueue_Post(queue, nullptr, 123, nullptr, nullptr)) return false; if (!MessageQueue_Post(queue, nullptr, 456, nullptr, nullptr)) return false; if (!MessageQueue_Post(queue, nullptr, 789, nullptr, nullptr)) return false; if (!MessageQueue_PostQuit(queue, 0)) return false; const DWORD status = WaitForSingleObject(thread, INFINITE); return (status == WAIT_OBJECT_0); } static bool test_operation(wMessageQueue* queue) { WINPR_ASSERT(queue); HANDLE thread = CreateThread(nullptr, 0, message_queue_consumer_thread, queue, 0, nullptr); if (!thread) { printf("failed to create thread\n"); return false; } const bool rc = test_operation_run(queue, thread); if (!CloseHandle(thread)) return false; return rc; } int TestMessageQueue(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[]) { if (!wrap_test(test_growth_big_move)) return -1; if (!wrap_test(test_growth_small_move)) return -2; if (!wrap_test(test_operation)) return -3; return 0; }