chromium/ash/system/network/network_detailed_network_view_unittest.cc

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

#include "ash/system/network/network_detailed_network_view.h"

#include <memory>

#include "ash/system/network/network_detailed_network_view_impl.h"
#include "ash/system/network/network_detailed_view.h"
#include "ash/system/network/network_list_mobile_header_view.h"
#include "ash/system/network/network_list_network_item_view.h"
#include "ash/system/network/network_list_wifi_header_view.h"
#include "ash/system/network/network_utils.h"
#include "ash/system/tray/detailed_view_delegate.h"
#include "ash/test/ash_test_base.h"
#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "chromeos/services/network_config/public/mojom/network_types.mojom-shared.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event_utils.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace ash {

namespace {

using ::chromeos::network_config::mojom::NetworkStatePropertiesPtr;
using ::chromeos::network_config::mojom::NetworkType;
using network_config::CrosNetworkConfigTestHelper;

const char kStubCellularDevicePath[] = "/device/stub_cellular_device";
const char kStubCellularDeviceName[] = "stub_cellular_device";
const char kCellularNetworkGuid[] = "cellular_guid";

class FakeNetworkDetailedNetworkViewDelegate
    : public NetworkDetailedNetworkView::Delegate {
 public:
  FakeNetworkDetailedNetworkViewDelegate() = default;
  ~FakeNetworkDetailedNetworkViewDelegate() override = default;

  bool last_mobile_toggle_state() { return last_mobile_toggle_state_; }

  size_t on_mobile_toggle_clicked_count() {
    return on_mobile_toggle_clicked_count_;
  }

  bool last_wifi_toggle_state() { return last_wifi_toggle_state_; }

  size_t on_wifi_toggle_clicked_count() {
    return on_wifi_toggle_clicked_count_;
  }

  size_t network_list_item_selected_count() const {
    return network_list_item_selected_count_;
  }

 private:
  // NetworkDetailedView::Delegate:
  void OnNetworkListItemSelected(
      const NetworkStatePropertiesPtr& network) override {
    network_list_item_selected_count_++;
    last_network_list_item_selected_ = mojo::Clone(network);
  }

  // NetworkDetailedNetworkView::Delegate:
  void OnWifiToggleClicked(bool new_state) override {
    on_wifi_toggle_clicked_count_++;
    last_wifi_toggle_state_ = new_state;
  }

  void OnMobileToggleClicked(bool new_state) override {
    on_mobile_toggle_clicked_count_++;
    last_mobile_toggle_state_ = new_state;
  }

  const NetworkStatePropertiesPtr& last_network_list_item_selected() const {
    return last_network_list_item_selected_;
  }

  bool last_mobile_toggle_state_ = false;
  size_t on_mobile_toggle_clicked_count_ = 0;

  bool last_wifi_toggle_state_ = false;
  size_t on_wifi_toggle_clicked_count_ = 0;

  size_t network_list_item_selected_count_ = 0;
  NetworkStatePropertiesPtr last_network_list_item_selected_;
};

}  // namespace

class NetworkDetailedNetworkViewTest : public AshTestBase {
 public:
  void SetUp() override {
    AshTestBase::SetUp();

    network_state_helper()->ClearDevices();

    network_state_helper()->manager_test()->AddTechnology(shill::kTypeCellular,
                                                          /*enabled=*/true);

    network_state_helper()->device_test()->AddDevice(
        kStubCellularDevicePath, shill::kTypeCellular, kStubCellularDeviceName);

    // Wait for network state and device change events to be handled.
    base::RunLoop().RunUntilIdle();

    detailed_view_delegate_ =
        std::make_unique<DetailedViewDelegate>(/*tray_controller=*/nullptr);

    std::unique_ptr<NetworkDetailedNetworkViewImpl>
        network_detailed_network_view =
            std::make_unique<NetworkDetailedNetworkViewImpl>(
                detailed_view_delegate_.get(),
                &fake_network_detailed_network_delagte_);

    widget_ = CreateFramelessTestWidget();
    widget_->SetFullscreen(true);
    network_detailed_network_view_ =
        widget_->SetContentsView(std::move(network_detailed_network_view));
  }

  void TearDown() override {
    widget_.reset();

    AshTestBase::TearDown();
  }

