tests/test_buffer.c

Tue, 02 Jan 2024 23:31:00 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 02 Jan 2024 23:31:00 +0100
changeset 791
945ee9bf2dd1
parent 789
9b2f5661bebd
child 792
3ca984931e1d
permissions
-rw-r--r--

generate (release) config.mk if none exists - fixes #350

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2023 Mike Becker, Olaf Wintermann All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "cx/test.h"
#include "util_allocator.h"

#include "cx/buffer.h"

static CX_TEST_SUBROUTINE(expect_default_flush_config, CxBuffer *buf) {
    CX_TEST_ASSERT(buf->flush_blkmax == 0);
    CX_TEST_ASSERT(buf->flush_blksize == 4096);
    CX_TEST_ASSERT(buf->flush_threshold == SIZE_MAX);
    CX_TEST_ASSERT(buf->flush_func == NULL);
    CX_TEST_ASSERT(buf->flush_target == NULL);
}

CX_TEST(test_buffer_init_wrap_space) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        CxBuffer buf;
        void *space = cxMalloc(alloc, 16);
        cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_DEFAULT);
        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
        CX_TEST_ASSERT(buf.space == space);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == 0);
        CX_TEST_ASSERT(buf.pos == 0);
        CX_TEST_ASSERT(buf.size == 0);
        CX_TEST_ASSERT(buf.capacity == 16);
        CX_TEST_ASSERT(buf.allocator == alloc);
        cxBufferDestroy(&buf);
        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
        cxFree(alloc, space);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_init_wrap_space_auto_extend) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        CxBuffer buf;
        void *space = cxMalloc(alloc, 16);
        cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_AUTO_EXTEND);
        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
        CX_TEST_ASSERT(buf.space == space);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == 0);
        CX_TEST_ASSERT(buf.pos == 0);
        CX_TEST_ASSERT(buf.size == 0);
        CX_TEST_ASSERT(buf.capacity == 16);
        CX_TEST_ASSERT(buf.allocator == alloc);
        cxBufferDestroy(&buf);
        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
        cxFree(alloc, space);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_init_wrap_space_auto_free) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        CxBuffer buf;
        void *space = cxMalloc(alloc, 16);
        cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_FREE_CONTENTS);
        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
        CX_TEST_ASSERT(buf.space == space);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS);
        CX_TEST_ASSERT(buf.pos == 0);
        CX_TEST_ASSERT(buf.size == 0);
        CX_TEST_ASSERT(buf.capacity == 16);
        CX_TEST_ASSERT(buf.allocator == alloc);
        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
        cxBufferDestroy(&buf);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_init_fresh_space) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        CxBuffer buf;
        cxBufferInit(&buf, NULL, 8, alloc, CX_BUFFER_DEFAULT);
        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
        CX_TEST_ASSERT(buf.space != NULL);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0);
        CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS);
        CX_TEST_ASSERT(buf.pos == 0);
        CX_TEST_ASSERT(buf.size == 0);
        CX_TEST_ASSERT(buf.capacity == 8);
        CX_TEST_ASSERT(buf.allocator == alloc);
        CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc)); // space is still allocated
        cxBufferDestroy(&buf);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_init_on_heap) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        CxBuffer *buf;
        void *space = cxMalloc(alloc, 16);
        buf = cxBufferCreate(space, 16, alloc, CX_BUFFER_FREE_CONTENTS);
        CX_TEST_ASSERT(buf != NULL);
        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, buf);
        CX_TEST_ASSERT(buf->space == space);
        CX_TEST_ASSERT((buf->flags & CX_BUFFER_AUTO_EXTEND) == 0);
        CX_TEST_ASSERT((buf->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS);
        CX_TEST_ASSERT(buf->pos == 0);
        CX_TEST_ASSERT(buf->size == 0);
        CX_TEST_ASSERT(buf->capacity == 16);
        CX_TEST_ASSERT(buf->allocator == alloc);
        cxBufferFree(buf);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_minimum_capacity_sufficient) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        void *space = cxMalloc(alloc, 8);
        CxBuffer buf;
        cxBufferInit(&buf, space, 8, alloc, CX_BUFFER_FREE_CONTENTS);
        memcpy(space, "Testing", 8);
        buf.size = 8;
        cxBufferMinimumCapacity(&buf, 6);
        CX_TEST_ASSERT(buf.capacity == 8);
        CX_TEST_ASSERT(buf.size == 8);
        CX_TEST_ASSERT(memcmp(buf.space, "Testing", 8) == 0);
        cxBufferDestroy(&buf);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_minimum_capacity_extend) {
    CxTestingAllocator talloc;
    cx_testing_allocator_init(&talloc);
    CxAllocator *alloc = &talloc.base;
    CX_TEST_DO {
        void *space = cxMalloc(alloc, 8);
        CxBuffer buf;
        cxBufferInit(&buf, space, 8, alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
        memcpy(space, "Testing", 8);
        buf.size = 8;
        cxBufferMinimumCapacity(&buf, 16);
        CX_TEST_ASSERT(buf.capacity == 16);
        CX_TEST_ASSERT(buf.size == 8);
        CX_TEST_ASSERT(memcmp(buf.space, "Testing", 8) == 0);
        cxBufferDestroy(&buf);
        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    }
    cx_testing_allocator_destroy(&talloc);
}

CX_TEST(test_buffer_clear) {
    char space[16];
    strcpy(space, "clear test");
    CxBuffer buf;
    cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    CX_TEST_DO {
        CX_TEST_ASSERT(buf.size == 0);
        // only clear the used part of the buffer
        cxBufferClear(&buf);
        CX_TEST_ASSERT(0 == memcmp(space, "clear test", 10));
        buf.size = 5;
        buf.pos = 3;
        cxBufferClear(&buf);
        CX_TEST_ASSERT(0 == memcmp(space, "\0\0\0\0\0 test", 10));
        CX_TEST_ASSERT(buf.size == 0);
        CX_TEST_ASSERT(buf.pos == 0);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_reset) {
    char space[16];
    strcpy(space, "reset test");
    CxBuffer buf;
    cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    CX_TEST_DO {
        buf.size = 5;
        buf.pos = 3;
        cxBufferReset(&buf);
        CX_TEST_ASSERT(0 == memcmp(space, "reset test", 10));
        CX_TEST_ASSERT(buf.size == 0);
        CX_TEST_ASSERT(buf.pos == 0);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_set_zero) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 0, SEEK_SET);
        CX_TEST_ASSERT(result == 0);
        CX_TEST_ASSERT(buf.pos == 0);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_set_valid) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 5, SEEK_SET);
        CX_TEST_ASSERT(result == 0);
        CX_TEST_ASSERT(buf.pos == 5);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_set_invalid) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 6, SEEK_SET);
        CX_TEST_ASSERT(result != 0);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_cur_zero) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 0, SEEK_CUR);
        CX_TEST_ASSERT(result == 0);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_cur_valid_positive) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 2, SEEK_CUR);
        CX_TEST_ASSERT(result == 0);
        CX_TEST_ASSERT(buf.pos == 5);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_cur_valid_negative) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, -3, SEEK_CUR);
        CX_TEST_ASSERT(result == 0);
        CX_TEST_ASSERT(buf.pos == 0);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_cur_invalid_positive) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 3, SEEK_CUR);
        CX_TEST_ASSERT(result != 0);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_cur_invalid_negative) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, -4, SEEK_CUR);
        CX_TEST_ASSERT(result != 0);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_end_zero) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 0, SEEK_END);
        // the (past-the-)end position is always invalid
        CX_TEST_ASSERT(result != 0);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_end_valid) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, -6, SEEK_END);
        CX_TEST_ASSERT(result == 0);
        CX_TEST_ASSERT(buf.pos == 0);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_end_invalid) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 1, SEEK_END);
        CX_TEST_ASSERT(result != 0);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CX_TEST(test_buffer_seek_whence_invalid) {
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    buf.size = 6;
    buf.pos = 3;
    CX_TEST_DO {
        int result = cxBufferSeek(&buf, 2, 9000);
        CX_TEST_ASSERT(result != 0);
        CX_TEST_ASSERT(buf.size == 6);
        CX_TEST_ASSERT(buf.pos == 3);
    }
    cxBufferDestroy(&buf);
}

