// Copyright 2014 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 "extensions/renderer/module_system_test.h"

#include <stddef.h>

#include <map>
#include <memory>
#include <string>
#include <utility>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_paths.h"
#include "extensions/common/value_builder.h"
#include "extensions/renderer/ipc_message_sender.h"
#include "extensions/renderer/logging_native_handler.h"
#include "extensions/renderer/native_extension_bindings_system.h"
#include "extensions/renderer/object_backed_native_handler.h"
#include "extensions/renderer/safe_builtins.h"
#include "extensions/renderer/script_context_set.h"
#include "extensions/renderer/string_source_map.h"
#include "extensions/renderer/test_v8_extension_configuration.h"
#include "extensions/renderer/utils_native_handler.h"
#include "gin/converter.h"
#include "ui/base/resource/resource_bundle.h"

namespace extensions {
namespace {

class FailsOnException : public ModuleSystem::ExceptionHandler {
 public:
  FailsOnException() : ModuleSystem::ExceptionHandler(nullptr) {}
  void HandleUncaughtException(const v8::TryCatch& try_catch) override {
    FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch);
  }
};

class GetAPINatives : public ObjectBackedNativeHandler {
 public:
  GetAPINatives(ScriptContext* context,
                NativeExtensionBindingsSystem* bindings_system)
      : ObjectBackedNativeHandler(context), bindings_system_(bindings_system) {
    DCHECK(bindings_system_);
  }
  ~GetAPINatives() override {}

  // ObjectBackedNativeHandler:
  void AddRoutes() override {
    auto get_api = [](ScriptContext* context,
                      NativeExtensionBindingsSystem* bindings_system,
                      const v8::FunctionCallbackInfo<v8::Value>& args) {
      CHECK_EQ(1, args.Length());
      CHECK(args[0]->IsString());
      std::string api_name = gin::V8ToString(context->isolate(), args[0]);
      v8::Local<v8::Object> api;
      if (bindings_system) {
        api = bindings_system->GetAPIObjectForTesting(context, api_name);
      } else {
        v8::Local<v8::Object> full_binding;
        CHECK(
            context->module_system()->Require(api_name).ToLocal(&full_binding))
            << "Failed to get: " << api_name;
        v8::Local<v8::Value> api_value;
        CHECK(full_binding
                  ->Get(context->v8_context(),
                        gin::StringToSymbol(context->isolate(), "binding"))
                  .ToLocal(&api_value))
            << "Failed to get: " << api_name;
        CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
        api = api_value.As<v8::Object>();
      }
      args.GetReturnValue().Set(api);
    };

    RouteHandlerFunction(
        "get", base::BindRepeating(get_api, context(), bindings_system_));
  }

 private:
  NativeExtensionBindingsSystem* bindings_system_ = nullptr;

  DISALLOW_COPY_AND_ASSIGN(GetAPINatives);
};

}  // namespace

// Native JS functions for doing asserts.
class ModuleSystemTestEnvironment::AssertNatives
    : public ObjectBackedNativeHandler {
 public:
  explicit AssertNatives(ScriptContext* context)
      : ObjectBackedNativeHandler(context),
        assertion_made_(false),
        failed_(false) {}

  // ObjectBackedNativeHandler:
  void AddRoutes() override {
    RouteHandlerFunction("AssertTrue",
                         base::BindRepeating(&AssertNatives::AssertTrue,
                                             base::Unretained(this)));
    RouteHandlerFunction("AssertFalse",
                         base::BindRepeating(&AssertNatives::AssertFalse,
                                             base::Unretained(this)));
  }

  bool assertion_made() { return assertion_made_; }
  bool failed() { return failed_; }

  void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
    CHECK_EQ(1, args.Length());
    assertion_made_ = true;
    failed_ = failed_ || !args[0]->ToBoolean(args.GetIsolate())->Value();
  }

  void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
    CHECK_EQ(1, args.Length());
    assertion_made_ = true;
    failed_ = failed_ || args[0]->ToBoolean(args.GetIsolate())->Value();
  }

 private:
  bool assertion_made_;
  bool failed_;
};

ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
    v8::Isolate* isolate,
    ScriptContextSet* context_set,
    scoped_refptr<const Extension> extension)
    : isolate_(isolate),
      context_holder_(new gin::ContextHolder(isolate_)),
      handle_scope_(isolate_),
      extension_(extension),
      context_set_(context_set),
      source_map_(new StringSourceMap()) {
  context_holder_->SetContext(v8::Context::New(
      isolate, TestV8ExtensionConfiguration::GetConfiguration()));

  {
    auto context = std::make_unique<ScriptContext>(
        context_holder_->context(),
        nullptr,  // WebFrame
        extension_.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension_.get(),
        Feature::BLESSED_EXTENSION_CONTEXT);
    context_ = context.get();
    context_set_->AddForTesting(std::move(context));
  }

  context_->v8_context()->Enter();
  assert_natives_ = new AssertNatives(context_);

  bindings_system_ = std::make_unique<NativeExtensionBindingsSystem>(nullptr);

  {
    std::unique_ptr<ModuleSystem> module_system(
        new ModuleSystem(context_, source_map_.get()));
    context_->SetModuleSystem(std::move(module_system));
  }
  ModuleSystem* module_system = context_->module_system();
  module_system->RegisterNativeHandler(
      "assert", std::unique_ptr<NativeHandler>(assert_natives_));
  module_system->RegisterNativeHandler(
      "logging",
      std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
  module_system->RegisterNativeHandler(
      "utils",
      std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
  module_system->RegisterNativeHandler(
      "apiGetter",
      std::make_unique<GetAPINatives>(context_, bindings_system_.get()));
  module_system->SetExceptionHandlerForTest(
      std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));

  bindings_system_->DidCreateScriptContext(context_);
  bindings_system_->UpdateBindingsForContext(context_);
}

ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
  if (context_)
    ShutdownModuleSystem();
}

