blob: 62f8a7bc0f215d0bd63413b3c06287dbbaa9e257 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/ui/views/cpp/fidl.h>
#include <gtest/gtest.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include "focus_delegate.h"
#include "tests/fakes/focuser.h"
#include "tests/fakes/platform_message.h"
#include "tests/fakes/view_ref_focused.h"
#include "third_party/rapidjson/include/rapidjson/document.h"
rapidjson::Value ParsePlatformMessage(std::string json) {
rapidjson::Document document;
document.Parse(json);
if (document.HasParseError() || !document.IsObject()) {
FML_LOG(ERROR) << "Could not parse document";
return rapidjson::Value();
}
return document.GetObject();
}
namespace flutter_runner::testing {
class FocusDelegateTest : public ::testing::Test {
protected:
FocusDelegateTest() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {}
void RunLoopUntilIdle() { loop_.RunUntilIdle(); }
void SetUp() override {
vrf_ = std::make_unique<FakeViewRefFocused>();
focuser_ = std::make_unique<FakeFocuser>();
focus_delegate_ = std::make_unique<FocusDelegate>(
vrf_bindings.AddBinding(vrf_.get()),
focuser_bindings.AddBinding(focuser_.get()));
}
void TearDown() override {
vrf_bindings.CloseAll();
focuser_bindings.CloseAll();
loop_.Quit();
loop_.ResetQuit();
}
std::unique_ptr<FakeViewRefFocused> vrf_;
std::unique_ptr<FakeFocuser> focuser_;
std::unique_ptr<FocusDelegate> focus_delegate_;
private:
async::Loop loop_;
fidl::BindingSet<ViewRefFocused> vrf_bindings;
fidl::BindingSet<Focuser> focuser_bindings;
FML_DISALLOW_COPY_AND_ASSIGN(FocusDelegateTest);
};
// Tests that WatchLoop() should callback and complete PlatformMessageResponses
// correctly, given a series of vrf invocations.
TEST_F(FocusDelegateTest, WatchCallbackSeries) {
std::vector<bool> vrf_states{false, true, true, false,
true, false, true, true};
std::size_t vrf_index = 0;
std::size_t callback_index = 0;
focus_delegate_->WatchLoop([&](bool focus_state) {
// Make sure the focus state that FocusDelegate gives us is consistent with
// what was fired from the vrf.
EXPECT_EQ(vrf_states[callback_index], focus_state);
// View.focus.getCurrent should complete with the current (up to date) focus
// state.
auto response = FakePlatformMessageResponse::Create();
EXPECT_TRUE(focus_delegate_->HandlePlatformMessage(
ParsePlatformMessage("{\"method\":\"View.focus.getCurrent\"}"),
response));
response->ExpectCompleted(focus_state ? "[true]" : "[false]");
// Ensure this callback always happens in lockstep with
// vrf_->ScheduleCallback.
EXPECT_EQ(vrf_index, callback_index++);
});
// Subsequent WatchLoop calls should not be respected.
focus_delegate_->WatchLoop([](bool _) {
ADD_FAILURE() << "Subsequent WatchLoops should not be respected!";
});
do {
// Ensure the next focus state is handled correctly.
auto response1 = FakePlatformMessageResponse::Create();
EXPECT_TRUE(focus_delegate_->HandlePlatformMessage(
ParsePlatformMessage("{\"method\":\"View.focus.getNext\"}"),
response1));
// Since there's already an outstanding PlatformMessageResponse, this one
// should be completed null.
auto response2 = FakePlatformMessageResponse::Create();
EXPECT_TRUE(focus_delegate_->HandlePlatformMessage(
ParsePlatformMessage("{\"method\":\"View.focus.getNext\"}"),
response2));
response2->ExpectCompleted("[null]");
// Post watch events and trigger the next vrf event.
RunLoopUntilIdle();
vrf_->ScheduleCallback(vrf_states[vrf_index]);
RunLoopUntilIdle();
// Next focus state should be completed by now.
response1->ExpectCompleted(vrf_states[vrf_index] ? "[true]" : "[false]");
// Check View.focus.getCurrent again, and increment vrf_index since we move
// on to the next focus state.
auto response3 = FakePlatformMessageResponse::Create();
EXPECT_TRUE(focus_delegate_->HandlePlatformMessage(
ParsePlatformMessage("{\"method\":\"View.focus.getCurrent\"}"),
response3));
response3->ExpectCompleted(vrf_states[vrf_index++] ? "[true]" : "[false]");
// vrf_->times_watched should always be 1 more than the amount of vrf events
// emitted.
EXPECT_EQ(vrf_index + 1, vrf_->times_watched);
} while (vrf_index < vrf_states.size());
}
// Tests that HandlePlatformMessage() completes a "View.focus.request" response
// with a non-error status code.
TEST_F(FocusDelegateTest, RequestFocusTest) {
// This "Mock" ViewRef serves as the target for the RequestFocus operation.
auto mock_view_ref_pair = scenic::ViewRefPair::New();
// Create the platform message request.
std::ostringstream message;
message << "{"
<< " \"method\":\"View.focus.request\","
<< " \"args\": {"
<< " \"viewRef\":"
<< mock_view_ref_pair.view_ref.reference.get() << " }"
<< "}";
// Dispatch the plaform message request with an expected completion response.
auto response = FakePlatformMessageResponse::Create();
EXPECT_TRUE(focus_delegate_->HandlePlatformMessage(
ParsePlatformMessage(message.str()), response));
RunLoopUntilIdle();
response->ExpectCompleted("[0]");
EXPECT_TRUE(focuser_->request_focus_called());
}
// Tests that HandlePlatformMessage() completes a "View.focus.request" response
// with a Error::DENIED status code.
TEST_F(FocusDelegateTest, RequestFocusFailTest) {
// This "Mock" ViewRef serves as the target for the RequestFocus operation.
auto mock_view_ref_pair = scenic::ViewRefPair::New();
// We're testing the focus failure case.
focuser_->fail_request_focus();
// Create the platform message request.
std::ostringstream message;
message << "{"
<< " \"method\":\"View.focus.request\","
<< " \"args\": {"
<< " \"viewRef\":"
<< mock_view_ref_pair.view_ref.reference.get() << " }"
<< "}";
// Dispatch the plaform message request with an expected completion response.
auto response = FakePlatformMessageResponse::Create();
EXPECT_TRUE(focus_delegate_->HandlePlatformMessage(
ParsePlatformMessage(message.str()), response));
RunLoopUntilIdle();
response->ExpectCompleted(
"[" +
std::to_string(
static_cast<std::underlying_type_t<fuchsia::ui::views::Error>>(
fuchsia::ui::views::Error::DENIED)) +
"]");
EXPECT_TRUE(focuser_->request_focus_called());
}
} // namespace flutter_runner::testing