Tue, 09 Dec 2025 12:13:43 +0100
add first tests
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2025 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 * POSSIBLIITY OF SUCH DAMAGE. */ #include "database.h" #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <cx/buffer.h> #include <cx/streams.h> #define TEST_DB "test.db" #define TEST_DATA_FILE "testdata.sql" // create test.db and execute testdata script int init_test_db(void) { sqlite3 *db; char *err_msg = NULL; FILE *f = fopen(TEST_DATA_FILE, "r"); if(!f) { fprintf(stderr, "Cannot open test data file %s: %s\n", TEST_DATA_FILE, strerror(errno)); } if(unlink(TEST_DB)) { if(errno != ENOENT) { fprintf(stderr, "Cannot unlink %s: %s\n", TEST_DB, strerror(errno)); fclose(f); return 1; } } if(sqlite3_open(TEST_DB, &db) != SQLITE_OK) { fprintf(stderr, "Cannot open database %s: %s\n", TEST_DB, sqlite3_errmsg(db)); fclose(f); return 1; } CxBuffer *buf = cxBufferCreate(NULL, 2048, NULL, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_FREE_CONTENTS); cx_stream_copy(f, buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite); int err = 0; if(buf->size > 0) { cxBufferTerminate(buf); if(sqlite3_exec(db, buf->space, 0, 0, &err_msg) != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); err = 1; } } else { fprintf(stderr, "Error: no file content\n"); err = 1; } cxBufferFree(buf); sqlite3_close(db); return err; } static DBUContext *ctx; static DBUConnection *conn; typedef struct Address { int64_t address_id; cxmutstr street; cxmutstr zip; cxmutstr city; } Address; typedef struct Person { int64_t person_id; cxmutstr name; cxmutstr email; int age; bool iscustomer; uint64_t hash; Address *address; CxList *roles; } Person; typedef struct Role { int64_t role_id; int64_t person_id; cxmutstr name; } Role; int init_db_tests(void) { ctx = dbuContextCreate(); DBUClass *address = dbuRegisterClass(ctx, "address", Address, address_id); dbuClassAdd(address, Address, street); dbuClassAdd(address, Address, zip); dbuClassAdd(address, Address, city); DBUClass *role = dbuRegisterClass(ctx, "role", Role, role_id); DBUClass *person = dbuRegisterClass(ctx, "person", Person, person_id); dbuClassAdd(person, Person, name); dbuClassAdd(person, Person, email); dbuClassAdd(person, Person, age); dbuClassAdd(person, Person, iscustomer); dbuClassAdd(person, Person, hash); dbuClassAddObj(person, "address_id", offsetof(Person, address), address); dbuClassAddCxLinkedList(person, "person_id", offsetof(Person, roles), role); dbuClassAddForeignKey(role, Role, person_id, person); dbuClassAdd(role, Role, name); return 0; } void cleanup_db_tests(void) { if(conn) { dbuConnectionFree(conn); } dbuContextFree(ctx); } CX_TEST(testSqliteConnection) { CX_TEST_DO { conn = dbuSQLiteConnection(TEST_DB); CX_TEST_ASSERT(conn); CX_TEST_ASSERT(dbuConnectionIsActive(conn)); } } CX_TEST(testConnectionExec) { CX_TEST_DO { CX_TEST_ASSERT(conn); int t1 = dbuConnectionExec(conn, "create table ExecTest1(a int);"); CX_TEST_ASSERT(t1 == 0); int t2 = dbuConnectionExec(conn, "insert into ExecTest1(a) values (1);"); CX_TEST_ASSERT(t2 == 0); int t3 = dbuConnectionExec(conn, "drop table ExecTest1;"); CX_TEST_ASSERT(t3 == 0); int fail = dbuConnectionExec(conn, "select * from Fail;"); CX_TEST_ASSERT(fail != 0); } } CX_TEST(testSingleValueQuery) { CX_TEST_DO { CX_TEST_ASSERT(conn); DBUQuery *q = dbuConnectionQuery(conn, NULL); CX_TEST_ASSERT(q); CX_TEST_ASSERT(dbuQuerySetSQL(q, "select 12;") == 0); CX_TEST_ASSERT(dbuQueryExec(q) == 0); DBUResult *r = dbuQueryGetResult(q); CX_TEST_ASSERT(r); int value; CX_TEST_ASSERT(dbuResultAsValue(r, &value) == 0); CX_TEST_ASSERT(value == 12); dbuQueryFree(q); } }