Newer
Older
libkc / modules / test / src / test_queue.c
Nomura Kei on 29 May 7 KB update
#include <stdio.h>
#include <errno.h>

#include <kc.h>
#include <kc_ut.h>
#include <kc_assert.h>
#include <kc_queue.h>
#include <kc_memory.h>
#include <kc_threads.h>

#include "ut.h"

// プロトタイプ宣言
static void test_queue_new(void);
static void test_queue_offer(void);
static void test_queue_put(void);
static void test_queue_size(void);
static void test_queue_offer_ng(void);
static void test_queue_malloc_error(void);

/**
 * KcQueue 単体テストスイート
 */
void suite_queue(void)
{
    KcUt *ut = KcUt_get_instance();
    ut->add(ut, UT_TESTCASE, "queue new/delete", test_queue_new);
    ut->add(ut, UT_TESTCASE, "queue offer/peek/poll", test_queue_offer);
    ut->add(ut, UT_TESTCASE, "queue put/take", test_queue_put);
    ut->add(ut, UT_TESTCASE, "queue size", test_queue_size);
    ut->add(ut, UT_TESTCASE, "queue offer ng", test_queue_offer_ng);
    ut->add(ut, UT_TESTCASE, "queue malloc error", test_queue_malloc_error);
}

/**
 * Queue 生成/破棄。
 *
 * @process KcQueue_new を実行する。。
 * @result KcQueue が生成されること。
 *
 * @process KcQueue_delete にて Queue を破棄する。
 * @result Queue が破棄されること。
 */
static void test_queue_new(void)
{
    KcQueue *queue = KcQueue_new(0);
    assert_not_null(queue);
    KcQueue_delete(queue);

    // リストが残った状態での削除
    queue = KcQueue_new(0);
    queue->offer(queue, "ABC", 4);
    assert_not_null(queue);
    KcQueue_delete(queue);
}

// for offer thread
static int test_queue_offer_thread(void *arg)
{
    KcQueue *queue = (KcQueue *)arg;
    for (int i = 0; i < 100; i++)
    {
        printf("offer: %d\n", i);
        queue->offer(queue, &i, sizeof(int));
        KcThread_sleep(0, 1, false);
    }
    return 0;
}

// for poll thread
static int test_queue_poll_thread(void *arg)
{
    KcQueue *queue = (KcQueue *)arg;
    for (int i = 0; i < 100; i++)
    {
        int *val = queue->peek(queue, NULL);
        if (val == NULL)
        {
            printf("peek: (null)\n");
        }
        else
        {
            printf("peek: %d\n", *val);
        }

        int element;
        size_t size = sizeof(int);
        bool is_success = queue->poll(queue, &element, &size);
        if (is_success)
        {
            printf("poll: %d\n", element);
        }
        else
        {
            printf("poll: (null)\n");
        }
        KcThread_sleep(0, 1, false);
    }
    return 0;
}

/**
 * キューへの値追加/取得。
 */
static void test_queue_offer(void)
{
    KcQueue *queue = KcQueue_new(10);

    KcThread *offer_thread = KcThread_new(test_queue_offer_thread);
    KcThread *poll_thread = KcThread_new(test_queue_poll_thread);

    offer_thread->start(offer_thread, queue);
    poll_thread->start(poll_thread, queue);

    offer_thread->join(offer_thread);
    poll_thread->join(poll_thread);

    KcQueue_delete(queue);
    KcThread_delete(offer_thread);
    KcThread_delete(poll_thread);
}

// for put thread
static int test_queue_put_thread(void *arg)
{
    KcQueue *queue = (KcQueue *)arg;
    for (int i = 0; i < 100; i++)
    {
        queue->put(queue, &i, sizeof(int));
        KcThread_sleep(0, 1000, false);
    }
    return 0;
}

// for take thread
static int test_queue_take_thread(void *arg)
{
    KcQueue *queue = (KcQueue *)arg;
    for (int i = 0; i < 100; i++)
    {
        int element;
        size_t size = sizeof(int);
        queue->take(queue, &element, &size);
        assert_equals(i, element);
        KcThread_sleep(0, 1, false);
    }
    return 0;
}

// for take thread
static int test_queue_take2_thread(void *arg)
{
    KcQueue *queue = (KcQueue *)arg;
    for (int i = 0; i < 100; i++)
    {
        int element;
        size_t size = sizeof(int);
        queue->take(queue, &element, &size);
        assert_equals(i, element);
        KcThread_sleep(0, 100 * 1000, false);
    }
    return 0;
}

/**
 * キューへの値追加/取得。
 */