  void AddCellularNetwork() {
    const std::string cellular_path =
        network_state_helper()->ConfigureService(base::StringPrintf(
            R"({"GUID": "%s", "Type": "cellular", "Technology": "LTE",
            "State": "idle"})",
            kCellularNetworkGuid));

    network_state_helper()->SetServiceProperty(
        cellular_path, std::string(shill::kDeviceProperty),
        base::Value(kStubCellularDevicePath));
    network_state_helper()->SetServiceProperty(
        cellular_path, std::string(shill::kStateProperty),
        base::Value(shill::kStateOnline));
    base::RunLoop().RunUntilIdle();
  }

  NetworkListNetworkItemView* AddNetworkListItem(NetworkType type) {
    return network_detailed_network_view()->AddNetworkListItem(type);
  }

  void NotifyNetworkListChanged() {
    network_detailed_network_view()->NotifyNetworkListChanged();
  }

  views::Button* FindSettingsButton() {
    return FindViewById<views::Button*>(
        NetworkDetailedView::NetworkDetailedViewChildId::kSettingsButton);
  }

  NetworkListWifiHeaderView* AddWifiSectionHeader() {
    return network_detailed_network_view()->AddWifiSectionHeader();
  }

  NetworkListMobileHeaderView* AddMobileSectionHeader() {
    return network_detailed_network_view()->AddMobileSectionHeader();
  }

  FakeNetworkDetailedNetworkViewDelegate* delegate() {
    return &fake_network_detailed_network_delagte_;
  }

  void SimulateMobileToggleClicked(bool new_state) {
    network_detailed_network_view()->OnMobileToggleClicked(new_state);
  }

  void SimulateWifiToggleClicked(bool new_state) {
    network_detailed_network_view()->OnWifiToggleClicked(new_state);
  }

 private:
  template <class T>
  T FindViewById(NetworkDetailedView::NetworkDetailedViewChildId id) {
    return static_cast<T>(
        network_detailed_network_view_->GetViewByID(static_cast<int>(id)));
  }

  NetworkDetailedNetworkViewImpl* network_detailed_network_view() {
    return network_detailed_network_view_;
  }

  NetworkStateTestHelper* network_state_helper() {
    return &network_config_helper_.network_state_helper();
  }

  std::unique_ptr<views::Widget> widget_;
  CrosNetworkConfigTestHelper network_config_helper_;
  FakeNetworkDetailedNetworkViewDelegate fake_network_detailed_network_delagte_;
  std::unique_ptr<DetailedViewDelegate> detailed_view_delegate_;
  raw_ptr<NetworkDetailedNetworkViewImpl, DanglingUntriaged>
      network_detailed_network_view_;
  base::HistogramTester histogram_tester_;
};

TEST_F(NetworkDetailedNetworkViewTest, ViewsAreCreated) {
  NetworkListNetworkItemView* network_list_item =
      AddNetworkListItem(NetworkType::kWiFi);
  ASSERT_NE(nullptr, network_list_item);

  NetworkListWifiHeaderView* wifi_section = AddWifiSectionHeader();
  ASSERT_NE(nullptr, wifi_section);

  NetworkListMobileHeaderView* mobile_section = AddMobileSectionHeader();
  ASSERT_NE(nullptr, mobile_section);
}

TEST_F(NetworkDetailedNetworkViewTest, ToggleInteractions) {
  EXPECT_EQ(0u, delegate()->on_mobile_toggle_clicked_count());
  EXPECT_FALSE(delegate()->last_mobile_toggle_state());

  SimulateMobileToggleClicked(/*new_state=*/true);
  EXPECT_EQ(1u, delegate()->on_mobile_toggle_clicked_count());
  EXPECT_TRUE(delegate()->last_mobile_toggle_state());

  EXPECT_EQ(0u, delegate()->on_wifi_toggle_clicked_count());
  EXPECT_FALSE(delegate()->last_wifi_toggle_state());

  SimulateWifiToggleClicked(/*new_state=*/true);
  EXPECT_EQ(1u, delegate()->on_wifi_toggle_clicked_count());
  EXPECT_TRUE(delegate()->last_wifi_toggle_state());
}

TEST_F(NetworkDetailedNetworkViewTest, ListItemClicked) {
  EXPECT_EQ(0u, delegate()->network_list_item_selected_count());
  NetworkListNetworkItemView* network_list_item =
      AddNetworkListItem(NetworkType::kWiFi);
  ASSERT_NE(nullptr, network_list_item);
  NotifyNetworkListChanged();
  LeftClickOn(network_list_item);
  EXPECT_EQ(1u, delegate()->network_list_item_selected_count());

  GetSessionControllerClient()->SetSessionState(
      session_manager::SessionState::LOCKED);
  LeftClickOn(network_list_item);
  EXPECT_EQ(1u, delegate()->network_list_item_selected_count());
}

TEST_F(NetworkDetailedNetworkViewTest, SettingsButton) {
  views::Button* settings_button = FindSettingsButton();

  EXPECT_TRUE(settings_button->GetEnabled());

  // When in OOBE and no active networks are available settings button is
  // disabled.
  GetSessionControllerClient()->SetSessionState(
      session_manager::SessionState::OOBE);
  NotifyNetworkListChanged();

  EXPECT_FALSE(settings_button->GetEnabled());

  // Add a network and check settings button state. When an active network
  // is present settings button should be enabled.
  AddCellularNetwork();
  NotifyNetworkListChanged();
  EXPECT_TRUE(settings_button->GetEnabled());
}

}  // namespace ash