#include "services/device/geolocation/geolocation_provider_impl.h"
#include <memory>
#include <string>
#include "base/at_exit.h"
#include "base/barrier_closure.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "services/device/geolocation/fake_location_provider.h"
#include "services/device/public/cpp/device_features.h"
#include "services/device/public/cpp/geolocation/location_system_permission_status.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
#include "services/device/public/cpp/test/fake_geolocation_system_permission_manager.h"
#endif
namespace device {
namespace {
TestFuture;
LocationSystemPermissionStatus;
MakeMatcher;
Matcher;
MatcherInterface;
MatchResultListener;
std::string kSystemPermissoinDeniedErrorMessage = …;
class GeolocationObserver { … };
class MockGeolocationObserver : public GeolocationObserver { … };
class AsyncMockGeolocationObserver : public MockGeolocationObserver { … };
class MockGeolocationCallbackWrapper { … };
class GeopositionResultEqMatcher
: public MatcherInterface<const mojom::GeopositionResult&> { … };
Matcher<const mojom::GeopositionResult&> GeopositionResultEq(
const mojom::GeopositionResult& expected) { … }
}
class GeolocationProviderTest : public testing::Test { … };
void GeolocationProviderTest::SetFakeLocationProviderManager() { … }
bool GeolocationProviderTest::ProvidersStarted() { … }
void GeolocationProviderTest::GetProvidersStarted() { … }
void GeolocationProviderTest::SendMockLocation(
const mojom::GeopositionResult& result) { … }
TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) { … }
TEST_F(GeolocationProviderTest, StartStop) { … }
TEST_F(GeolocationProviderTest, StalePositionNotSent) { … }
TEST_F(GeolocationProviderTest, OverrideLocationForTesting) { … }
namespace {
class MockGeolocationInternalsObserver
: public mojom::GeolocationInternalsObserver { … };
}
TEST_F(GeolocationProviderTest, InitializeWhileObservingDiagnostics) { … }
TEST_F(GeolocationProviderTest, MultipleDiagnosticsObservers) { … }
TEST_F(GeolocationProviderTest, DiagnosticsObserverDisabled) { … }
#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
TEST_F(GeolocationProviderTest, StartProviderAfterSystemPermissionGranted) {
SetFakeLocationProviderManager();
MockGeolocationObserver mock_observer;
EXPECT_CALL(mock_observer, OnLocationUpdate).Times(0);
GeolocationProviderImpl::LocationUpdateCallback callback =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&mock_observer));
base::CallbackListSubscription subscription =
provider()->AddLocationUpdateCallback(callback,
true);
EXPECT_FALSE(ProvidersStarted());
SetSystemPermission(LocationSystemPermissionStatus::kAllowed);
EXPECT_TRUE(ProvidersStarted());
TestFuture<mojom::GeopositionResultPtr> future;
EXPECT_CALL(mock_observer, OnLocationUpdate)
.WillOnce([&](const mojom::GeopositionResult& result) {
future.SetValue(result.Clone());
});
SendMockLocation(*position_result1_);
EXPECT_EQ(future.Get()->get_position(), position_result1_->get_position());
subscription = {};
EXPECT_FALSE(ProvidersStarted());
}
TEST_F(GeolocationProviderTest, AddCallbackWhenSystemPermissionDenied) {
SetFakeLocationProviderManager();
SetSystemPermission(LocationSystemPermissionStatus::kDenied);
MockGeolocationObserver mock_observer;
TestFuture<mojom::GeopositionResultPtr> future;
EXPECT_CALL(mock_observer, OnLocationUpdate)
.WillOnce([&](const mojom::GeopositionResult& result) {
future.SetValue(result.Clone());
});
GeolocationProviderImpl::LocationUpdateCallback callback =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&mock_observer));
base::CallbackListSubscription subscription =
provider()->AddLocationUpdateCallback(callback,
true);
EXPECT_EQ(future.Take()->get_error(), error_result_->get_error());
EXPECT_FALSE(ProvidersStarted());
}
TEST_F(GeolocationProviderTest,
ReportPermissionDeniedOnSystemPermissionDenied) {
SetFakeLocationProviderManager();
SetSystemPermission(LocationSystemPermissionStatus::kAllowed);
MockGeolocationObserver mock_observer;
GeolocationProviderImpl::LocationUpdateCallback callback =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&mock_observer));
base::CallbackListSubscription subscription =
provider()->AddLocationUpdateCallback(callback,
true);
EXPECT_TRUE(ProvidersStarted());
TestFuture<mojom::GeopositionResultPtr> position_future;
EXPECT_CALL(mock_observer, OnLocationUpdate)
.WillOnce([&](const mojom::GeopositionResult& result) {
position_future.SetValue(result.Clone());
});
SendMockLocation(*position_result1_);
EXPECT_EQ(position_future.Get()->get_position(),
position_result1_->get_position());
TestFuture<mojom::GeopositionResultPtr> error_future;
EXPECT_CALL(mock_observer, OnLocationUpdate)
.WillOnce([&](const mojom::GeopositionResult& result) {
error_future.SetValue(result.Clone());
});
SetSystemPermission(LocationSystemPermissionStatus::kDenied);
EXPECT_EQ(error_future.Get()->get_error(), error_result_->get_error());
subscription = {};
EXPECT_FALSE(ProvidersStarted());
}
TEST_F(GeolocationProviderTest,
SystemPermissionAllowedAfterSystemPermissionDenied) {
SetFakeLocationProviderManager();
SetSystemPermission(LocationSystemPermissionStatus::kDenied);
TestFuture<mojom::GeopositionResultPtr> error_future;
MockGeolocationObserver mock_observer1;
GeolocationProviderImpl::LocationUpdateCallback callback1 =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&mock_observer1));
EXPECT_CALL(mock_observer1, OnLocationUpdate)
.WillOnce([&](const mojom::GeopositionResult& result) {
error_future.SetValue(result.Clone());
});
base::CallbackListSubscription subscription1 =
provider()->AddLocationUpdateCallback(callback1,
true);
EXPECT_EQ(error_future.Get()->get_error(), error_result_->get_error());
subscription1 = {};
EXPECT_FALSE(ProvidersStarted());
SetSystemPermission(LocationSystemPermissionStatus::kAllowed);
MockGeolocationObserver mock_observer2;
GeolocationProviderImpl::LocationUpdateCallback callback2 =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&mock_observer2));
base::CallbackListSubscription subscription2 =
provider()->AddLocationUpdateCallback(callback2,
true);
EXPECT_TRUE(ProvidersStarted());
TestFuture<mojom::GeopositionResultPtr> position_future;
EXPECT_CALL(mock_observer2, OnLocationUpdate)
.WillOnce([&](const mojom::GeopositionResult& result) {
position_future.SetValue(result.Clone());
});
SendMockLocation(*position_result1_);
EXPECT_EQ(position_future.Get()->get_position(),
position_result1_->get_position());
subscription2 = {};
EXPECT_FALSE(ProvidersStarted());
}
#endif
}