blob: 437580eff14c4764f59cbd76b7390c5d7aa9d4d7 [file] [log] [blame]
// 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_service.h"
#include <stdint.h>
#include "base/memory/ptr_util.h"
#include "content/browser/geofencing/geofencing_provider.h"
#include "content/browser/geofencing/geofencing_registration_delegate.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_t geofencing_registration_id,
GeofencingStatus status));
MOCK_METHOD1(RegionEntered, void(int64_t geofencing_registration_id));
MOCK_METHOD1(RegionExited, void(int64_t geofencing_registration_id));
};
class MockGeofencingProvider : public GeofencingProvider {
public:
MOCK_METHOD3(RegisterRegion,
void(int64_t geofencing_registration_id,
const blink::WebCircularGeofencingRegion& region,
const StatusCallback& callback));
MOCK_METHOD1(UnregisterRegion, void(int64_t 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(base::WrapUnique(provider_));
}
int RegistrationCount() { return service_->RegistrationCountForTesting(); }
int64_t RegisterRegionSync(const WebCircularGeofencingRegion& region,
GeofencingStatus provider_status) {
scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
// The registration ID that is passed to the provider.
int64_t 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_t 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<MessageLoopRunner> runner(new MessageLoopRunner());
int64_t 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<MessageLoopRunner> 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_t 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