From 5be5eb4689aff1a9a723c2be967dad8a18b6ac15 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:06:28 +1000 Subject: [PATCH 1/5] fix(core): unit test action_que insert terminated Adds the KM_CORE_IT_END terminator to action_clone test before calling km_core_state_queue_action_items Fixes:#16341 --- core/tests/unit/kmnkbd/state_api.tests.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/tests/unit/kmnkbd/state_api.tests.cpp b/core/tests/unit/kmnkbd/state_api.tests.cpp index d500a1bd06..9bef122534 100644 --- a/core/tests/unit/kmnkbd/state_api.tests.cpp +++ b/core/tests/unit/kmnkbd/state_api.tests.cpp @@ -423,7 +423,13 @@ action_clone.option = &clone_persist_opt; if (test_clone_2->actions().back().type == KM_CORE_IT_END) { test_clone_2->actions().pop_back(); } -km_core_state_queue_action_items(test_clone_2, &action_clone); + +km_core_action_item action_clone_queue[] = { + action_clone, + {KM_CORE_IT_END} +}; + +km_core_state_queue_action_items(test_clone_2, action_clone_queue); test_clone_2->actions().commit(); // Test debug dump From 16e6a5634c9b17e570a448e491a8f6333ad61cd4 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:23:56 +1000 Subject: [PATCH 2/5] fix(core): make coherence check a debug assert This also adds a null pointer check to KM_CORE_IT_PERSIST_OPT case in km::core::action_item_list_to_actions_object Fixes: #16340 --- core/src/action.cpp | 4 ++++ core/src/state.cpp | 9 +++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/src/action.cpp b/core/src/action.cpp index ca6b0b30d8..eb2c4cc66c 100644 --- a/core/src/action.cpp +++ b/core/src/action.cpp @@ -103,6 +103,10 @@ bool km::core::action_item_list_to_actions_object( break; case KM_CORE_IT_PERSIST_OPT: { + assert(action_items->option != nullptr); + if(action_items->option != nullptr) { + return false; + } // TODO: lowpri: replace existing item if already present in options vector? km::core::option opt(static_cast(action_items->option->scope), action_items->option->key, diff --git a/core/src/state.cpp b/core/src/state.cpp index 3bf9efb358..d06f0f6e60 100644 --- a/core/src/state.cpp +++ b/core/src/state.cpp @@ -44,15 +44,12 @@ actions::actions(actions const &other) size_t opt_index = 0; for (auto &item : *this) { if (item.type == KM_CORE_IT_PERSIST_OPT) { - if (opt_index < _option_items_stack.size()) { - item.option = &_option_items_stack[opt_index++]; - } else { - // no matching item in the stack; clear pointer. - item.option = nullptr; - } + assert(opt_index < _option_items_stack.size()); + item.option = &_option_items_stack[opt_index++]; } } } +} state::state(km::core::abstract_processor & ap, km_core_option_item const *env) : _processor(ap) From f8be03cf8bdd7cb18ac333b618d3a5fbb4825238 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:59:10 +1000 Subject: [PATCH 3/5] fix(core): fix typo plus temp remove null check --- core/src/action.cpp | 8 ++++---- core/src/state.cpp | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/action.cpp b/core/src/action.cpp index eb2c4cc66c..2fe7694ccc 100644 --- a/core/src/action.cpp +++ b/core/src/action.cpp @@ -103,10 +103,10 @@ bool km::core::action_item_list_to_actions_object( break; case KM_CORE_IT_PERSIST_OPT: { - assert(action_items->option != nullptr); - if(action_items->option != nullptr) { - return false; - } + // assert(action_items->option != nullptr); + // if(action_items->option != nullptr) { + // return false; + // } // TODO: lowpri: replace existing item if already present in options vector? km::core::option opt(static_cast(action_items->option->scope), action_items->option->key, diff --git a/core/src/state.cpp b/core/src/state.cpp index d06f0f6e60..fcc6578914 100644 --- a/core/src/state.cpp +++ b/core/src/state.cpp @@ -49,7 +49,6 @@ actions::actions(actions const &other) } } } -} state::state(km::core::abstract_processor & ap, km_core_option_item const *env) : _processor(ap) From 8b0f6d3297fafd4269bd60eba4e89b34ab1b7f12 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:29:18 +1000 Subject: [PATCH 4/5] fix(core): add null check --- core/src/action.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/action.cpp b/core/src/action.cpp index 2fe7694ccc..f76634ea0c 100644 --- a/core/src/action.cpp +++ b/core/src/action.cpp @@ -103,10 +103,10 @@ bool km::core::action_item_list_to_actions_object( break; case KM_CORE_IT_PERSIST_OPT: { - // assert(action_items->option != nullptr); - // if(action_items->option != nullptr) { - // return false; - // } + assert(action_items->option != nullptr); + if(action_items->option == nullptr) { + return false; + } // TODO: lowpri: replace existing item if already present in options vector? km::core::option opt(static_cast(action_items->option->scope), action_items->option->key, From 4522e087a3f912b23d62bee192585e7a676757dc Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:41:15 +1000 Subject: [PATCH 5/5] fix(core): fix indenting in state_api_tests --- core/tests/unit/kmnkbd/state_api.tests.cpp | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/core/tests/unit/kmnkbd/state_api.tests.cpp b/core/tests/unit/kmnkbd/state_api.tests.cpp index 9bef122534..0ecc1787cf 100644 --- a/core/tests/unit/kmnkbd/state_api.tests.cpp +++ b/core/tests/unit/kmnkbd/state_api.tests.cpp @@ -413,42 +413,42 @@ int main(int argc, char * argv[]) clone_state_deleted_text )); -// Add two actions before cloning the state again -try_status(km_core_process_event(test_state, KM_CORE_VKEY_F3, 0, 1, KM_CORE_EVENT_FLAG_DEFAULT)); -try_status(km_core_state_clone(test_state, &test_clone_2)); + // Add two actions before cloning the state again + try_status(km_core_process_event(test_state, KM_CORE_VKEY_F3, 0, 1, KM_CORE_EVENT_FLAG_DEFAULT)); + try_status(km_core_state_clone(test_state, &test_clone_2)); -// Now put an option in the test_clone_2 state only -km_core_action_item action_clone = {KM_CORE_IT_PERSIST_OPT, {0,}, }; -action_clone.option = &clone_persist_opt; -if (test_clone_2->actions().back().type == KM_CORE_IT_END) { - test_clone_2->actions().pop_back(); -} + // Now put an option in the test_clone_2 state only + km_core_action_item action_clone = {KM_CORE_IT_PERSIST_OPT, {0,}, }; + action_clone.option = &clone_persist_opt; + if (test_clone_2->actions().back().type == KM_CORE_IT_END) { + test_clone_2->actions().pop_back(); + } -km_core_action_item action_clone_queue[] = { - action_clone, - {KM_CORE_IT_END} -}; + km_core_action_item action_clone_queue[] = { + action_clone, + {KM_CORE_IT_END} + }; -km_core_state_queue_action_items(test_clone_2, action_clone_queue); -test_clone_2->actions().commit(); + km_core_state_queue_action_items(test_clone_2, action_clone_queue); + test_clone_2->actions().commit(); - // Test debug dump -auto doc3 = get_json_doc(*test_state), doc4 = get_json_doc(*test_clone_2); -std::cout << "doc3:" << std::endl; -std::cout << doc3 << std::endl; -std::cout << "doc4:" << std::endl; -std::cout << doc4 << std::endl; -if (doc3 == doc4) return __LINE__; + // Test debug dump + auto doc3 = get_json_doc(*test_state), doc4 = get_json_doc(*test_clone_2); + std::cout << "doc3:" << std::endl; + std::cout << doc3 << std::endl; + std::cout << "doc4:" << std::endl; + std::cout << doc4 << std::endl; + if (doc3 == doc4) return __LINE__; -km_core_action_item action_tp3 = {KM_CORE_IT_PERSIST_OPT, {0,}, }; -action_tp3.option = &test_point_3_opt; + km_core_action_item action_tp3 = {KM_CORE_IT_PERSIST_OPT, {0,}, }; + action_tp3.option = &test_point_3_opt; -km_core_action_item action_tp4 = {KM_CORE_IT_PERSIST_OPT, {0,}, }; -action_tp4.option = &test_point_4_opt; + km_core_action_item action_tp4 = {KM_CORE_IT_PERSIST_OPT, {0,}, }; + action_tp4.option = &test_point_4_opt; -test_assert(action_items(test_state, {action_tp3, action_tp4, {KM_CORE_IT_END}})); -// Check that test_clone_2 has the same persisted options plus the extra queued option. -test_assert(action_items(test_clone_2, {action_tp3, action_tp4, action_clone, {KM_CORE_IT_END}})); + test_assert(action_items(test_state, {action_tp3, action_tp4, {KM_CORE_IT_END}})); + // Check that test_clone_2 has the same persisted options plus the extra queued option. + test_assert(action_items(test_clone_2, {action_tp3, action_tp4, action_clone, {KM_CORE_IT_END}})); // Destroy them km_core_state_dispose(test_state);