From d90820afc7fec7d50ec65578d0070b003ff3ccc1 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 27 Sep 2020 09:52:00 +0200 Subject: [PATCH] tests: Add a test case for activation-ordered layer switching The new test case exercises a few corners of the system: we test that without any layer changes, we start out on the right one. We also test that shifting to another layer preserves the current caching behaviour. We test that the layers are indeed looped through in activation order, rather than index order. And finally, we test that explicitly turning off the single active layer will have us fall back to layer 0. We only test layer shifts, not locks and moves, because we only changed the ordering, not how those behave otherwise. Signed-off-by: Gergely Nagy --- .../layers/activation-order/sketch.ino | 98 ++++++++++ .../layers/activation-order/test/testcase.cpp | 177 ++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 tests/features/layers/activation-order/sketch.ino create mode 100644 tests/features/layers/activation-order/test/testcase.cpp diff --git a/tests/features/layers/activation-order/sketch.ino b/tests/features/layers/activation-order/sketch.ino new file mode 100644 index 00000000..cf592980 --- /dev/null +++ b/tests/features/layers/activation-order/sketch.ino @@ -0,0 +1,98 @@ +/* -*- 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 "Kaleidoscope.h" + +#include "Kaleidoscope-Macros.h" + +// *INDENT-OFF* + +KEYMAPS( + [0] = KEYMAP_STACKED + ( + Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,M(0) + ,ShiftToLayer(1) + + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A ,Key_A + ,Key_A ,Key_A ,Key_A ,Key_A + ,ShiftToLayer(2) + ), + + [1] = KEYMAP_STACKED + ( + Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B + ,___ + + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B ,Key_B + ,Key_B ,Key_B ,Key_B ,Key_B + ,___ + ), + + [2] = KEYMAP_STACKED + ( + Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C + ,___ + + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C ,Key_C + ,Key_C ,Key_C ,Key_C ,Key_C + ,___ + ) +) // KEYMAPS( + +// *INDENT-ON* + +KALEIDOSCOPE_INIT_PLUGINS(Macros); + +const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) { + switch (macroIndex) { + case 0: + if (keyToggledOn(keyState)) + Layer.deactivate(0); + else + Layer.activate(0); + break; + } + return MACRO_NONE; +} + +void setup() { + Kaleidoscope.setup(); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/tests/features/layers/activation-order/test/testcase.cpp b/tests/features/layers/activation-order/test/testcase.cpp new file mode 100644 index 00000000..31ab26c1 --- /dev/null +++ b/tests/features/layers/activation-order/test/testcase.cpp @@ -0,0 +1,177 @@ +/* -*- 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" + +SETUP_GOOGLETEST(); + +namespace kaleidoscope { +namespace testing { +namespace { + +using ::testing::IsEmpty; + +class LayerActivationOrder : public VirtualDeviceTest { + public: + void SingleKeyTest(Key k) { + sim_.Press(0, 0); // k + auto state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(k)); + + sim_.Release(0, 0); // k + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + IsEmpty()); + + state = RunCycle(); + + // 2 cycles after releasing k + EXPECT_EQ(state->HIDReports()->Keyboard().size(), 0); + } +}; + +TEST_F(LayerActivationOrder, BaseLayerHasNotRegressed) { + SingleKeyTest(Key_A); +} + +TEST_F(LayerActivationOrder, ShifToLayerOne) { + // Pressing (3,6) shifts to Layer 1, and we stay there until release. + + sim_.Press(3, 6); // ShiftToLayer(1) + auto state = RunCycle(); + + SingleKeyTest(Key_B); + + // Releasing (3,6) gets us back to the base layer + sim_.Release(3, 6); // ShiftToLayer(1) + state = RunCycle(); + + SingleKeyTest(Key_A); +} + +TEST_F(LayerActivationOrder, ShiftingWithCaching) { + // Pressing (0, 0) will activate A + sim_.Press(0, 0); + auto state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_A)); + + // Pressing (3, 6) will switch to Layer 1 + sim_.Press(3, 6); + state = RunCycle(); + + // ...since we're still pressing (0, 0), and there was no change in the HID + // states, we shouldn't emit a report. + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 0); + + // Pressing (0, 1), the report shall contain 'A' _and_ 'B'. + sim_.Press(0, 1); + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_A)); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_B)); + + // Releasing (0, 0), the report should now contain B only + sim_.Release(0, 0); + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_B)); + + // Release (0, 1) + sim_.Release(0, 1); + state = RunCycle(); + + // Test B in isolation again + SingleKeyTest(Key_B); + + // Release the layer key as well. + sim_.Release(3, 6); + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 0); +} + +TEST_F(LayerActivationOrder, Ordering) { + // Pressing (3, 9) will switch to Layer 2 + sim_.Press(3, 9); + auto state = RunCycle(); + + // Pressing (0, 0) will activate 'C' + sim_.Press(0, 0); + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_C)); + + // Pressing (3, 6) will activate Layer 1 + sim_.Press(3, 6); + state = RunCycle(); + + // Pressing (0, 1) will activate 'B' now, due to activation ordering. + sim_.Press(0, 1); + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_C)); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_B)); + + sim_.Release(0, 0); + sim_.Release(0, 1); + sim_.Release(3, 6); + sim_.Release(3, 9); + state = RunCycle(); +} + +TEST_F(LayerActivationOrder, LayerZero) { + sim_.Press(3, 7); // Macro#0: Layer.deactivate(0) + auto state = RunCycle(); + + sim_.Press(0, 0); // A + state = RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT( + state->HIDReports()->Keyboard(0).ActiveKeycodes(), + Contains(Key_A)); +} + +} // namespace +} // namespace testing +} // namespace kaleidoscope