From a24bdccee0580d1263733bc7e66e4e4f97713f19 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Tue, 23 Nov 2021 03:31:01 +0100 Subject: [Tests] Increase QMK test coverage take 2 (#15269) * Add per-test keymaps * Add better trace and info logs for failed unit-tests * Add layer state assertion with tracing message * Use individual test binaries configuration options * Add basic qmk functionality tests * Add tap hold configurations tests * Add auto shift tests Co-authored-by: Nick Brassel --- tests/basic/test_action_layer.cpp | 427 +++++++++++++++++++++++++++++++++----- 1 file changed, 374 insertions(+), 53 deletions(-) (limited to 'tests/basic/test_action_layer.cpp') diff --git a/tests/basic/test_action_layer.cpp b/tests/basic/test_action_layer.cpp index d00a0859b9..1b12d13642 100644 --- a/tests/basic/test_action_layer.cpp +++ b/tests/basic/test_action_layer.cpp @@ -14,39 +14,54 @@ * along with this program. If not, see . */ +#include "gtest/gtest.h" +#include "keyboard_report_util.hpp" #include "test_common.hpp" using testing::_; -using testing::Return; +using testing::InSequence; class ActionLayer : public TestFixture {}; -// TEST_F(ActionLayer, LayerStateDBG) { -// layer_state_set(0); -// } - -// TEST_F(ActionLayer, LayerStateSet) { -// layer_state_set(0); -// EXPECT_EQ(layer_state, 0); -// layer_state_set(0b001100); -// EXPECT_EQ(layer_state, 0b001100); -// } - -// TEST_F(ActionLayer, LayerStateIs) { -// layer_state_set(0); -// EXPECT_EQ(layer_state_is(0), true); -// EXPECT_EQ(layer_state_is(1), true); -// layer_state_set(1); -// EXPECT_EQ(layer_state_is(0), true); -// EXPECT_EQ(layer_state_is(1), true); -// layer_state_set(2); -// EXPECT_EQ(layer_state_is(0), false); -// EXPECT_EQ(layer_state_is(1), false); -// EXPECT_EQ(layer_state_is(2), true); -// } +TEST_F(ActionLayer, LayerStateDBG) { + TestDriver driver; + + layer_state_set(0); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerStateSet) { + TestDriver driver; + + layer_state_set(0); + EXPECT_EQ(layer_state, 0); + layer_state_set(0b001100); + EXPECT_EQ(layer_state, 0b001100); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerStateIs) { + TestDriver driver; + + layer_state_set(0); + EXPECT_EQ(layer_state_is(0), true); + EXPECT_EQ(layer_state_is(1), false); + layer_state_set(1); + EXPECT_EQ(layer_state_is(0), true); + EXPECT_EQ(layer_state_is(1), false); + layer_state_set(2); + EXPECT_EQ(layer_state_is(0), false); + EXPECT_EQ(layer_state_is(1), true); + EXPECT_EQ(layer_state_is(2), false); + + testing::Mock::VerifyAndClearExpectations(&driver); +} TEST_F(ActionLayer, LayerStateCmp) { - uint32_t prev_layer; + TestDriver driver; + uint32_t prev_layer; prev_layer = 0; EXPECT_EQ(layer_state_cmp(prev_layer, 0), true); @@ -60,33 +75,339 @@ TEST_F(ActionLayer, LayerStateCmp) { EXPECT_EQ(layer_state_cmp(prev_layer, 0), false); EXPECT_EQ(layer_state_cmp(prev_layer, 1), true); EXPECT_EQ(layer_state_cmp(prev_layer, 2), false); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerClear) { + TestDriver driver; + + layer_clear(); + EXPECT_EQ(layer_state, 0); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerMove) { + TestDriver driver; + + layer_move(0); + EXPECT_EQ(layer_state, 1); + layer_move(3); + EXPECT_EQ(layer_state, 0b1000); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerOn) { + TestDriver driver; + + layer_clear(); + layer_on(1); + layer_on(3); + layer_on(3); + EXPECT_EQ(layer_state, 0b1010); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerOff) { + TestDriver driver; + + layer_clear(); + layer_on(1); + layer_on(3); + layer_off(3); + layer_off(2); + EXPECT_EQ(layer_state, 0b0010); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, MomentaryLayerDoesNothing) { + TestDriver driver; + KeymapKey layer_key = KeymapKey{0, 0, 0, MO(1)}; + + set_keymap({layer_key}); + + /* Press and release MO, nothing should happen. */ + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_key.press(); + run_one_scan_loop(); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_key.release(); + run_one_scan_loop(); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, MomentaryLayerWithKeypress) { + TestDriver driver; + KeymapKey layer_key = KeymapKey{0, 0, 0, MO(1)}; + + /* These keys must have the same position in the matrix, only the layer is different. */ + KeymapKey regular_key = KeymapKey{0, 1, 0, KC_A}; + set_keymap({layer_key, regular_key, KeymapKey{1, 1, 0, KC_B}}); + + /* Press MO. */ + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Press key on layer 1 */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B))).Times(1); + regular_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Release key on layer 1 */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + regular_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Release MO */ + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, ToggleLayerDoesNothing) { + GTEST_SKIP() << "TODO: Toggle layer does not activate the expected layer on key press but on release."; + + TestDriver driver; + KeymapKey layer_key = KeymapKey{0, 0, 0, TG(1)}; + + set_keymap({layer_key}); + + /* Press TG. Layer state should not change as it's applied on release. */ + EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0); + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Release TG. */ + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, ToggleLayerUpAndDown) { + GTEST_SKIP() << "TODO: Toggle layer does not activate the expected layer on key press but on release."; + + TestDriver driver; + KeymapKey toggle_layer_1_on_layer_0 = KeymapKey{0, 0, 0, TG(1)}; + KeymapKey toggle_layer_0_on_layer_1 = KeymapKey{1, 1, 0, TG(0)}; + + set_keymap({toggle_layer_1_on_layer_0, toggle_layer_0_on_layer_1}); + + /* Toggle Layer 1. */ + EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0); + toggle_layer_1_on_layer_0.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + toggle_layer_1_on_layer_0.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Toggle Layer 0. */ + EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0); + toggle_layer_0_on_layer_1.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + toggle_layer_0_on_layer_1.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerTapToggleDoesNothing) { + GTEST_SKIP() << "TODO: Tap toggle layer does not activate the expected layer on key press."; + + TestDriver driver; + KeymapKey layer_key = KeymapKey{0, 0, 0, TT(1)}; + + set_keymap({layer_key}); + + /* Press and release TT. */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(2); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerTapToggleWithKeypress) { + GTEST_SKIP() << "TODO: Tap toggle layer does not activate the expected layer on key press."; + + TestDriver driver; + KeymapKey layer_key = KeymapKey{0, 0, 0, TT(1)}; + + /* These keys must have the same position in the matrix, only the layer is different. */ + KeymapKey regular_key = KeymapKey{0, 1, 0, KC_A}; + set_keymap({layer_key, regular_key, KeymapKey{1, 1, 0, KC_B}}); + + /* Press TT. */ + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B))).Times(1); + regular_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + regular_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(ActionLayer, LayerTapToggleWithToggleWithKeypress) { + GTEST_SKIP() << "TODO: Tap toggle layer does not activate the expected layer on key press."; + + TestDriver driver; + KeymapKey layer_key = KeymapKey{0, 0, 0, TT(1)}; + + /* These keys must have the same position in the matrix, only the layer is different. */ + KeymapKey regular_key = KeymapKey{0, 1, 0, KC_A}; + set_keymap({layer_key, regular_key, KeymapKey{1, 1, 0, KC_B}}); + + /* Tap TT five times . */ + /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(9); + + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + + layer_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + layer_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + + testing::Mock::VerifyAndClearExpectations(&driver); + + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B))).Times(1); + regular_key.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + regular_key.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); } -// TEST_F(ActionLayer, LayerClear) { -// layer_clear(); -// EXPECT_EQ(layer_state, 0); -// } - -// TEST_F(ActionLayer, LayerMove) { -// layer_move(0); -// EXPECT_EQ(layer_state, 1); -// layer_move(3); -// EXPECT_EQ(layer_state, 0b1000); -// } - -// TEST_F(ActionLayer, LayerOn) { -// layer_clear(); -// layer_on(1); -// layer_on(3); -// layer_on(3); -// EXPECT_EQ(layer_state, 0b1010); -// } - -// TEST_F(ActionLayer, LayerOff) { -// layer_clear(); -// layer_on(1); -// layer_on(3); -// layer_off(3); -// layer_off(2); -// EXPECT_EQ(layer_state, 0b1000); -// } +TEST_F(ActionLayer, LayerTapReleasedBeforeKeypressReleaseWithModifiers) { + GTEST_SKIP() << "TODO: Modifiers are erroneously discarded on layer changes, although a key that introduced the modifier is still held."; + TestDriver driver; + InSequence s; + + KeymapKey layer_0_key_0 = KeymapKey{0, 0, 0, LT(1, KC_T)}; + KeymapKey layer_1_key_1 = KeymapKey{1, 1, 0, RALT(KC_9)}; + + set_keymap({layer_0_key_0, layer_1_key_1}); + + /* Press layer tap and wait for tapping term to switch to layer 1 */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + layer_0_key_0.press(); + idle_for(TAPPING_TERM); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Press key with layer 1 mapping, result basically expected + * altough more reports are send then necessary. */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_RALT))).Times(1); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_RALT, KC_9))).Times(1); + layer_1_key_1.press(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Release layer tap key, no report is send because key is still held. */ + EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0); + layer_0_key_0.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); + + /* Unregister keycode and modifier. */ + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_RALT))).Times(1); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1); + layer_1_key_1.release(); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(0)); + testing::Mock::VerifyAndClearExpectations(&driver); +} -- cgit v1.2.3