a24bdccee0580d1263733bc7e66e4e4f97713f19

Author
Stefan Kerkmann <karlk90@pm.me>
Committer
GitHub <noreply@github.com>
Date

Message

 [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 <nick@tzarc.org>

Diff

This diff is truncated to protect this page.

   1diff --git a/Makefile b/Makefile
   2index c221cb89e02189e8c1b656413c025576d37b5402..88f430619e39f866744b3498e183de59c7d603c2 100644
   3--- a/Makefile
   4+++ b/Makefile
   5@@ -378,11 +378,12 @@ define PARSE_ALL_KEYMAPS
   6 endef
   7 
   8 define BUILD_TEST
   9-    TEST_NAME := $1
  10+    TEST_PATH := $1
  11+    TEST_NAME := $$(notdir $$(TEST_PATH))
  12     MAKE_TARGET := $2
  13     COMMAND := $1
  14     MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_test.mk $$(MAKE_TARGET)
  15-    MAKE_VARS := TEST=$$(TEST_NAME) FULL_TESTS="$$(FULL_TESTS)"
  16+    MAKE_VARS := TEST=$$(TEST_NAME) TEST_PATH=$$(TEST_PATH) FULL_TESTS="$$(FULL_TESTS)"
  17     MAKE_MSG := $$(MSG_MAKE_TEST)
  18     $$(eval $$(call BUILD))
  19     ifneq ($$(MAKE_TARGET),clean)
  20@@ -406,7 +407,7 @@ define PARSE_TEST
  21     ifeq ($$(TEST_NAME),all)
  22         MATCHED_TESTS := $$(TEST_LIST)
  23     else
  24-        MATCHED_TESTS := $$(foreach TEST,$$(TEST_LIST),$$(if $$(findstring $$(TEST_NAME),$$(TEST)),$$(TEST),))
  25+        MATCHED_TESTS := $$(foreach TEST, $$(TEST_LIST),$$(if $$(findstring $$(TEST_NAME), $$(notdir $$(TEST))), $$(TEST),))
  26     endif
  27     $$(foreach TEST,$$(MATCHED_TESTS),$$(eval $$(call BUILD_TEST,$$(TEST),$$(TEST_TARGET))))
  28 endef
  29diff --git a/build_full_test.mk b/build_full_test.mk
  30index f8030cb0600db6aa1eb467ba2c02a2bbc2530198..4cd1ac61b53fd2d93e7729f3a7927853c756c605 100644
  31--- a/build_full_test.mk
  32+++ b/build_full_test.mk
  33@@ -13,21 +13,24 @@
  34 # You should have received a copy of the GNU General Public License
  35 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  36 
  37-#include $(TMK_PATH)/protocol.mk
  38+$(TEST)_INC := \
  39+	tests\test_common\common_config.h
  40 
  41-TEST_PATH=tests/$(TEST)
  42-
  43-$(TEST)_SRC= \
  44-	$(TEST_PATH)/keymap.c \
  45+$(TEST)_SRC := \
  46 	$(TMK_COMMON_SRC) \
  47 	$(QUANTUM_SRC) \
  48 	$(SRC) \
  49+	tests/test_common/keymap.c \
  50 	tests/test_common/matrix.c \
  51 	tests/test_common/test_driver.cpp \
  52 	tests/test_common/keyboard_report_util.cpp \
  53-	tests/test_common/test_fixture.cpp
  54-$(TEST)_SRC += $(patsubst $(ROOTDIR)/%,%,$(wildcard $(TEST_PATH)/*.cpp))
  55+	tests/test_common/test_fixture.cpp \
  56+	tests/test_common/test_keymap_key.cpp \
  57+	tests/test_common/test_logger.cpp \
  58+	$(patsubst $(ROOTDIR)/%,%,$(wildcard $(TEST_PATH)/*.cpp))
  59+
  60+$(TEST)_DEFS := $(TMK_COMMON_DEFS) $(OPT_DEFS)
  61+
  62+$(TEST)_CONFIG := $(TEST_PATH)/config.h
  63 
  64-$(TEST)_DEFS=$(TMK_COMMON_DEFS) $(OPT_DEFS)
  65-$(TEST)_CONFIG=$(TEST_PATH)/config.h
  66-VPATH+=$(TOP_DIR)/tests/test_common
  67+VPATH += $(TOP_DIR)/tests/test_common
  68diff --git a/build_test.mk b/build_test.mk
  69index 36cb7936edd6094f97327d7b7f8134566abd8cb5..136a0455f01c87a6dd98204df9e476f88b675dd7 100644
  70--- a/build_test.mk
  71+++ b/build_test.mk
  72@@ -16,14 +16,14 @@ TEST_OBJ = $(BUILD_DIR)/test_obj
  73 OUTPUTS := $(TEST_OBJ)/$(TEST) $(GTEST_OUTPUT)
  74 
  75 GTEST_INC := \
  76-	$(LIB_PATH)/googletest/googletest/include\
  77-	$(LIB_PATH)/googletest/googlemock/include\
  78+	$(LIB_PATH)/googletest/googletest/include \
  79+	$(LIB_PATH)/googletest/googlemock/include
  80 
  81-GTEST_INTERNAL_INC :=\
  82-	$(LIB_PATH)/googletest/googletest\
  83+GTEST_INTERNAL_INC := \
  84+	$(LIB_PATH)/googletest/googletest \
  85 	$(LIB_PATH)/googletest/googlemock
  86 
  87-$(GTEST_OUTPUT)_SRC :=\
  88+$(GTEST_OUTPUT)_SRC := \
  89 	googletest/src/gtest-all.cc\
  90 	googlemock/src/gmock-all.cc
  91 
  92@@ -33,9 +33,9 @@ $(GTEST_OUTPUT)_INC := $(GTEST_INC) $(GTEST_INTERNAL_INC)
  93 LDFLAGS += -lstdc++ -lpthread -shared-libgcc
  94 CREATE_MAP := no
  95 
  96-VPATH +=\
  97-	$(LIB_PATH)/googletest\
  98-	$(LIB_PATH)/googlemock\
  99+VPATH += \
 100+	$(LIB_PATH)/googletest \
 101+	$(LIB_PATH)/googlemock \
 102 	$(LIB_PATH)/printf
 103 
 104 all: elf
 105@@ -49,7 +49,8 @@ CONSOLE_ENABLE = yes
 106 endif
 107 
 108 ifneq ($(filter $(FULL_TESTS),$(TEST)),)
 109-include tests/$(TEST)/rules.mk
 110+include tests/test_common/build.mk
 111+include $(TEST_PATH)/test.mk
 112 endif
 113 
 114 include common_features.mk
 115diff --git a/testlist.mk b/testlist.mk
 116index cff784dad61dcc3551d1be8d5659dea212df1638..d2bb571be64f562d7adff1d46c4c6e979460146b 100644
 117--- a/testlist.mk
 118+++ b/testlist.mk
 119@@ -1,5 +1,5 @@
 120-TEST_LIST = $(notdir $(patsubst %/rules.mk,%,$(wildcard $(ROOT_DIR)/tests/*/rules.mk)))
 121-FULL_TESTS := $(TEST_LIST)
 122+TEST_LIST = $(sort $(patsubst %/test.mk,%, $(shell find $(ROOT_DIR)tests -type f -name test.mk)))
 123+FULL_TESTS := $(notdir $(TEST_LIST))
 124 
 125 include $(QUANTUM_PATH)/debounce/tests/testlist.mk
 126 include $(QUANTUM_PATH)/encoder/tests/testlist.mk
 127diff --git a/tests/auto_shift/config.h b/tests/auto_shift/config.h
 128new file mode 100644
 129index 0000000000000000000000000000000000000000..4f343b45299531730d47ae5e07d11cc8fde5702d
 130--- /dev/null
 131+++ b/tests/auto_shift/config.h
 132@@ -0,0 +1,19 @@
 133+/* Copyright 2021 Stefan Kerkmann
 134+ *
 135+ * This program is free software: you can redistribute it and/or modify
 136+ * it under the terms of the GNU General Public License as published by
 137+ * the Free Software Foundation, either version 2 of the License, or
 138+ * (at your option) any later version.
 139+ *
 140+ * This program is distributed in the hope that it will be useful,
 141+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 142+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 143+ * GNU General Public License for more details.
 144+ *
 145+ * You should have received a copy of the GNU General Public License
 146+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 147+ */
 148+
 149+#pragma once
 150+
 151+#include "test_common.h"
 152diff --git a/tests/auto_shift/test.mk b/tests/auto_shift/test.mk
 153new file mode 100644
 154index 0000000000000000000000000000000000000000..4259c606e472940f512b0d092e351d34cb7a02c9
 155--- /dev/null
 156+++ b/tests/auto_shift/test.mk
 157@@ -0,0 +1,20 @@
 158+# Copyright 2021 Stefan Kerkmann
 159+#
 160+# This program is free software: you can redistribute it and/or modify
 161+# it under the terms of the GNU General Public License as published by
 162+# the Free Software Foundation, either version 2 of the License, or
 163+# (at your option) any later version.
 164+#
 165+# This program is distributed in the hope that it will be useful,
 166+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 167+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 168+# GNU General Public License for more details.
 169+#
 170+# You should have received a copy of the GNU General Public License
 171+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 172+
 173+# --------------------------------------------------------------------------------
 174+# Keep this file, even if it is empty, as a marker that this folder contains tests
 175+# --------------------------------------------------------------------------------
 176+
 177+AUTO_SHIFT_ENABLE = yes
 178diff --git a/tests/auto_shift/test_auto_shift.cpp b/tests/auto_shift/test_auto_shift.cpp
 179new file mode 100644
 180index 0000000000000000000000000000000000000000..9c5ed9a8326a829f5a053c6bb1b405612230ff51
 181--- /dev/null
 182+++ b/tests/auto_shift/test_auto_shift.cpp
 183@@ -0,0 +1,73 @@
 184+/* Copyright 2021 Stefan Kerkmann
 185+ *
 186+ * This program is free software: you can redistribute it and/or modify
 187+ * it under the terms of the GNU General Public License as published by
 188+ * the Free Software Foundation, either version 2 of the License, or
 189+ * (at your option) any later version.
 190+ *
 191+ * This program is distributed in the hope that it will be useful,
 192+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 193+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 194+ * GNU General Public License for more details.
 195+ *
 196+ * You should have received a copy of the GNU General Public License
 197+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 198+ */
 199+
 200+#include "keyboard_report_util.hpp"
 201+#include "keycode.h"
 202+#include "test_common.hpp"
 203+#include "action_tapping.h"
 204+#include "test_fixture.hpp"
 205+#include "test_keymap_key.hpp"
 206+
 207+using testing::_;
 208+using testing::InSequence;
 209+
 210+class AutoShift : public TestFixture {};
 211+
 212+TEST_F(AutoShift, key_release_before_timeout) {
 213+    TestDriver driver;
 214+    InSequence s;
 215+    auto       regular_key = KeymapKey(0, 2, 0, KC_A);
 216+
 217+    set_keymap({regular_key});
 218+
 219+    /* Press regular key */
 220+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 221+    regular_key.press();
 222+    run_one_scan_loop();
 223+    testing::Mock::VerifyAndClearExpectations(&driver);
 224+
 225+    /* Release regular key */
 226+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A)));
 227+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 228+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 229+    regular_key.release();
 230+    run_one_scan_loop();
 231+    testing::Mock::VerifyAndClearExpectations(&driver);
 232+}
 233+
 234+TEST_F(AutoShift, key_release_after_timeout) {
 235+    TestDriver driver;
 236+    InSequence s;
 237+    auto       regular_key = KeymapKey(0, 2, 0, KC_A);
 238+
 239+    set_keymap({regular_key});
 240+
 241+    /* Press regular key */
 242+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 243+    regular_key.press();
 244+    idle_for(AUTO_SHIFT_TIMEOUT);
 245+    testing::Mock::VerifyAndClearExpectations(&driver);
 246+
 247+    /* Release regular key */
 248+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT, KC_A)));
 249+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
 250+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 251+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 252+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 253+    regular_key.release();
 254+    run_one_scan_loop();
 255+    testing::Mock::VerifyAndClearExpectations(&driver);
 256+}
 257diff --git a/tests/basic/config.h b/tests/basic/config.h
 258index 99bd62d991c4bf6bc4228cc3548277b1d1f9a1ae..85fa9d691d08ab9d119d707f96247cbabea4c5e7 100644
 259--- a/tests/basic/config.h
 260+++ b/tests/basic/config.h
 261@@ -16,5 +16,4 @@
 262 
 263 #pragma once
 264 
 265-#define MATRIX_ROWS 4
 266-#define MATRIX_COLS 10
 267+#include "test_common.h"
 268diff --git a/tests/basic/keymap.c b/tests/basic/keymap.c
 269deleted file mode 100644
 270index 2b5747abb7cbcf61090e2be466f2504b88b0980f..0000000000000000000000000000000000000000
 271--- a/tests/basic/keymap.c
 272+++ /dev/null
 273@@ -1,45 +0,0 @@
 274-/* Copyright 2017 Fred Sundvik
 275- *
 276- * This program is free software: you can redistribute it and/or modify
 277- * it under the terms of the GNU General Public License as published by
 278- * the Free Software Foundation, either version 2 of the License, or
 279- * (at your option) any later version.
 280- *
 281- * This program is distributed in the hope that it will be useful,
 282- * but WITHOUT ANY WARRANTY; without even the implied warranty of
 283- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 284- * GNU General Public License for more details.
 285- *
 286- * You should have received a copy of the GNU General Public License
 287- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 288- */
 289-
 290-#include "quantum.h"
 291-
 292-// Don't rearrange keys as existing tests might rely on the order
 293-// Col2, Row 0 has to be KC_NO, because tests rely on it
 294-
 295-#define COMBO1 RSFT(LCTL(KC_O))
 296-
 297-const uint16_t PROGMEM
 298-               keymaps[][MATRIX_ROWS][MATRIX_COLS] =
 299-        {
 300-            [0] =
 301-                {
 302-                    // 0    1      2      3        4        5        6       7            8      9
 303-                    {KC_A, KC_B, KC_NO, KC_LSFT, KC_RSFT, KC_LCTL, COMBO1, SFT_T(KC_P), M(0), KC_NO},
 304-                    {KC_EQL, KC_PLUS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
 305-                    {KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
 306-                    {KC_C, KC_D, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
 307-                },
 308-};
 309-
 310-const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
 311-    if (record->event.pressed) {
 312-        switch (id) {
 313-            case 0:
 314-                return MACRO(D(LSFT), T(H), U(LSFT), T(E), T(L), T(L), T(O), T(SPACE), W(100), D(LSFT), T(W), U(LSFT), I(10), T(O), T(R), T(L), T(D), D(LSFT), T(1), U(LSFT), END);
 315-        }
 316-    }
 317-    return MACRO_NONE;
 318-};
 319diff --git a/tests/basic/test.mk b/tests/basic/test.mk
 320new file mode 100644
 321index 0000000000000000000000000000000000000000..29690d1adf7b4530aeed9679a8194b1271437623
 322--- /dev/null
 323+++ b/tests/basic/test.mk
 324@@ -0,0 +1,18 @@
 325+# Copyright 2017 Fred Sundvik
 326+#
 327+# This program is free software: you can redistribute it and/or modify
 328+# it under the terms of the GNU General Public License as published by
 329+# the Free Software Foundation, either version 2 of the License, or
 330+# (at your option) any later version.
 331+#
 332+# This program is distributed in the hope that it will be useful,
 333+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 334+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 335+# GNU General Public License for more details.
 336+#
 337+# You should have received a copy of the GNU General Public License
 338+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 339+
 340+# --------------------------------------------------------------------------------
 341+# Keep this file, even if it is empty, as a marker that this folder contains tests
 342+# --------------------------------------------------------------------------------
 343diff --git a/tests/basic/test_action_layer.cpp b/tests/basic/test_action_layer.cpp
 344index d00a0859b9c66d87ef92ecbc72b2a6d509b35b4d..1b12d13642fe18b6e84a42ea2ac4adfcfa1407f1 100644
 345--- a/tests/basic/test_action_layer.cpp
 346+++ b/tests/basic/test_action_layer.cpp
 347@@ -14,39 +14,54 @@
 348  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 349  */
 350 
 351+#include "gtest/gtest.h"
 352+#include "keyboard_report_util.hpp"
 353 #include "test_common.hpp"
 354 
 355 using testing::_;
 356-using testing::Return;
 357+using testing::InSequence;
 358 
 359 class ActionLayer : public TestFixture {};
 360 
 361-// TEST_F(ActionLayer, LayerStateDBG) {
 362-//     layer_state_set(0);
 363-// }
 364-
 365-// TEST_F(ActionLayer, LayerStateSet) {
 366-//     layer_state_set(0);
 367-//     EXPECT_EQ(layer_state, 0);
 368-//     layer_state_set(0b001100);
 369-//     EXPECT_EQ(layer_state, 0b001100);
 370-// }
 371-
 372-// TEST_F(ActionLayer, LayerStateIs) {
 373-//     layer_state_set(0);
 374-//     EXPECT_EQ(layer_state_is(0), true);
 375-//     EXPECT_EQ(layer_state_is(1), true);
 376-//     layer_state_set(1);
 377-//     EXPECT_EQ(layer_state_is(0), true);
 378-//     EXPECT_EQ(layer_state_is(1), true);
 379-//     layer_state_set(2);
 380-//     EXPECT_EQ(layer_state_is(0), false);
 381-//     EXPECT_EQ(layer_state_is(1), false);
 382-//     EXPECT_EQ(layer_state_is(2), true);
 383-// }
 384+TEST_F(ActionLayer, LayerStateDBG) {
 385+    TestDriver driver;
 386+
 387+    layer_state_set(0);
 388+
 389+    testing::Mock::VerifyAndClearExpectations(&driver);
 390+}
 391+
 392+TEST_F(ActionLayer, LayerStateSet) {
 393+    TestDriver driver;
 394+
 395+    layer_state_set(0);
 396+    EXPECT_EQ(layer_state, 0);
 397+    layer_state_set(0b001100);
 398+    EXPECT_EQ(layer_state, 0b001100);
 399+
 400+    testing::Mock::VerifyAndClearExpectations(&driver);
 401+}
 402+
 403+TEST_F(ActionLayer, LayerStateIs) {
 404+    TestDriver driver;
 405+
 406+    layer_state_set(0);
 407+    EXPECT_EQ(layer_state_is(0), true);
 408+    EXPECT_EQ(layer_state_is(1), false);
 409+    layer_state_set(1);
 410+    EXPECT_EQ(layer_state_is(0), true);
 411+    EXPECT_EQ(layer_state_is(1), false);
 412+    layer_state_set(2);
 413+    EXPECT_EQ(layer_state_is(0), false);
 414+    EXPECT_EQ(layer_state_is(1), true);
 415+    EXPECT_EQ(layer_state_is(2), false);
 416+
 417+    testing::Mock::VerifyAndClearExpectations(&driver);
 418+}
 419 
 420 TEST_F(ActionLayer, LayerStateCmp) {
 421-    uint32_t prev_layer;
 422+    TestDriver driver;
 423+    uint32_t   prev_layer;
 424 
 425     prev_layer = 0;
 426     EXPECT_EQ(layer_state_cmp(prev_layer, 0), true);
 427@@ -60,33 +75,339 @@ TEST_F(ActionLayer, LayerStateCmp) {
 428     EXPECT_EQ(layer_state_cmp(prev_layer, 0), false);
 429     EXPECT_EQ(layer_state_cmp(prev_layer, 1), true);
 430     EXPECT_EQ(layer_state_cmp(prev_layer, 2), false);
 431+
 432+    testing::Mock::VerifyAndClearExpectations(&driver);
 433+}
 434+
 435+TEST_F(ActionLayer, LayerClear) {
 436+    TestDriver driver;
 437+
 438+    layer_clear();
 439+    EXPECT_EQ(layer_state, 0);
 440+
 441+    testing::Mock::VerifyAndClearExpectations(&driver);
 442+}
 443+
 444+TEST_F(ActionLayer, LayerMove) {
 445+    TestDriver driver;
 446+
 447diff --git a/tests/basic/test_keypress.cpp b/tests/basic/test_keypress.cpp
 448index cf839f8c16d5afdf2816c9a5c371bebfba1ac5a0..1c175c9d56a7e0c0dd58e70c4d877d6294c2b410 100644
 449--- a/tests/basic/test_keypress.cpp
 450+++ b/tests/basic/test_keypress.cpp
 451@@ -14,11 +14,11 @@
 452  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 453  */
 454 
 455+#include "keycode.h"
 456 #include "test_common.hpp"
 457 
 458 using testing::_;
 459 using testing::InSequence;
 460-using testing::Return;
 461 
 462 class KeyPress : public TestFixture {};
 463 
 464@@ -30,96 +30,157 @@ TEST_F(KeyPress, SendKeyboardIsNotCalledWhenNoKeyIsPressed) {
 465 
 466 TEST_F(KeyPress, CorrectKeyIsReportedWhenPressed) {
 467     TestDriver driver;
 468-    press_key(0, 0);
 469-    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A)));
 470+    auto       key = KeymapKey(0, 0, 0, KC_A);
 471+
 472+    set_keymap({key});
 473+
 474+    key.press();
 475+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(key.report_code)));
 476     keyboard_task();
 477-    release_key(0, 0);
 478+
 479+    key.release();
 480     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 481     keyboard_task();
 482 }
 483 
 484+TEST_F(KeyPress, ANonMappedKeyDoesNothing) {
 485+    TestDriver driver;
 486+    auto       key = KeymapKey(0, 0, 0, KC_NO);
 487+
 488+    set_keymap({key});
 489+
 490+    key.press();
 491+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 492+    keyboard_task();
 493+    keyboard_task();
 494+}
 495+
 496 TEST_F(KeyPress, CorrectKeysAreReportedWhenTwoKeysArePressed) {
 497     TestDriver driver;
 498-    press_key(1, 0);
 499-    press_key(0, 3);
 500+    auto       key_b = KeymapKey(0, 0, 0, KC_B);
 501+    auto       key_c = KeymapKey(0, 1, 1, KC_C);
 502+
 503+    set_keymap({key_b, key_c});
 504+
 505+    key_b.press();
 506+    key_c.press();
 507     // Note that QMK only processes one key at a time
 508     // See issue #1476 for more information
 509-    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B)));
 510+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(key_b.report_code)));
 511     keyboard_task();
 512-    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B, KC_C)));
 513+
 514+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(key_b.report_code, key_c.report_code)));
 515     keyboard_task();
 516-    release_key(1, 0);
 517-    release_key(0, 3);
 518+
 519+    key_b.release();
 520+    key_c.release();
 521     // Note that the first key released is the first one in the matrix order
 522-    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C)));
 523-    keyboard_task();
 524-    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 525+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(key_c.report_code)));
 526     keyboard_task();
 527-}
 528 
 529-TEST_F(KeyPress, ANonMappedKeyDoesNothing) {
 530-    TestDriver driver;
 531-    press_key(2, 0);
 532-    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 533-    keyboard_task();
 534+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 535     keyboard_task();
 536 }
 537 
 538 TEST_F(KeyPress, LeftShiftIsReportedCorrectly) {
 539     TestDriver driver;
 540-    press_key(3, 0);
 541-    press_key(0, 0);
 542+    auto       key_a    = KeymapKey(0, 0, 0, KC_A);
 543+    auto       key_lsft = KeymapKey(0, 3, 0, KC_LSFT);
 544+
 545+    set_keymap({key_a, key_lsft});
 546+
 547+    key_lsft.press();
 548+    key_a.press();
 549+
 550     // Unfortunately modifiers are also processed in the wrong order
 551diff --git a/tests/basic/test_macro.cpp b/tests/basic/test_macro.cpp
 552index 1ac6f473fc819d5d4cdceb9ad6f873c18a09e7eb..ae2f3b32e3fb0b3def641f5a58593e05f4deab9f 100644
 553--- a/tests/basic/test_macro.cpp
 554+++ b/tests/basic/test_macro.cpp
 555@@ -24,10 +24,25 @@ class Macro : public TestFixture {};
 556 
 557 #define AT_TIME(t) WillOnce(InvokeWithoutArgs([current_time]() { EXPECT_EQ(timer_elapsed32(current_time), t); }))
 558 
 559+extern "C" const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
 560+    if (record->event.pressed) {
 561+        switch (id) {
 562+            case 0:
 563+                return MACRO(D(LSFT), T(H), U(LSFT), T(E), T(L), T(L), T(O), T(SPACE), W(100), D(LSFT), T(W), U(LSFT), I(10), T(O), T(R), T(L), T(D), D(LSFT), T(1), U(LSFT), END);
 564+        }
 565+    }
 566+    return MACRO_NONE;
 567+};
 568+
 569 TEST_F(Macro, PlayASimpleMacro) {
 570     TestDriver driver;
 571     InSequence s;
 572-    press_key(8, 0);
 573+    auto       key_macro = KeymapKey(0, 8, 0, M(0));
 574+
 575+    set_keymap({key_macro});
 576+
 577+    key_macro.press();
 578+
 579     uint32_t current_time = timer_read32();
 580     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LEFT_SHIFT))).AT_TIME(0);
 581     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LEFT_SHIFT, KC_H))).AT_TIME(0);
 582@@ -68,4 +83,6 @@ TEST_F(Macro, PlayASimpleMacro) {
 583     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LEFT_SHIFT))).AT_TIME(210);
 584     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).AT_TIME(220);
 585     run_one_scan_loop();
 586+
 587+    key_macro.release();
 588 }
 589diff --git a/tests/basic/test_one_shot_keys.cpp b/tests/basic/test_one_shot_keys.cpp
 590new file mode 100644
 591index 0000000000000000000000000000000000000000..98178912e4cc47d2d2a0e57c24d134f91902a4be
 592--- /dev/null
 593+++ b/tests/basic/test_one_shot_keys.cpp
 594@@ -0,0 +1,197 @@
 595+/* Copyright 2021 Stefan Kerkmann
 596+ *
 597+ * This program is free software: you can redistribute it and/or modify
 598+ * it under the terms of the GNU General Public License as published by
 599+ * the Free Software Foundation, either version 2 of the License, or
 600+ * (at your option) any later version.
 601+ *
 602+ * This program is distributed in the hope that it will be useful,
 603+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 604+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 605+ * GNU General Public License for more details.
 606+ *
 607+ * You should have received a copy of the GNU General Public License
 608+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 609+ */
 610+
 611+#include "action_util.h"
 612+#include "keyboard_report_util.hpp"
 613+#include "test_common.hpp"
 614+
 615+using testing::_;
 616+using testing::InSequence;
 617+
 618+class OneShot : public TestFixture {};
 619+class OneShotParametrizedTestFixture : public ::testing::WithParamInterface<std::pair<KeymapKey, KeymapKey>>, public OneShot {};
 620+
 621+TEST_F(OneShot, OSMWithoutAdditionalKeypressDoesNothing) {
 622+    TestDriver driver;
 623+    auto       osm_key = KeymapKey(0, 0, 0, OSM(MOD_LSFT), KC_LSFT);
 624+
 625+    set_keymap({osm_key});
 626+
 627+    /* Press and release OSM key*/
 628+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 629+    osm_key.press();
 630+    run_one_scan_loop();
 631+    osm_key.release();
 632+    run_one_scan_loop();
 633+    testing::Mock::VerifyAndClearExpectations(&driver);
 634+
 635+    /* OSM are added when an actual report is send */
 636+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(osm_key.report_code)));
 637+    send_keyboard_report();
 638+    testing::Mock::VerifyAndClearExpectations(&driver);
 639+
 640+    /* Make unit-test pass */
 641+    clear_oneshot_mods();
 642+}
 643+
 644+#if defined(ONESHOT_TIMEOUT)
 645+
 646+TEST_P(OneShotParametrizedTestFixture, OSMExpiredDoesNothing) {
 647+    TestDriver driver;
 648+    KeymapKey  osm_key     = GetParam().first;
 649+    KeymapKey  regular_key = GetParam().second;
 650+
 651+    set_keymap({osm_key, regular_key});
 652+
 653+    /* Press and release OSM */
 654+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 655+    osm_key.press();
 656+    run_one_scan_loop();
 657+    osm_key.release();
 658+    idle_for(ONESHOT_TIMEOUT);
 659+    testing::Mock::VerifyAndClearExpectations(&driver);
 660+
 661+    /* Press regular key */
 662+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(regular_key.report_code))).Times(1);
 663+    regular_key.press();
 664+    run_one_scan_loop();
 665+    testing::Mock::VerifyAndClearExpectations(&driver);
 666+
 667+    /* Release regular key */
 668+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 669+    regular_key.release();
 670+    run_one_scan_loop();
 671+    testing::Mock::VerifyAndClearExpectations(&driver);
 672+}
 673+
 674+#endif
 675+
 676+TEST_P(OneShotParametrizedTestFixture, OSMWithAdditionalKeypress) {
 677+    TestDriver driver;
 678+    KeymapKey  osm_key     = GetParam().first;
 679+    KeymapKey  regular_key = GetParam().second;
 680+
 681+    set_keymap({osm_key, regular_key});
 682+
 683+    /* Press and release OSM */
 684+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 685+    osm_key.press();
 686+    run_one_scan_loop();
 687+    osm_key.release();
 688+    run_one_scan_loop();
 689+    testing::Mock::VerifyAndClearExpectations(&driver);
 690+
 691+    /* Press regular key */
 692+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(osm_key.report_code, regular_key.report_code))).Times(1);
 693+    regular_key.press();
 694diff --git a/tests/basic/test_tapping.cpp b/tests/basic/test_tapping.cpp
 695index 88ab97eb6e69bdd20c6a9fe1fdfb575dd2730f0a..e4a7e4a9f3f0df3c834f5e2d5f5c829dac7db9ea 100644
 696--- a/tests/basic/test_tapping.cpp
 697+++ b/tests/basic/test_tapping.cpp
 698@@ -14,8 +14,11 @@
 699  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 700  */
 701 
 702+#include "keyboard_report_util.hpp"
 703+#include "keycode.h"
 704 #include "test_common.hpp"
 705 #include "action_tapping.h"
 706+#include "test_keymap_key.hpp"
 707 
 708 using testing::_;
 709 using testing::InSequence;
 710@@ -25,14 +28,19 @@ class Tapping : public TestFixture {};
 711 TEST_F(Tapping, TapA_SHFT_T_KeyReportsKey) {
 712     TestDriver driver;
 713     InSequence s;
 714+    auto       key_shift_hold_p_tap = KeymapKey(0, 7, 0, SFT_T(KC_P));
 715+
 716+    set_keymap({key_shift_hold_p_tap});
 717 
 718-    press_key(7, 0);
 719     // Tapping keys does nothing on press
 720+    key_shift_hold_p_tap.press();
 721     EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 722     run_one_scan_loop();
 723-    release_key(7, 0);
 724+
 725     // First we get the key press
 726+    key_shift_hold_p_tap.release();
 727     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 728+
 729     // Then the release
 730     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 731     run_one_scan_loop();
 732@@ -41,12 +49,21 @@ TEST_F(Tapping, TapA_SHFT_T_KeyReportsKey) {
 733 TEST_F(Tapping, HoldA_SHFT_T_KeyReportsShift) {
 734     TestDriver driver;
 735     InSequence s;
 736+    auto       mod_tap_hold_key = KeymapKey(0, 7, 0, SFT_T(KC_P));
 737+
 738+    set_keymap({mod_tap_hold_key});
 739+
 740+    mod_tap_hold_key.press();
 741 
 742-    press_key(7, 0);
 743     // Tapping keys does nothing on press
 744     EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 745     idle_for(TAPPING_TERM);
 746-    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LEFT_SHIFT)));
 747+
 748+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
 749+    run_one_scan_loop();
 750+
 751+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 752+    mod_tap_hold_key.release();
 753     run_one_scan_loop();
 754 }
 755 
 756@@ -54,12 +71,16 @@ TEST_F(Tapping, ANewTapWithinTappingTermIsBuggy) {
 757     // See issue #1478 for more information
 758     TestDriver driver;
 759     InSequence s;
 760+    auto       key_shift_hold_p_tap = KeymapKey(0, 7, 0, SFT_T(KC_P));
 761+
 762+    set_keymap({key_shift_hold_p_tap});
 763 
 764-    press_key(7, 0);
 765     // Tapping keys does nothing on press
 766+    key_shift_hold_p_tap.press();
 767     EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 768     run_one_scan_loop();
 769-    release_key(7, 0);
 770+    key_shift_hold_p_tap.release();
 771+
 772     // First we get the key press
 773     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 774     // Then the release
 775@@ -67,19 +88,20 @@ TEST_F(Tapping, ANewTapWithinTappingTermIsBuggy) {
 776     run_one_scan_loop();
 777 
 778     // This sends KC_P, even if it should do nothing
 779-    press_key(7, 0);
 780+    key_shift_hold_p_tap.press();
 781     // This test should not succed if everything works correctly
 782     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 783     run_one_scan_loop();
 784-    release_key(7, 0);
 785+
 786+    key_shift_hold_p_tap.release();
 787     EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 788     idle_for(TAPPING_TERM + 1);
 789 
 790     // On the other hand, nothing is sent if we are outside the tapping term
 791-    press_key(7, 0);
 792+    key_shift_hold_p_tap.press();
 793     EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 794     run_one_scan_loop();
 795-    release_key(7, 0);
 796+    key_shift_hold_p_tap.release();
 797 
 798diff --git a/tests/tap_hold_configurations/default_mod_tap/config.h b/tests/tap_hold_configurations/default_mod_tap/config.h
 799new file mode 100644
 800index 0000000000000000000000000000000000000000..5955b8600a8750f244ef051d401a201c2dea5a76
 801--- /dev/null
 802+++ b/tests/tap_hold_configurations/default_mod_tap/config.h
 803@@ -0,0 +1,21 @@
 804+/* Copyright 2021 Stefan Kerkmann
 805+ *
 806+ * This program is free software: you can redistribute it and/or modify
 807+ * it under the terms of the GNU General Public License as published by
 808+ * the Free Software Foundation, either version 2 of the License, or
 809+ * (at your option) any later version.
 810+ *
 811+ * This program is distributed in the hope that it will be useful,
 812+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 813+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 814+ * GNU General Public License for more details.
 815+ *
 816+ * You should have received a copy of the GNU General Public License
 817+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 818+ */
 819+
 820+#pragma once
 821+
 822+#include "test_common.h"
 823+
 824+#define IGNORE_MOD_TAP_INTERRUPT
 825diff --git a/tests/tap_hold_configurations/default_mod_tap/test.mk b/tests/tap_hold_configurations/default_mod_tap/test.mk
 826new file mode 100644
 827index 0000000000000000000000000000000000000000..cfab996e0ef819205d9c1662559032fab99b8c1c
 828--- /dev/null
 829+++ b/tests/tap_hold_configurations/default_mod_tap/test.mk
 830@@ -0,0 +1,18 @@
 831+# Copyright 2021 Stefan Kerkmann
 832+#
 833+# This program is free software: you can redistribute it and/or modify
 834+# it under the terms of the GNU General Public License as published by
 835+# the Free Software Foundation, either version 2 of the License, or
 836+# (at your option) any later version.
 837+#
 838+# This program is distributed in the hope that it will be useful,
 839+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 840+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 841+# GNU General Public License for more details.
 842+#
 843+# You should have received a copy of the GNU General Public License
 844+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 845+
 846+# --------------------------------------------------------------------------------
 847+# Keep this file, even if it is empty, as a marker that this folder contains tests
 848+# --------------------------------------------------------------------------------
 849diff --git a/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp b/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp
 850new file mode 100644
 851index 0000000000000000000000000000000000000000..90befcdffd1553c44c48ae90ccc10e6a3e6e3249
 852--- /dev/null
 853+++ b/tests/tap_hold_configurations/default_mod_tap/test_tap_hold.cpp
 854@@ -0,0 +1,230 @@
 855+/* Copyright 2021 Stefan Kerkmann
 856+ *
 857+ * This program is free software: you can redistribute it and/or modify
 858+ * it under the terms of the GNU General Public License as published by
 859+ * the Free Software Foundation, either version 2 of the License, or
 860+ * (at your option) any later version.
 861+ *
 862+ * This program is distributed in the hope that it will be useful,
 863+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 864+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 865+ * GNU General Public License for more details.
 866+ *
 867+ * You should have received a copy of the GNU General Public License
 868+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 869+ */
 870+
 871+#include "keyboard_report_util.hpp"
 872+#include "keycode.h"
 873+#include "test_common.hpp"
 874+#include "action_tapping.h"
 875+#include "test_fixture.hpp"
 876+#include "test_keymap_key.hpp"
 877+
 878+using testing::_;
 879+using testing::InSequence;
 880+
 881+class DefaultTapHold : public TestFixture {};
 882+
 883+TEST_F(DefaultTapHold, tap_regular_key_while_mod_tap_key_is_held) {
 884+    TestDriver driver;
 885+    InSequence s;
 886+    auto       mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
 887+    auto       regular_key      = KeymapKey(0, 2, 0, KC_A);
 888+
 889+    set_keymap({mod_tap_hold_key, regular_key});
 890+
 891+    /* Press mod-tap-hold key. */
 892+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 893+    mod_tap_hold_key.press();
 894+    run_one_scan_loop();
 895+    testing::Mock::VerifyAndClearExpectations(&driver);
 896+
 897+    /* Press regular key. */
 898+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 899+    regular_key.press();
 900+    run_one_scan_loop();
 901+    testing::Mock::VerifyAndClearExpectations(&driver);
 902+
 903+    /* Release regular key. */
 904+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 905+    regular_key.release();
 906+    run_one_scan_loop();
 907+    testing::Mock::VerifyAndClearExpectations(&driver);
 908+
 909+    /* Release mod-tap-hold key. */
 910+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 911+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P, KC_A)));
 912+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 913+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 914+    mod_tap_hold_key.release();
 915+    run_one_scan_loop();
 916+    testing::Mock::VerifyAndClearExpectations(&driver);
 917+
 918+    /* Idle for tapping term of mod tap hold key. */
 919+    idle_for(TAPPING_TERM - 3);
 920+    testing::Mock::VerifyAndClearExpectations(&driver);
 921+}
 922+
 923+TEST_F(DefaultTapHold, tap_mod_tap_key_while_mod_tap_key_is_held) {
 924+    TestDriver driver;
 925+    InSequence s;
 926+    auto       first_mod_tap_hold_key  = KeymapKey(0, 1, 0, SFT_T(KC_P));
 927+    auto       second_mod_tap_hold_key = KeymapKey(0, 2, 0, RSFT_T(KC_A));
 928+
 929+    set_keymap({first_mod_tap_hold_key, second_mod_tap_hold_key});
 930+
 931+    /* Press first mod-tap-hold key */
 932+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 933+    first_mod_tap_hold_key.press();
 934+    run_one_scan_loop();
 935+    testing::Mock::VerifyAndClearExpectations(&driver);
 936+
 937+    /* Press second tap-hold key */
 938+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 939+    second_mod_tap_hold_key.press();
 940+    run_one_scan_loop();
 941+    testing::Mock::VerifyAndClearExpectations(&driver);
 942+
 943+    /* Release second tap-hold key */
 944+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
 945+    second_mod_tap_hold_key.release();
 946+    run_one_scan_loop();
 947+    testing::Mock::VerifyAndClearExpectations(&driver);
 948+
 949+    /* Release first mod-tap-hold key */
 950+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 951+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P, KC_A)));
 952+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
 953+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
 954diff --git a/tests/tap_hold_configurations/ignore_mod_tap_interrupt/config.h b/tests/tap_hold_configurations/ignore_mod_tap_interrupt/config.h
 955new file mode 100644
 956index 0000000000000000000000000000000000000000..5955b8600a8750f244ef051d401a201c2dea5a76
 957--- /dev/null
 958+++ b/tests/tap_hold_configurations/ignore_mod_tap_interrupt/config.h
 959@@ -0,0 +1,21 @@
 960+/* Copyright 2021 Stefan Kerkmann
 961+ *
 962+ * This program is free software: you can redistribute it and/or modify
 963+ * it under the terms of the GNU General Public License as published by
 964+ * the Free Software Foundation, either version 2 of the License, or
 965+ * (at your option) any later version.
 966+ *
 967+ * This program is distributed in the hope that it will be useful,
 968+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 969+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 970+ * GNU General Public License for more details.
 971+ *
 972+ * You should have received a copy of the GNU General Public License
 973+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 974+ */
 975+
 976+#pragma once
 977+
 978+#include "test_common.h"
 979+
 980+#define IGNORE_MOD_TAP_INTERRUPT
 981diff --git a/tests/tap_hold_configurations/ignore_mod_tap_interrupt/test.mk b/tests/tap_hold_configurations/ignore_mod_tap_interrupt/test.mk
 982new file mode 100644
 983index 0000000000000000000000000000000000000000..efecca2c22f09099d78348c694cede8d28467229
 984--- /dev/null
 985+++ b/tests/tap_hold_configurations/ignore_mod_tap_interrupt/test.mk
 986@@ -0,0 +1,18 @@
 987+# Copyright 2021 Stefan Kerkmann
 988+#
 989+# This program is free software: you can redistribute it and/or modify
 990+# it under the terms of the GNU General Public License as published by
 991+# the Free Software Foundation, either version 2 of the License, or
 992+# (at your option) any later version.
 993+#
 994+# This program is distributed in the hope that it will be useful,
 995+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 996+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 997+# GNU General Public License for more details.
 998+#
 999+# You should have received a copy of the GNU General Public License
