// Copyright 2014 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 "content/browser/geofencing/geofencing_provider.h" #include "content/browser/geofencing/geofencing_registration_delegate.h" #include "content/browser/geofencing/geofencing_service.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h" using blink::WebCircularGeofencingRegion; namespace { bool RegionsMatch(const WebCircularGeofencingRegion& expected, const WebCircularGeofencingRegion& arg) { return testing::Matches(expected.latitude)(arg.latitude) && testing::Matches(expected.longitude)(arg.longitude) && testing::Matches(expected.radius)(arg.radius); } } // namespace namespace content { class MockGeofencingRegistrationDelegate : public GeofencingRegistrationDelegate { public: MOCK_METHOD2(RegistrationFinished, void(int64 geofencing_registration_id, GeofencingStatus status)); MOCK_METHOD1(RegionEntered, void(int64 geofencing_registration_id)); MOCK_METHOD1(RegionExited, void(int64 geofencing_registration_id)); }; class MockGeofencingProvider : public GeofencingProvider { public: MOCK_METHOD3(RegisterRegion, void(int64 geofencing_registration_id, const blink::WebCircularGeofencingRegion& region, const StatusCallback& callback)); MOCK_METHOD1(UnregisterRegion, void(int64 geofencing_registration_id)); }; ACTION_P(QuitRunner, runner) { runner->Quit(); } ACTION_P(SaveRegistrationId, geofencing_registration_id) { *geofencing_registration_id = arg0; } ACTION_P(SaveStatusCallback, callback) { *callback = arg2; } MATCHER_P(WebCircularGeofencingRegionEq, expected, "") { return RegionsMatch(expected, arg); } class GeofencingServiceTest : public testing::Test { public: GeofencingServiceTest() : service_(nullptr) { test_region_.latitude = 37.421999; test_region_.longitude = -122.084015; test_region_.radius = 100; } void SetUp() override { service_ = new GeofencingServiceImpl(); } void TearDown() override { delete service_; } void SetProviderForTests() { provider_ = new MockGeofencingProvider(); service_->SetProviderForTesting(make_scoped_ptr(provider_)); } int RegistrationCount() { return service_->RegistrationCountForTesting(); } int64 RegisterRegionSync(const WebCircularGeofencingRegion& region, GeofencingStatus provider_status) { scoped_refptr runner(new MessageLoopRunner()); // The registration ID that is passed to the provider. int64 provider_registration_id = -1; // The callback that is passed to the provider. GeofencingProvider::StatusCallback callback; EXPECT_CALL( *provider_, RegisterRegion( testing::_, WebCircularGeofencingRegionEq(region), testing::_)) .WillOnce(testing::DoAll(SaveRegistrationId(&provider_registration_id), SaveStatusCallback(&callback))); int64 geofencing_registration_id = service_->RegisterRegion(region, &delegate_); // Service should have synchronously called the provider. CHECK(!callback.is_null()); CHECK(provider_registration_id == geofencing_registration_id); // Finish up registration by calling the callback and waiting for the // delegate to be called. EXPECT_CALL( delegate_, RegistrationFinished(geofencing_registration_id, provider_status)) .WillOnce(QuitRunner(runner)); callback.Run(provider_status); runner->Run(); return geofencing_registration_id; } protected: TestBrowserThreadBundle threads_; GeofencingServiceImpl* service_; MockGeofencingProvider* provider_; MockGeofencingRegistrationDelegate delegate_; WebCircularGeofencingRegion test_region_; }; TEST_F(GeofencingServiceTest, RegisterRegion_NoProvider) { scoped_refptr runner(new MessageLoopRunner()); int64 geofencing_registration_id = service_->RegisterRegion(test_region_, &delegate_); EXPECT_CALL(delegate_, RegistrationFinished( geofencing_registration_id, GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE)) .WillOnce(QuitRunner(runner)); runner->Run(); EXPECT_EQ(0, RegistrationCount()); } TEST_F(GeofencingServiceTest, RegisterRegion_FailsInProvider) { SetProviderForTests(); RegisterRegionSync(test_region_, GEOFENCING_STATUS_ERROR); EXPECT_EQ(0, RegistrationCount()); } TEST_F(GeofencingServiceTest, RegisterRegion_SucceedsInProvider) { SetProviderForTests(); RegisterRegionSync(test_region_, GEOFENCING_STATUS_OK); EXPECT_EQ(1, RegistrationCount()); } TEST_F(GeofencingServiceTest, UnregisterRegion_AfterRegistration) { SetProviderForTests(); int geofencing_registration_id = RegisterRegionSync(test_region_, GEOFENCING_STATUS_OK); EXPECT_EQ(1, RegistrationCount()); EXPECT_CALL(*provider_, UnregisterRegion(geofencing_registration_id)); service_->UnregisterRegion(geofencing_registration_id); EXPECT_EQ(0, RegistrationCount()); } TEST_F(GeofencingServiceTest, UnregisterRegion_DuringSuccesfullRegistration) { SetProviderForTests(); scoped_refptr runner(new MessageLoopRunner()); // The callback that is passed to the provider. GeofencingProvider::StatusCallback callback; EXPECT_CALL( *provider_, RegisterRegion( testing::_, WebCircularGeofencingRegionEq(test_region_), testing::_)) .WillOnce(SaveStatusCallback(&callback)); int64 geofencing_registration_id = service_->RegisterRegion(test_region_, &delegate_); // Service should have synchronously called the provider. CHECK(!callback.is_null()); // Call unregister before registration is finished. service_->UnregisterRegion(geofencing_registration_id); // Finish up registration by calling the callback and waiting for the // provider to be called. The delegate should not be called in this case. EXPECT_CALL(delegate_, RegistrationFinished(testing::_, testing::_)).Times(0); EXPECT_CALL(*provider_, UnregisterRegion(geofencing_registration_id)) .WillOnce(QuitRunner(runner)); callback.Run(GEOFENCING_STATUS_OK); runner->Run(); EXPECT_EQ(0, RegistrationCount()); } } // namespace content