feat(core): refactor ldml test 🙀

- rearrange classes so we can get to dynamic subtests
This commit is contained in:
Steven R. Loomis 2023-02-14 10:33:24 -06:00
parent 8ea87aa828
commit c40c19db3f
3 changed files with 145 additions and 54 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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