static void test_queue_put(void)
{
    {
        KcQueue *queue = KcQueue_new(0);
        KcThread *put_thread = KcThread_new(test_queue_put_thread);
        KcThread *take_thread = KcThread_new(test_queue_take_thread);

        put_thread->start(put_thread, queue);
        take_thread->start(take_thread, queue);

        put_thread->join(put_thread);
        take_thread->join(take_thread);
        KcThread_delete(put_thread);
        KcThread_delete(take_thread);
        KcQueue_delete(queue);
    }

    // PUT ブロックパターン
    {
        KcQueue *queue = KcQueue_new(5);
        KcThread *put_thread = KcThread_new(test_queue_put_thread);
        KcThread *take_thread = KcThread_new(test_queue_take2_thread);
        put_thread->start(put_thread, queue);
        take_thread->start(take_thread, queue);

        put_thread->join(put_thread);
        take_thread->join(take_thread);
        KcThread_delete(put_thread);
        KcThread_delete(take_thread);
        KcQueue_delete(queue);
    }
}

/**
 * キューサイズ取得
 */
static void test_queue_size(void)
{
    KcQueue *queue = KcQueue_new(0);

    // キューへ追加
    bool ret = queue->offer(queue, "ABC", 4);
    assert_true(ret);
    ret = queue->offer(queue, "DEFG", 5);
    int size = queue->size(queue);
    assert_equals(2, size);
    bool is_empty = queue->is_empty(queue);
    assert_false(is_empty);

    bool is_contains = queue->contains(queue, "ABC", 4);
    assert_true(is_contains);
    is_contains = queue->contains(queue, "DEFG", 5);
    assert_true(is_contains);

    char buffer[10];
    size_t element_size;
    // 取り出し [peek]
    const char *val = (const char *)queue->peek(queue, &element_size);
    assert_equals(4, element_size);
    assert_equals("ABC", val);
    size = queue->size(queue);
    assert_equals(2, size);
    is_empty = queue->is_empty(queue);
    assert_false(is_empty);
    // 取り出し [poll] (サイズ不足)
    for (int i = 0; i < 10; i++)
    {
        buffer[i] = 'X';
    }
    buffer[9] = '\0';
    element_size = 2;
    queue->poll(queue, buffer, &element_size);
    assert_equals("ABXXXXXXX", buffer);
    assert_equals(4, element_size);
    size = queue->size(queue);
    assert_equals(1, size);
    is_empty = queue->is_empty(queue);
    assert_false(is_empty);
    is_contains = queue->contains(queue, "ABC", 4);
    assert_false(is_contains);
    is_contains = queue->contains(queue, "DEFG", 5);
    assert_true(is_contains);

    // 取り出し [poll]
    for (int i = 0; i < 10; i++)
    {
        buffer[i] = 'X';
    }
    buffer[9] = '\0';
    element_size = 10;
    queue->poll(queue, buffer, &element_size);
    assert_equals("DEFG", buffer);
    assert_equals(5, element_size);
    size = queue->size(queue);
    assert_equals(0, size);
    is_empty = queue->is_empty(queue);
    assert_true(is_empty);
    is_contains = queue->contains(queue, "ABC", 4);
    assert_false(is_contains);
    is_contains = queue->contains(queue, "DEFG", 5);
    assert_false(is_contains);

    KcQueue_delete(queue);
}

/**
 * offer 失敗。
 */
static void test_queue_offer_ng(void)
{
    KcQueue *queue = KcQueue_new(3);

    bool ret;
    ret = queue->offer(queue, "ABC", 4);
    assert_true(ret);
    ret = queue->offer(queue, "DEF", 4);
    assert_true(ret);
    ret = queue->offer(queue, "GHI", 4);
    assert_true(ret);
    ret = queue->offer(queue, "JKL", 4);
    assert_false(ret);

    queue->clear(queue);
    ret = queue->is_empty(queue);
    assert_true(ret);

    KcQueue_delete(queue);
}

/**
 * Queue メモリ確保失敗。
 */
static void test_queue_malloc_error(void)
{
    // メモリ確保失敗
    KcQueue *queue;
    ut_alloc_control(0)
    {
        queue = KcQueue_new(0);
    }
    assert_null(queue);

    // 内部管理のリストメモリ確保失敗
    ut_alloc_control(1)
    {
        queue = KcQueue_new(0);
    }
    assert_null(queue);

    // 追加時のメモリ確保失敗

    queue = KcQueue_new(10);
    ut_alloc_control(0)
    {
        bool ret = queue->offer(queue, "XYZ", 4);
        assert_false(ret);
    }
    KcQueue_delete(queue);
}