diff --git a/tests/plugins/OneShot/basic/common.h b/tests/plugins/OneShot/basic/common.h
new file mode 100644
index 00000000..ada552b0
--- /dev/null
+++ b/tests/plugins/OneShot/basic/common.h
@@ -0,0 +1,33 @@
+// -*- mode: c++ -*-
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2020 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+#include "keymap.h"
+
+namespace kaleidoscope {
+namespace testing {
+
+constexpr uint16_t ONESHOT_TIMEOUT = 200;
+constexpr uint16_t ONESHOT_HOLD_TIMEOUT = 50;
+
+} // namespace testing
+} // namespace kaleidoscope
diff --git a/tests/plugins/OneShot/basic/keymap-overrides.h b/tests/plugins/OneShot/basic/keymap-overrides.h
new file mode 100644
index 00000000..d5526808
--- /dev/null
+++ b/tests/plugins/OneShot/basic/keymap-overrides.h
@@ -0,0 +1,45 @@
+// -*- mode: c++ -*-
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2020 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+#include "testing/keymap-defaults.h"
+
+#include
+
+namespace kaleidoscope {
+namespace testing {
+namespace keymap {
+
+class Keymap : public KeymapDefaults {
+ public:
+ // Layer 0
+ static constexpr Key key_0AA = Key_S;
+ static constexpr Key key_0AB = Key_D;
+
+ static constexpr Key key_0BA = OSM(LeftShift);
+ static constexpr Key key_0BB = OSM(LeftGui);
+ static constexpr Key key_0BC = OSM(LeftControl);
+
+ static constexpr Key key_0CA = OSL(1);
+};
+
+} // namespace keymap
+} // namespace testing
+} // namespace kaleidoscope
diff --git a/tests/plugins/OneShot/basic/keymap.h b/tests/plugins/OneShot/basic/keymap.h
new file mode 100644
index 00000000..1a187167
--- /dev/null
+++ b/tests/plugins/OneShot/basic/keymap.h
@@ -0,0 +1,31 @@
+// -*- mode: c++ -*-
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2020 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+// Default key values to be used in sketches are defined from the
+// `keymap-defaults.h` file, provided by Kaleidoscope.
+#include "testing/keymap-defaults.h"
+
+// For keys of interest, the values can be overridden by defining them in the
+// `keymap-overrides.h` file, in this directory.
+#include "keymap-overrides.h"
+
+// Finally, we include this file so we can refer to key values in the keymap
+// more briefly (`key_0AA` vs `Keymap::key_0AA`, both in the
+// `kaleidoscope::testing::keymap` namespace).
+#include "testing/keymap-aliases.inc"
diff --git a/tests/plugins/OneShot/basic/sketch.ino b/tests/plugins/OneShot/basic/sketch.ino
new file mode 100644
index 00000000..c6a09555
--- /dev/null
+++ b/tests/plugins/OneShot/basic/sketch.ino
@@ -0,0 +1,39 @@
+/* -*- mode: c++ -*-
+ * Copyright (C) 2020 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#include
+#include
+
+#include "./common.h"
+#include "testing/default-layers.h"
+
+using namespace kaleidoscope::testing::keymap;
+
+KEYMAPS(LAYER_0, LAYER_1);
+
+// Use Qukeys
+KALEIDOSCOPE_INIT_PLUGINS(OneShot);
+
+void setup() {
+ Kaleidoscope.setup();
+
+ OneShot.time_out = kaleidoscope::testing::ONESHOT_TIMEOUT;
+ OneShot.hold_time_out = kaleidoscope::testing::ONESHOT_HOLD_TIMEOUT;
+}
+
+void loop() {
+ Kaleidoscope.loop();
+}
diff --git a/tests/plugins/OneShot/basic/test/testcase.cpp b/tests/plugins/OneShot/basic/test/testcase.cpp
new file mode 100644
index 00000000..9debf086
--- /dev/null
+++ b/tests/plugins/OneShot/basic/test/testcase.cpp
@@ -0,0 +1,81 @@
+/* -*- mode: c++ -*-
+ * Copyright (C) 2020 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#include "testing/setup-googletest.h"
+
+#include "../common.h"
+
+SETUP_GOOGLETEST();
+
+namespace kaleidoscope {
+namespace testing {
+namespace {
+
+using namespace kaleidoscope::testing::keymap;
+
+constexpr KeyAddr key_addr_OSM_LeftControl = addr_BC;
+constexpr KeyAddr key_addr_OSM_LeftGui = addr_BB;
+constexpr KeyAddr key_addr_OSM_LeftShift = addr_BA;
+constexpr KeyAddr key_addr_OSL_1 = addr_CA;
+constexpr KeyAddr key_addr_S = addr_AA;
+constexpr KeyAddr key_addr_D = addr_AB;
+
+class OneShotBasic : public VirtualDeviceTest {};
+
+TEST_F(OneShotBasic, OneShotModifier) {
+
+ // Tap `OSM(LeftShift)`
+ PressKey(Millis{10}, key_addr_OSM_LeftShift);
+ ExpectReport(Cycles{1}, AddKeycodes{Key_LeftShift},
+ "Report should contain only `LeftShift`");
+ ReleaseKey(Millis{20}, key_addr_OSM_LeftShift);
+
+ // Tap `Key_S`
+ PressKey(Millis{10}, key_addr_S);
+ ExpectReport(Cycles{1}, AddKeycodes{Key_S},
+ "Report should contain `LeftShift` & `S`");
+ ExpectReport(Cycles{1}, RemoveKeycodes{Key_LeftShift},
+ "Report should be contain only `S`");
+ ReleaseKey(Millis{10}, key_addr_S);
+ ExpectReport(Cycles{1}, RemoveKeycodes{Key_S},
+ "Report should be empty");
+
+ sim_.RunForMillis(10);
+
+
+ CHECK_EXPECTED_REPORTS()
+}
+
+TEST_F(OneShotBasic, OsmTimeout) {
+
+ ClearState();
+
+ // Tap `OSM(LeftShift)`
+ PressKey(Millis{10}, key_addr_OSM_LeftShift);
+ ExpectReport(Cycles{1}, AddKeycodes{Key_LeftShift},
+ "Report should contain only `LeftShift`");
+ ReleaseKey(Millis{20}, key_addr_OSM_LeftShift);
+
+ RunFrom(EventTimestamp(0), Millis{ONESHOT_TIMEOUT});
+ ExpectReport(Cycles{3}, RemoveKeycodes{Key_LeftShift},
+ "Report should be empty");
+
+ CHECK_EXPECTED_REPORTS()
+}
+
+} // namespace
+} // namespace testing
+} // namespace kaleidoscope