CxTestSuite *cx_test_suite_buffer(void) {
    CxTestSuite *suite = cx_test_suite_new("buffer");

    cx_test_register(suite, test_buffer_init_wrap_space);
    cx_test_register(suite, test_buffer_init_wrap_space_auto_extend);
    cx_test_register(suite, test_buffer_init_wrap_space_auto_free);
    cx_test_register(suite, test_buffer_init_fresh_space);
    cx_test_register(suite, test_buffer_init_on_heap);
    cx_test_register(suite, test_buffer_minimum_capacity_sufficient);
    cx_test_register(suite, test_buffer_minimum_capacity_extend);
    cx_test_register(suite, test_buffer_clear);
    cx_test_register(suite, test_buffer_reset);
    cx_test_register(suite, test_buffer_seek_set_zero);
    cx_test_register(suite, test_buffer_seek_set_valid);
    cx_test_register(suite, test_buffer_seek_set_invalid);
    cx_test_register(suite, test_buffer_seek_cur_zero);
    cx_test_register(suite, test_buffer_seek_cur_valid_positive);
    cx_test_register(suite, test_buffer_seek_cur_valid_negative);
    cx_test_register(suite, test_buffer_seek_cur_invalid_positive);
    cx_test_register(suite, test_buffer_seek_cur_invalid_negative);
    cx_test_register(suite, test_buffer_seek_end_zero);
    cx_test_register(suite, test_buffer_seek_end_valid);
    cx_test_register(suite, test_buffer_seek_end_invalid);
    cx_test_register(suite, test_buffer_seek_whence_invalid);
    
    return suite;
}

mercurial