blob: 02dbf0b26bb2bbe8696df6a4e03075118bd83d68 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "third_party/blink/renderer/modules/presentation/presentation_availability_state.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/modules/presentation/mock_presentation_service.h"
#include "third_party/blink/renderer/modules/presentation/presentation_availability_callbacks.h"
#include "third_party/blink/renderer/modules/presentation/presentation_availability_observer.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
using testing::_;
namespace blink {
using mojom::blink::ScreenAvailability;
class MockPresentationAvailabilityObserver
: public GarbageCollected<MockPresentationAvailabilityObserver>,
public PresentationAvailabilityObserver {
USING_GARBAGE_COLLECTED_MIXIN(MockPresentationAvailabilityObserver);
public:
explicit MockPresentationAvailabilityObserver(const Vector<KURL>& urls)
: urls_(urls) {}
~MockPresentationAvailabilityObserver() override = default;
MOCK_METHOD1(AvailabilityChanged, void(ScreenAvailability availability));
const Vector<KURL>& Urls() const override { return urls_; }
private:
const Vector<KURL> urls_;
};
class MockPresentationAvailabilityCallbacks
: public PresentationAvailabilityCallbacks {
public:
MockPresentationAvailabilityCallbacks()
: PresentationAvailabilityCallbacks(nullptr, WTF::Vector<KURL>()) {}
~MockPresentationAvailabilityCallbacks() override = default;
MOCK_METHOD1(Resolve, void(bool value));
MOCK_METHOD0(RejectAvailabilityNotSupported, void());
};
class PresentationAvailabilityStateTest : public testing::Test {
public:
PresentationAvailabilityStateTest()
: url1_(KURL("https://www.example.com/1.html")),
url2_(KURL("https://www.example.com/2.html")),
url3_(KURL("https://www.example.com/3.html")),
url4_(KURL("https://www.example.com/4.html")),
urls_({url1_, url2_, url3_, url4_}),
mock_observer_all_urls_(
MakeGarbageCollected<MockPresentationAvailabilityObserver>(urls_)),
mock_observer1_(
MakeGarbageCollected<MockPresentationAvailabilityObserver>(
Vector<KURL>({url1_, url2_, url3_}))),
mock_observer2_(
MakeGarbageCollected<MockPresentationAvailabilityObserver>(
Vector<KURL>({url2_, url3_, url4_}))),
mock_observer3_(
MakeGarbageCollected<MockPresentationAvailabilityObserver>(
Vector<KURL>({url2_, url3_}))),
mock_observers_({mock_observer1_, mock_observer2_, mock_observer3_}),
mock_presentation_service_(),
state_(MakeGarbageCollected<PresentationAvailabilityState>(
&mock_presentation_service_)) {}
~PresentationAvailabilityStateTest() override = default;
void ChangeURLState(const KURL& url, ScreenAvailability state) {
if (state != ScreenAvailability::UNKNOWN)
state_->UpdateAvailability(url, state);
}
void RequestAvailabilityAndAddObservers() {
for (auto& mock_observer : mock_observers_) {
state_->RequestAvailability(
mock_observer->Urls(),
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>());
state_->AddObserver(mock_observer);
}
}
// Tests that PresenationService is called for getAvailability(urls), after
// |urls| change state to |states|. This function takes ownership of
// |mock_callback|.
void TestRequestAvailability(
const Vector<KURL>& urls,
const Vector<ScreenAvailability>& states,
MockPresentationAvailabilityCallbacks* mock_callback) {
DCHECK_EQ(urls.size(), states.size());
for (const auto& url : urls) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url))
.Times(1);
}
state_->RequestAvailability(urls, mock_callback);
for (wtf_size_t i = 0; i < urls.size(); i++)
ChangeURLState(urls[i], states[i]);
}
protected:
const KURL url1_;
const KURL url2_;
const KURL url3_;
const KURL url4_;
const Vector<KURL> urls_;
Persistent<MockPresentationAvailabilityObserver> mock_observer_all_urls_;
Persistent<MockPresentationAvailabilityObserver> mock_observer1_;
Persistent<MockPresentationAvailabilityObserver> mock_observer2_;
Persistent<MockPresentationAvailabilityObserver> mock_observer3_;
Vector<Persistent<MockPresentationAvailabilityObserver>> mock_observers_;
MockPresentationService mock_presentation_service_;
Persistent<PresentationAvailabilityState> state_;
};
TEST_F(PresentationAvailabilityStateTest, RequestAvailability) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url));
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url));
}
state_->RequestAvailability(
urls_, MakeGarbageCollected<MockPresentationAvailabilityCallbacks>());
state_->UpdateAvailability(url1_, ScreenAvailability::AVAILABLE);
for (const auto& url : urls_)
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url));
state_->AddObserver(mock_observer_all_urls_);
EXPECT_CALL(*mock_observer_all_urls_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
state_->UpdateAvailability(url1_, ScreenAvailability::UNAVAILABLE);
EXPECT_CALL(*mock_observer_all_urls_,
AvailabilityChanged(ScreenAvailability::AVAILABLE));
state_->UpdateAvailability(url1_, ScreenAvailability::AVAILABLE);
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url));
}
state_->RemoveObserver(mock_observer_all_urls_);
// After RemoveObserver(), |mock_observer_all_urls_| should no longer be
// notified.
EXPECT_CALL(*mock_observer_all_urls_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE))
.Times(0);
state_->UpdateAvailability(url1_, ScreenAvailability::UNAVAILABLE);
}
TEST_F(PresentationAvailabilityStateTest,
ScreenAvailabilitySourceNotSupported) {
for (const auto& url : urls_)
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url));
state_->AddObserver(mock_observer_all_urls_);
EXPECT_CALL(*mock_observer_all_urls_,
AvailabilityChanged(ScreenAvailability::SOURCE_NOT_SUPPORTED));
state_->UpdateAvailability(url1_, ScreenAvailability::SOURCE_NOT_SUPPORTED);
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url));
}
state_->RemoveObserver(mock_observer_all_urls_);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlNoAvailabilityChange) {
auto* mock_callback = MakeGarbageCollected<
testing::StrictMock<MockPresentationAvailabilityCallbacks>>();
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url1_))
.Times(1);
state_->RequestAvailability(Vector<KURL>({url1_}), mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesAvailable) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, Resolve(true));
TestRequestAvailability({url1_}, {ScreenAvailability::AVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesNotCompatible) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, Resolve(false));
TestRequestAvailability({url1_}, {ScreenAvailability::SOURCE_NOT_SUPPORTED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesUnavailable) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, Resolve(false));
TestRequestAvailability({url1_}, {ScreenAvailability::UNAVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesUnsupported) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, RejectAvailabilityNotSupported());
TestRequestAvailability({url1_}, {ScreenAvailability::DISABLED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesAvailable) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, Resolve(true)).Times(1);
TestRequestAvailability(
{url1_, url2_},
{ScreenAvailability::AVAILABLE, ScreenAvailability::AVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesUnavailable) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, Resolve(false)).Times(1);
TestRequestAvailability(
{url1_, url2_},
{ScreenAvailability::UNAVAILABLE, ScreenAvailability::UNAVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesNotCompatible) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, Resolve(false)).Times(1);
TestRequestAvailability({url1_, url2_},
{ScreenAvailability::SOURCE_NOT_SUPPORTED,
ScreenAvailability::SOURCE_NOT_SUPPORTED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesUnsupported) {
auto* mock_callback =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback, RejectAvailabilityNotSupported()).Times(1);
TestRequestAvailability(
{url1_, url2_},
{ScreenAvailability::DISABLED, ScreenAvailability::DISABLED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityReturnsDirectlyForAlreadyListeningUrls) {
// First getAvailability() call.
auto* mock_callback_1 =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback_1, Resolve(false)).Times(1);
Vector<ScreenAvailability> state_seq = {ScreenAvailability::UNAVAILABLE,
ScreenAvailability::AVAILABLE,
ScreenAvailability::UNAVAILABLE};
TestRequestAvailability({url1_, url2_, url3_}, state_seq, mock_callback_1);
// Second getAvailability() call.
for (const auto& url : mock_observer3_->Urls()) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
}
auto* mock_callback_2 =
MakeGarbageCollected<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(*mock_callback_2, Resolve(true)).Times(1);
state_->RequestAvailability(mock_observer3_->Urls(), mock_callback_2);
}
TEST_F(PresentationAvailabilityStateTest, StartListeningListenToEachURLOnce) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
}
RequestAvailabilityAndAddObservers();
}
TEST_F(PresentationAvailabilityStateTest, StopListeningListenToEachURLOnce) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url))
.Times(1);
}
EXPECT_CALL(*mock_observer1_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
EXPECT_CALL(*mock_observer2_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
EXPECT_CALL(*mock_observer3_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
RequestAvailabilityAndAddObservers();
// Clean up callbacks.
ChangeURLState(url2_, ScreenAvailability::UNAVAILABLE);
for (auto& mock_observer : mock_observers_)
state_->RemoveObserver(mock_observer);
}
TEST_F(PresentationAvailabilityStateTest,
StopListeningDoesNotStopIfURLListenedByOthers) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
}
// |url1_| is only listened to by |observer1_|.
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url1_))
.Times(1);
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url2_))
.Times(0);
EXPECT_CALL(mock_presentation_service_,
StopListeningForScreenAvailability(url3_))
.Times(0);
RequestAvailabilityAndAddObservers();
for (auto& mock_observer : mock_observers_)
state_->AddObserver(mock_observer);
EXPECT_CALL(*mock_observer1_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
EXPECT_CALL(*mock_observer2_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
EXPECT_CALL(*mock_observer3_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
// Clean up callbacks.
ChangeURLState(url2_, ScreenAvailability::UNAVAILABLE);
state_->RemoveObserver(mock_observer1_);
}
TEST_F(PresentationAvailabilityStateTest,
UpdateAvailabilityInvokesAvailabilityChanged) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
}
EXPECT_CALL(*mock_observer1_,
AvailabilityChanged(ScreenAvailability::AVAILABLE));
RequestAvailabilityAndAddObservers();
ChangeURLState(url1_, ScreenAvailability::AVAILABLE);
EXPECT_CALL(*mock_observer1_,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
ChangeURLState(url1_, ScreenAvailability::UNAVAILABLE);
EXPECT_CALL(*mock_observer1_,
AvailabilityChanged(ScreenAvailability::SOURCE_NOT_SUPPORTED));
ChangeURLState(url1_, ScreenAvailability::SOURCE_NOT_SUPPORTED);
}
TEST_F(PresentationAvailabilityStateTest,
UpdateAvailabilityInvokesMultipleAvailabilityChanged) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
}
for (auto& mock_observer : mock_observers_) {
EXPECT_CALL(*mock_observer,
AvailabilityChanged(ScreenAvailability::AVAILABLE));
}
RequestAvailabilityAndAddObservers();
ChangeURLState(url2_, ScreenAvailability::AVAILABLE);
for (auto& mock_observer : mock_observers_) {
EXPECT_CALL(*mock_observer,
AvailabilityChanged(ScreenAvailability::UNAVAILABLE));
}
ChangeURLState(url2_, ScreenAvailability::UNAVAILABLE);
}
TEST_F(PresentationAvailabilityStateTest,
SourceNotSupportedPropagatedToMultipleObservers) {
for (const auto& url : urls_) {
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url))
.Times(1);
}
RequestAvailabilityAndAddObservers();
for (auto& mock_observer : mock_observers_) {
EXPECT_CALL(*mock_observer,
AvailabilityChanged(ScreenAvailability::SOURCE_NOT_SUPPORTED));
}
ChangeURLState(url2_, ScreenAvailability::SOURCE_NOT_SUPPORTED);
}
} // namespace blink