void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
                                                 const std::string& code) {
  source_map_->RegisterModule(name, code);
}

void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
                                                 int resource_id,
                                                 bool gzipped) {
  const std::string& code = ui::ResourceBundle::GetSharedInstance()
                                .GetRawDataResource(resource_id)
                                .as_string();
  source_map_->RegisterModule(name, code, gzipped);
}

void ModuleSystemTestEnvironment::OverrideNativeHandler(
    const std::string& name,
    const std::string& code) {
  RegisterModule(name, code);
  context_->module_system()->OverrideNativeHandlerForTest(name);
}

void ModuleSystemTestEnvironment::RegisterTestFile(
    const std::string& module_name,
    const std::string& file_name) {
  base::FilePath test_js_file_path;
  ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_js_file_path));
  test_js_file_path = test_js_file_path.AppendASCII(file_name);
  std::string test_js;
  ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
  source_map_->RegisterModule(module_name, test_js);
}

void ModuleSystemTestEnvironment::ShutdownGin() {
  context_holder_.reset();
}

void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
  CHECK(context_->is_valid());
  context_->v8_context()->Exit();
  context_set_->Remove(context_);
  base::RunLoop().RunUntilIdle();
  context_ = nullptr;
  assert_natives_ = nullptr;
}

v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
    const std::string& name) {
  v8::EscapableHandleScope handle_scope(isolate_);
  v8::Local<v8::Object> object = v8::Object::New(isolate_);
  isolate_->GetCurrentContext()
      ->Global()
      ->Set(context_->v8_context(),
            v8::String::NewFromUtf8(isolate_, name.c_str(),
                                    v8::NewStringType::kInternalized)
                .ToLocalChecked(),
            object)
      .ToChecked();
  return handle_scope.Escape(object);
}

ModuleSystemTest::ModuleSystemTest()
    : isolate_(v8::Isolate::GetCurrent()),
      context_set_(&extension_ids_),
      should_assertions_be_made_(true) {}

ModuleSystemTest::~ModuleSystemTest() {
}

void ModuleSystemTest::SetUp() {
  extension_ = CreateExtension();
  env_ = CreateEnvironment();
  base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
}

void ModuleSystemTest::TearDown() {
  // All tests must assert at least once unless otherwise specified.
  if (env_->assert_natives()) {  // The context may have already been shutdown.
    EXPECT_EQ(should_assertions_be_made_,
              env_->assert_natives()->assertion_made());
    EXPECT_FALSE(env_->assert_natives()->failed());
  } else {
    EXPECT_FALSE(should_assertions_be_made_);
  }
  env_.reset();
  v8::HeapStatistics stats;
  isolate_->GetHeapStatistics(&stats);
  size_t old_heap_size = 0;
  // Run the GC until the heap size reaches a steady state to ensure that
  // all the garbage is collected.
  while (stats.used_heap_size() != old_heap_size) {
    old_heap_size = stats.used_heap_size();
    isolate_->RequestGarbageCollectionForTesting(
        v8::Isolate::kFullGarbageCollection);
    isolate_->GetHeapStatistics(&stats);
  }
}

scoped_refptr<const Extension> ModuleSystemTest::CreateExtension() {
  std::unique_ptr<base::DictionaryValue> manifest =
      DictionaryBuilder()
          .Set("name", "test")
          .Set("version", "1.0")
          .Set("manifest_version", 2)
          .Build();
  return ExtensionBuilder().SetManifest(std::move(manifest)).Build();
}

std::unique_ptr<ModuleSystemTestEnvironment>
ModuleSystemTest::CreateEnvironment() {
  return std::make_unique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
                                                       extension_);
}

void ModuleSystemTest::ExpectNoAssertionsMade() {
  should_assertions_be_made_ = false;
}

void ModuleSystemTest::RunResolvedPromises() {
  v8::MicrotasksScope::PerformCheckpoint(isolate_);
}

}  // namespace extensions
