blob: 802ae4dcef000f35b539bfc9fb16d04b0c936bed [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 "modules/presentation/PresentationAvailabilityState.h"
#include "modules/presentation/MockPresentationService.h"
#include "modules/presentation/PresentationAvailabilityCallbacks.h"
#include "modules/presentation/PresentationAvailabilityObserver.h"
#include "platform/weborigin/KURL.h"
#include "platform/wtf/Vector.h"
#include "platform/wtf/text/WTFString.h"
#include "public/platform/WebCallbacks.h"
#include "public/platform/modules/presentation/WebPresentationError.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
namespace blink {
using mojom::blink::ScreenAvailability;
class MockPresentationAvailabilityObserver
: public PresentationAvailabilityObserver {
public:
explicit MockPresentationAvailabilityObserver(const Vector<KURL>& urls)
: urls_(urls) {}
~MockPresentationAvailabilityObserver() override {}
MOCK_METHOD1(AvailabilityChanged, void(ScreenAvailability availability));
const Vector<KURL>& Urls() const override { return urls_; }
private:
const Vector<KURL> urls_;
};
class MockPresentationAvailabilityCallbacks
: public PresentationAvailabilityCallbacks {
public:
MOCK_METHOD1(OnSuccess, void(bool value));
MOCK_METHOD1(OnError, void(const blink::WebPresentationError&));
};
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_(urls_),
mock_observer1_({url1_, url2_, url3_}),
mock_observer2_({url2_, url3_, url4_}),
mock_observer3_({url2_, url3_}),
mock_observers_({&mock_observer1_, &mock_observer2_, &mock_observer3_}),
mock_presentation_service_(),
state_(&mock_presentation_service_) {}
~PresentationAvailabilityStateTest() override {}
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(),
std::make_unique<PresentationAvailabilityCallbacks>());
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 std::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,
std::unique_ptr<MockPresentationAvailabilityCallbacks>(mock_callback));
for (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_;
MockPresentationAvailabilityObserver mock_observer_all_urls_;
MockPresentationAvailabilityObserver mock_observer1_;
MockPresentationAvailabilityObserver mock_observer2_;
MockPresentationAvailabilityObserver mock_observer3_;
std::vector<MockPresentationAvailabilityObserver*> mock_observers_;
MockPresentationService mock_presentation_service_;
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_, std::make_unique<PresentationAvailabilityCallbacks>());
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 =
new testing::StrictMock<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(mock_presentation_service_, ListenForScreenAvailability(url1_))
.Times(1);
state_.RequestAvailability(
Vector<KURL>({url1_}),
std::unique_ptr<PresentationAvailabilityCallbacks>(mock_callback));
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesAvailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnSuccess(true));
TestRequestAvailability({url1_}, {ScreenAvailability::AVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesNotCompatible) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnSuccess(false));
TestRequestAvailability({url1_}, {ScreenAvailability::SOURCE_NOT_SUPPORTED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesUnavailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnSuccess(false));
TestRequestAvailability({url1_}, {ScreenAvailability::UNAVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityOneUrlBecomesUnsupported) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnError(_));
TestRequestAvailability({url1_}, {ScreenAvailability::DISABLED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesAvailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnSuccess(true)).Times(1);
TestRequestAvailability(
{url1_, url2_},
{ScreenAvailability::AVAILABLE, ScreenAvailability::AVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesUnavailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnSuccess(false)).Times(1);
TestRequestAvailability(
{url1_, url2_},
{ScreenAvailability::UNAVAILABLE, ScreenAvailability::UNAVAILABLE},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesNotCompatible) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnSuccess(false)).Times(1);
TestRequestAvailability({url1_, url2_},
{ScreenAvailability::SOURCE_NOT_SUPPORTED,
ScreenAvailability::SOURCE_NOT_SUPPORTED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityMultipleUrlsAllBecomesUnsupported) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, OnError(_)).Times(1);
TestRequestAvailability(
{url1_, url2_},
{ScreenAvailability::DISABLED, ScreenAvailability::DISABLED},
mock_callback);
}
TEST_F(PresentationAvailabilityStateTest,
RequestAvailabilityReturnsDirectlyForAlreadyListeningUrls) {
// First getAvailability() call.
auto* mock_callback_1 = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback_1, OnSuccess(false)).Times(1);
std::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 = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback_2, OnSuccess(true)).Times(1);
state_.RequestAvailability(
mock_observer3_.Urls(),
std::unique_ptr<MockPresentationAvailabilityCallbacks>(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