feat(core): infrastructure for normalization of output

Relates to #9999.

Establishes functions, unit test sources, normalization entry point and
an effectively no-op unit test for normalization support.
This commit is contained in:
Marc Durdin 2024-01-16 13:46:46 +07:00
parent ba1f5921cf
commit e39affe93b
9 changed files with 172 additions and 9 deletions

View file

@ -116,7 +116,7 @@ km_core_context_items_dispose(km_core_context_item *context_items);
*/
KMN_API
km_core_context *
km_core_state_context(km_core_state *state);
km_core_state_context(km_core_state const *state);
/**
* Get access to the state object's application context.
@ -127,7 +127,7 @@ km_core_state_context(km_core_state *state);
*/
KMN_API
km_core_context *
km_core_state_app_context(km_core_state *state);
km_core_state_app_context(km_core_state const *state);
/*
```

View file

@ -16,7 +16,7 @@
#include "state.hpp"
#include "option.hpp"
km_core_actions const * km::core::action_item_list_to_actions_object(
km_core_actions * km::core::action_item_list_to_actions_object(
km_core_action_item const *action_items
) {
assert(action_items != nullptr);

View file

@ -14,8 +14,14 @@
namespace km {
namespace core
{
km_core_actions const *action_item_list_to_actions_object(
km_core_actions *action_item_list_to_actions_object(
km_core_action_item const *action_items
);
bool actions_normalize(
km_core_context const *cached_context,
km_core_context const *app_context,
km_core_actions *actions
);
} // namespace core
} // namespace km

View file

@ -0,0 +1,34 @@
/*
Copyright: © 2024 SIL International.
Description: Implementation of the action output normalization.
Create Date: 16 Jan 2024
Authors: Marc Durdin (MCD)
History: 16 Jan 2024 - MCD - Initial implementation from #9999
*/
#include <cassert>
#include <algorithm>
#include <sstream>
#include <memory>
#include "action.hpp"
#include "state.hpp"
#include "option.hpp"
bool km::core::actions_normalize(
km_core_context const *cached_context,
km_core_context const *app_context,
km_core_actions *actions
) {
assert(actions != nullptr);
assert(cached_context != nullptr);
assert(app_context != nullptr);
if(actions == nullptr || cached_context == nullptr || app_context == nullptr) {
return false;
}
// Normalize output to NFC
//TODO
// actions->code_points_to_delete++;
return true;
}

View file

@ -33,7 +33,16 @@ km_core_actions const * km_core_state_get_actions(
return nullptr;
}
return action_item_list_to_actions_object(action_items);
km_core_actions * result = action_item_list_to_actions_object(action_items);
if(state->processor().supports_normalization()) {
// Normalize to NFC for those keyboard processors that support it
if(!actions_normalize(km_core_state_context(state), km_core_state_app_context(state), result)) {
km_core_actions_dispose(result);
return nullptr;
}
}
return result;
}
km_core_status km_core_actions_dispose(

View file

@ -65,20 +65,20 @@ void km_core_state_dispose(km_core_state *state)
}
km_core_context *km_core_state_context(km_core_state *state)
km_core_context *km_core_state_context(km_core_state const *state)
{
assert(state);
if (!state) return nullptr;
return static_cast<km_core_context *>(&state->context());
return static_cast<km_core_context *>(&(const_cast<km_core_state *>(state)->context()));
}
km_core_context *km_core_state_app_context(km_core_state *state)
km_core_context *km_core_state_app_context(km_core_state const *state)
{
assert(state);
if (!state) return nullptr;
return static_cast<km_core_context *>(&state->app_context());
return static_cast<km_core_context *>(&(const_cast<km_core_state *>(state)->app_context()));
}
km_core_status km_core_state_get_intermediate_context(

View file

@ -42,6 +42,7 @@ endif
kmx_files = files(
'actions_normalize.cpp',
'action.cpp',
'option.cpp',
'keyboard.cpp',

View file

@ -26,6 +26,7 @@ tests = [
['debug-api', 'debug_api.cpp'],
['kmx_xstring', 'test_kmx_xstring.cpp'],
['kmx_context', 'test_kmx_context.cpp'],
['test_actions_normalize', 'test_actions_normalize.cpp'],
]
test_path = join_paths(meson.current_build_dir(), '..', 'kmx')

View file

@ -0,0 +1,112 @@
/*
Copyright: © 2018 SIL International.
Description: Tests for the context API family of functions.
Create Date: 23 Oct 2023
Authors: Marc Durdin
History: 23 Oct 2023 - MCD - Initial implementation.
*/
#include <string>
#include "keyman_core.h"
#include "path.hpp"
#include "action.hpp"
#include <test_assert.h>
#include "../emscripten_filesystem.h"
km_core_option_item test_env_opts[] =
{
KM_CORE_OPTIONS_END
};
km_core_keyboard * test_kb = nullptr;
km_core_state * test_state = nullptr;
km_core_actions * test_actions = nullptr;
std::string arg_path;
void teardown() {
if(test_state) {
km_core_state_dispose(test_state);
test_state = nullptr;
}
if(test_kb) {
km_core_keyboard_dispose(test_kb);
test_kb = nullptr;
}
if(test_actions) {
delete [] test_actions->output;
delete test_actions;
test_actions = nullptr;
}
}
void setup(const km_core_cp *context, int actions_code_points_to_delete, const std::u32string actions_output) {
teardown();
km::core::path path = km::core::path::join(arg_path, "..", "ldml", "keyboards", "k_001_tiny.kmx");
try_status(km_core_keyboard_load(path.native().c_str(), &test_kb));
try_status(km_core_state_create(test_kb, test_env_opts, &test_state));
assert(km_core_state_context_set_if_needed(test_state, context) == KM_CORE_CONTEXT_STATUS_UPDATED);
test_actions = new km_core_actions;
test_actions->code_points_to_delete = actions_code_points_to_delete;
test_actions->output = new km_core_usv[actions_output.length() + 1];
actions_output.copy(test_actions->output, actions_output.length());
test_actions->output[actions_output.length()] = 0;
}
//-------------------------------------------------------------------------------------
void test_no_normalization() {
setup(u"abc", 0, U"def");
const int expected_delete = 0;
const std::u32string expected_output = U"def";
assert(km::core::actions_normalize(km_core_state_context(test_state), km_core_state_app_context(test_state), test_actions));
assert(expected_delete == test_actions->code_points_to_delete);
assert(expected_output == test_actions->output);
teardown();
}
//-------------------------------------------------------------------------------------
// Launcher
//-------------------------------------------------------------------------------------
constexpr const auto help_str = "\
test_actions_normalize [--color] <BUILD_PATH>\n\
\n\
--color Force color output\n\
BUILD_PATH Path where test_actions_normalize.exe is found; kmx files are\n\
located relative to this path.\n";
int error_args() {
std::cerr << "test_actions_normalize: Invalid arguments." << std::endl;
std::cout << help_str;
return 1;
}
int main(int argc, char *argv []) {
if(argc < 2) {
return error_args();
}
auto arg_color = std::string(argv[1]) == "--color";
if(arg_color && argc < 3) {
return error_args();
}
console_color::enabled = console_color::isaterminal() || arg_color;
#ifdef __EMSCRIPTEN__
arg_path = get_wasm_file_path(argv[arg_color ? 2 : 1]);
#else
arg_path = argv[arg_color ? 2 : 1];
#endif
// actions
test_no_normalization();
}