// Copyright 2020 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 "cast/sender/cast_app_availability_tracker.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "platform/test/fake_clock.h" namespace openscreen { namespace cast { namespace { using ::testing::UnorderedElementsAreArray; MATCHER_P(CastMediaSourcesEqual, expected, "") { if (expected.size() != arg.size()) return false; return std::equal( expected.begin(), expected.end(), arg.begin(), [](const CastMediaSource& source1, const CastMediaSource& source2) { return source1.source_id() == source2.source_id(); }); } } // namespace class CastAppAvailabilityTrackerTest : public ::testing::Test { public: CastAppAvailabilityTrackerTest() : clock_(Clock::now()) {} ~CastAppAvailabilityTrackerTest() override = default; Clock::time_point Now() const { return clock_.now(); } protected: FakeClock clock_; CastAppAvailabilityTracker tracker_; }; TEST_F(CastAppAvailabilityTrackerTest, RegisterSource) { CastMediaSource source1("cast:AAA?clientId=1", {"AAA"}); CastMediaSource source2("cast:AAA?clientId=2", {"AAA"}); std::vector expected_app_ids = {"AAA"}; EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(source1)); EXPECT_EQ(std::vector{}, tracker_.RegisterSource(source1)); EXPECT_EQ(std::vector{}, tracker_.RegisterSource(source2)); tracker_.UnregisterSource(source1); tracker_.UnregisterSource(source2); EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(source1)); EXPECT_EQ(expected_app_ids, tracker_.GetRegisteredApps()); } TEST_F(CastAppAvailabilityTrackerTest, RegisterSourceReturnsMultipleAppIds) { CastMediaSource source1("urn:x-org.chromium.media:source:tab:1", {"0F5096E8", "85CDB22F"}); // Mirorring app ids. std::vector expected_app_ids = {"0F5096E8", "85CDB22F"}; EXPECT_THAT(tracker_.RegisterSource(source1), UnorderedElementsAreArray(expected_app_ids)); EXPECT_THAT(tracker_.GetRegisteredApps(), UnorderedElementsAreArray(expected_app_ids)); } TEST_F(CastAppAvailabilityTrackerTest, MultipleAppIdsAlreadyTrackingOne) { // One of the mirroring app IDs. CastMediaSource source1("cast:0F5096E8?clientId=123", {"0F5096E8"}); std::vector new_app_ids = {"0F5096E8"}; std::vector registered_app_ids = {"0F5096E8"}; EXPECT_EQ(new_app_ids, tracker_.RegisterSource(source1)); EXPECT_EQ(registered_app_ids, tracker_.GetRegisteredApps()); CastMediaSource source2("urn:x-org.chromium.media:source:tab:1", {"0F5096E8", "85CDB22F"}); new_app_ids = {"85CDB22F"}; registered_app_ids = {"0F5096E8", "85CDB22F"}; EXPECT_EQ(new_app_ids, tracker_.RegisterSource(source2)); EXPECT_THAT(tracker_.GetRegisteredApps(), UnorderedElementsAreArray(registered_app_ids)); } TEST_F(CastAppAvailabilityTrackerTest, UpdateAppAvailability) { CastMediaSource source1("cast:AAA?clientId=1", {"AAA"}); CastMediaSource source2("cast:AAA?clientId=2", {"AAA"}); CastMediaSource source3("cast:BBB?clientId=3", {"BBB"}); tracker_.RegisterSource(source3); // |source3| not affected. EXPECT_THAT( tracker_.UpdateAppAvailability( "receiverId1", "AAA", {AppAvailabilityResult::kAvailable, Now()}), CastMediaSourcesEqual(std::vector())); std::vector receivers_1 = {"receiverId1"}; std::vector receivers_1_2 = {"receiverId1", "receiverId2"}; std::vector sources_1 = {source1}; std::vector sources_1_2 = {source1, source2}; // Tracker returns available receivers even though sources aren't registered. EXPECT_EQ(receivers_1, tracker_.GetAvailableReceivers(source1)); EXPECT_EQ(receivers_1, tracker_.GetAvailableReceivers(source2)); EXPECT_TRUE(tracker_.GetAvailableReceivers(source3).empty()); tracker_.RegisterSource(source1); // Only |source1| is registered for this app. EXPECT_THAT( tracker_.UpdateAppAvailability( "receiverId2", "AAA", {AppAvailabilityResult::kAvailable, Now()}), CastMediaSourcesEqual(sources_1)); EXPECT_THAT(tracker_.GetAvailableReceivers(source1), UnorderedElementsAreArray(receivers_1_2)); EXPECT_THAT(tracker_.GetAvailableReceivers(source2), UnorderedElementsAreArray(receivers_1_2)); EXPECT_TRUE(tracker_.GetAvailableReceivers(source3).empty()); tracker_.RegisterSource(source2); EXPECT_THAT( tracker_.UpdateAppAvailability( "receiverId2", "AAA", {AppAvailabilityResult::kUnavailable, Now()}), CastMediaSourcesEqual(sources_1_2)); EXPECT_EQ(receivers_1, tracker_.GetAvailableReceivers(source1)); EXPECT_EQ(receivers_1, tracker_.GetAvailableReceivers(source2)); EXPECT_TRUE(tracker_.GetAvailableReceivers(source3).empty()); } TEST_F(CastAppAvailabilityTrackerTest, RemoveResultsForReceiver) { CastMediaSource source1("cast:AAA?clientId=1", {"AAA"}); tracker_.UpdateAppAvailability("receiverId1", "AAA", {AppAvailabilityResult::kAvailable, Now()}); EXPECT_EQ(AppAvailabilityResult::kAvailable, tracker_.GetAvailability("receiverId1", "AAA").availability); std::vector expected_receiver_ids = {"receiverId1"}; EXPECT_EQ(expected_receiver_ids, tracker_.GetAvailableReceivers(source1)); // Unrelated receiver ID. tracker_.RemoveResultsForReceiver("receiverId2"); EXPECT_EQ(AppAvailabilityResult::kAvailable, tracker_.GetAvailability("receiverId1", "AAA").availability); EXPECT_EQ(expected_receiver_ids, tracker_.GetAvailableReceivers(source1)); tracker_.RemoveResultsForReceiver("receiverId1"); EXPECT_EQ(AppAvailabilityResult::kUnknown, tracker_.GetAvailability("receiverId1", "AAA").availability); EXPECT_EQ(std::vector{}, tracker_.GetAvailableReceivers(source1)); } } // namespace cast } // namespace openscreen