diff --git a/testing/Cycles.h b/testing/Cycles.h
new file mode 100644
index 00000000..93633c5e
--- /dev/null
+++ b/testing/Cycles.h
@@ -0,0 +1,29 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include
+
+namespace kaleidoscope {
+namespace testing {
+
+struct Cycles {
+ uint32_t value;
+};
+
+} // namespace testing
+} // namespace kaleidoscope
diff --git a/testing/ExpectedKeyboardReport.cpp b/testing/ExpectedKeyboardReport.cpp
index 152a5af5..ad4e3508 100644
--- a/testing/ExpectedKeyboardReport.cpp
+++ b/testing/ExpectedKeyboardReport.cpp
@@ -31,7 +31,7 @@ const std::set & ExpectedKeyboardReport::Keycodes() const {
return keycodes_;
}
-uint32_t ExpectedKeyboardReport::Timestamp() const {
+Millis ExpectedKeyboardReport::Timestamp() const {
return timestamp_;
}
diff --git a/testing/ExpectedKeyboardReport.h b/testing/ExpectedKeyboardReport.h
index 85ef298c..a87cfb20 100644
--- a/testing/ExpectedKeyboardReport.h
+++ b/testing/ExpectedKeyboardReport.h
@@ -21,23 +21,25 @@
#include
#include
+#include "testing/Millis.h"
+
namespace kaleidoscope {
namespace testing {
class ExpectedKeyboardReport {
public:
- ExpectedKeyboardReport(uint32_t timestamp,
+ ExpectedKeyboardReport(Millis timestamp,
const std::set & keycodes,
std::string message = "");
const std::set & Keycodes() const;
- uint32_t Timestamp() const;
+ Millis Timestamp() const;
const std::string & Message() const;
private:
- uint32_t timestamp_;
+ Millis timestamp_;
std::set keycodes_;
std::string failure_message_;
};
diff --git a/testing/Millis.h b/testing/Millis.h
new file mode 100644
index 00000000..77fc7b0f
--- /dev/null
+++ b/testing/Millis.h
@@ -0,0 +1,111 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include
+
+namespace kaleidoscope {
+namespace testing {
+
+struct Millis {
+ uint32_t value;
+
+ constexpr bool operator==(const Millis& other) const {
+ return this->value == other.value;
+ }
+ constexpr bool operator!=(const Millis& other) const {
+ return !(*this == other);
+ }
+ constexpr bool operator<(const Millis& other) const {
+ return this->value < other.value;
+ }
+ constexpr bool operator>(const Millis& other) const {
+ return this->value > other.value;
+ }
+ constexpr bool operator<=(const Millis& other) const {
+ return this->value <= other.value;
+ }
+ constexpr bool operator>=(const Millis& other) const {
+ return this->value >= other.value;
+ }
+
+ Millis operator+(const Millis& other) {
+ return Millis{this->value + other.value};
+ }
+ Millis operator-(const Millis& other) {
+ return Millis{this->value - other.value};
+ }
+ Millis operator+(const uint32_t raw) {
+ return Millis{this->value + raw};
+ }
+ Millis operator-(const uint32_t raw) {
+ return Millis{this->value - raw};
+ }
+
+ Millis& operator=(const uint32_t raw) {
+ this->value = raw;
+ return *this;
+ }
+ Millis& operator+=(const uint32_t raw) {
+ this->value += raw;
+ return *this;
+ }
+ Millis& operator-=(const uint32_t raw) {
+ this->value -= raw;
+ return *this;
+ }
+
+ constexpr bool operator<(uint32_t raw) const {
+ return this->value < raw;
+ }
+ constexpr bool operator>(uint32_t raw) const {
+ return this->value > raw;
+ }
+ constexpr bool operator<=(uint32_t raw) const {
+ return this->value <= raw;
+ }
+ constexpr bool operator>=(uint32_t raw) const {
+ return this->value >= raw;
+ }
+
+ operator size_t() {
+ return value;
+ }
+};
+
+constexpr bool operator<(uint32_t x, const Millis& y) {
+ return x < y.value;
+}
+constexpr bool operator>(uint32_t x, const Millis& y) {
+ return x > y.value;
+}
+constexpr bool operator<=(uint32_t x, const Millis& y) {
+ return x <= y.value;
+}
+constexpr bool operator>=(uint32_t x, const Millis& y) {
+ return x >= y.value;
+}
+
+constexpr Millis operator+(uint32_t x, const Millis& y) {
+ return Millis{x + y.value};
+}
+constexpr Millis operator-(uint32_t x, const Millis& y) {
+ return Millis{x - y.value};
+}
+
+} // namespace testing
+} // namespace kaleidoscope
diff --git a/testing/VirtualDeviceTest.cpp b/testing/VirtualDeviceTest.cpp
index 80d3a0d4..59b9ad92 100644
--- a/testing/VirtualDeviceTest.cpp
+++ b/testing/VirtualDeviceTest.cpp
@@ -31,6 +31,24 @@ std::unique_ptr VirtualDeviceTest::RunCycle() {
return State::Snapshot();
}
+// =============================================================================
+void VirtualDeviceTest::Run(Cycles n) {
+ sim_.RunCycles(n.value);
+}
+
+void VirtualDeviceTest::Run(Millis t) {
+ sim_.RunForMillis(t);
+}
+
+void VirtualDeviceTest::RunUntil(Millis end) {
+ uint32_t t0 = Runtime.millisAtCycleStart();
+ Run(Millis{end - t0});
+}
+
+void VirtualDeviceTest::RunFrom(Millis start, Millis t) {
+ RunUntil(Millis{start + t});
+}
+
// =============================================================================
void VirtualDeviceTest::LoadState() {
output_state_ = State::Snapshot();
@@ -47,24 +65,44 @@ const HIDState* VirtualDeviceTest::HIDReports() const {
return output_state_->HIDReports();
}
-uint32_t VirtualDeviceTest::ReportTimestamp(size_t index) const {
+Millis VirtualDeviceTest::ReportTimestamp(size_t index) const {
uint32_t t = output_state_->HIDReports()->Keyboard(index).Timestamp();
- return t;
+ return Millis{t};
}
// -----------------------------------------------------------------------------
-uint32_t VirtualDeviceTest::EventTimestamp(size_t index) const {
- return input_timestamps_[index];
+Millis VirtualDeviceTest::EventTimestamp(size_t index) const {
+ return Millis{input_timestamps_[index]};
}
// =============================================================================
void VirtualDeviceTest::PressKey(KeyAddr addr) {
sim_.Press(addr);
- input_timestamps_.push_back(Runtime.millisAtCycleStart());
+ input_timestamps_.push_back(Millis{Runtime.millisAtCycleStart()});
}
void VirtualDeviceTest::ReleaseKey(KeyAddr addr) {
sim_.Release(addr);
- input_timestamps_.push_back(Runtime.millisAtCycleStart());
+ input_timestamps_.push_back(Millis{Runtime.millisAtCycleStart()});
+}
+
+// -----------------------------------------------------------------------------
+void VirtualDeviceTest::PressKey(Cycles n, KeyAddr addr) {
+ sim_.RunCycles(n.value);
+ PressKey(addr);
+}
+void VirtualDeviceTest::ReleaseKey(Cycles n, KeyAddr addr) {
+ sim_.RunCycles(n.value);
+ ReleaseKey(addr);
+}
+
+// -----------------------------------------------------------------------------
+void VirtualDeviceTest::PressKey(Millis t, KeyAddr addr) {
+ sim_.RunForMillis(t);
+ PressKey(addr);
+}
+void VirtualDeviceTest::ReleaseKey(Millis t, KeyAddr addr) {
+ sim_.RunForMillis(t);
+ ReleaseKey(addr);
}
@@ -86,7 +124,7 @@ void VirtualDeviceTest::ExpectReport(Keycodes keys,
void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys,
RemoveKeycodes removed_keys,
std::string description) {
- uint32_t report_timestamp = Runtime.millisAtCycleStart();
+ Millis report_timestamp{Runtime.millisAtCycleStart()};
for (Key key : added_keys) {
AddToReport(key);
}
@@ -109,6 +147,34 @@ void VirtualDeviceTest::ExpectReport(RemoveKeycodes removed_keys,
ExpectReport(AddKeycodes{}, removed_keys, description);
}
+// -----------------------------------------------------------------------------
+void VirtualDeviceTest::ExpectReport(Cycles n,
+ AddKeycodes added_keys,
+ std::string description) {
+ sim_.RunCycles(n.value);
+ ExpectReport(added_keys, description);
+}
+void VirtualDeviceTest::ExpectReport(Cycles n,
+ RemoveKeycodes removed_keys,
+ std::string description) {
+ sim_.RunCycles(n.value);
+ ExpectReport(removed_keys, description);
+}
+
+// -----------------------------------------------------------------------------
+void VirtualDeviceTest::ExpectReport(Millis t,
+ AddKeycodes added_keys,
+ std::string description) {
+ sim_.RunForMillis(t);
+ ExpectReport(added_keys, description);
+}
+void VirtualDeviceTest::ExpectReport(Millis t,
+ RemoveKeycodes removed_keys,
+ std::string description) {
+ sim_.RunForMillis(t);
+ ExpectReport(removed_keys, description);
+}
+
// =============================================================================
void VirtualDeviceTest::ClearReport() {
current_keyboard_keycodes_.clear();
diff --git a/testing/VirtualDeviceTest.h b/testing/VirtualDeviceTest.h
index d2c17620..b5c61ba1 100644
--- a/testing/VirtualDeviceTest.h
+++ b/testing/VirtualDeviceTest.h
@@ -18,6 +18,8 @@
#include
+#include "testing/Cycles.h"
+#include "testing/Millis.h"
#include "testing/ExpectedKeyboardReport.h"
#include "testing/SimHarness.h"
#include "testing/State.h"
@@ -59,6 +61,24 @@ class VirtualDeviceTest : public ::testing::Test {
SimHarness sim_;
+ // ---------------------------------------------------------------------------
+ // Utility functions to advance time in the simulator.
+
+ // Run the simulator `n` cycles
+ void Run(Cycles n);
+
+ // Run the simulator `t` (virtual) milliseconds
+ void Run(Millis t);
+
+ // Run the simulator until the (virtual) clock reaches `end` milliseconds
+ void RunUntil(Millis end);
+
+ // Run the simulator until the (virtual) clock advances `t` milliseconds past
+ // `start`. This is most useful when testing timeouts based on an input event
+ // that is not the most recent one (e.g. a timeout following a keypress, but
+ // with a key release in between).
+ void RunFrom(Millis start, Millis t);
+
// ---------------------------------------------------------------------------
// A representation of the set of observed HID reports accumulated by the
// simulator as a testcase executes. It starts out empty, and a call to
@@ -79,21 +99,28 @@ class VirtualDeviceTest : public ::testing::Test {
const HIDState* HIDReports() const;
// Get the timestamp of a logged Keyboard HID report
- uint32_t ReportTimestamp(size_t index) const;
+ Millis ReportTimestamp(size_t index) const;
// ---------------------------------------------------------------------------
// A vector of timestamps for input events. Calls to `PressKey()` &
// `ReleaseKey()` append timestamps to it when called.
- std::vector input_timestamps_ = {};
+ std::vector input_timestamps_ = {};
// Get the timestamp of a logged input event from `output_state_`
- uint32_t EventTimestamp(size_t index) const;
+ Millis EventTimestamp(size_t index) const;
// ---------------------------------------------------------------------------
// Press/release a keyswitch & log the input event timestamp
void PressKey(KeyAddr addr);
void ReleaseKey(KeyAddr addr);
+ // Run for `n` cycles, then press/release a keyswitch
+ void PressKey(Cycles n, KeyAddr addr);
+ void ReleaseKey(Cycles n, KeyAddr addr);
+
+ // Run for `t` milliseconds, then press/release a keyswitch
+ void PressKey(Millis t, KeyAddr addr);
+ void ReleaseKey(Millis t, KeyAddr addr);
// ---------------------------------------------------------------------------
// The following functions all add an expected value of HID report to the
@@ -112,6 +139,12 @@ class VirtualDeviceTest : public ::testing::Test {
void ExpectReport(AddKeycodes added_keys, std::string description);
void ExpectReport(RemoveKeycodes removed_keys, std::string description);
+ void ExpectReport(Cycles n, AddKeycodes added_keys, std::string description);
+ void ExpectReport(Cycles n, RemoveKeycodes removed_keys, std::string description);
+
+ void ExpectReport(Millis t, AddKeycodes added_keys, std::string description);
+ void ExpectReport(Millis t, RemoveKeycodes removed_keys, std::string description);
+
// ---------------------------------------------------------------------------
std::set current_keyboard_keycodes_ = {};
// Manage the set of keycodes expected in the next report