Add event queue functions to testing infrastructure

This change adds a set of functions to the `VirtualDeviceTest` class to make it
possible to write simpler testcases involving timed keyswitch press and release
events along with corresponding keyboard HID reports.

Other outputs (Consumer & System Control HID reports, LEDs, et cetera) are
not yet included.
pull/966/head
Michael Richters 4 years ago committed by Jesse Vincent
parent a28a745059
commit 78e9ec4291
No known key found for this signature in database
GPG Key ID: CC228463465E40BC

@ -0,0 +1,43 @@
/* -*- 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 <http://www.gnu.org/licenses/>.
*/
#include "testing/ExpectedKeyboardReport.h"
namespace kaleidoscope {
namespace testing {
ExpectedKeyboardReport::ExpectedKeyboardReport(uint32_t timestamp,
const std::set<uint8_t> &keycodes,
std::string message) {
timestamp_ = timestamp;
keycodes_ = std::set<uint8_t>(keycodes);
failure_message_ = message;
}
const std::set<uint8_t> & ExpectedKeyboardReport::Keycodes() const {
return keycodes_;
}
uint32_t ExpectedKeyboardReport::Timestamp() const {
return timestamp_;
}
const std::string & ExpectedKeyboardReport::Message() const {
return failure_message_;
}
} // namespace testing
} // namespace kaleidoscope

@ -0,0 +1,46 @@
/* -*- 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <vector>
#include <set>
#include <string>
namespace kaleidoscope {
namespace testing {
class ExpectedKeyboardReport {
public:
ExpectedKeyboardReport(uint32_t timestamp,
const std::set<uint8_t> & keycodes,
std::string message = "");
const std::set<uint8_t> & Keycodes() const;
uint32_t Timestamp() const;
const std::string & Message() const;
private:
uint32_t timestamp_;
std::set<uint8_t> keycodes_;
std::string failure_message_;
};
} // namespace testing
} // namespace kaleidoscope

@ -31,5 +31,76 @@ std::unique_ptr<State> VirtualDeviceTest::RunCycle() {
return State::Snapshot();
}
// =============================================================================
void VirtualDeviceTest::LoadState() {
output_state_ = State::Snapshot();
}
void VirtualDeviceTest::ClearState() {
output_state_ = nullptr;
input_timestamps_.clear();
expected_reports_.clear();
}
const HIDState* VirtualDeviceTest::HIDReports() const {
if (output_state_ == nullptr) return nullptr;
return output_state_->HIDReports();
}
uint32_t VirtualDeviceTest::ReportTimestamp(size_t index) const {
uint32_t t = output_state_->HIDReports()->Keyboard(index).Timestamp();
return t;
}
// -----------------------------------------------------------------------------
uint32_t VirtualDeviceTest::EventTimestamp(size_t index) const {
return input_timestamps_[index];
}
// =============================================================================
void VirtualDeviceTest::PressKey(KeyAddr addr) {
sim_.Press(addr);
input_timestamps_.push_back(Runtime.millisAtCycleStart());
}
void VirtualDeviceTest::ReleaseKey(KeyAddr addr) {
sim_.Release(addr);
input_timestamps_.push_back(Runtime.millisAtCycleStart());
}
// =============================================================================
void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys,
RemoveKeycodes removed_keys,
std::string description) {
uint32_t report_timestamp = Runtime.millisAtCycleStart();
for (Key key : added_keys) {
AddToReport(key);
}
for (Key key : removed_keys) {
RemoveFromReport(key);
}
ExpectedKeyboardReport new_report(report_timestamp,
current_keyboard_keycodes_,
description);
expected_reports_.push_back(new_report);
}
// -----------------------------------------------------------------------------
void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys,
std::string description) {
ExpectReport(added_keys, RemoveKeycodes{}, description);
}
void VirtualDeviceTest::ExpectReport(RemoveKeycodes removed_keys,
std::string description) {
ExpectReport(AddKeycodes{}, removed_keys, description);
}
// =============================================================================
void VirtualDeviceTest::AddToReport(Key key) {
current_keyboard_keycodes_.insert(key.getKeyCode());
}
void VirtualDeviceTest::RemoveFromReport(Key key) {
current_keyboard_keycodes_.erase(key.getKeyCode());
}
} // namespace testing
} // namespace kaleidoscope

@ -18,6 +18,7 @@
#include <cstddef>
#include "testing/ExpectedKeyboardReport.h"
#include "testing/SimHarness.h"
#include "testing/State.h"
@ -29,6 +30,21 @@
namespace kaleidoscope {
namespace testing {
// -----------------------------------------------------------------------------
// Utility classes for use in `PressKey()`/`ReleaseKey()` & `ExpectReport()`
// method invocations. These make those calls simpler by providing
// differentiated types for those polymorphic functions.
class AddKeycodes : public std::set<Key> {
public:
AddKeycodes(std::initializer_list<Key> list) : std::set<Key>(list) {}
};
class RemoveKeycodes : public std::set<Key> {
public:
RemoveKeycodes(std::initializer_list<Key> list) : std::set<Key>(list) {}
};
// -----------------------------------------------------------------------------
// The base class for testcases
class VirtualDeviceTest : public ::testing::Test {
protected:
void SetUp();
@ -36,6 +52,65 @@ class VirtualDeviceTest : public ::testing::Test {
std::unique_ptr<State> RunCycle();
SimHarness sim_;
// ---------------------------------------------------------------------------
// 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
// `LoadState()` is required in order to load those reports into this
// `output_state_` variable so that they can be used.
std::unique_ptr<State> output_state_ = nullptr;
// Load any accumulated observed HID reports from the simulator (since the
// previous call to this function).
void LoadState();
// Clear previous state. This should be used at the beginning of each
// `TEST_F()` call to clear out any accumulated state in the input and output
// queues.
void ClearState();
// Get a pointer to the current list of observed HID reports
const HIDState* HIDReports() const;
// Get the timestamp of a logged Keyboard HID report
uint32_t ReportTimestamp(size_t index) const;
// ---------------------------------------------------------------------------
// A vector of timestamps for input events. Calls to `PressKey()` &
// `ReleaseKey()` append timestamps to it when called.
std::vector<uint32_t> input_timestamps_ = {};
// Get the timestamp of a logged input event from `output_state_`
uint32_t EventTimestamp(size_t index) const;
// ---------------------------------------------------------------------------
// Press/release a keyswitch & log the input event timestamp
void PressKey(KeyAddr addr);
void ReleaseKey(KeyAddr addr);
// ---------------------------------------------------------------------------
// The following functions all add an expected value of HID report to the
// queue. They specify modifications to the current (expected) report, and a
// message to display if verification fails. Some versions allow multiple
// keycode changes in a single report; others only a single keycode. Some run
// the simulator for a specified number of milliseconds or cycles first. These
// expected-value reports are all stored in a vector:
std::vector<ExpectedKeyboardReport> expected_reports_ = {};
void ExpectReport(AddKeycodes added_keys,
RemoveKeycodes removed_keys,
std::string description);
void ExpectReport(AddKeycodes added_keys, std::string description);
void ExpectReport(RemoveKeycodes removed_keys, std::string description);
// ---------------------------------------------------------------------------
std::set<uint8_t> current_keyboard_keycodes_ = {};
// Add to/remove from the set of keycodes expected in the next report
void AddToReport(Key key);
void RemoveFromReport(Key key);
};
} // namespace testing

Loading…
Cancel
Save