text: // Copyright 2021 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 "services/device/geolocation/wifi_data_provider_lacros.h"
  
  #include "base/run_loop.h"
  #include "base/strings/string_number_conversions.h"
  #include "base/test/bind.h"
  #include "base/test/task_environment.h"
  #include "services/device/geolocation/wifi_polling_policy.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace {
  
  constexpr int kDefaultIntervalMillis = 200;
  constexpr int kNoChangeIntervalMillis = 300;
  constexpr int kTwoNoChangeIntervalMillis = 400;
  constexpr int kNoWifiIntervalMillis = 100;
  
  }  // namespace
  
  namespace device {
  
  class WifiDataProviderLacrosTest : public testing::Test {
   public:
    void SetUp() override {
      WifiPollingPolicy::Initialize(
          std::make_unique<GenericWifiPollingPolicy<
              kDefaultIntervalMillis, kNoChangeIntervalMillis,
              kTwoNoChangeIntervalMillis, kNoWifiIntervalMillis>>());
      polling_policy_ = WifiPollingPolicy::Get();
      provider_ = new WifiDataProviderLacros();
      Test::SetUp();
    }
  
    void TearDown() override {
      polling_policy_ = nullptr;
      WifiPollingPolicy::Shutdown();
      Test::TearDown();
    }
  
    void CallDidWifiScanTask(bool service_initialized,
                             bool data_available,
                             int num_aps) {
      std::vector<crosapi::mojom::AccessPointDataPtr> ap_data_vector;
      for (int i = 0; i < num_aps; ++i) {
        auto ap_data = crosapi::mojom::AccessPointData::New();
        ap_data->mac_address = base::NumberToString16(i);
        ap_data->radio_signal_strength = i;
        ap_data->channel = i;
        ap_data->signal_to_noise = i;
        ap_data->ssid = base::NumberToString16(i);
        ap_data_vector.push_back(std::move(ap_data));
      }
      provider_->DidWifiScanTaskForTesting(service_initialized, data_available,
                                           base::TimeDelta(),
                                           std::move(ap_data_vector));
      base::RunLoop().RunUntilIdle();
    }
  
    WifiDataProviderLacros* provider() { return provider_.get(); }
  
   private:
    base::test::SingleThreadTaskEnvironment task_environment_;
    WifiPollingPolicy* polling_policy_ = nullptr;
    scoped_refptr<WifiDataProviderLacros> provider_;
  };
  
  TEST_F(WifiDataProviderLacrosTest, NoDataWhenNoScanTaskHasCompleted) {
    WifiData wifi_data;
  
    // By default the provider should not have any wifi data.
    EXPECT_FALSE(provider()->GetData(&wifi_data));
    EXPECT_TRUE(wifi_data.access_point_data.empty());
  }
  
  TEST_F(WifiDataProviderLacrosTest, NoDataWhenServiceIsNotInitialized) {
    WifiData wifi_data;
    EXPECT_FALSE(provider()->GetData(&wifi_data));
  
    // The provider should indicate it does not have any wifi data if the service
    // is reported to be uninitialized.
    CallDidWifiScanTask(false, false, 0);
    EXPECT_FALSE(provider()->GetData(&wifi_data));
    EXPECT_TRUE(wifi_data.access_point_data.empty());
  }
  
  TEST_F(WifiDataProviderLacrosTest, RespondsCorrectlyWhenDataIsNotAvailable) {
    WifiData wifi_data;
    EXPECT_FALSE(provider()->GetData(&wifi_data));
  
    // Simulate a successful callback to DidWifiScanTask().
    CallDidWifiScanTask(true, true, 1);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(1u, wifi_data.access_point_data.size());
  
    // The provider should continue to report the most recent wifi data
    // successfully returned by the callback.
    CallDidWifiScanTask(true, false, 0);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(1u, wifi_data.access_point_data.size());
  }
  
  TEST_F(WifiDataProviderLacrosTest, DoesNotNotifyWhenIncommingDataIsIdentical) {
    WifiData wifi_data;
    EXPECT_FALSE(provider()->GetData(&wifi_data));
  
    int times_called = 0;
    auto wifi_data_callback =
        base::BindLambdaForTesting([&]() { times_called++; });
    provider()->AddCallback(&wifi_data_callback);
  
    // Simulate a successful callback to DidWifiScanTask().
    CallDidWifiScanTask(true, true, 2);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(2u, wifi_data.access_point_data.size());
    EXPECT_EQ(1, times_called);
  
    // Simulate a successful callback to DidWifiScanTask() with the same data as
    // before. This should not trigger any callbacks.
    CallDidWifiScanTask(true, false, 2);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(2u, wifi_data.access_point_data.size());
    EXPECT_EQ(1, times_called);
  
    provider()->RemoveCallback(&wifi_data_callback);
  }
  
  TEST_F(WifiDataProviderLacrosTest,
         NotifiesWhenIncommingDataIsSufficientlyDifferent) {
    WifiData wifi_data;
    EXPECT_FALSE(provider()->GetData(&wifi_data));
  
    int times_called = 0;
    WifiData original_wifi_data = wifi_data;
    auto wifi_data_callback =
        base::BindLambdaForTesting([&]() { times_called++; });
    provider()->AddCallback(&wifi_data_callback);
  
    // Simulate a successful callback to DidWifiScanTask().
    CallDidWifiScanTask(true, true, 2);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(2u, wifi_data.access_point_data.size());
    EXPECT_EQ(1, times_called);
  
    // Simulate a successful callback to DidWifiScanTask() with the significantly
    // different wifi data (>50% difference). This should trigger callbacks with
    // the new data.
    original_wifi_data = wifi_data;
    CallDidWifiScanTask(true, true, 5);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(5u, wifi_data.access_point_data.size());
    EXPECT_EQ(2, times_called);
    EXPECT_TRUE(original_wifi_data.DiffersSignificantly(wifi_data));
  
    // Simulate a successful callback to DidWifiScanTask() with very similar wifi
    // data (<50% difference). This should not trigger callbacks.
    original_wifi_data = wifi_data;
    CallDidWifiScanTask(true, true, 6);
    EXPECT_TRUE(provider()->GetData(&wifi_data));
    EXPECT_EQ(6u, wifi_data.access_point_data.size());
    EXPECT_EQ(2, times_called);
    EXPECT_FALSE(original_wifi_data.DiffersSignificantly(wifi_data));
  
    provider()->RemoveCallback(&wifi_data_callback);
  }
  
  }  // namespace device
  