171 lines
7.3 KiB
C++
171 lines
7.3 KiB
C++
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <boost/asio/io_context.hpp>
|
|
#include <boost/asio/post.hpp>
|
|
|
|
#include <vamp_protocol/gesture.hpp>
|
|
#include <vamp_zero/touch_input.hpp>
|
|
|
|
|
|
namespace {
|
|
|
|
auto touch_event(luma::touch_phase phase, std::chrono::steady_clock::time_point time, std::int32_t id = 1) -> luma::touch_event {
|
|
return {.points = {{.id = id, .phase = phase}}, .time = time};
|
|
}
|
|
|
|
struct touch_sample {
|
|
std::bool_t pressed;
|
|
std::uint64_t milliseconds;
|
|
};
|
|
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(zero_and_pico_share_timestamped_gesture_transitions) {
|
|
auto sequences = std::vector<std::vector<touch_sample>>{
|
|
{{true, 0}, {false, 30}},
|
|
{{true, 0}, {false, 30}, {true, 200}, {false, 300}},
|
|
{{true, 0}, {false, 40}, {true, 180}, {false, 260}},
|
|
{{true, 0}, {false, 40}, {true, 180}, {false, 261}},
|
|
{{true, 0}, {false, 40}, {true, 261}, {false, 300}},
|
|
{{true, 50}, {true, 749}, {true, 750}, {true, 900}, {false, 910}},
|
|
{{true, 0}, {false, 40}, {true, 180}, {false, 880}},
|
|
{{true, 0}, {false, 699}},
|
|
{{true, 0}, {false, 700}},
|
|
};
|
|
auto expected = std::vector<std::vector<std::string>>{
|
|
{"next"},
|
|
{"next", "next"},
|
|
{"previous"},
|
|
{"next", "next"},
|
|
{"next", "next"},
|
|
{"select"},
|
|
{"select"},
|
|
{"next"},
|
|
{"select"},
|
|
};
|
|
for (auto index = std::size_t{}; index < sequences.size(); ++index) {
|
|
auto io = boost::asio::io_context{};
|
|
auto zero_commands = std::vector<std::string>{};
|
|
auto pico_commands = std::vector<std::string>{};
|
|
auto zero = vamp_zero::touch_input{io.get_executor(), [&](auto command) { zero_commands.emplace_back(vamp_protocol::page_command_name(command)); }};
|
|
auto pico = vamp_protocol::gesture_state{};
|
|
auto base = std::chrono::steady_clock::now() - std::chrono::seconds{10};
|
|
auto down = std::bool_t{false};
|
|
for (auto sample : sequences[index]) {
|
|
auto phase = sample.pressed ? (down ? luma::touch_phase::MOVE : luma::touch_phase::DOWN) : luma::touch_phase::UP;
|
|
BOOST_TEST(zero.handle(touch_event(phase, base + std::chrono::milliseconds{sample.milliseconds})));
|
|
if (auto command = pico.update(sample.pressed, sample.milliseconds)) {
|
|
pico_commands.emplace_back(vamp_protocol::page_command_name(*command));
|
|
}
|
|
down = sample.pressed;
|
|
}
|
|
if (auto command = pico.update(false, 2000U)) {
|
|
pico_commands.emplace_back(vamp_protocol::page_command_name(*command));
|
|
}
|
|
io.run();
|
|
BOOST_TEST(zero_commands == expected[index], boost::test_tools::per_element());
|
|
BOOST_TEST(pico_commands == expected[index], boost::test_tools::per_element());
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(shared_gesture_deadline_and_reset_discard_pending_actions) {
|
|
auto gesture = vamp_protocol::gesture_state{};
|
|
BOOST_TEST(!gesture.pending_deadline());
|
|
BOOST_TEST(!gesture.update(true, 0U));
|
|
BOOST_TEST(!gesture.update(false, 30U));
|
|
BOOST_REQUIRE(gesture.pending_deadline());
|
|
BOOST_TEST(*gesture.pending_deadline() == 251U);
|
|
BOOST_TEST(!gesture.update(false, 250U));
|
|
BOOST_TEST(!gesture.update(true, 250U));
|
|
BOOST_TEST(!gesture.pending_deadline());
|
|
gesture.reset();
|
|
BOOST_TEST(!gesture.pending_deadline());
|
|
BOOST_TEST(!gesture.update(false, 2000U));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(zero_touch_timer_emits_a_single_tap_without_further_input) {
|
|
auto io = boost::asio::io_context{};
|
|
auto commands = std::vector<std::string>{};
|
|
auto touch = vamp_zero::touch_input{io.get_executor(), [&](auto command) { commands.emplace_back(vamp_protocol::page_command_name(command)); }};
|
|
auto now = std::chrono::steady_clock::now();
|
|
touch.handle(touch_event(luma::touch_phase::DOWN, now));
|
|
touch.handle(touch_event(luma::touch_phase::UP, now));
|
|
io.poll();
|
|
BOOST_TEST(commands.empty());
|
|
io.run();
|
|
BOOST_REQUIRE_EQUAL(commands.size(), 1U);
|
|
BOOST_TEST(commands.front() == "next");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(zero_touch_filters_other_fingers_and_cancels_pending_actions) {
|
|
auto io = boost::asio::io_context{};
|
|
auto commands = std::vector<std::string>{};
|
|
auto touch = vamp_zero::touch_input{io.get_executor(), [&](auto command) { commands.emplace_back(vamp_protocol::page_command_name(command)); }};
|
|
auto base = std::chrono::steady_clock::now() - std::chrono::seconds{10};
|
|
BOOST_TEST(touch.handle(touch_event(luma::touch_phase::DOWN, base)));
|
|
BOOST_TEST(!touch.handle(touch_event(luma::touch_phase::DOWN, base, 2)));
|
|
BOOST_TEST(!touch.handle(touch_event(luma::touch_phase::UP, base, 2)));
|
|
BOOST_TEST(touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{30})));
|
|
BOOST_TEST(touch.handle(touch_event(luma::touch_phase::DOWN, base + std::chrono::milliseconds{200})));
|
|
BOOST_TEST(touch.handle(touch_event(luma::touch_phase::CANCEL, base + std::chrono::milliseconds{210})));
|
|
BOOST_TEST(!touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{220})));
|
|
io.run();
|
|
BOOST_TEST(commands.empty());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(zero_touch_stale_timer_cannot_consume_newer_gesture) {
|
|
auto io = boost::asio::io_context{};
|
|
auto commands = std::vector<std::string>{};
|
|
auto touch = vamp_zero::touch_input{io.get_executor(), [&](auto command) { commands.emplace_back(vamp_protocol::page_command_name(command)); }};
|
|
auto base = std::chrono::steady_clock::now() - std::chrono::seconds{10};
|
|
touch.handle(touch_event(luma::touch_phase::DOWN, base));
|
|
touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{30}));
|
|
boost::asio::post(io, [&] {
|
|
touch.handle(touch_event(luma::touch_phase::DOWN, base + std::chrono::milliseconds{200}));
|
|
touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{220}));
|
|
});
|
|
io.run();
|
|
BOOST_REQUIRE_EQUAL(commands.size(), 1U);
|
|
BOOST_TEST(commands.front() == "previous");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(zero_touch_stop_and_destruction_suppress_queued_commands) {
|
|
for (auto hold : {false, true}) {
|
|
auto io = boost::asio::io_context{};
|
|
auto commands = std::vector<std::string>{};
|
|
{
|
|
auto touch = vamp_zero::touch_input{io.get_executor(), [&](auto command) { commands.emplace_back(vamp_protocol::page_command_name(command)); }};
|
|
auto base = std::chrono::steady_clock::now() - std::chrono::seconds{10};
|
|
touch.handle(touch_event(luma::touch_phase::DOWN, base));
|
|
touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{hold ? 700 : 30}));
|
|
touch.stop();
|
|
BOOST_TEST(!touch.handle(touch_event(luma::touch_phase::DOWN, base)));
|
|
}
|
|
io.run();
|
|
BOOST_TEST(commands.empty());
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(zero_touch_reset_discards_old_score_gestures_but_accepts_new_input) {
|
|
auto io = boost::asio::io_context{};
|
|
auto commands = std::vector<std::string>{};
|
|
auto touch = vamp_zero::touch_input{io.get_executor(), [&](auto command) { commands.emplace_back(vamp_protocol::page_command_name(command)); }};
|
|
auto base = std::chrono::steady_clock::now() - std::chrono::seconds{10};
|
|
touch.handle(touch_event(luma::touch_phase::DOWN, base));
|
|
touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{700}));
|
|
touch.reset();
|
|
io.run();
|
|
BOOST_TEST(commands.empty());
|
|
io.restart();
|
|
touch.handle(touch_event(luma::touch_phase::DOWN, base));
|
|
touch.handle(touch_event(luma::touch_phase::UP, base + std::chrono::milliseconds{30}));
|
|
io.run();
|
|
BOOST_REQUIRE_EQUAL(commands.size(), 1U);
|
|
BOOST_TEST(commands.front() == "next");
|
|
}
|