1000+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1001+
1002+# --------------------------------------------------------------------------------
1003+# Keep this file, even if it is empty, as a marker that this folder contains tests
1004+# --------------------------------------------------------------------------------
1005diff --git a/tests/tap_hold_configurations/ignore_mod_tap_interrupt/test_tap_hold.cpp b/tests/tap_hold_configurations/ignore_mod_tap_interrupt/test_tap_hold.cpp
1006new file mode 100644
1007index 0000000000000000000000000000000000000000..1702d604d319e1ea9d6d0a4359d7ca15352a3019
1008--- /dev/null
1009+++ b/tests/tap_hold_configurations/ignore_mod_tap_interrupt/test_tap_hold.cpp
1010@@ -0,0 +1,136 @@
1011+/* Copyright 2021 Stefan Kerkmann
1012+ *
1013+ * This program is free software: you can redistribute it and/or modify
1014+ * it under the terms of the GNU General Public License as published by
1015+ * the Free Software Foundation, either version 2 of the License, or
1016+ * (at your option) any later version.
1017+ *
1018+ * This program is distributed in the hope that it will be useful,
1019+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1020+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1021+ * GNU General Public License for more details.
1022+ *
1023+ * You should have received a copy of the GNU General Public License
1024+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1025+ */
1026+
1027+#include "keyboard_report_util.hpp"
1028+#include "keycode.h"
1029+#include "test_common.hpp"
1030+#include "action_tapping.h"
1031+#include "test_fixture.hpp"
1032+#include "test_keymap_key.hpp"
1033+
1034+using testing::_;
1035+using testing::InSequence;
1036+
1037+class IgnoreModTapInterrupt : public TestFixture {};
1038+
1039+TEST_F(IgnoreModTapInterrupt, tap_regular_key_while_mod_tap_key_is_held) {
1040+    TestDriver driver;
1041+    InSequence s;
1042+    auto       mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
1043+    auto       regular_key      = KeymapKey(0, 2, 0, KC_A);
1044+
1045+    set_keymap({mod_tap_hold_key, regular_key});
1046+
1047+    /* Press mod-tap-hold key */
1048+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1049+    mod_tap_hold_key.press();
1050+    run_one_scan_loop();
1051+    testing::Mock::VerifyAndClearExpectations(&driver);
1052+
1053+    /* Press regular key */
1054+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1055+    regular_key.press();
1056+    run_one_scan_loop();
1057+    testing::Mock::VerifyAndClearExpectations(&driver);
1058+
1059+    /* Release regular key */
1060+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1061+    regular_key.release();
1062+    run_one_scan_loop();
1063+    testing::Mock::VerifyAndClearExpectations(&driver);
1064+
1065+    /* Release mod-tap-hold key */
1066+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1067+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A, KC_P)));
1068+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1069+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1070+    mod_tap_hold_key.release();
1071+    run_one_scan_loop();
1072+    testing::Mock::VerifyAndClearExpectations(&driver);
1073+}
1074+
1075+TEST_F(IgnoreModTapInterrupt, tap_mod_tap_key_while_mod_tap_key_is_held) {
1076+    TestDriver driver;
1077+    InSequence s;
1078+    auto       first_mod_tap_hold_key  = KeymapKey(0, 1, 0, SFT_T(KC_P));
1079+    auto       second_mod_tap_hold_key = KeymapKey(0, 2, 0, RSFT_T(KC_A));
1080+
1081+    set_keymap({first_mod_tap_hold_key, second_mod_tap_hold_key});
1082+
1083+    /* Press first mod-tap-hold key */
1084+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1085+    first_mod_tap_hold_key.press();
1086+    run_one_scan_loop();
1087+    testing::Mock::VerifyAndClearExpectations(&driver);
1088+
1089+    /* Press second tap-hold key */
1090+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1091+    second_mod_tap_hold_key.press();
1092+    run_one_scan_loop();
1093+    testing::Mock::VerifyAndClearExpectations(&driver);
1094+
1095+    /* Release second tap-hold key */
1096+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1097+    second_mod_tap_hold_key.release();
1098+    run_one_scan_loop();
1099+    testing::Mock::VerifyAndClearExpectations(&driver);
1100+
1101+    /* Release first mod-tap-hold key */
1102+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1103+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A, KC_P)));
1104+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1105+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1106+    first_mod_tap_hold_key.release();
1107+    run_one_scan_loop();
1108+    testing::Mock::VerifyAndClearExpectations(&driver);
1109+}
1110diff --git a/tests/tap_hold_configurations/permissive_hold/config.h b/tests/tap_hold_configurations/permissive_hold/config.h
1111new file mode 100644
1112index 0000000000000000000000000000000000000000..2d5a9849e7d7c72a68542b3905b3c2a037f3d25f
1113--- /dev/null
1114+++ b/tests/tap_hold_configurations/permissive_hold/config.h
1115@@ -0,0 +1,21 @@
1116+/* Copyright 2021 Stefan Kerkmann
1117+ *
1118+ * This program is free software: you can redistribute it and/or modify
1119+ * it under the terms of the GNU General Public License as published by
1120+ * the Free Software Foundation, either version 2 of the License, or
1121+ * (at your option) any later version.
1122+ *
1123+ * This program is distributed in the hope that it will be useful,
1124+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1125+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1126+ * GNU General Public License for more details.
1127+ *
1128+ * You should have received a copy of the GNU General Public License
1129+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1130+ */
1131+
1132+#pragma once
1133+
1134+#include "test_common.h"
1135+
1136+#define PERMISSIVE_HOLD
1137diff --git a/tests/tap_hold_configurations/permissive_hold/test.mk b/tests/tap_hold_configurations/permissive_hold/test.mk
1138new file mode 100644
1139index 0000000000000000000000000000000000000000..efecca2c22f09099d78348c694cede8d28467229
1140--- /dev/null
1141+++ b/tests/tap_hold_configurations/permissive_hold/test.mk
1142@@ -0,0 +1,18 @@
1143+# Copyright 2021 Stefan Kerkmann
1144+#
1145+# This program is free software: you can redistribute it and/or modify
1146+# it under the terms of the GNU General Public License as published by
1147+# the Free Software Foundation, either version 2 of the License, or
1148+# (at your option) any later version.
1149+#
1150+# This program is distributed in the hope that it will be useful,
1151+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1152+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1153+# GNU General Public License for more details.
1154+#
1155+# You should have received a copy of the GNU General Public License
1156+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1157+
1158+# --------------------------------------------------------------------------------
1159+# Keep this file, even if it is empty, as a marker that this folder contains tests
1160+# --------------------------------------------------------------------------------
1161diff --git a/tests/tap_hold_configurations/permissive_hold/test_one_shot_keys.cpp b/tests/tap_hold_configurations/permissive_hold/test_one_shot_keys.cpp
1162new file mode 100644
1163index 0000000000000000000000000000000000000000..aa71ec397f8af136a618a616243830471de37b9b
1164--- /dev/null
1165+++ b/tests/tap_hold_configurations/permissive_hold/test_one_shot_keys.cpp
1166@@ -0,0 +1,76 @@
1167+/* Copyright 2021 Stefan Kerkmann
1168+ *
1169+ * This program is free software: you can redistribute it and/or modify
1170+ * it under the terms of the GNU General Public License as published by
1171+ * the Free Software Foundation, either version 2 of the License, or
1172+ * (at your option) any later version.
1173+ *
1174+ * This program is distributed in the hope that it will be useful,
1175+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1176+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1177+ * GNU General Public License for more details.
1178+ *
1179+ * You should have received a copy of the GNU General Public License
1180+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1181+ */
1182+
1183+#include "action_util.h"
1184+#include "keyboard_report_util.hpp"
1185+#include "test_common.hpp"
1186+
1187+using testing::_;
1188+using testing::InSequence;
1189+
1190+class OneShot : public TestFixture {};
1191+class OneShotParametrizedTestFixture : public ::testing::WithParamInterface<std::pair<KeymapKey, KeymapKey>>, public OneShot {};
1192+
1193+TEST_P(OneShotParametrizedTestFixture, OSMAsRegularModifierWithAdditionalKeypress) {
1194+    TestDriver driver;
1195+    KeymapKey  osm_key     = GetParam().first;
1196+    KeymapKey  regular_key = GetParam().second;
1197+
1198+    set_keymap({osm_key, regular_key});
1199+
1200+    /* Press OSM */
1201+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1202+    osm_key.press();
1203+    run_one_scan_loop();
1204+    testing::Mock::VerifyAndClearExpectations(&driver);
1205+
1206+    /* Press regular key */
1207+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1208+    regular_key.press();
1209+    run_one_scan_loop();
1210+    testing::Mock::VerifyAndClearExpectations(&driver);
1211+
1212+    /* Release regular key */
1213+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(osm_key.report_code))).Times(2);
1214+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(regular_key.report_code, osm_key.report_code))).Times(1);
1215+    regular_key.release();
1216+    run_one_scan_loop();
1217+    testing::Mock::VerifyAndClearExpectations(&driver);
1218+
1219+    /* Release OSM */
1220+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1);
1221+    osm_key.release();
1222+    run_one_scan_loop();
1223+    testing::Mock::VerifyAndClearExpectations(&driver);
1224+}
1225+
1226+// clang-format off
1227+
1228+INSTANTIATE_TEST_CASE_P(
1229+    OneShotModifierTests,
1230+    OneShotParametrizedTestFixture,
1231+    ::testing::Values(
1232+        /* first is osm key, second is regular key. */
1233+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_LSFT), KC_LSFT}, KeymapKey{0, 1, 1, KC_A}),
1234+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_LCTL), KC_LCTL}, KeymapKey{0, 1, 1, KC_A}),
1235+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_LALT), KC_LALT}, KeymapKey{0, 1, 1, KC_A}),
1236+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_LGUI), KC_LGUI}, KeymapKey{0, 1, 1, KC_A}),
1237+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_RCTL), KC_RCTL}, KeymapKey{0, 1, 1, KC_A}),
1238+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_RSFT), KC_RSFT}, KeymapKey{0, 1, 1, KC_A}),
1239+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_RALT), KC_RALT}, KeymapKey{0, 1, 1, KC_A}),
1240+        std::make_pair(KeymapKey{0, 0, 0, OSM(MOD_RGUI), KC_RGUI}, KeymapKey{0, 1, 1, KC_A})
1241+        ));
1242+// clang-format on
1243diff --git a/tests/tap_hold_configurations/permissive_hold/test_tap_hold.cpp b/tests/tap_hold_configurations/permissive_hold/test_tap_hold.cpp
1244new file mode 100644
1245index 0000000000000000000000000000000000000000..ab9dd1518bb2f2efee321c7437c505a467fead49
1246--- /dev/null
1247+++ b/tests/tap_hold_configurations/permissive_hold/test_tap_hold.cpp
1248@@ -0,0 +1,132 @@
1249+/* Copyright 2021 Stefan Kerkmann
1250+ *
1251+ * This program is free software: you can redistribute it and/or modify
1252+ * it under the terms of the GNU General Public License as published by
1253+ * the Free Software Foundation, either version 2 of the License, or
1254+ * (at your option) any later version.
1255+ *
1256+ * This program is distributed in the hope that it will be useful,
1257+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1258+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1259+ * GNU General Public License for more details.
1260+ *
1261+ * You should have received a copy of the GNU General Public License
1262+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1263+ */
1264+
1265+#include "keyboard_report_util.hpp"
1266+#include "keycode.h"
1267+#include "test_common.hpp"
1268+#include "action_tapping.h"
1269+#include "test_fixture.hpp"
1270+#include "test_keymap_key.hpp"
1271+
1272+using testing::_;
1273+using testing::InSequence;
1274+class PermissiveHold : public TestFixture {};
1275+
1276+TEST_F(PermissiveHold, tap_regular_key_while_mod_tap_key_is_held) {
1277+    TestDriver driver;
1278+    InSequence s;
1279+    auto       mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
1280+    auto       regular_key      = KeymapKey(0, 2, 0, KC_A);
1281+
1282+    set_keymap({mod_tap_hold_key, regular_key});
1283+
1284+    /* Press mod-tap-hold key */
1285+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1286+    mod_tap_hold_key.press();
1287+    run_one_scan_loop();
1288+    testing::Mock::VerifyAndClearExpectations(&driver);
1289+
1290+    /* Press regular key */
1291+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1292+    regular_key.press();
1293+    run_one_scan_loop();
1294+    testing::Mock::VerifyAndClearExpectations(&driver);
1295+
1296+    /* Release regular key */
1297+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT)));
1298+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT, regular_key.report_code)));
1299+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT)));
1300+    regular_key.release();
1301+    run_one_scan_loop();
1302+    testing::Mock::VerifyAndClearExpectations(&driver);
1303+
1304+    /* Release mod-tap-hold key */
1305+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1306+    mod_tap_hold_key.release();
1307+    run_one_scan_loop();
1308+    testing::Mock::VerifyAndClearExpectations(&driver);
1309+}
1310+
1311+TEST_F(PermissiveHold, tap_mod_tap_key_while_mod_tap_key_is_held) {
1312+    TestDriver driver;
1313+    InSequence s;
1314+    auto       first_mod_tap_hold_key  = KeymapKey(0, 1, 0, SFT_T(KC_P));
1315+    auto       second_mod_tap_hold_key = KeymapKey(0, 2, 0, RSFT_T(KC_A));
1316+
1317+    set_keymap({first_mod_tap_hold_key, second_mod_tap_hold_key});
1318+
1319+    /* Press first mod-tap-hold key */
1320+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1321+    first_mod_tap_hold_key.press();
1322+    run_one_scan_loop();
1323+    testing::Mock::VerifyAndClearExpectations(&driver);
1324+
1325+    /* Press second mod-tap-hold key */
1326+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1327+    second_mod_tap_hold_key.press();
1328+    run_one_scan_loop();
1329+    testing::Mock::VerifyAndClearExpectations(&driver);
1330+
1331+    /* Release second mod-tap-hold key */
1332+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT)));
1333+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT, second_mod_tap_hold_key.report_code)));
1334+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT)));
1335+    second_mod_tap_hold_key.release();
1336+    run_one_scan_loop();
1337+    testing::Mock::VerifyAndClearExpectations(&driver);
1338+
1339+    /* Release first mod-tap-hold key */
1340+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1341+    first_mod_tap_hold_key.release();
1342+    run_one_scan_loop();
1343+    testing::Mock::VerifyAndClearExpectations(&driver);
1344+}
1345+
1346+TEST_F(PermissiveHold, tap_regular_key_while_layer_tap_key_is_held) {
1347+    TestDriver driver;
1348diff --git a/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/config.h b/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/config.h
1349new file mode 100644
1350index 0000000000000000000000000000000000000000..a6abd50bbee792c480fefcbf1e015c84231a7540
1351--- /dev/null
1352+++ b/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/config.h
1353@@ -0,0 +1,22 @@
1354+/* Copyright 2021 Stefan Kerkmann
1355+ *
1356+ * This program is free software: you can redistribute it and/or modify
1357+ * it under the terms of the GNU General Public License as published by
1358+ * the Free Software Foundation, either version 2 of the License, or
1359+ * (at your option) any later version.
1360+ *
1361+ * This program is distributed in the hope that it will be useful,
1362+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1363+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1364+ * GNU General Public License for more details.
1365+ *
1366+ * You should have received a copy of the GNU General Public License
1367+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1368+ */
1369+
1370+#pragma once
1371+
1372+#include "test_common.h"
1373+
1374+#define IGNORE_MOD_TAP_INTERRUPT
1375+#define PERMISSIVE_HOLD
1376diff --git a/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/test.mk b/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/test.mk
1377new file mode 100644
1378index 0000000000000000000000000000000000000000..efecca2c22f09099d78348c694cede8d28467229
1379--- /dev/null
1380+++ b/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/test.mk
1381@@ -0,0 +1,18 @@
1382+# Copyright 2021 Stefan Kerkmann
1383+#
1384+# This program is free software: you can redistribute it and/or modify
1385+# it under the terms of the GNU General Public License as published by
1386+# the Free Software Foundation, either version 2 of the License, or
1387+# (at your option) any later version.
1388+#
1389+# This program is distributed in the hope that it will be useful,
1390+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1391+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1392+# GNU General Public License for more details.
1393+#
1394+# You should have received a copy of the GNU General Public License
1395+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1396+
1397+# --------------------------------------------------------------------------------
1398+# Keep this file, even if it is empty, as a marker that this folder contains tests
1399+# --------------------------------------------------------------------------------
1400diff --git a/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/test_tap_hold.cpp b/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/test_tap_hold.cpp
1401new file mode 100644
1402index 0000000000000000000000000000000000000000..67f394653f3a76964d5d0ce8c9fb71865b4cb642
1403--- /dev/null
1404+++ b/tests/tap_hold_configurations/permissive_hold_ignore_mod_tap_interrupt/test_tap_hold.cpp
1405@@ -0,0 +1,134 @@
1406+
1407+/* Copyright 2021 Stefan Kerkmann
1408+ *
1409+ * This program is free software: you can redistribute it and/or modify
1410+ * it under the terms of the GNU General Public License as published by
1411+ * the Free Software Foundation, either version 2 of the License, or
1412+ * (at your option) any later version.
1413+ *
1414+ * This program is distributed in the hope that it will be useful,
1415+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1416+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1417+ * GNU General Public License for more details.
1418+ *
1419+ * You should have received a copy of the GNU General Public License
1420+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1421+ */
1422+
1423+#include "keyboard_report_util.hpp"
1424+#include "keycode.h"
1425+#include "test_common.hpp"
1426+#include "action_tapping.h"
1427+#include "test_fixture.hpp"
1428+#include "test_keymap_key.hpp"
1429+
1430+using testing::_;
1431+using testing::InSequence;
1432+
1433+class PermissiveHold_IgnoreModTapInterrupt : public TestFixture {};
1434+
1435+TEST_F(PermissiveHold_IgnoreModTapInterrupt, tap_regular_key_while_mod_tap_key_is_held) {
1436+    TestDriver driver;
1437+    InSequence s;
1438+    auto       mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
1439+    auto       regular_key      = KeymapKey(0, 2, 0, KC_A);
1440+
1441+    set_keymap({mod_tap_hold_key, regular_key});
1442+
1443+    /* Press mod-tap-hold key */
1444+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1445+    mod_tap_hold_key.press();
1446+    run_one_scan_loop();
1447+    testing::Mock::VerifyAndClearExpectations(&driver);
1448+
1449+    /* Press regular key */
1450+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1451+    regular_key.press();
1452+    run_one_scan_loop();
1453+    testing::Mock::VerifyAndClearExpectations(&driver);
1454+
1455+    /* Release regular key */
1456+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1457+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT, KC_A)));
1458+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1459+    regular_key.release();
1460+    run_one_scan_loop();
1461+    testing::Mock::VerifyAndClearExpectations(&driver);
1462+
1463+    /* Release mod-tap-hold key */
1464+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1465+    mod_tap_hold_key.release();
1466+    run_one_scan_loop();
1467+    testing::Mock::VerifyAndClearExpectations(&driver);
1468+}
1469+
1470+TEST_F(PermissiveHold_IgnoreModTapInterrupt, tap_mod_tap_key_while_mod_tap_key_is_held) {
1471+    TestDriver driver;
1472+    InSequence s;
1473+    auto       first_mod_tap_hold_key  = KeymapKey(0, 1, 0, SFT_T(KC_P));
1474+    auto       second_mod_tap_hold_key = KeymapKey(0, 2, 0, RSFT_T(KC_A));
1475+
1476+    set_keymap({first_mod_tap_hold_key, second_mod_tap_hold_key});
1477+
1478+    /* Press first mod-tap-hold key */
1479+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1480+    first_mod_tap_hold_key.press();
1481+    run_one_scan_loop();
1482+    testing::Mock::VerifyAndClearExpectations(&driver);
1483+
1484+    /* Press second tap-hold key */
1485+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1486+    second_mod_tap_hold_key.press();
1487+    run_one_scan_loop();
1488+    testing::Mock::VerifyAndClearExpectations(&driver);
1489+
1490+    /* Release second tap-hold key */
1491+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1492+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT, KC_A)));
1493+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1494+    second_mod_tap_hold_key.release();
1495+    run_one_scan_loop();
1496+    testing::Mock::VerifyAndClearExpectations(&driver);
1497+
1498+    /* Release first mod-tap-hold key */
1499+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1500+    first_mod_tap_hold_key.release();
1501+    run_one_scan_loop();
1502+    testing::Mock::VerifyAndClearExpectations(&driver);
1503+}
1504+
1505diff --git a/tests/tap_hold_configurations/retro_tapping/config.h b/tests/tap_hold_configurations/retro_tapping/config.h
1506new file mode 100644
1507index 0000000000000000000000000000000000000000..4b38f2644b83d3df0a7deea08dd9cc5b8a5c623b
1508--- /dev/null
1509+++ b/tests/tap_hold_configurations/retro_tapping/config.h
1510@@ -0,0 +1,21 @@
1511+/* Copyright 2021 Stefan Kerkmann
1512+ *
1513+ * This program is free software: you can redistribute it and/or modify
1514+ * it under the terms of the GNU General Public License as published by
1515+ * the Free Software Foundation, either version 2 of the License, or
1516+ * (at your option) any later version.
1517+ *
1518+ * This program is distributed in the hope that it will be useful,
1519+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1520+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1521+ * GNU General Public License for more details.
1522+ *
1523+ * You should have received a copy of the GNU General Public License
1524+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1525+ */
1526+
1527+#pragma once
1528+
1529+#include "test_common.h"
1530+
1531+#define RETRO_TAPPING
1532diff --git a/tests/tap_hold_configurations/retro_tapping/test.mk b/tests/tap_hold_configurations/retro_tapping/test.mk
1533new file mode 100644
1534index 0000000000000000000000000000000000000000..efecca2c22f09099d78348c694cede8d28467229
1535--- /dev/null
1536+++ b/tests/tap_hold_configurations/retro_tapping/test.mk
1537@@ -0,0 +1,18 @@
1538+# Copyright 2021 Stefan Kerkmann
1539+#
1540+# This program is free software: you can redistribute it and/or modify
1541+# it under the terms of the GNU General Public License as published by
1542+# the Free Software Foundation, either version 2 of the License, or
1543+# (at your option) any later version.
1544+#
1545+# This program is distributed in the hope that it will be useful,
1546+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1547+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1548+# GNU General Public License for more details.
1549+#
1550+# You should have received a copy of the GNU General Public License
1551+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1552+
1553+# --------------------------------------------------------------------------------
1554+# Keep this file, even if it is empty, as a marker that this folder contains tests
1555+# --------------------------------------------------------------------------------
1556diff --git a/tests/tap_hold_configurations/retro_tapping/test_tap_hold.cpp b/tests/tap_hold_configurations/retro_tapping/test_tap_hold.cpp
1557new file mode 100644
1558index 0000000000000000000000000000000000000000..59ae77f78119ad329201c2592bf4147b47b50a7a
1559--- /dev/null
1560+++ b/tests/tap_hold_configurations/retro_tapping/test_tap_hold.cpp
1561@@ -0,0 +1,52 @@
1562+
1563+/* Copyright 2021 Stefan Kerkmann
1564+ *
1565+ * This program is free software: you can redistribute it and/or modify
1566+ * it under the terms of the GNU General Public License as published by
1567+ * the Free Software Foundation, either version 2 of the License, or
1568+ * (at your option) any later version.
1569+ *
1570+ * This program is distributed in the hope that it will be useful,
1571+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1572+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1573+ * GNU General Public License for more details.
1574+ *
1575+ * You should have received a copy of the GNU General Public License
1576+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1577+ */
1578+
1579+#include "keyboard_report_util.hpp"
1580+#include "keycode.h"
1581+#include "test_common.hpp"
1582+#include "action_tapping.h"
1583+#include "test_fixture.hpp"
1584+#include "test_keymap_key.hpp"
1585+
1586+using testing::_;
1587+using testing::InSequence;
1588+
1589+class RetroTapping : public TestFixture {};
1590+
1591+TEST_F(RetroTapping, tap_and_hold_mod_tap_hold_key) {
1592+    TestDriver driver;
1593+    InSequence s;
1594+    auto       mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
1595+
1596+    set_keymap({mod_tap_hold_key});
1597+
1598+    /* Press mod-tap-hold key. */
1599+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1600+    mod_tap_hold_key.press();
1601+    idle_for(TAPPING_TERM);
1602+    testing::Mock::VerifyAndClearExpectations(&driver);
1603+
1604+    /* Release mod-tap-hold key. */
1605+    /* TODO: Why is LSHIFT send at all? */
1606+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSHIFT)));
1607+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1608+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1609+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1610+    mod_tap_hold_key.release();
1611+    run_one_scan_loop();
1612+    testing::Mock::VerifyAndClearExpectations(&driver);
1613+}
1614diff --git a/tests/tap_hold_configurations/retro_tapping/test_tapping.cpp b/tests/tap_hold_configurations/retro_tapping/test_tapping.cpp
1615new file mode 100644
1616index 0000000000000000000000000000000000000000..cf23df8317186a010549dc82a44657372cb89f2c
1617--- /dev/null
1618+++ b/tests/tap_hold_configurations/retro_tapping/test_tapping.cpp
1619@@ -0,0 +1,112 @@
1620+/* Copyright 2021 Stefan Kerkmann
1621+ *
1622+ * This program is free software: you can redistribute it and/or modify
1623+ * it under the terms of the GNU General Public License as published by
1624+ * the Free Software Foundation, either version 2 of the License, or
1625+ * (at your option) any later version.
1626+ *
1627+ * This program is distributed in the hope that it will be useful,
1628+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1629+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1630+ * GNU General Public License for more details.
1631+ *
1632+ * You should have received a copy of the GNU General Public License
1633+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1634+ */
1635+
1636+#include "keyboard_report_util.hpp"
1637+#include "keycode.h"
1638+#include "test_common.hpp"
1639+#include "action_tapping.h"
1640+#include "test_keymap_key.hpp"
1641+
1642+using testing::_;
1643+using testing::InSequence;
1644+
1645+class Tapping : public TestFixture {};
1646+
1647+TEST_F(Tapping, HoldA_SHFT_T_KeyReportsShift) {
1648+    TestDriver driver;
1649+    InSequence s;
1650+    auto       mod_tap_hold_key = KeymapKey(0, 7, 0, SFT_T(KC_P));
1651+
1652+    set_keymap({mod_tap_hold_key});
1653+
1654+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1655+    mod_tap_hold_key.press();
1656+    idle_for(TAPPING_TERM);
1657+    testing::Mock::VerifyAndClearExpectations(&driver);
1658+
1659+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1660+    run_one_scan_loop();
1661+    testing::Mock::VerifyAndClearExpectations(&driver);
1662+
1663+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1664+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1665+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1666+    mod_tap_hold_key.release();
1667+    run_one_scan_loop();
1668+    testing::Mock::VerifyAndClearExpectations(&driver);
1669+}
1670+
1671+TEST_F(Tapping, ANewTapWithinTappingTermIsBuggy) {
1672+    TestDriver driver;
1673+    InSequence s;
1674+    auto       key_shift_hold_p_tap = KeymapKey(0, 7, 0, SFT_T(KC_P));
1675+
1676+    set_keymap({key_shift_hold_p_tap});
1677+
1678+    /* Press mod_tap_hold key */
1679+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1680+    key_shift_hold_p_tap.press();
1681+    run_one_scan_loop();
1682+    testing::Mock::VerifyAndClearExpectations(&driver);
1683+
1684+    /* Release mod_tap_hold key */
1685+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1686+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1687+    key_shift_hold_p_tap.release();
1688+    run_one_scan_loop();
1689+    testing::Mock::VerifyAndClearExpectations(&driver);
1690+
1691+    /* Press mod_tap_hold key again */
1692+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1693+    key_shift_hold_p_tap.press();
1694+    run_one_scan_loop();
1695+    testing::Mock::VerifyAndClearExpectations(&driver);
1696+
1697+    /* Release mod_tap_hold key again */
1698+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1699+    key_shift_hold_p_tap.release();
1700+    idle_for(TAPPING_TERM + 1);
1701+    testing::Mock::VerifyAndClearExpectations(&driver);
1702+
1703+    /* Press mod_tap_hold key again */
1704+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1705+    key_shift_hold_p_tap.press();
1706+    run_one_scan_loop();
1707+    testing::Mock::VerifyAndClearExpectations(&driver);
1708+
1709+    /* Release mod_tap_hold key again */
1710+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_P)));
1711+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1712+    key_shift_hold_p_tap.release();
1713+    idle_for(TAPPING_TERM + 1);
1714+    testing::Mock::VerifyAndClearExpectations(&driver);
1715+
1716+    /* Press mod_tap_hold key again */
1717+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1718+    key_shift_hold_p_tap.press();
1719diff --git a/tests/tap_hold_configurations/tapping_force_hold/config.h b/tests/tap_hold_configurations/tapping_force_hold/config.h
1720new file mode 100644
1721index 0000000000000000000000000000000000000000..3b4646338a3054aa404da289b7c4c68baa855488
1722--- /dev/null
1723+++ b/tests/tap_hold_configurations/tapping_force_hold/config.h
1724@@ -0,0 +1,21 @@
1725+/* Copyright 2021 Stefan Kerkmann
1726+ *
1727+ * This program is free software: you can redistribute it and/or modify
1728+ * it under the terms of the GNU General Public License as published by
1729+ * the Free Software Foundation, either version 2 of the License, or
1730+ * (at your option) any later version.
1731+ *
1732+ * This program is distributed in the hope that it will be useful,
1733+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1734+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1735+ * GNU General Public License for more details.
1736+ *
1737+ * You should have received a copy of the GNU General Public License
1738+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1739+ */
1740+
1741+#pragma once
1742+
1743+#include "test_common.h"
1744+
1745+#define TAPPING_FORCE_HOLD
1746diff --git a/tests/tap_hold_configurations/tapping_force_hold/test.mk b/tests/tap_hold_configurations/tapping_force_hold/test.mk
1747new file mode 100644
1748index 0000000000000000000000000000000000000000..efecca2c22f09099d78348c694cede8d28467229
1749--- /dev/null
1750+++ b/tests/tap_hold_configurations/tapping_force_hold/test.mk
1751@@ -0,0 +1,18 @@
1752+# Copyright 2021 Stefan Kerkmann
1753+#
1754+# This program is free software: you can redistribute it and/or modify
1755+# it under the terms of the GNU General Public License as published by
1756+# the Free Software Foundation, either version 2 of the License, or
1757+# (at your option) any later version.
1758+#
1759+# This program is distributed in the hope that it will be useful,
1760+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1761+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1762+# GNU General Public License for more details.
1763+#
1764+# You should have received a copy of the GNU General Public License
1765+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1766+
1767+# --------------------------------------------------------------------------------
1768+# Keep this file, even if it is empty, as a marker that this folder contains tests
1769+# --------------------------------------------------------------------------------
1770diff --git a/tests/tap_hold_configurations/tapping_force_hold/test_action_layer.cpp b/tests/tap_hold_configurations/tapping_force_hold/test_action_layer.cpp
1771new file mode 100644
1772index 0000000000000000000000000000000000000000..02416eed7365f18302c2eac201c8ff6f07f19a2a
1773--- /dev/null
1774+++ b/tests/tap_hold_configurations/tapping_force_hold/test_action_layer.cpp
1775@@ -0,0 +1,81 @@
1776+/* Copyright 2021 Stefan Kerkmann
1777+ *
1778+ * This program is free software: you can redistribute it and/or modify
1779+ * it under the terms of the GNU General Public License as published by
1780+ * the Free Software Foundation, either version 2 of the License, or
1781+ * (at your option) any later version.
1782+ *
1783+ * This program is distributed in the hope that it will be useful,
1784+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1785+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1786+ * GNU General Public License for more details.
1787+ *
1788+ * You should have received a copy of the GNU General Public License
1789+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1790+ */
1791+
1792+#include "keyboard_report_util.hpp"
1793+#include "test_common.hpp"
1794+
1795+using testing::_;
1796+using testing::InSequence;
1797+
1798+class ActionLayer : public TestFixture {};
1799+
1800+TEST_F(ActionLayer, LayerTapToggleWithToggleWithKeypress) {
1801+    TestDriver driver;
1802+    KeymapKey  layer_key = KeymapKey{0, 0, 0, TT(1)};
1803+
1804+    /* These keys must have the same position in the matrix, only the layer is different. */
1805+    KeymapKey regular_key = KeymapKey{0, 1, 0, KC_A};
1806+    set_keymap({layer_key, regular_key, KeymapKey{1, 1, 0, KC_B}});
1807+
1808+    /* Tap TT five times . */
1809+    /* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */
1810+    /* TODO: Tapping Force Hold breaks TT */
1811+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(10);
1812+
1813+    layer_key.press();
1814+    run_one_scan_loop();
1815+    layer_key.release();
1816+    run_one_scan_loop();
1817+    expect_layer_state(0);
1818+
1819+    layer_key.press();
1820+    run_one_scan_loop();
1821+    layer_key.release();
1822+    run_one_scan_loop();
1823+    expect_layer_state(0);
1824+
1825+    layer_key.press();
1826+    run_one_scan_loop();
1827+    layer_key.release();
1828+    run_one_scan_loop();
1829+    expect_layer_state(0);
1830+
1831+    layer_key.press();
1832+    run_one_scan_loop();
1833+    layer_key.release();
1834+    run_one_scan_loop();
1835+    expect_layer_state(0);
1836+
1837+    layer_key.press();
1838+    run_one_scan_loop();
1839+    layer_key.release();
1840+    run_one_scan_loop();
1841+    expect_layer_state(0);
1842+
1843+    testing::Mock::VerifyAndClearExpectations(&driver);
1844+
1845+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A))).Times(1);
1846+    regular_key.press();
1847+    run_one_scan_loop();
1848+    expect_layer_state(0);
1849+    testing::Mock::VerifyAndClearExpectations(&driver);
1850+
1851+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1);
1852+    regular_key.release();
1853+    run_one_scan_loop();
1854+    expect_layer_state(0);
1855+    testing::Mock::VerifyAndClearExpectations(&driver);
1856+}
1857diff --git a/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp b/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp
1858new file mode 100644
1859index 0000000000000000000000000000000000000000..cb6842961724dca048652e0a4c283d7dcf42c38b
1860--- /dev/null
1861+++ b/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp
1862@@ -0,0 +1,215 @@
1863+
1864+/* Copyright 2021 Stefan Kerkmann
1865+ *
1866+ * This program is free software: you can redistribute it and/or modify
1867+ * it under the terms of the GNU General Public License as published by
1868+ * the Free Software Foundation, either version 2 of the License, or
1869+ * (at your option) any later version.
1870+ *
1871+ * This program is distributed in the hope that it will be useful,
1872+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1873+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1874+ * GNU General Public License for more details.
1875+ *
1876+ * You should have received a copy of the GNU General Public License
1877+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1878+ */
1879+
1880+#include "keyboard_report_util.hpp"
1881+#include "keycode.h"
1882+#include "test_common.hpp"
1883+#include "action_tapping.h"
1884+#include "test_fixture.hpp"
1885+#include "test_keymap_key.hpp"
1886+
1887+using testing::_;
1888+using testing::InSequence;
1889+
1890+class TappingForceHold : public TestFixture {};
1891+
1892+TEST_F(TappingForceHold, tap_regular_key_while_mod_tap_key_is_held) {
1893+    TestDriver driver;
1894+    InSequence s;
1895+    auto       mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
1896+    auto       regular_key      = KeymapKey(0, 2, 0, KC_A);
1897+
1898+    set_keymap({mod_tap_hold_key, regular_key});
1899+
1900+    /* Press mod-tap-hold key. */
1901+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1902+    mod_tap_hold_key.press();
1903+    run_one_scan_loop();
1904+    testing::Mock::VerifyAndClearExpectations(&driver);
1905+
1906+    /* Press regular key. */
1907+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1908+    regular_key.press();
1909+    run_one_scan_loop();
1910+    testing::Mock::VerifyAndClearExpectations(&driver);
1911+
1912+    /* Release regular key. */
1913+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1914+    regular_key.release();
1915+    run_one_scan_loop();
1916+    testing::Mock::VerifyAndClearExpectations(&driver);
1917+
1918+    /* Release mod-tap-hold key. */
1919+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1920+    mod_tap_hold_key.release();
1921+    run_one_scan_loop();
1922+    testing::Mock::VerifyAndClearExpectations(&driver);
1923+
1924+    /* Idle for tapping term of mod tap hold key. */
1925+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1926+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT, KC_A)));
1927+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1928+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
1929+    idle_for(TAPPING_TERM - 3);
1930+    testing::Mock::VerifyAndClearExpectations(&driver);
1931+}
1932+
1933+TEST_F(TappingForceHold, tap_mod_tap_key_while_mod_tap_key_is_held) {
1934+    TestDriver driver;
1935+    InSequence s;
1936+    auto       first_mod_tap_hold_key  = KeymapKey(0, 1, 0, SFT_T(KC_P));
1937+    auto       second_mod_tap_hold_key = KeymapKey(0, 2, 0, RSFT_T(KC_A));
1938+
1939+    set_keymap({first_mod_tap_hold_key, second_mod_tap_hold_key});
1940+
1941+    /* Press first mod-tap-hold key */
1942+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1943+    first_mod_tap_hold_key.press();
1944+    run_one_scan_loop();
1945+    testing::Mock::VerifyAndClearExpectations(&driver);
1946+
1947+    /* Press second tap-hold key */
1948+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1949+    second_mod_tap_hold_key.press();
1950+    run_one_scan_loop();
1951+    testing::Mock::VerifyAndClearExpectations(&driver);
1952+
1953+    /* Release second tap-hold key */
1954+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
1955+    second_mod_tap_hold_key.release();
1956+    run_one_scan_loop();
1957+    testing::Mock::VerifyAndClearExpectations(&driver);
1958+
1959+    /* Release first mod-tap-hold key */
1960+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT)));
1961+    first_mod_tap_hold_key.release();
1962diff --git a/tests/basic/rules.mk b/tests/test_common/build.mk
1963rename from tests/basic/rules.mk
1964rename to tests/test_common/build.mk
1965index 9fb5d436109604765e9f0d930f61f307705f4008..aeb30578549a2205ee695f7ec64349a206343564 100644
1966--- a/tests/basic/rules.mk
1967+++ b/tests/test_common/build.mk
1968@@ -1,4 +1,4 @@
1969-# Copyright 2017 Fred Sundvik
1970+# Copyright 2021 Stefan Kerkmann
1971 #
1972 # This program is free software: you can redistribute it and/or modify
1973 # it under the terms of the GNU General Public License as published by
1974@@ -13,4 +13,4 @@
1975 # You should have received a copy of the GNU General Public License
1976 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
1977 
1978-CUSTOM_MATRIX=yes
1979+CUSTOM_MATRIX=yes
1980diff --git a/tests/test_common/keyboard_report_util.cpp b/tests/test_common/keyboard_report_util.cpp
1981index f73cf239e0505c5102d1b4c5e06830e34a1abf42..e148c76beb7ed8e5a9f6b85990db478575f32ecb 100644
1982--- a/tests/test_common/keyboard_report_util.cpp
1983+++ b/tests/test_common/keyboard_report_util.cpp
1984@@ -44,16 +44,21 @@ bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs) {
1985     return lhs.mods == rhs.mods && lhskeys == rhskeys;
1986 }
1987 
1988-std::ostream& operator<<(std::ostream& stream, const report_keyboard_t& value) {
1989-    stream << "Keyboard report:" << std::endl;
1990-    stream << "Mods: " << (uint32_t)value.mods << std::endl;
1991-    stream << "Keys: ";
1992+std::ostream& operator<<(std::ostream& stream, const report_keyboard_t& report) {
1993+    auto keys = get_keys(report);
1994+
1995     // TODO: This should probably print friendly names for the keys
1996-    for (uint32_t k : get_keys(value)) {
1997-        stream << k << " ";
1998+    stream << "Keyboard Report: Mods (" << (uint32_t)report.mods << ") Keys (";
1999+
2000+    for (auto key = keys.cbegin(); key != keys.cend();) {
2001+        stream << +(*key);
2002+        key++;
2003+        if (key != keys.cend()) {
2004+            stream << ",";
2005+        }
2006     }
2007-    stream << std::endl;
2008-    return stream;
2009+
2010+    return stream << ")" << std::endl;
2011 }
2012 
2013 KeyboardReportMatcher::KeyboardReportMatcher(const std::vector<uint8_t>& keys) {
2014diff --git a/tests/test_common/keymap.c b/tests/test_common/keymap.c
2015new file mode 100644
2016index 0000000000000000000000000000000000000000..fc3a56a0073f34ad12762f59dadfaa810cec8a39
2017--- /dev/null
2018+++ b/tests/test_common/keymap.c
2019@@ -0,0 +1,33 @@
2020+/* Copyright 2017 Fred Sundvik
2021+ *
2022+ * This program is free software: you can redistribute it and/or modify
2023+ * it under the terms of the GNU General Public License as published by
2024+ * the Free Software Foundation, either version 2 of the License, or
2025+ * (at your option) any later version.
2026+ *
2027+ * This program is distributed in the hope that it will be useful,
2028+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2029+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2030+ * GNU General Public License for more details.
2031+ *
2032+ * You should have received a copy of the GNU General Public License
2033+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2034+ */
2035+
2036+#include "quantum.h"
2037+
2038+// clang-format off
2039+
2040+const uint16_t PROGMEM
2041+               keymaps[][MATRIX_ROWS][MATRIX_COLS] =
2042+        {
2043+            [0] =
2044+                {
2045+                   {KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
2046+                   {KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
2047+                   {KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
2048+                   {KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO},
2049+                },
2050+};
2051+
2052+// clang-format on
2053diff --git a/tests/test_common/test_common.h b/tests/test_common/test_common.h
2054new file mode 100644
2055index 0000000000000000000000000000000000000000..19ffcddceaec2cc3caf34ec5f9f647818e7b7caa
2056--- /dev/null
2057+++ b/tests/test_common/test_common.h
2058@@ -0,0 +1,4 @@
2059+#pragma once
2060+
2061+#define MATRIX_ROWS 4
2062+#define MATRIX_COLS 10
2063diff --git a/tests/test_common/test_driver.cpp b/tests/test_common/test_driver.cpp
2064index 84e249d838e523b016bccdb60bf3c888d7eb5975..2fa2b6a2e791a28b83307ca2af77c7fd1ae0603b 100644
2065--- a/tests/test_common/test_driver.cpp
2066+++ b/tests/test_common/test_driver.cpp
2067@@ -27,7 +27,10 @@ TestDriver::~TestDriver() { m_this = nullptr; }
2068 
2069 uint8_t TestDriver::keyboard_leds(void) { return m_this->m_leds; }
2070 
2071-void TestDriver::send_keyboard(report_keyboard_t* report) { m_this->send_keyboard_mock(*report); }
2072+void TestDriver::send_keyboard(report_keyboard_t* report) {
2073+    test_logger.trace() << *report;
2074+    m_this->send_keyboard_mock(*report);
2075+}
2076 
2077 void TestDriver::send_mouse(report_mouse_t* report) { m_this->send_mouse_mock(*report); }
2078 
2079diff --git a/tests/test_common/test_driver.hpp b/tests/test_common/test_driver.hpp
2080index f86308df95e1f9f7a1595d3f8a2f8d92a4dcecc6..f9197b3634b0cbf0e4db82809ea39c55f476df15 100644
2081--- a/tests/test_common/test_driver.hpp
2082+++ b/tests/test_common/test_driver.hpp
2083@@ -20,25 +20,26 @@
2084 #include <stdint.h>
2085 #include "host.h"
2086 #include "keyboard_report_util.hpp"
2087-
2088+#include "test_logger.hpp"
2089 
2090 class TestDriver {
2091-public:
2092+   public:
2093     TestDriver();
2094     ~TestDriver();
2095     void set_leds(uint8_t leds) { m_leds = leds; }
2096 
2097-    MOCK_METHOD1(send_keyboard_mock, void (report_keyboard_t&));
2098-    MOCK_METHOD1(send_mouse_mock, void (report_mouse_t&));
2099-    MOCK_METHOD1(send_system_mock, void (uint16_t));
2100-    MOCK_METHOD1(send_consumer_mock, void (uint16_t));
2101-private:
2102-    static uint8_t keyboard_leds(void);
2103-    static void send_keyboard(report_keyboard_t *report);
2104-    static void send_mouse(report_mouse_t* report);
2105-    static void send_system(uint16_t data);
2106-    static void send_consumer(uint16_t data);
2107-    host_driver_t m_driver;
2108-    uint8_t m_leds = 0;
2109+    MOCK_METHOD1(send_keyboard_mock, void(report_keyboard_t&));
2110+    MOCK_METHOD1(send_mouse_mock, void(report_mouse_t&));
2111+    MOCK_METHOD1(send_system_mock, void(uint16_t));
2112+    MOCK_METHOD1(send_consumer_mock, void(uint16_t));
2113+
2114+   private:
2115+    static uint8_t     keyboard_leds(void);
2116+    static void        send_keyboard(report_keyboard_t* report);
2117+    static void        send_mouse(report_mouse_t* report);
2118+    static void        send_system(uint16_t data);
2119+    static void        send_consumer(uint16_t data);
2120+    host_driver_t      m_driver;
2121+    uint8_t            m_leds = 0;
2122     static TestDriver* m_this;
2123 };
2124diff --git a/tests/test_common/test_fixture.cpp b/tests/test_common/test_fixture.cpp
2125index e041df7128df9e59e48622ea1a4266932619c0bf..0601b171913786a5b7df045f239fc6ae73183200 100644
2126--- a/tests/test_common/test_fixture.cpp
2127+++ b/tests/test_common/test_fixture.cpp
2128@@ -1,26 +1,48 @@
2129 #include "test_fixture.hpp"
2130+#include <algorithm>
2131+#include <cstdint>
2132+#include <cstdio>
2133+#include <cstdlib>
2134+#include "gmock/gmock-cardinalities.h"
2135 #include "gmock/gmock.h"
2136+#include "gtest/gtest.h"
2137+#include "keyboard_report_util.hpp"
2138+#include "keycode.h"
2139 #include "test_driver.hpp"
2140+#include "test_logger.hpp"
2141 #include "test_matrix.h"
2142-#include "keyboard.h"
2143-#include "action.h"
2144-#include "action_tapping.h"
2145+#include "test_keymap_key.hpp"
2146 
2147 extern "C" {
2148+#include "action.h"
2149+#include "action_tapping.h"
2150+#include "action_util.h"
2151+#include "action_layer.h"
2152 #include "debug.h"
2153 #include "eeconfig.h"
2154-#include "action_layer.h"
2155+#include "keyboard.h"
2156+#include "keymap.h"
2157 
2158 void set_time(uint32_t t);
2159 void advance_time(uint32_t ms);
2160 }
2161 
2162 using testing::_;
2163-using testing::AnyNumber;
2164-using testing::Between;
2165-using testing::Return;
2166+
2167+/* This is used for dynamic dispatching keymap_key_to_keycode calls to the current active test_fixture. */
2168+TestFixture* TestFixture::m_this = nullptr;
2169+
2170+/* Override weak QMK function to allow the usage of isolated per-test keymaps in unit-tests.
2171+ * The actual call is dynamicaly dispatched to the current active test fixture, which in turn has it's own keymap. */
2172+extern "C" uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t position) {
2173+    uint16_t keycode;
2174+    TestFixture::m_this->get_keycode(layer, position, &keycode);
2175+    return keycode;
2176+}
2177 
2178 void TestFixture::SetUpTestCase() {
2179+    test_logger.info() << "TestFixture setup-up start." << std::endl;
2180+
2181     // The following is enough to bootstrap the values set in main
2182     eeconfig_init_quantum();
2183     eeconfig_update_debug(debug_config.raw);
2184@@ -28,23 +50,99 @@ void TestFixture::SetUpTestCase() {
2185     TestDriver driver;
2186     EXPECT_CALL(driver, send_keyboard_mock(_));
2187     keyboard_init();
2188+
2189+    test_logger.info() << "TestFixture setup-up end." << std::endl;
2190 }
2191 
2192 void TestFixture::TearDownTestCase() {}
2193 
2194-TestFixture::TestFixture() {}
2195+TestFixture::TestFixture() { m_this = this; }
2196 
2197 TestFixture::~TestFixture() {
2198+    test_logger.info() << "TestFixture clean-up start." << std::endl;
2199     TestDriver driver;
2200-    // Run for a while to make sure all keys are completely released
2201-    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(AnyNumber());
2202-    layer_clear();
2203+
2204+    EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(2);
2205+
2206+    /* Reset keyboard state. */
2207     clear_all_keys();
2208-    idle_for(TAPPING_TERM + 10);
2209+
2210+    clear_keyboard();
2211+
2212+    clear_oneshot_mods();
2213+    clear_oneshot_locked_mods();
2214+    reset_oneshot_layer();
2215+
2216+    layer_clear();
2217+
2218+#if defined(SWAP_HANDS_ENABLE)
2219+    clear_oneshot_swaphands();
2220+#endif
2221+
2222+    idle_for(TAPPING_TERM * 10);
2223+    testing::Mock::VerifyAndClearExpectations(&driver);
2224+
2225+    /* Verify that the matrix really is cleared */
2226+    EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
2227+    idle_for(TAPPING_TERM * 10);
2228diff --git a/tests/test_common/test_fixture.hpp b/tests/test_common/test_fixture.hpp
2229index 340503665b67f60b0bed9c38e7576b221408acba..73b5d8d3e8e53ab4cc2aacee0544b790dc7c1881 100644
2230--- a/tests/test_common/test_fixture.hpp
2231+++ b/tests/test_common/test_fixture.hpp
2232@@ -16,15 +16,34 @@
2233 
2234 #pragma once
2235 
2236+#include <cstdint>
2237+#include <unordered_map>
2238+#include <optional>
2239 #include "gtest/gtest.h"
2240+#include "keyboard.h"
2241+#include "test_keymap_key.hpp"
2242 
2243 class TestFixture : public testing::Test {
2244-public:
2245+   public:
2246+    static TestFixture* m_this;
2247+
2248     TestFixture();
2249     ~TestFixture();
2250     static void SetUpTestCase();
2251     static void TearDownTestCase();
2252 
2253+    void set_keymap(std::initializer_list<KeymapKey> keycodes);
2254+    void add_key(const KeymapKey key);
2255+
2256+    const KeymapKey* find_key(const layer_t layer_t, const keypos_t position) const;
2257+    void                     get_keycode(const layer_t layer, const keypos_t position, uint16_t* result) const;
2258+
2259     void run_one_scan_loop();
2260     void idle_for(unsigned ms);
2261+
2262+    void expect_layer_state(layer_t layer) const;
2263+
2264+   protected:
2265+    void                   print_test_log() const;
2266+    std::vector<KeymapKey> keymap;
2267 };
2268diff --git a/tests/test_common/test_keymap_key.cpp b/tests/test_common/test_keymap_key.cpp
2269new file mode 100644
2270index 0000000000000000000000000000000000000000..878ae097bfa21f7fc0b2164b2368593b3d22c736
2271--- /dev/null
2272+++ b/tests/test_common/test_keymap_key.cpp
2273@@ -0,0 +1,30 @@
2274+/* Copyright 2021 Stefan Kerkmann
2275+ *
2276+ * This program is free software: you can redistribute it and/or modify
2277+ * it under the terms of the GNU General Public License as published by
2278+ * the Free Software Foundation, either version 2 of the License, or
2279+ * (at your option) any later version.
2280+ *
2281+ * This program is distributed in the hope that it will be useful,
2282+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2283+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2284+ * GNU General Public License for more details.
2285+ *
2286+ * You should have received a copy of the GNU General Public License
2287+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2288+ */
2289+
2290+#include "test_keymap_key.hpp"
2291+#include "test_logger.hpp"
2292+#include "gtest/gtest-message.h"
2293+#include "gtest/gtest.h"
2294+
2295+void KeymapKey::press() {
2296+    test_logger.trace() << "Key pressed:  (" << +this->position.col << "," << +this->position.row << ")" << std::endl;
2297+    press_key(this->position.col, this->position.row);
2298+}
2299+
2300+void KeymapKey::release() {
2301+    test_logger.trace() << "Key released: (" << +this->position.col << "," << +this->position.row << ")" << std::endl;
2302+    release_key(this->position.col, this->position.row);
2303+}
2304diff --git a/tests/test_common/test_keymap_key.hpp b/tests/test_common/test_keymap_key.hpp
2305new file mode 100644
2306index 0000000000000000000000000000000000000000..7861cb4a324e9845744dc090d557936649250108
2307--- /dev/null
2308+++ b/tests/test_common/test_keymap_key.hpp
2309@@ -0,0 +1,46 @@
2310+/* Copyright 2021 Stefan Kerkmann
2311+ *
2312+ * This program is free software: you can redistribute it and/or modify
2313+ * it under the terms of the GNU General Public License as published by
2314+ * the Free Software Foundation, either version 2 of the License, or
2315+ * (at your option) any later version.
2316+ *
2317+ * This program is distributed in the hope that it will be useful,
2318+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2319+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2320+ * GNU General Public License for more details.
2321+ *
2322+ * You should have received a copy of the GNU General Public License
2323+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2324+ */
2325+
2326+#pragma once
2327+
2328+extern "C" {
2329+#include "keyboard.h"
2330+#include "test_matrix.h"
2331+}
2332+
2333+#include <cassert>
2334+
2335+typedef uint8_t layer_t;
2336+
2337+struct KeymapKey {
2338+    KeymapKey(layer_t layer, uint8_t col, uint8_t row, uint16_t keycode) : layer(layer), position({.col = col, .row = row}), code(keycode), report_code(keycode) { validate(); }
2339+    KeymapKey(layer_t layer, uint8_t col, uint8_t row, uint16_t keycode, uint16_t report_code) : layer(layer), position({.col = col, .row = row}), code(keycode), report_code(report_code) { validate(); }
2340+
2341+    void press();
2342+    void release();
2343+
2344+    const layer_t  layer;
2345+    const keypos_t position;
2346+    const uint16_t code;
2347+    /* Sometimes the keycode does not match the code that is send in the usb report, so we provide it here. */
2348+    const uint16_t report_code;
2349+
2350+   private:
2351+    void validate() {
2352+        assert(position.col <= MATRIX_COLS);
2353+        assert(position.row <= MATRIX_ROWS);
2354+    }
2355+};
2356diff --git a/tests/test_common/test_logger.cpp b/tests/test_common/test_logger.cpp
2357new file mode 100644
2358index 0000000000000000000000000000000000000000..959fdde5ec56987cde6f6e9c75bdfdda97b06eba
2359--- /dev/null
2360+++ b/tests/test_common/test_logger.cpp
2361@@ -0,0 +1,39 @@
2362+/* Copyright 2021 Stefan Kerkmann
2363+ *
2364+ * This program is free software: you can redistribute it and/or modify
2365+ * it under the terms of the GNU General Public License as published by
2366+ * the Free Software Foundation, either version 2 of the License, or
2367+ * (at your option) any later version.
2368+ *
2369+ * This program is distributed in the hope that it will be useful,
2370+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2371+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2372+ * GNU General Public License for more details.
2373+ *
2374+ * You should have received a copy of the GNU General Public License
2375+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2376+ */
2377+
2378+#include <iostream>
2379+#include "test_logger.hpp"
2380+
2381+TestLogger test_logger;
2382+
2383+TestLogger& TestLogger::info() {
2384+    *this << "[ INFO     ] ";
2385+    return *this;
2386+}
2387+
2388+TestLogger& TestLogger::trace() {
2389+    *this << "[ TRACE    ] ";
2390+    return *this;
2391+}
2392+
2393+TestLogger& TestLogger::error() {
2394+    *this << "[ ERROR    ] ";
2395+    return *this;
2396+}
2397+
2398+void TestLogger::reset() { this->m_log.str(""); };
2399+
2400+void TestLogger::print_log() { std::cerr << this->m_log.str(); }
2401diff --git a/tests/test_common/test_logger.hpp b/tests/test_common/test_logger.hpp
2402new file mode 100644
2403index 0000000000000000000000000000000000000000..348af7fab860a088a08574252fd642b5de4aed6f
2404--- /dev/null
2405+++ b/tests/test_common/test_logger.hpp
2406@@ -0,0 +1,35 @@
2407+/* Copyright 2021 Stefan Kerkmann
2408+ *
2409+ * This program is free software: you can redistribute it and/or modify
2410+ * it under the terms of the GNU General Public License as published by
2411+ * the Free Software Foundation, either version 2 of the License, or
2412+ * (at your option) any later version.
2413+ *
2414+ * This program is distributed in the hope that it will be useful,
2415+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2416+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2417+ * GNU General Public License for more details.
2418+ *
2419+ * You should have received a copy of the GNU General Public License
2420+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2421+ */
2422+
2423+#pragma once
2424+
2425+#include <ostream>
2426+#include <sstream>
2427+
2428+class TestLogger : public std::ostream {
2429+   public:
2430+    TestLogger() : std::ostream(&m_log){};
2431+    TestLogger& info();
2432+    TestLogger& trace();
2433+    TestLogger& error();
2434+    void print_log();
2435+    void reset();
2436+
2437+   private:
2438+    std::stringbuf m_log;
2439+};
2440+
2441+extern TestLogger test_logger;