From c40c19db3fdfdaff016e75f35920f9a71f8bb08b Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 14 Feb 2023 10:33:24 -0600 Subject: [PATCH] =?UTF-8?q?feat(core):=20refactor=20ldml=20test=20?= =?UTF-8?q?=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rearrange classes so we can get to dynamic subtests --- core/tests/unit/ldml/ldml.cpp | 57 +++++++++------ core/tests/unit/ldml/ldml_test_source.cpp | 84 +++++++++++++++++++---- core/tests/unit/ldml/ldml_test_source.hpp | 58 +++++++++++----- 3 files changed, 145 insertions(+), 54 deletions(-) diff --git a/core/tests/unit/ldml/ldml.cpp b/core/tests/unit/ldml/ldml.cpp index 0b93f1a918..4f05b045dd 100644 --- a/core/tests/unit/ldml/ldml.cpp +++ b/core/tests/unit/ldml/ldml.cpp @@ -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] \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; } diff --git a/core/tests/unit/ldml/ldml_test_source.cpp b/core/tests/unit/ldml/ldml_test_source.cpp index 87baf17315..239862b053 100644 --- a/core/tests/unit/ldml/ldml_test_source.cpp +++ b/core/tests/unit/ldml/ldml_test_source.cpp @@ -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 diff --git a/core/tests/unit/ldml/ldml_test_source.hpp b/core/tests/unit/ldml/ldml_test_source.hpp index e23b8d801f..f87a276978 100644 --- a/core/tests/unit/ldml/ldml_test_source.hpp +++ b/core/tests/unit/ldml/ldml_test_source.hpp @@ -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