#include #include #include "key_mapper.h" using namespace roro; void setUp() {} void tearDown() {} static RawKeys chars(std::vector c) { RawKeys r; r.chars = c; return r; } static RawKeys withFn(std::vector c) { RawKeys r = chars(c); r.fn = true; return r; } static RawKeys optOnly() { RawKeys r; r.opt = true; return r; } static std::vector press(KeyMapper& m, const RawKeys& r) { return m.update(r); } static void release(KeyMapper& m) { m.update(RawKeys{}); } void test_plain_character() { KeyMapper m; auto ev = press(m, chars({'a'})); TEST_ASSERT_EQUAL(1, ev.size()); TEST_ASSERT_EQUAL(static_cast(Key::Char), static_cast(ev[0].key)); TEST_ASSERT_EQUAL('a', ev[0].ch); } void test_held_key_is_not_repeated_on_later_changes() { KeyMapper m; press(m, chars({'a'})); auto ev = press(m, chars({'a', 'b'})); // rolling: b pressed while a still held TEST_ASSERT_EQUAL(1, ev.size()); TEST_ASSERT_EQUAL('b', ev[0].ch); } void test_same_key_again_after_release() { KeyMapper m; press(m, chars({'a'})); release(m); TEST_ASSERT_EQUAL(1, press(m, chars({'a'})).size()); } void test_fn_combos_are_arrows() { KeyMapper m; TEST_ASSERT_EQUAL(static_cast(Key::Up), static_cast(press(m, withFn({';'}))[0].key)); release(m); TEST_ASSERT_EQUAL(static_cast(Key::Down), static_cast(press(m, withFn({'.'}))[0].key)); release(m); TEST_ASSERT_EQUAL(static_cast(Key::Left), static_cast(press(m, withFn({','}))[0].key)); release(m); TEST_ASSERT_EQUAL(static_cast(Key::Right), static_cast(press(m, withFn({'/'}))[0].key)); } void test_backtick_is_back_and_fn_backtick_is_home() { KeyMapper m; TEST_ASSERT_EQUAL(static_cast(Key::Back), static_cast(press(m, chars({'`'}))[0].key)); release(m); TEST_ASSERT_EQUAL(static_cast(Key::Home), static_cast(press(m, withFn({'`'}))[0].key)); } void test_enter_delete_tab() { KeyMapper m; RawKeys r; r.enter = true; TEST_ASSERT_EQUAL(static_cast(Key::Select), static_cast(press(m, r)[0].key)); release(m); r = RawKeys{}; r.del = true; TEST_ASSERT_EQUAL(static_cast(Key::Delete), static_cast(press(m, r)[0].key)); release(m); r = RawKeys{}; r.tab = true; TEST_ASSERT_EQUAL(static_cast(Key::Tab), static_cast(press(m, r)[0].key)); } void test_ctrl_and_alt_flags_are_carried() { KeyMapper m; RawKeys r = chars({'c'}); r.ctrl = true; auto ev = press(m, r); TEST_ASSERT_TRUE(ev[0].ctrl); TEST_ASSERT_EQUAL('c', ev[0].ch); } void test_compose_acute() { KeyMapper m; TEST_ASSERT_EQUAL(0, press(m, optOnly()).size()); release(m); TEST_ASSERT_EQUAL(0, press(m, chars({'\''})).size()); release(m); auto ev = press(m, chars({'e'})); TEST_ASSERT_EQUAL(1, ev.size()); TEST_ASSERT_EQUAL(0xE9, ev[0].ch); // é } void test_compose_while_holding_opt() { KeyMapper m; RawKeys r = chars({'`'}); r.opt = true; TEST_ASSERT_EQUAL(0, press(m, r).size()); // grave accent, not Back release(m); auto ev = press(m, chars({'a'})); TEST_ASSERT_EQUAL(0xE0, ev[0].ch); // à } void test_compose_table() { struct Case { char accent, base; uint32_t expected; } cases[] = {{'^', 'e', 0xEA}, {'"', 'e', 0xEB}, {',', 'c', 0xE7}, {',', 'C', 0xC7}, {'~', 'n', 0xF1}, {'\'', 'E', 0xC9}, {'`', 'u', 0xF9}, {'"', 'i', 0xEF}}; for (auto& c : cases) { KeyMapper m; press(m, optOnly()); release(m); press(m, chars({c.accent})); release(m); auto ev = press(m, chars({c.base})); TEST_ASSERT_EQUAL_HEX32(c.expected, ev[0].ch); } } void test_unknown_combination_types_both_characters() { KeyMapper m; press(m, optOnly()); release(m); press(m, chars({'\''})); release(m); auto ev = press(m, chars({'z'})); TEST_ASSERT_EQUAL(2, ev.size()); TEST_ASSERT_EQUAL('\'', ev[0].ch); TEST_ASSERT_EQUAL('z', ev[1].ch); } void test_opt_followed_by_a_non_accent_types_it_normally() { KeyMapper m; press(m, optOnly()); release(m); auto ev = press(m, chars({'x'})); TEST_ASSERT_EQUAL(1, ev.size()); TEST_ASSERT_EQUAL('x', ev[0].ch); } void test_pressing_opt_twice_cancels() { KeyMapper m; press(m, optOnly()); release(m); press(m, optOnly()); release(m); auto ev = press(m, chars({'`'})); TEST_ASSERT_EQUAL(static_cast(Key::Back), static_cast(ev[0].key)); } void test_compose_state_is_visible_for_the_ui() { KeyMapper m; TEST_ASSERT_EQUAL(0, m.pendingCompose()); press(m, optOnly()); TEST_ASSERT_EQUAL('*', m.pendingCompose()); // armed, no accent yet release(m); press(m, chars({'^'})); TEST_ASSERT_EQUAL('^', m.pendingCompose()); } int main() { UNITY_BEGIN(); RUN_TEST(test_plain_character); RUN_TEST(test_held_key_is_not_repeated_on_later_changes); RUN_TEST(test_same_key_again_after_release); RUN_TEST(test_fn_combos_are_arrows); RUN_TEST(test_backtick_is_back_and_fn_backtick_is_home); RUN_TEST(test_enter_delete_tab); RUN_TEST(test_ctrl_and_alt_flags_are_carried); RUN_TEST(test_compose_acute); RUN_TEST(test_compose_while_holding_opt); RUN_TEST(test_compose_table); RUN_TEST(test_unknown_combination_types_both_characters); RUN_TEST(test_opt_followed_by_a_non_accent_types_it_normally); RUN_TEST(test_pressing_opt_twice_cancels); RUN_TEST(test_compose_state_is_visible_for_the_ui); return UNITY_END(); }