keycode_cache_tests.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* Copyright 2025 Garretonzo
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "gtest/gtest.h"
  17. extern "C" {
  18. #include "quantum/action_layer.h"
  19. #include "quantum/action.h"
  20. #include "quantum/dynamic_keymap.h"
  21. #include "quantum/quantum_keycodes.h"
  22. #include "quantum/keymap_common.h"
  23. #include "keycode_cache_mock.h"
  24. }
  25. // Mock variables for testing
  26. extern "C" {
  27. // These need to be defined for the tests to compile
  28. bool disable_action_cache = false;
  29. }
  30. class KeycodeCacheTest : public ::testing::Test {
  31. protected:
  32. void SetUp() override {
  33. // Reset any global state before each test
  34. disable_action_cache = false;
  35. // Initialize test key position
  36. test_key.row = 0;
  37. test_key.col = 0;
  38. // Initialize test keycodes
  39. initial_keycode = KC_A;
  40. changed_keycode = KC_B;
  41. // Set initial keymap
  42. dynamic_keymap_set_keycode(0, test_key.row, test_key.col, initial_keycode);
  43. }
  44. void TearDown() override {
  45. // Clean up after each test
  46. disable_action_cache = false;
  47. }
  48. keypos_t test_key;
  49. uint16_t initial_keycode;
  50. uint16_t changed_keycode;
  51. };
  52. #ifdef KEYCODE_CACHE_ENABLE
  53. TEST_F(KeycodeCacheTest, TestKeycodeMatchOnPressAndRelease) {
  54. // Test that store_or_get_action works with keycode cache enabled
  55. // The keycode when pressed should match the keycode when released
  56. // Press the key
  57. action_t press_action = store_or_get_action(true, test_key);
  58. // Release the key
  59. action_t release_action = store_or_get_action(false, test_key);
  60. // Both actions should be for the same keycode
  61. EXPECT_EQ(press_action.code, release_action.code);
  62. EXPECT_EQ(press_action.code, action_for_keycode(initial_keycode).code);
  63. }
  64. TEST_F(KeycodeCacheTest, TestCacheLimitExceeded) {
  65. // Test that when keycode cache limit is exceeded,
  66. // it falls back to default functionality
  67. // Fill the cache to the limit
  68. keypos_t keys[KEYCODE_CACHE_LIMIT + 1];
  69. for (int i = 0; i <= KEYCODE_CACHE_LIMIT; i++) {
  70. keys[i].row = i / MATRIX_COLS;
  71. keys[i].col = i % MATRIX_COLS;
  72. dynamic_keymap_set_keycode(0, keys[i].row, keys[i].col, KC_A + i);
  73. // Press each key
  74. store_or_get_action(true, keys[i]);
  75. }
  76. // The last key should not be cached (exceeds limit)
  77. // Change its keycode
  78. uint16_t new_keycode = KC_Z;
  79. dynamic_keymap_set_keycode(0, keys[KEYCODE_CACHE_LIMIT].row, keys[KEYCODE_CACHE_LIMIT].col, new_keycode);
  80. // Release the last key - should get the NEW keycode (not cached)
  81. action_t release_action = store_or_get_action(false, keys[KEYCODE_CACHE_LIMIT]);
  82. EXPECT_EQ(release_action.code, action_for_keycode(new_keycode).code);
  83. // Clean up - release all other keys
  84. for (int i = 0; i < KEYCODE_CACHE_LIMIT; i++) {
  85. store_or_get_action(false, keys[i]);
  86. }
  87. }
  88. TEST_F(KeycodeCacheTest, TestDynamicKeymapChangeWithCache) {
  89. // Test with keycode cache: a key is pressed, during the press
  90. // dynamic_keymap_set_keycode remaps the key to a different key,
  91. // then when released, the released key should match the initial key
  92. // Press the key (should cache initial_keycode)
  93. action_t press_action = store_or_get_action(true, test_key);
  94. EXPECT_EQ(press_action.code, action_for_keycode(initial_keycode).code);
  95. // While key is pressed, change the keymap
  96. dynamic_keymap_set_keycode(0, test_key.row, test_key.col, changed_keycode);
  97. // Release the key - should get the ORIGINAL cached keycode
  98. action_t release_action = store_or_get_action(false, test_key);
  99. EXPECT_EQ(release_action.code, action_for_keycode(initial_keycode).code);
  100. EXPECT_NE(release_action.code, action_for_keycode(changed_keycode).code);
  101. }
  102. #endif // KEYCODE_CACHE_ENABLE
  103. TEST_F(KeycodeCacheTest, TestDynamicKeymapChangeWithoutCache) {
  104. // Test without keycode cache: a key is pressed, during the press
  105. // dynamic_keymap_set_keycode remaps the key to a different key,
  106. // then when released, the released key should match the NEW key
  107. // Disable cache for this test
  108. disable_action_cache = true;
  109. // Press the key
  110. action_t press_action = store_or_get_action(true, test_key);
  111. EXPECT_EQ(press_action.code, action_for_keycode(initial_keycode).code);
  112. // While key is pressed, change the keymap
  113. dynamic_keymap_set_keycode(0, test_key.row, test_key.col, changed_keycode);
  114. // Release the key - should get the NEW keycode (no cache)
  115. action_t release_action = store_or_get_action(false, test_key);
  116. EXPECT_EQ(release_action.code, action_for_keycode(changed_keycode).code);
  117. EXPECT_NE(release_action.code, action_for_keycode(initial_keycode).code);
  118. }
  119. #ifdef KEYCODE_CACHE_ENABLE
  120. TEST_F(KeycodeCacheTest, TestCacheUpdateExistingKey) {
  121. // Test that pressing the same key twice updates the cache entry
  122. // rather than creating a duplicate
  123. // Press the key
  124. store_or_get_action(true, test_key);
  125. // Change the keymap
  126. dynamic_keymap_set_keycode(0, test_key.row, test_key.col, changed_keycode);
  127. // Press the same key again (should update existing cache entry)
  128. action_t second_press_action = store_or_get_action(true, test_key);
  129. EXPECT_EQ(second_press_action.code, action_for_keycode(changed_keycode).code);
  130. // Release should get the updated keycode
  131. action_t release_action = store_or_get_action(false, test_key);
  132. EXPECT_EQ(release_action.code, action_for_keycode(changed_keycode).code);
  133. }
  134. TEST_F(KeycodeCacheTest, TestCacheRemovalOnRelease) {
  135. // Test that releasing a key removes it from the cache
  136. // Press and release a key
  137. store_or_get_action(true, test_key);
  138. store_or_get_action(false, test_key);
  139. // Change the keymap
  140. dynamic_keymap_set_keycode(0, test_key.row, test_key.col, changed_keycode);
  141. // Press the key again - should use new keycode (not cached)
  142. action_t press_action = store_or_get_action(true, test_key);
  143. EXPECT_EQ(press_action.code, action_for_keycode(changed_keycode).code);
  144. // Clean up
  145. store_or_get_action(false, test_key);
  146. }
  147. TEST_F(KeycodeCacheTest, TestMultipleKeysInCache) {
  148. // Test that multiple keys can be cached simultaneously
  149. keypos_t key1 = {0, 0};
  150. keypos_t key2 = {0, 1};
  151. uint16_t keycode1 = KC_A;
  152. uint16_t keycode2 = KC_B;
  153. // Set up keymaps
  154. dynamic_keymap_set_keycode(0, key1.row, key1.col, keycode1);
  155. dynamic_keymap_set_keycode(0, key2.row, key2.col, keycode2);
  156. // Press both keys
  157. action_t press1 = store_or_get_action(true, key1);
  158. action_t press2 = store_or_get_action(true, key2);
  159. EXPECT_EQ(press1.code, action_for_keycode(keycode1).code);
  160. EXPECT_EQ(press2.code, action_for_keycode(keycode2).code);
  161. // Change both keymaps
  162. dynamic_keymap_set_keycode(0, key1.row, key1.col, KC_X);
  163. dynamic_keymap_set_keycode(0, key2.row, key2.col, KC_Y);
  164. // Release both keys - should get original keycodes
  165. action_t release1 = store_or_get_action(false, key1);
  166. action_t release2 = store_or_get_action(false, key2);
  167. EXPECT_EQ(release1.code, action_for_keycode(keycode1).code);
  168. EXPECT_EQ(release2.code, action_for_keycode(keycode2).code);
  169. }
  170. #endif // KEYCODE_CACHE_ENABLE