]> uap-core.de Git - note.git/commitdiff
add tests for note_store_create_default, user_settings_is_valid and note_store_reload
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 11 Jan 2026 10:45:06 +0000 (11:45 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 11 Jan 2026 10:45:06 +0000 (11:45 +0100)
14 files changed:
application/application.c
application/store.c
application/store.h
application/tests/test-store.c
application/tests/test-store.h
application/tests/testmain.c
dbutils/db.c
ui/cocoa/toolkit.m
ui/common/properties.c
ui/common/threadpool.c
ui/common/threadpool.h
ui/gtk/toolkit.c
ui/motif/toolkit.c
ui/ui/toolkit.h

index 6af37245792853894d2d485e93844c004e9978af..d41693aef9bb3ee0e52ef3b07f8b7d9c052e83f5 100644 (file)
@@ -98,7 +98,10 @@ void application_startup(UiEvent *event, void *data) {
     
     cxMempoolFree(mp);
     
-    note_store_reload();
+    if(note_store_reload()) {
+        fprintf(stderr, "Error: note_store_reload failed\n");
+        exit(1);
+    }
     
     ui_window_default_size(1600, 1200);
     window_create();
index efdbf8a8b1b6661e98efc07d0c81ef508550ce28..45a7f2575ed3aea458c9bf8ffcff6391959a8f3d 100644 (file)
@@ -43,9 +43,8 @@
 #include "types.h"
 #include "store_sqlite.h"
 
-#include "../dbutils/dbutils/db.h"
-#include "../dbutils/dbutils/sqlite.h"
-#include "cx/mempool.h"
+#include <dbutils/dbutils/sqlite.h>
+#include <cx/mempool.h>
 
 #define SQL_REPOSITORY_GET_ALL "select * from repositories;"
 
@@ -225,6 +224,10 @@ CxList* note_store_get_user_settings(const CxAllocator *a, const char *host, con
     return usersettings;
 }
 
+DBUConnection* note_store_get_connection() {
+    return connection;
+}
+
 void close_note_store() {
     dbuConnectionFree(connection);
     connection = NULL;
@@ -250,7 +253,7 @@ int user_settings_is_valid(
     if(settings->host && host && strcmp(settings->host, host)) {
         return 0;
     }
-    if(settings->user && host && strcmp(settings->user, user)) {
+    if(settings->user && user && strcmp(settings->user, user)) {
         return 0;
     }
     if(settings->profile_name && profile && strcmp(settings->profile_name, profile)) {
@@ -369,7 +372,7 @@ int note_store_create_default(const char *host, const char *user) {
  * Reloads the NoteStore structure. The previous NoteStore* pointer will be
  * invalid after this call
  */
-void note_store_reload() {
+int note_store_reload() {
     // load notebook/collection structure
     CxMempool *mp = cxMempoolCreateSimple(64);
     const CxAllocator *a = mp->allocator;
@@ -383,7 +386,7 @@ void note_store_reload() {
     if(!collections) {
         fprintf(stderr, "Error: cannot query note store\n");
         cxMempoolFree(mp);
-        return;
+        return 1;
     }
     
     // NoteStore root object
@@ -439,6 +442,8 @@ void note_store_reload() {
     }
     
     current_store = store;
+    
+    return 0;
 }
 
 NoteStore* note_store_get() {
index 4a190183b783c5c7f0324e5f0f04f29ac9483270..d60dacfd6d2f9df0aedfa4ca23f07398d89bdd5c 100644 (file)
@@ -33,6 +33,7 @@
 #include "types.h"
 #include <cx/list.h>
 #include <cx/mempool.h>
+#include <dbutils/dbutils/db.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,6 +65,8 @@ int init_note_store();
 
 CxList* note_store_get_user_settings(const CxAllocator *a, const char *host, const char *user, const char *profile);
 
+DBUConnection* note_store_get_connection();
+
 void close_note_store();
 
 int user_settings_is_valid(
@@ -81,7 +84,7 @@ void note_store_set_settings(
 
 int note_store_create_default(const char *host, const char *user);
 
-void note_store_reload();
+int note_store_reload();
 
 NoteStore* note_store_get();
 
index 0beb76de060bd9ce43e95315efd007a9f6def2f2..33e9b2ccef3cef0faddc7bfbc9a79c3a3892d47f 100644 (file)
 
 #include "../store.h"
 
+#include <dbutils/dbutils/db.h>
+#include <dbutils/dbutils/sqlite.h>
+
+static int64_t test_root_resource_id;
+static int64_t test_repository_id;
+static bool test_store_initialized = FALSE;
+
 CX_TEST(test_init_note_store) {
     CX_TEST_DO {
         int ret = init_note_store();
@@ -42,5 +49,91 @@ CX_TEST(test_init_note_store) {
         // the database
         int ret2 = init_note_store();
         CX_TEST_ASSERT(ret2 == 0);
+        
+        DBUConnection *conn = note_store_get_connection();
+        CX_TEST_ASSERT(conn);
+    }
+}
+
+CX_TEST(test_note_store_create_default) {
+    CX_TEST_DO {
+        DBUConnection *conn = note_store_get_connection();
+        CX_TEST_ASSERT(conn);
+        
+        int ret = note_store_create_default("testhost", "testuser");
+        CX_TEST_ASSERT(ret == 0);
+        
+        DBUResult *result = dbuSqlExec(conn, NULL,
+                "select r.repository_id, c.resource_id from user_settings u "
+                "inner join repositories r on u.default_repository_id = r.repository_id "
+                "inner join resources c on u.default_collection_id = c.resource_id "
+                "where host = 'testhost' and user = 'testuser';");
+        CX_TEST_ASSERT(result);
+        
+        CX_TEST_ASSERT(dbuResultHasData(result));
+        test_repository_id = dbuResultGetInt(result, 0);
+        test_root_resource_id = dbuResultGetInt(result, 1);
+        
+        dbuResultNextRow(result);
+        CX_TEST_ASSERT(!dbuResultHasData(result)); // result should only have 1 row
+        
+        dbuResultFree(result);
+        
+        note_store_set_settings("testhost", "testuser", "default", test_repository_id, test_root_resource_id);
+        
+        test_store_initialized = TRUE;
+    }
+}
+
+CX_TEST(test_user_settings_is_valid) {
+    CX_TEST_DO {
+        UserSettings settings1;
+        settings1.host = "testhost";
+        settings1.user = "testuser";
+        settings1.profile_name = "default";
+        
+        CX_TEST_ASSERT(user_settings_is_valid(&settings1, "testhost", "testuser", "default"));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings1, "testhost", "testuser", NULL));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings1, "testhost", NULL, "default"));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings1, NULL, "testuser", "default"));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings1, NULL, NULL, NULL));
+        
+        UserSettings settings2;
+        settings2.host = NULL;
+        settings2.user = NULL;
+        settings2.profile_name = NULL;
+        
+        CX_TEST_ASSERT(user_settings_is_valid(&settings2, "testhost", "testuser", "default"));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings2, "testhost", "testuser", NULL));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings2, "testhost", NULL, "default"));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings2, NULL, "testuser", "default"));
+        CX_TEST_ASSERT(user_settings_is_valid(&settings2, NULL, NULL, NULL));
+        
+        // invalid settings
+        
+        UserSettings invalid1;
+        invalid1.host = "testhost2";
+        invalid1.user = "root";
+        invalid1.profile_name = "test";
+        
+        CX_TEST_ASSERT(!user_settings_is_valid(&invalid1, "testhost", "root", "test"));
+        CX_TEST_ASSERT(!user_settings_is_valid(&invalid1, "testhost2", "testuser", "test"));
+        CX_TEST_ASSERT(!user_settings_is_valid(&invalid1, "testhost2", "root", "default"));
+    }
+}
+
+
+CX_TEST(test_note_store_reload) {
+    CX_TEST_DO {
+        CX_TEST_ASSERT(!note_store_reload());
+        NoteStore *store = note_store_get();
+        CX_TEST_ASSERT(store);
+        CX_TEST_ASSERT(store->mp);
+        CX_TEST_ASSERT(store->root);
+        CX_TEST_ASSERT(store->repositories);
+        
+        CX_TEST_ASSERT(store->root->children);
+        CX_TEST_ASSERT(cxListSize(store->root->children) > 0); // there should be some default groups/notebooks
     }
 }
