mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 08:25:32 +00:00
feat(core): refactor ldml test 🙀
- rearrange classes so we can get to dynamic subtests
This commit is contained in:
parent
8ea87aa828
commit
c40c19db3f
3 changed files with 145 additions and 54 deletions
|
|
@ -144,26 +144,16 @@ apply_action(
|
|||
}
|
||||
|
||||
int
|
||||
run_test(const km::kbp::path &source, const km::kbp::path &compiled) {
|
||||
std::string keys = "";
|
||||
std::u16string expected = u"", context = u"";
|
||||
bool expected_beep = false;
|
||||
bool expected_error = false;
|
||||
km::tests::LdmlTestSource test_source;
|
||||
run_test(const km::kbp::path &source, const km::kbp::path &compiled, km::tests::LdmlTestSource& test_source) {
|
||||
|
||||
int result = test_source.load_source(source, keys, expected, context, expected_beep, expected_error);
|
||||
if (result != 0) return result;
|
||||
|
||||
std::cout << "source file = " << source << std::endl
|
||||
<< "compiled file = " << compiled << std::endl;
|
||||
|
||||
km_kbp_keyboard * test_kb = nullptr;
|
||||
km_kbp_state * test_state = nullptr;
|
||||
|
||||
const km_kbp_status expect_load_status = expected_error ? KM_KBP_STATUS_INVALID_KEYBOARD : KM_KBP_STATUS_OK;
|
||||
const km_kbp_status expect_load_status = test_source.get_expected_load_status();
|
||||
assert_equal(km_kbp_keyboard_load(compiled.c_str(), &test_kb), expect_load_status);
|
||||
|
||||
if (expected_error) {
|
||||
if (expect_load_status != KM_KBP_STATUS_OK) {
|
||||
std::cout << "Keyboard was expected to be invalid, so exiting " << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -173,7 +163,7 @@ run_test(const km::kbp::path &source, const km::kbp::path &compiled) {
|
|||
|
||||
// Setup context
|
||||
km_kbp_context_item *citems = nullptr;
|
||||
try_status(km_kbp_context_items_from_utf16(context.c_str(), &citems));
|
||||
try_status(km_kbp_context_items_from_utf16(test_source.get_context().c_str(), &citems));
|
||||
try_status(km_kbp_context_set(km_kbp_state_context(test_state), citems));
|
||||
|
||||
// Make a copy of the setup context for the test
|
||||
|
|
@ -185,10 +175,10 @@ run_test(const km::kbp::path &source, const km::kbp::path &compiled) {
|
|||
km_kbp_context_items_dispose(citems);
|
||||
|
||||
// Setup baseline text store
|
||||
std::u16string text_store = context;
|
||||
std::u16string text_store = test_source.get_context();
|
||||
|
||||
// Run through key events, applying output for each event
|
||||
for (auto p = test_source.next_key(keys); p.vk != 0; p = test_source.next_key(keys)) {
|
||||
for (auto p = test_source.next_key(); p.vk != 0; p = test_source.next_key()) {
|
||||
// Because a normal system tracks caps lock state itself,
|
||||
// we mimic that in the tests. We assume caps lock state is
|
||||
// updated on key_down before the processor receives the
|
||||
|
|
@ -231,7 +221,7 @@ run_test(const km::kbp::path &source, const km::kbp::path &compiled) {
|
|||
}
|
||||
|
||||
// Test if the beep action was as expected
|
||||
if (g_beep_found != expected_beep)
|
||||
if (g_beep_found != test_source.get_expected_beep())
|
||||
return __LINE__;
|
||||
|
||||
// Compare final output - retrieve internal context
|
||||
|
|
@ -251,15 +241,15 @@ run_test(const km::kbp::path &source, const km::kbp::path &compiled) {
|
|||
|
||||
km_kbp_context_items_dispose(citems);
|
||||
|
||||
std::cout << "expected : " << string_to_hex(expected) << " [" << expected << "]" << std::endl;
|
||||
std::cout << "expected : " << string_to_hex(test_source.get_expected()) << " [" << test_source.get_expected() << "]" << std::endl;
|
||||
std::cout << "text store: " << string_to_hex(text_store) << " [" << text_store << "]" << std::endl;
|
||||
std::cout << "context : " << string_to_hex(buf) << " [" << buf << "]" << std::endl;
|
||||
|
||||
// Compare internal context with expected result
|
||||
if (buf != expected) return __LINE__;
|
||||
if (buf != test_source.get_expected()) return __LINE__;
|
||||
|
||||
// Compare text store with expected result
|
||||
if (text_store != expected) return __LINE__;
|
||||
if (text_store != test_source.get_expected()) return __LINE__;
|
||||
|
||||
// Destroy them
|
||||
km_kbp_state_dispose(test_state);
|
||||
|
|
@ -268,6 +258,31 @@ run_test(const km::kbp::path &source, const km::kbp::path &compiled) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all tests for this keyboard
|
||||
*/
|
||||
int run_all_tests(const km::kbp::path &source, const km::kbp::path &compiled) {
|
||||
std::cout << "source file = " << source << std::endl
|
||||
<< "compiled file = " << compiled << std::endl;
|
||||
|
||||
km::tests::LdmlEmbeddedTestSource embedded_test_source;
|
||||
|
||||
int embedded_result = embedded_test_source.load_source(source);
|
||||
if (embedded_result == 0) {
|
||||
// embedded loaded OK, try it
|
||||
std::cout << "TEST: " << source << " (embedded)" << std::endl;
|
||||
embedded_result = run_test(source, compiled, embedded_test_source);
|
||||
} else {
|
||||
// TODO-LDML: load JSON here
|
||||
// return embedded_result;
|
||||
}
|
||||
|
||||
// TODO-LDML: aggregate result
|
||||
return embedded_result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
constexpr const auto help_str =
|
||||
"\
|
||||
ldml [--color] <LDML_TEST_FILE> <KMX_FILE>\n\
|
||||
|
|
@ -299,7 +314,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
console_color::enabled = console_color::isaterminal() || arg_color;
|
||||
|
||||
int rc = run_test(argv[first_arg], argv[first_arg + 1]);
|
||||
int rc = run_all_tests(argv[first_arg], argv[first_arg + 1]);
|
||||
if (rc != 0) {
|
||||
std::cerr << "FAILED" << std::endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,19 @@ namespace tests {
|
|||
LdmlTestSource::LdmlTestSource() {
|
||||
}
|
||||
|
||||
|
||||
LdmlTestSource::~LdmlTestSource() {
|
||||
|
||||
}
|
||||
|
||||
km_kbp_status LdmlTestSource::get_expected_load_status() {
|
||||
return KM_KBP_STATUS_OK;
|
||||
}
|
||||
|
||||
bool LdmlTestSource::get_expected_beep() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// String trim functions from https://stackoverflow.com/a/217605/1836776
|
||||
// trim from start (in place)
|
||||
static inline void
|
||||
|
|
@ -44,8 +57,16 @@ trim(std::string &s) {
|
|||
rtrim(s);
|
||||
}
|
||||
|
||||
LdmlEmbeddedTestSource::LdmlEmbeddedTestSource() {
|
||||
|
||||
}
|
||||
|
||||
LdmlEmbeddedTestSource::~LdmlEmbeddedTestSource() {
|
||||
|
||||
}
|
||||
|
||||
std::u16string
|
||||
LdmlTestSource::parse_source_string(std::string const &s) {
|
||||
LdmlEmbeddedTestSource::parse_source_string(std::string const &s) {
|
||||
std::u16string t;
|
||||
for (auto p = s.begin(); p != s.end(); p++) {
|
||||
if (*p == '\\') {
|
||||
|
|
@ -80,7 +101,7 @@ LdmlTestSource::parse_source_string(std::string const &s) {
|
|||
}
|
||||
|
||||
bool
|
||||
LdmlTestSource::is_token(const std::string token, std::string &line) {
|
||||
LdmlEmbeddedTestSource::is_token(const std::string token, std::string &line) {
|
||||
if (line.compare(0, token.length(), token) == 0) {
|
||||
line = line.substr(token.length());
|
||||
trim(line);
|
||||
|
|
@ -90,13 +111,7 @@ LdmlTestSource::is_token(const std::string token, std::string &line) {
|
|||
}
|
||||
|
||||
int
|
||||
LdmlTestSource::load_source(
|
||||
const km::kbp::path &path,
|
||||
std::string &keys,
|
||||
std::u16string &expected,
|
||||
std::u16string &context,
|
||||
bool &expected_beep,
|
||||
bool &expected_error) {
|
||||
LdmlEmbeddedTestSource::load_source( const km::kbp::path &path ) {
|
||||
const std::string s_keys = "@@keys: ";
|
||||
const std::string s_expected = "@@expected: ";
|
||||
const std::string s_context = "@@context: ";
|
||||
|
|
@ -142,8 +157,41 @@ LdmlTestSource::load_source(
|
|||
return 0;
|
||||
}
|
||||
|
||||
km_kbp_status
|
||||
LdmlEmbeddedTestSource::get_expected_load_status() {
|
||||
return expected_error ? KM_KBP_STATUS_INVALID_KEYBOARD : KM_KBP_STATUS_OK;
|
||||
}
|
||||
|
||||
const std::u16string&
|
||||
LdmlEmbeddedTestSource::get_context() const {
|
||||
return context;
|
||||
}
|
||||
|
||||
bool LdmlEmbeddedTestSource::get_expected_beep() const {
|
||||
return expected_beep;
|
||||
}
|
||||
|
||||
const std::u16string& LdmlEmbeddedTestSource::get_expected() const {
|
||||
return expected;
|
||||
}
|
||||
|
||||
int
|
||||
LdmlEmbeddedTestSource::caps_lock_state() {
|
||||
return _caps_lock_on ? KM_KBP_MODIFIER_CAPS : 0;
|
||||
}
|
||||
|
||||
void
|
||||
LdmlEmbeddedTestSource::toggle_caps_lock_state() {
|
||||
_caps_lock_on = !_caps_lock_on;
|
||||
}
|
||||
|
||||
void
|
||||
LdmlEmbeddedTestSource::set_caps_lock_on(bool caps_lock_on) {
|
||||
_caps_lock_on = caps_lock_on;
|
||||
}
|
||||
|
||||
key_event
|
||||
LdmlTestSource::char_to_event(char ch) {
|
||||
LdmlEmbeddedTestSource::char_to_event(char ch) {
|
||||
assert(ch >= 32);
|
||||
return {
|
||||
km::kbp::kmx::s_char_to_vkey[(int)ch - 32].vk,
|
||||
|
|
@ -151,7 +199,7 @@ LdmlTestSource::char_to_event(char ch) {
|
|||
}
|
||||
|
||||
uint16_t
|
||||
LdmlTestSource::get_modifier(std::string const m) {
|
||||
LdmlEmbeddedTestSource::get_modifier(std::string const m) {
|
||||
for (int i = 0; km::kbp::kmx::s_modifier_names[i].name; i++) {
|
||||
if (m == km::kbp::kmx::s_modifier_names[i].name) {
|
||||
return km::kbp::kmx::s_modifier_names[i].modifier;
|
||||
|
|
@ -161,7 +209,7 @@ LdmlTestSource::get_modifier(std::string const m) {
|
|||
}
|
||||
|
||||
km_kbp_virtual_key
|
||||
LdmlTestSource::get_vk(std::string const &vk) {
|
||||
LdmlEmbeddedTestSource::get_vk(std::string const &vk) {
|
||||
for (int i = 1; i < 256; i++) {
|
||||
if (vk == km::kbp::kmx::s_key_names[i]) {
|
||||
return i;
|
||||
|
|
@ -171,7 +219,7 @@ LdmlTestSource::get_vk(std::string const &vk) {
|
|||
}
|
||||
|
||||
key_event
|
||||
LdmlTestSource::vkey_to_event(std::string const &vk_event) {
|
||||
LdmlEmbeddedTestSource::vkey_to_event(std::string const &vk_event) {
|
||||
// vkey format is MODIFIER MODIFIER K_NAME
|
||||
// std::cout << "VK=" << vk_event << std::endl;
|
||||
|
||||
|
|
@ -197,8 +245,15 @@ LdmlTestSource::vkey_to_event(std::string const &vk_event) {
|
|||
}
|
||||
|
||||
key_event
|
||||
LdmlTestSource::next_key(std::string &keys) {
|
||||
LdmlEmbeddedTestSource::next_key() {
|
||||
// mutate this->keys
|
||||
return next_key(keys);
|
||||
}
|
||||
|
||||
key_event
|
||||
LdmlEmbeddedTestSource::next_key(std::string &keys) {
|
||||
// Parse the next element of the string, chop it off, and return it
|
||||
// mutates keys
|
||||
if (keys.length() == 0)
|
||||
return {0, 0};
|
||||
char ch = keys[0];
|
||||
|
|
@ -218,5 +273,6 @@ LdmlTestSource::next_key(std::string &keys) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace tests
|
||||
} // namespace km
|
||||
|
|
|
|||
|
|
@ -11,33 +11,47 @@ struct key_event {
|
|||
uint16_t modifier_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* pure virtual representing a test source, or a specific subtest
|
||||
*/
|
||||
class LdmlTestSource {
|
||||
public:
|
||||
LdmlTestSource();
|
||||
virtual ~LdmlTestSource();
|
||||
virtual key_event next_key() = 0;
|
||||
virtual int caps_lock_state() = 0;
|
||||
virtual void toggle_caps_lock_state() = 0;
|
||||
virtual void set_caps_lock_on(bool caps_lock_on) = 0;
|
||||
virtual km_kbp_status get_expected_load_status();
|
||||
virtual const std::u16string &get_context() const = 0;
|
||||
virtual const std::u16string &get_expected() const = 0;
|
||||
virtual bool get_expected_beep() const;
|
||||
};
|
||||
|
||||
int load_source(
|
||||
const km::kbp::path &path,
|
||||
std::string &keys,
|
||||
std::u16string &expected,
|
||||
std::u16string &context,
|
||||
bool &expected_beep,
|
||||
bool &expected_error);
|
||||
class LdmlEmbeddedTestSource : public LdmlTestSource {
|
||||
public:
|
||||
LdmlEmbeddedTestSource();
|
||||
virtual ~LdmlEmbeddedTestSource();
|
||||
|
||||
key_event next_key(std::string &keys);
|
||||
/**
|
||||
* Load the test_source from comments in the .xml source
|
||||
*/
|
||||
int load_source(const km::kbp::path &path);
|
||||
|
||||
int
|
||||
caps_lock_state() {
|
||||
return _caps_lock_on ? KM_KBP_MODIFIER_CAPS : 0;
|
||||
}
|
||||
virtual key_event next_key();
|
||||
|
||||
void
|
||||
toggle_caps_lock_state() {
|
||||
_caps_lock_on = !_caps_lock_on;
|
||||
}
|
||||
virtual int
|
||||
caps_lock_state();
|
||||
|
||||
void set_caps_lock_on(bool caps_lock_on) {
|
||||
_caps_lock_on = caps_lock_on;
|
||||
}
|
||||
virtual void
|
||||
toggle_caps_lock_state();
|
||||
|
||||
virtual void set_caps_lock_on(bool caps_lock_on);
|
||||
|
||||
virtual km_kbp_status get_expected_load_status();
|
||||
virtual const std::u16string &get_context() const;
|
||||
virtual bool get_expected_beep() const;
|
||||
virtual const std::u16string &get_expected() const;
|
||||
|
||||
private:
|
||||
bool _caps_lock_on = false;
|
||||
|
|
@ -48,6 +62,12 @@ private:
|
|||
uint16_t get_modifier(std::string const m);
|
||||
km_kbp_virtual_key get_vk(std::string const &vk);
|
||||
key_event vkey_to_event(std::string const &vk_event);
|
||||
key_event next_key(std::string &keys);
|
||||
|
||||
std::string keys = "";
|
||||
std::u16string expected = u"", context = u"";
|
||||
bool expected_beep = false;
|
||||
bool expected_error = false;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue