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

#import <UIKit/UIKit.h>

#import <functional>

#import "base/test/scoped_feature_list.h"
#import "ios/web/common/features.h"
#import "ios/web/common/uikit_ui_util.h"
#import "ios/web/public/test/web_test_with_web_state.h"
#import "ios/web/public/web_client.h"
#import "ios/web/public/web_state.h"

namespace web {

namespace {
// Overrides GetWindowedContainer.
class FakeWebClient : public WebClient {
  UIView* GetWindowedContainer() override {
    if (!windowed_container) {
      windowed_container = [[UIView alloc] init];
    }
    return windowed_container;
  }

  UIView* windowed_container = nil;
};
}  // namespace

// Test fixture for the KeepRenderProcessAlive flag.
class KeepRenderProcessAliveTest : public WebTestWithWebState {
 protected:
  KeepRenderProcessAliveTest()
      : WebTestWithWebState(std::make_unique<FakeWebClient>()) {
    scoped_feature_list_.InitAndEnableFeature(
        web::features::kKeepsRenderProcessAlive);
  }

  KeepRenderProcessAliveTest(const KeepRenderProcessAliveTest&) = delete;
  KeepRenderProcessAliveTest& operator=(const KeepRenderProcessAliveTest&) =
      delete;

  void SetUp() override {
    WebTestWithWebState::SetUp();
    ASSERT_EQ(0U, GetWebClient()->GetWindowedContainer().subviews.count);
    ASSERT_TRUE(LoadHtml("<body></body>"));
    // WebTestWithWebState adds the view to thie view hierarchy.  Remove it for
    // the beginning of each test.
    [web_state()->GetView() removeFromSuperview];
  }

  bool WindowedContainerHasSubview() {
    return GetWebClient()->GetWindowedContainer().subviews.count == 1;
  }

  bool IsSubviewOfKeyWindow(UIView* view) {
    return view.superview == GetKeyWindow();
  }

  UIWindow* GetKeyWindow() { return GetAnyKeyWindow(); }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

// Test's that nothing is added to the WindowedContainer when
// -KeepRenderProcessAlive is disabled.
TEST_F(KeepRenderProcessAliveTest, KeepRenderProcessAliveOff) {
  web_state()->SetKeepRenderProcessAlive(false);
  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));

  [GetKeyWindow() addSubview:web_state()->GetView()];

  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_TRUE(IsSubviewOfKeyWindow(web_state()->GetView()));

  [web_state()->GetView() removeFromSuperview];
  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));
}

// Test's that the webState view is added to the windowed container when
// -KeepRenderProcessAlive is enabled and the the webState view has no window,
// and removed when the webState is added back to a window.
TEST_F(KeepRenderProcessAliveTest, KeepRenderProcessAliveOn) {
  web_state()->SetKeepRenderProcessAlive(true);
  ASSERT_TRUE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));

  [GetKeyWindow() addSubview:web_state()->GetView()];
  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_TRUE(IsSubviewOfKeyWindow(web_state()->GetView()));

  [web_state()->GetView() removeFromSuperview];
  ASSERT_TRUE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));
}

// Test's that the webState view is added or removed from the windowed
// container when -KeepRenderProcessAlive is enabled or disabled, respectively.
TEST_F(KeepRenderProcessAliveTest, KeepRenderProcessAliveToggle) {
  web_state()->SetKeepRenderProcessAlive(true);
  ASSERT_TRUE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));

  web_state()->SetKeepRenderProcessAlive(false);
  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));

  web_state()->SetKeepRenderProcessAlive(true);
  [GetKeyWindow() addSubview:web_state()->GetView()];
  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_TRUE(IsSubviewOfKeyWindow(web_state()->GetView()));

  [web_state()->GetView() removeFromSuperview];
  ASSERT_TRUE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));

  web_state()->SetKeepRenderProcessAlive(false);
  ASSERT_FALSE(WindowedContainerHasSubview());
  ASSERT_FALSE(IsSubviewOfKeyWindow(web_state()->GetView()));
}

}  // namespace web
