Files
kaleidoscope-mirror/testing/VirtualDeviceTest.h
Michael Richters 9b04d6663c Run IWYU (with the new tools) on test simulator code
This mixes some manual work (IWYU pragmas, a better solution to the Arduino
preprocessor macros problem) with automated running of the tools.  At this
point, it would be too much work to separate these into distinct commits, and
there isn't that much value to doing so.

There are still some things we could do to make things more robust, as some of
the headers need to be in a certain order, which happens to be in the same sort
order used by IWYU (`testing/*` files need to come after certain headers than
include `Arduino.h`), but it's probably not worth the clutter of adding an `#if
1` just to stop IWYU from re-ordering them.

I tried to get `#pragma push_macro("max")/pop_macro("max")` to work, but ended
up getting completely nonsensical compilation errors, so I gave up on it.

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
2022-05-08 12:48:59 -05:00

147 lines
5.8 KiB
C++

/* -*- mode: c++ -*-
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
*
* 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
// IWYU pragma: no_include <__memory/unique_ptr.h>
#include <cstddef> // for size_t
#include <cstdint> // for uint32_t, int8_t, uint8_t
#include <initializer_list> // for initializer_list
#include <memory> // IWYU pragma: keep
#include <set> // for set
#include <vector> // for vector
#include "kaleidoscope/KeyAddr.h" // for KeyAddr
#include "kaleidoscope/key_defs.h" // for Key
#include "testing/ExpectedKeyboardReport.h" // for ExpectedKeyboardReport
#include "testing/ExpectedMouseReport.h" // for ExpectedMouseReport
#include "testing/HIDState.h" // for HIDState
#include "testing/SimHarness.h" // for SimHarness
#include "testing/State.h" // for State
#include "testing/gtest.h" // for Test
#include "testing/iostream.h" // for string
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) {}
};
class Keycodes : public std::set<Key> {
public:
Keycodes(std::initializer_list<Key> list)
: std::set<Key>(list) {}
};
// -----------------------------------------------------------------------------
// The base class for testcases
class VirtualDeviceTest : public ::testing::Test {
protected:
void SetUp();
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_keyboard_reports_ = {};
void ExpectKeyboardReport(AddKeycodes added_keys,
RemoveKeycodes removed_keys,
std::string description);
void ExpectKeyboardReport(Keycodes added_keys, std::string description);
void ExpectKeyboardReport(AddKeycodes added_keys, std::string description);
void ExpectKeyboardReport(RemoveKeycodes removed_keys, std::string description);
std::vector<ExpectedMouseReport> expected_mouse_reports_ = {};
void ExpectMouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t v, int8_t h, std::string description);
// ---------------------------------------------------------------------------
std::set<uint8_t> current_keyboard_keycodes_ = {};
// Manage the set of keycodes expected in the next report
void ClearKeyboardReport();
void AddToKeyboardReport(Key key);
void RemoveFromKeyboardReport(Key key);
// ---------------------------------------------------------------------------
// Compare accumulated observed and expected reports, matching both timestamps
// and keycodes.
void CheckReports() const;
void CheckKeyboardReports() const;
void CheckMouseReports() const;
};
} // namespace testing
} // namespace kaleidoscope