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

#include "components/optimization_guide/content/renderer/page_text_agent.h"

#include <string>

#include "base/strings/strcat.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/test/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/web/web_local_frame.h"

namespace optimization_guide {

namespace {

class TestConsumer : public mojom::PageTextConsumer {
 public:
  TestConsumer() = default;
  ~TestConsumer() override = default;

  std::u16string text() const { return base::StrCat(chunks_); }
  bool on_chunks_end_called() const { return on_chunks_end_called_; }
  size_t num_chunks() const { return chunks_.size(); }

  void Bind(mojo::PendingReceiver<mojom::PageTextConsumer> pending_receiver) {
    receiver_.Bind(std::move(pending_receiver));
  }

  // mojom::PageTextConsumer:
  void OnTextDumpChunk(const std::u16string& chunk) override {
    ASSERT_FALSE(on_chunks_end_called_);
    chunks_.push_back(chunk);
  }

  void OnChunksEnd() override { on_chunks_end_called_ = true; }

 private:
  mojo::Receiver<mojom::PageTextConsumer> receiver_{this};
  std::vector<std::u16string> chunks_;
  bool on_chunks_end_called_ = false;
};

}  // namespace

class PageTextAgentRenderViewTest : public content::RenderViewTest {
 public:
  PageTextAgentRenderViewTest() = default;
  ~PageTextAgentRenderViewTest() override = default;
};

TEST_F(PageTextAgentRenderViewTest, AMPSubframeFirstLayout) {
  // Create and get a subframe.
  LoadHTML(
      "<html><body>"
      "  <p>hello</p>"
      "  <iframe name=sub srcdoc=\"<p>world</p>\"></iframe>"
      "</body></html>");
  content::RenderFrame* subframe = content::RenderFrame::FromWebFrame(
      GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());

  PageTextAgent subframe_agent(subframe);

  // Send the request.
  mojo::PendingRemote<mojom::PageTextConsumer> consumer_remote;
  TestConsumer consumer;
  consumer.Bind(consumer_remote.InitWithNewPipeAndPassReceiver());

  auto request = mojom::PageTextDumpRequest::New();
  request->max_size = 1024;
  request->event = mojom::TextDumpEvent::kFirstLayout;
  subframe_agent.RequestPageTextDump(std::move(request),
                                     std::move(consumer_remote));

  // Simulate a page load.
  subframe_agent.DidObserveLoadingBehavior(
      blink::LoadingBehaviorFlag::kLoadingBehaviorAmpDocumentLoaded);
  subframe_agent.DidFinishLoad();
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(consumer.on_chunks_end_called());
}

TEST_F(PageTextAgentRenderViewTest, NotAMPSubframeLoadFinished) {
  // Create and get a subframe.
  LoadHTML(
      "<html><body>"
      "  <p>hello</p>"
      "  <iframe name=sub srcdoc=\"<p>world</p>\"></iframe>"
      "</body></html>");
  content::RenderFrame* subframe = content::RenderFrame::FromWebFrame(
      GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());

  PageTextAgent subframe_agent(subframe);

  // Send the request.
  mojo::PendingRemote<mojom::PageTextConsumer> consumer_remote;
  TestConsumer consumer;
  consumer.Bind(consumer_remote.InitWithNewPipeAndPassReceiver());

  auto request = mojom::PageTextDumpRequest::New();
  request->max_size = 1024;
  request->event = mojom::TextDumpEvent::kFinishedLoad;
  subframe_agent.RequestPageTextDump(std::move(request),
                                     std::move(consumer_remote));

  // Simulate a page load.
  subframe_agent.DidObserveLoadingBehavior(
      blink::LoadingBehaviorFlag::kLoadingBehaviorNone);
  subframe_agent.DidFinishLoad();
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(consumer.on_chunks_end_called());
}

TEST_F(PageTextAgentRenderViewTest, MainFrame) {
  // Create and get a subframe.
  LoadHTML(
      "<html><body>"
      "  <p>hello</p>"
      "</body></html>");
  content::RenderFrame* mainframe =
      content::RenderFrame::FromWebFrame(GetMainFrame());

  PageTextAgent subframe_agent(mainframe);

  // Send the request.
  mojo::PendingRemote<mojom::PageTextConsumer> consumer_remote;
  TestConsumer consumer;
  consumer.Bind(consumer_remote.InitWithNewPipeAndPassReceiver());

  auto request = mojom::PageTextDumpRequest::New();
  request->max_size = 1024;
  request->event = mojom::TextDumpEvent::kFinishedLoad;
  subframe_agent.RequestPageTextDump(std::move(request),
                                     std::move(consumer_remote));

  // Simulate a page load.
  subframe_agent.DidObserveLoadingBehavior(
      blink::LoadingBehaviorFlag::kLoadingBehaviorAmpDocumentLoaded);
  subframe_agent.DidFinishLoad();
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(consumer.on_chunks_end_called());
}

TEST_F(PageTextAgentRenderViewTest, AMPSuccessCase) {
  // Create and get a subframe.
  LoadHTML(
      "<html><body>"
      "  <p>hello</p>"
      "  <iframe name=sub srcdoc=\"<p>world</p>\"></iframe>"
      "</body></html>");
  content::RenderFrame* subframe = content::RenderFrame::FromWebFrame(
      GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());

  PageTextAgent subframe_agent(subframe);

  // Send the request.
  mojo::PendingRemote<mojom::PageTextConsumer> consumer_remote;
  TestConsumer consumer;
  consumer.Bind(consumer_remote.InitWithNewPipeAndPassReceiver());

  auto request = mojom::PageTextDumpRequest::New();
  request->max_size = 1024;
  request->event = mojom::TextDumpEvent::kFinishedLoad;
  subframe_agent.RequestPageTextDump(std::move(request),
                                     std::move(consumer_remote));

  // Simulate a page load.
  subframe_agent.DidObserveLoadingBehavior(
      blink::LoadingBehaviorFlag::kLoadingBehaviorAmpDocumentLoaded);
  subframe_agent.DidFinishLoad();
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(consumer.on_chunks_end_called());
  EXPECT_EQ(u"world", consumer.text());
}

}  // namespace optimization_guide
