spiegel-keyman/core/tests/unit/kmnkbd/debug_items.hpp

191 lines
6.3 KiB
C++

#include <iostream>
#include <keyman/keyboardprocessor.h>
#include <keyman/keyboardprocessor_debug.h>
#include "kmx/kmx_base.h"
#include "kmx/kmx_xstring.h"
#include "../test_assert.h"
using namespace km::kbp::kmx;
namespace {
// TODO: consider using same const approach in kmx_base.h
// but this ripples through a whole lot of code
typedef struct tagDEBUG_GROUP
{
KMX_WCHAR const * dpName;
KEY const * dpKeyArray; // [LPKEY] address of first item in key array
KMX_WCHAR const * dpMatch;
KMX_WCHAR const * dpNoMatch;
KMX_DWORD cxKeyArray; // in array entries
KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
} DEBUG_GROUP, *LPDEBUG_GROUP;
typedef struct tagDEBUG_KEY
{
KMX_WCHAR Key;
KMX_DWORD Line;
KMX_DWORD ShiftFlags;
KMX_WCHAR const * dpOutput;
KMX_WCHAR const * dpContext;
} DEBUG_KEY, *LPDEBUG_KEY;
typedef struct tagDEBUG_STORE
{
KMX_DWORD dwSystemID;
KMX_WCHAR const * dpName;
KMX_WCHAR const * dpValue;
} DEBUG_STORE, *LPDEBUG_STORE;
const char *debug_item_types[] = {
"KM_KBP_DEBUG_BEGIN", // = 0,
"//KM_KBP_DEBUG_BEGIN_ANSI", // = 1, // not supported; instead rewrite ansi keyboards to Unicode with mcompile
"KM_KBP_DEBUG_GROUP_ENTER", // = 2,
"KM_KBP_DEBUG_GROUP_EXIT", // = 3,
"KM_KBP_DEBUG_RULE_ENTER", // = 4,
"KM_KBP_DEBUG_RULE_EXIT", // = 5,
"KM_KBP_DEBUG_MATCH_ENTER", // = 6,
"KM_KBP_DEBUG_MATCH_EXIT", // = 7,
"KM_KBP_DEBUG_NOMATCH_ENTER", // = 8,
"KM_KBP_DEBUG_NOMATCH_EXIT", // = 9,
"KM_KBP_DEBUG_END", // = 10,
"KM_KBP_DEBUG_SET_OPTION", // = 11
};
void print_debug_item(const char *title, km_kbp_state_debug_item const & item) {
LPGROUP gp = static_cast<LPGROUP>(item.kmx_info.group);
LPKEY rule = static_cast<LPKEY>(item.kmx_info.rule);
LPSTORE store = static_cast<LPSTORE>(item.kmx_info.option.store);
std::cout
<< "debug_item " << title << std::endl
<< " type: " << debug_item_types[item.type] << std::endl
<< " flags: " << item.flags << std::endl
<< " key_info: (vk: " << item.key_info.vk
<< " mod: " << item.key_info.modifier_state
<< " char: " << item.key_info.character << ")" << std::endl;
std::cout
<< " kmx_info: "<< std::endl
<< " context: '" << item.kmx_info.context << "'" << std::endl
<< " action: " << item.kmx_info.first_action << std::endl;
if(gp) std::cout
<< " group: " << gp->dpName << std::endl;
if(rule) std::cout
<< " rule: " << std::endl
<< " key: " << rule->Key << std::endl
<< " shift: " << rule->ShiftFlags << std::endl
<< " line: " << rule->Line << std::endl;
std::cout
<< " offsets: ";
std::copy(
std::begin(item.kmx_info.store_offsets),
std::end(item.kmx_info.store_offsets),
std::ostream_iterator<uint16_t>(std::cout, " ")
);
std::cout << std::endl;
if(store) std::cout
<< " option.store: " << std::endl
<< " name: " << store->dpName << std::endl
<< " value: " << store->dpString << std::endl;
if(store) std::cout
<< " option.value: " << item.kmx_info.option.value << std::endl;
}
bool are_store_offsets_equal(const uint16_t (&lhs)[DEBUG_STORE_OFFSETS_SIZE], const uint16_t (&rhs)[DEBUG_STORE_OFFSETS_SIZE]) {
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
// !memcmp(lhs, rhs, sizeof(lhs));
}
bool operator==(
km_kbp_state_debug_item const & lhs,
km_kbp_state_debug_item const & rhs
) {
auto result = (lhs.type == rhs.type && lhs.flags == rhs.flags && lhs.kmx_info.first_action == rhs.kmx_info.first_action);
if(result) {
LPGROUP lgp = static_cast<LPGROUP>(lhs.kmx_info.group), rgp = static_cast<LPGROUP>(rhs.kmx_info.group);
LPKEY lrule = static_cast<LPKEY>(lhs.kmx_info.rule), rrule = static_cast<LPKEY>(rhs.kmx_info.rule);
LPSTORE loption_store = static_cast<LPSTORE>(lhs.kmx_info.option.store), roption_store = static_cast<LPSTORE>(rhs.kmx_info.option.store);
switch(lhs.type) {
case KM_KBP_DEBUG_BEGIN:
result = lhs.key_info.character == rhs.key_info.character &&
lhs.key_info.modifier_state == rhs.key_info.modifier_state &&
lhs.key_info.vk == rhs.key_info.vk;
break;
case KM_KBP_DEBUG_END:
break;
case KM_KBP_DEBUG_GROUP_ENTER:
case KM_KBP_DEBUG_GROUP_EXIT:
case KM_KBP_DEBUG_MATCH_ENTER:
case KM_KBP_DEBUG_MATCH_EXIT:
case KM_KBP_DEBUG_NOMATCH_ENTER:
case KM_KBP_DEBUG_NOMATCH_EXIT:
assert(lgp != nullptr);
assert(rgp != nullptr);
assert(lgp->dpName != nullptr);
assert(rgp->dpName != nullptr);
result = u16cmp(lgp->dpName, rgp->dpName) == 0;
break;
case KM_KBP_DEBUG_RULE_ENTER:
case KM_KBP_DEBUG_RULE_EXIT:
assert(lgp != nullptr);
assert(rgp != nullptr);
assert(lgp->dpName != nullptr);
assert(rgp->dpName != nullptr);
assert(lrule != nullptr);
assert(rrule != nullptr);
result = u16cmp(lgp->dpName, rgp->dpName) == 0 &&
lrule->Line == rrule->Line &&
lrule->Key == rrule->Key &&
lrule->ShiftFlags == rrule->ShiftFlags &&
u16cmp(lhs.kmx_info.context, rhs.kmx_info.context) == 0 &&
are_store_offsets_equal(lhs.kmx_info.store_offsets, rhs.kmx_info.store_offsets);
break;
case KM_KBP_DEBUG_SET_OPTION:
assert(loption_store != nullptr && roption_store != nullptr);
result =
u16cmp(loption_store->dpName, roption_store->dpName) == 0 &&
u16cmp(lhs.kmx_info.option.value, rhs.kmx_info.option.value) == 0;
break;
default:
assert(false);
result = false;
}
}
if(!result) {
print_debug_item("actual", lhs);
print_debug_item("expected", rhs);
}
return result;
}
bool debug_items(
km_kbp_state const * state,
std::initializer_list<km_kbp_state_debug_item> const & expected
) {
size_t n = 0;
auto act = km_kbp_state_debug_items(state, &n);
for (auto &rhs: expected) {
if ((int)--n < 0) {
std::cout << "expected longer than actual" << std::endl;
print_debug_item("next expected item:", rhs);
return false;
}
if (!(*act++ == rhs)) return false;
}
if(n != 0) {
std::cout << "actual longer than expected" << std::endl;
print_debug_item("next actual item:", *act);
return false;
}
return true;
}
};