chromium/services/device/geolocation/location_provider_manager_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "services/device/geolocation/location_provider_manager.h"

#include <memory>
#include <utility>

#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/ranges/algorithm.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "services/device/geolocation/fake_location_provider.h"
#include "services/device/geolocation/fake_position_cache.h"
#include "services/device/public/cpp/device_features.h"
#include "services/device/public/cpp/geolocation/geoposition.h"
#include "services/device/public/cpp/geolocation/location_provider.h"
#include "services/device/public/mojom/geoposition.mojom.h"
#include "services/network/test/test_shared_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

NiceMock;

namespace device {
namespace {

std::unique_ptr<LocationProvider> NullLocationProvider() {}

class MockLocationObserver {};

void SetPositionFix(FakeLocationProvider* provider,
                    double latitude,
                    double longitude,
                    double accuracy) {}

void SetErrorPosition(FakeLocationProvider* provider,
                      mojom::GeopositionErrorCode error_code) {}

// TODO(lethalantidote): Populate a Geoposition in the class from kConstants
// and then just copy that with "=" versus using a helper function.
void SetReferencePosition(FakeLocationProvider* provider) {}

}  // namespace

class TestingLocationProviderManager : public LocationProviderManager {};

class GeolocationLocationProviderManagerTest : public testing::Test {};

// Basic test of the text fixture.
TEST_F(GeolocationLocationProviderManagerTest, CreateDestroy) {}

// Tests OnPermissionGranted().
TEST_F(GeolocationLocationProviderManagerTest, OnPermissionGranted) {}

#if !BUILDFLAG(IS_ANDROID)
// Tests basic operation (valid position and error position update) for network
// location provider.
TEST_F(GeolocationLocationProviderManagerTest, NetworkOnly) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
// Tests basic operation (valid position and error position update) for system
// location provider.
TEST_F(GeolocationLocationProviderManagerTest, PlatformOnly) {
  ASSERT_TRUE(
      SetExperimentMode(mojom::LocationProviderManagerMode::kPlatformOnly));
  InitializeLocationProviderManager(base::BindRepeating(&NullLocationProvider),
                                    url_loader_factory_);
  ASSERT_TRUE(location_provider_manager_);

  EXPECT_FALSE(network_location_provider());
  EXPECT_FALSE(system_location_provider());
  location_provider_manager_->StartProvider(false);

  EXPECT_FALSE(network_location_provider());
  ASSERT_TRUE(system_location_provider());
  EXPECT_EQ(mojom::GeolocationDiagnostics::ProviderState::kLowAccuracy,
            system_location_provider()->state());
  EXPECT_FALSE(observer_->last_result());

  SetReferencePosition(system_location_provider());

  ASSERT_TRUE(observer_->last_result());
  if (observer_->last_result()->is_position()) {
    ASSERT_TRUE(system_location_provider()->GetPosition());
    EXPECT_EQ(
        system_location_provider()->GetPosition()->get_position()->latitude,
        observer_->last_result()->get_position()->latitude);
  }

  EXPECT_FALSE(system_location_provider()->is_permission_granted());
  EXPECT_FALSE(location_provider_manager_->HasPermissionBeenGrantedForTest());
  location_provider_manager_->OnPermissionGranted();
  EXPECT_TRUE(location_provider_manager_->HasPermissionBeenGrantedForTest());
  EXPECT_TRUE(system_location_provider()->is_permission_granted());

  // In `kPlatformOnly` mode, an error position is reported directly.
  SetErrorPosition(system_location_provider(),
                   mojom::GeopositionErrorCode::kPositionUnavailable);
  EXPECT_TRUE(system_location_provider()->GetPosition()->is_error());
  EXPECT_TRUE(observer_->last_result()->is_error());
  EXPECT_EQ(system_location_provider()->GetPosition()->get_error(),
            observer_->last_result()->get_error());
}
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)

// Tests basic operation (single position fix) with no network location
// provider, no system location provider and a custom system location provider.
TEST_F(GeolocationLocationProviderManagerTest, CustomSystemProviderOnly) {}

#if !BUILDFLAG(IS_ANDROID)
// Tests flipping from Low to High accuracy mode as requested by a location
// observer.
TEST_F(GeolocationLocationProviderManagerTest, SetObserverOptions) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
// TODO(crbug.com/346842084): kHybridPlatform mode currently behaves the
// same as kPlatformOnly. fallback mechanism will not be added until platform
// provider is fully evaluated.
TEST_F(GeolocationLocationProviderManagerTest, HybridPlatformFallback) {
  ASSERT_TRUE(
      SetExperimentMode(mojom::LocationProviderManagerMode::kHybridPlatform));
  InitializeLocationProviderManager(base::BindRepeating(&NullLocationProvider),
                                    url_loader_factory_);
  ASSERT_TRUE(location_provider_manager_);

  EXPECT_FALSE(network_location_provider());
  EXPECT_FALSE(system_location_provider());
  location_provider_manager_->StartProvider(false);

  EXPECT_FALSE(network_location_provider());
  ASSERT_TRUE(system_location_provider());
  EXPECT_EQ(mojom::GeolocationDiagnostics::ProviderState::kLowAccuracy,
            system_location_provider()->state());
  EXPECT_FALSE(observer_->last_result());

  SetReferencePosition(system_location_provider());

  ASSERT_TRUE(observer_->last_result());
  if (observer_->last_result()->is_position()) {
    ASSERT_TRUE(system_location_provider()->GetPosition());
    EXPECT_EQ(
        system_location_provider()->GetPosition()->get_position()->latitude,
        observer_->last_result()->get_position()->latitude);
  }

  SetErrorPosition(system_location_provider(),
                   mojom::GeopositionErrorCode::kPositionUnavailable);
  EXPECT_TRUE(system_location_provider()->GetPosition()->is_error());
  EXPECT_TRUE(observer_->last_result()->is_error());
  EXPECT_EQ(system_location_provider()->GetPosition()->get_error(),
            observer_->last_result()->get_error());

  // Ensure that network location provider is not created since fallback
  // mechanism isn't implemented yet.
  EXPECT_FALSE(network_location_provider());
}

#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)

}  // namespace device