+
index b918cf33a8a54fca76504626d9be4f1f5d0cee28..92dabd578140ae3057ff38c0383d7eedc9dfb015 100644 (file)
@@ -36,6 +36,11 @@ extern "C" {
 #endif
 
 CX_TEST(test_init_note_store);
+CX_TEST(test_note_store_create_default);
+CX_TEST(test_user_settings_is_valid);
+
+CX_TEST(test_note_store_reload);
+
 
 
 #ifdef __cplusplus
index 4da0c0580d0b6df83bce12b9232d9c32a2120079..bc272e14b796812b3c4425970f24ba67830442b7 100644 (file)
@@ -36,6 +36,8 @@
 #include "test-editor.h"
 #include "test-store.h"
 
+#include "../types.h"
+
 int main(int argc, char **argv) {
     struct stat s;
     if(!stat("notetestdata", &s)) {
@@ -44,10 +46,14 @@ int main(int argc, char **argv) {
     
     ui_setappdir("notetestdata");
     ui_init(NULL, 0, NULL);
+    register_types();
     
     CxTestSuite *suite = cx_test_suite_new("note");
     
     cx_test_register(suite, test_init_note_store);
+    cx_test_register(suite, test_note_store_create_default);
+    cx_test_register(suite, test_user_settings_is_valid);
+    cx_test_register(suite, test_note_store_reload);
     
     cx_test_register(suite, test_parse_markdown_para);
     cx_test_register(suite, test_parse_markdown_formatting_simple);
index a2a0d89fbc282d2cad1657bc54f8931863cd7278..0dbea991aaac2ba7e852b463861324cc68788f21 100644 (file)
@@ -123,7 +123,7 @@ int64_t dbuResultGetInt(DBUResult *result, int field) {
     if(result->optional_getInt) {
         return result->optional_getInt(result, field);
     } else {
-        cxstring s = result->getText(result, 0);
+        cxstring s = result->getText(result, field);
         int64_t value = 0;
         cx_strtoi64(s, &value, 10);
         return value;
index c0e9edff00451902f89af3e37c9db80ffe7404f9..ae6f4c724f72ceb57e3068a8c2efab805931ceae 100644 (file)
@@ -174,6 +174,11 @@ void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd)
 @end
 
 void ui_call_mainthread(ui_threadfunc tf, void* td) {
+    if(uic_mainthread_calls_is_buffered()) {
+        uic_add_buffered_mainthread_call(tf, td);
+        return;
+    }
+    
     UiAppCallback *cb = [[UiAppCallback alloc]initWithCallback:tf userdata:td];
     [cb callMainThread];
 }
index 10c118195a23eed77a077b5ee69eb59a993d352b..bedc918793d62061bde27bebbe6703ac8e7d516b 100644 (file)
@@ -234,10 +234,6 @@ void uic_load_app_properties() {
         return;
     }
     
-    //if(!ui_appname()) {
-    //    // applications without name cannot load app properties
-    //    return;
-    //}
     
     char *dir = ui_configfile(NULL);
     if(!dir) {
index 3b4c096509861abc266c59e5698daf5aa16d342e..5d3b72adee40f53fb1b84b3e5ddf4c2f630d4d59 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "threadpool.h"
 #include "context.h"
+#include <cx/linked_list.h>
 
 #include <pthread.h>
 #include <stdio.h>
 
 static threadpool_job kill_job;
 
+
+
+static pthread_mutex_t mc_buffer_mutex;
+static CxList *mainthread_call_buffer;
+static volatile int mainthread_call_buffered = 0;
+
+typedef struct UiMainCall {
+    ui_threadfunc func;
+    void *data;
+} UiMainCall;
+
+void uic_init_threads(void) {
+    pthread_mutex_init(&mc_buffer_mutex, NULL);
+    mainthread_call_buffer = cxLinkedListCreate(NULL, sizeof(UiMainCall));
+}
+
+int uic_mainthread_calls_is_buffered(void) {
+    return mainthread_call_buffered;
+}
+
+void uic_add_buffered_mainthread_call(ui_threadfunc func, void *data) {
+    pthread_mutex_lock(&mc_buffer_mutex);
+    UiMainCall call;
+    call.func = func;
+    call.data = data;
+    cxListAdd(mainthread_call_buffer, &call);
+    pthread_mutex_unlock(&mc_buffer_mutex);
+}
+
+
+void ui_buffer_mainthread_calls(UiBool enable_buffering) {
+    mainthread_call_buffered = enable_buffering;
+    if(!enable_buffering) {
+        ui_exec_buffered_mainthread_calls();
+    }
+}
+void ui_exec_buffered_mainthread_calls(void) {
+    pthread_mutex_lock(&mc_buffer_mutex);
+    CxIterator i = cxListIterator(mainthread_call_buffer);
+    cx_foreach(UiMainCall *, call, i) {
+        if(call->func) {
+            call->func(call->data);
+        }
+    }
+    cxListClear(mainthread_call_buffer);
+    pthread_mutex_unlock(&mc_buffer_mutex);
+}
+
+
+
 UiThreadpool* threadpool_new(int min, int max) {
     UiThreadpool *pool = malloc(sizeof(UiThreadpool));
     pool->queue = ui_queue_create();
index 4a997f6802a0cab9f4af2a630c935749263f9720..8413b240acdece14f2bd9e7485316f7c1844b67b 100644 (file)
 extern "C" {
 #endif
     
+void uic_init_threads(void);
+int uic_mainthread_calls_is_buffered(void);
+void uic_add_buffered_mainthread_call(ui_threadfunc func, void *data);
+    
 typedef struct UiQueueElm UiQueueElm;
 typedef struct UiQueue    UiQueue;
     
index 10cba07f253f00e366c6ba1cc94c5b12b9a535de..d775f3b08613724e2ea7cba291a7d9f9cb2a7a0b 100644 (file)
@@ -76,6 +76,7 @@ UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
     uic_toolbar_init();
     ui_image_init();
     uic_load_app_properties();
+    uic_init_threads();
     
 #if GTK_MAJOR_VERSION >= 4
     scale_factor = 1; // TODO
@@ -203,6 +204,11 @@ static gboolean ui_idle_func(void *data) {
 }
 
 void ui_call_mainthread(ui_threadfunc tf, void* td) {
+    if(uic_mainthread_calls_is_buffered()) {
+        uic_add_buffered_mainthread_call(tf, td);
+        return;
+    }
+    
     UiJob *job = malloc(sizeof(UiJob));
     job->job_func = tf;
     job->job_data = td;
index fe49df16fb985c554375afb0d3fbc467c526a66b..da7ab6ec822308087fdfdec13db0e527766d15e5 100644 (file)
@@ -221,6 +221,11 @@ static void* ui_jobthread(void *data) {
 }
 
 void ui_call_mainthread(ui_threadfunc tf, void* td) {
+    if(uic_mainthread_calls_is_buffered()) {
+        uic_add_buffered_mainthread_call(tf, td);
+        return;
+    }
+    
     UiJob *job = malloc(sizeof(UiJob));
     memset(job, 0, sizeof(UiJob));
     job->job_func = tf;
index 606420e693432f6210068f3fdad744db5f591f9d..6c0152b94546d4f7f4615bb2d24eaed535df9e57 100644 (file)
@@ -556,6 +556,10 @@ UIEXPORT void ui_close(UiObject *obj);
 
 UIEXPORT void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd);
 UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td);
+
+UIEXPORT void ui_buffer_mainthread_calls(UiBool enable_buffering);
+UIEXPORT void ui_exec_buffered_mainthread_calls(void);
+
 UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads);
 UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool);
 UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd);