Zadania rekrutacyjne i ćwiczeniowe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

175 lines
4.5 KiB

#include "thread/TaskQueue.h"
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
// Testing macros:
#define RUN_TEST(test_function) \
do {test_setup();test_function();test_teardown();} while (0)
#define CHECK(type, value, operator, expected, message) \
do {if (!(value operator expected)) { \
printf("-- Failed: %s\n---- Failed expression: %" #type " %s %" #type "\n", \
message, value, #operator, expected); ++failCounter;\
} else {printf("-- PASSED (%s %s %s)\n", \
#value, #operator, #expected);}} while (0)
static int failCounter = 0;
// usage:
// CHECK(type, actual, operator, expected, message);
// RUN_TEST(test_function);
enum {
IDX_RESULT_TASK_1 = 0,
IDX_RESULT_TASK_2,
IDX_RESULT_TASK_ORDER,
IDX_RESULT_TASK_STOP,
IDX_RESULT_BLOCK,
IDX_RESULT_NOTIFY,
IDX_RESULT_COUNT
};
static int taskResults[IDX_RESULT_COUNT] = {0};
static BlockerHandle blockerHnd = 99;
static TaskQueuePtr globalQueue = NULL;
void testTask1(void*);
void testTask2(void*);
void testTaskStop(void*);
void testTaskPostItself(void*);
void blockMock(BlockerHandle);
void notifyMock(BlockerHandle);
static void test_setup(void){}
static void test_teardown(void){}
static void test_createTaskQueue(void)
{
TaskQueuePtr queue = createTaskQueue(blockerHnd, &blockMock, &notifyMock);
CHECK(p, (void*)queue, !=, NULL, "createTaskQueue should return a valid task queue");
freeTaskQueue(&queue);
}
static void test_runQueue(void)
{
const char* msg = "runQueue should execute enqueued tasks in order with no loop";
TaskQueuePtr queue = createTaskQueue(blockerHnd, &blockMock, &notifyMock);
enqueueTask(queue, &testTask1, NULL);
enqueueTask(queue, &testTask2, NULL);
enqueueTask(queue, &testTaskStop, queue);
runQueue(queue);
CHECK(i, taskResults[IDX_RESULT_TASK_1] , ==, 1, msg);
CHECK(i, taskResults[IDX_RESULT_TASK_2] , ==, 2, msg);
CHECK(i, taskResults[IDX_RESULT_TASK_ORDER], ==, 3, msg);
CHECK(i, taskResults[IDX_RESULT_TASK_STOP] , ==, 1, msg);
freeTaskQueue(&queue);
}
static void test_enqueueNotify(void)
{
const char* msg = "Enqueueing new task should notify the blocker";
TaskQueuePtr queue = createTaskQueue(blockerHnd, &blockMock, &notifyMock);
memset(taskResults, 0, sizeof(taskResults));
enqueueTask(queue, &testTask1, NULL);
enqueueTask(queue, &testTask1, NULL);
CHECK(i, taskResults[IDX_RESULT_NOTIFY], ==, 2, msg);
freeTaskQueue(&queue);
}
static void test_stopNotify(void)
{
const char* msg = "Stopping the queue should notify the blocker";
TaskQueuePtr queue = createTaskQueue(blockerHnd, &blockMock, &notifyMock);
memset(taskResults, 0, sizeof(taskResults));
enqueueTask(queue, &testTaskStop, queue);
runQueue(queue);
CHECK(i, taskResults[IDX_RESULT_NOTIFY], ==, 2, msg); // enqueue + stop
freeTaskQueue(&queue);
}
static void test_blockOnEmpty(void)
{
const char* msg = "Empty queue should lock the blocker";
TaskQueuePtr queue = createTaskQueue(blockerHnd, &blockMock, &notifyMock);
memset(taskResults, 0, sizeof(taskResults));
globalQueue = queue;
enqueueTask(queue, &testTask1, NULL);
runQueue(queue);
CHECK(i, taskResults[IDX_RESULT_BLOCK], ==, 1, msg);
freeTaskQueue(&queue);
}
static void test_leak(void)
{
// This is a leak test for valgrind.
// The scenario is that a task enqueueing itself again
// shouldn't cause infinite loop nor memory leak.
TaskQueuePtr queue = createTaskQueue(blockerHnd, &blockMock, &notifyMock);
enqueueTask(queue, &testTaskPostItself, queue);
enqueueTask(queue, &testTaskStop, queue);
runQueue(queue);
freeTaskQueue(&queue);
}
int main(void) {
RUN_TEST(test_createTaskQueue);
RUN_TEST(test_runQueue);
RUN_TEST(test_enqueueNotify);
RUN_TEST(test_stopNotify);
RUN_TEST(test_blockOnEmpty);
RUN_TEST(test_leak);
return failCounter;
}
// ---
void blockMock(BlockerHandle blocker)
{
(void)blocker;
taskResults[IDX_RESULT_BLOCK] += 1;
if (globalQueue) {
stopQueue(globalQueue);
}
}
void notifyMock(BlockerHandle blocker)
{
(void)blocker;
taskResults[IDX_RESULT_NOTIFY] += 1;
}
void testTask1(void* data)
{
(void)data;
taskResults[IDX_RESULT_TASK_1] += 1;
taskResults[IDX_RESULT_TASK_ORDER] += 6;
}
void testTask2(void* data)
{
(void)data;
taskResults[IDX_RESULT_TASK_2] += 2;
taskResults[IDX_RESULT_TASK_ORDER] /= 2;
}
void testTaskStop(void* data)
{
taskResults[IDX_RESULT_TASK_STOP] += 1;
stopQueue((TaskQueuePtr)data);
}
void testTaskPostItself(void* data)
{
enqueueTask((TaskQueuePtr)data, testTaskPostItself, data);
}