910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/api/test/test_api.h"

#include <string>

#include "base/command_line.h"
#include "base/memory/singleton.h"
#include "content/public/common/content_switches.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/test/test_api_observer_registry.h"
#include "extensions/browser/extension_function_dispatcher.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/api/test.h"

namespace {

// If you see this error in your test, you need to set the config state
// to be returned by chrome.test.getConfig().  Do this by calling
// TestGetConfigFunction::set_test_config_state(Value* state)
// in test set up.
const char kNoTestConfigDataError[] = "Test configuration was not set.";

const char kNotTestProcessError[] =
    "The chrome.test namespace is only available in tests.";

}  // namespace

namespace extensions {

namespace Log = api::test::Log;
namespace NotifyFail = api::test::NotifyFail;
namespace PassMessage = api::test::PassMessage;
namespace WaitForRoundTrip = api::test::WaitForRoundTrip;

TestExtensionFunction::~TestExtensionFunction() = default;

bool TestExtensionFunction::PreRunValidation(std::string* error) {
  if (!ExtensionFunction::PreRunValidation(error))
    return false;
  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
    *error = kNotTestProcessError;
    return false;
  }
  return true;
}

TestNotifyPassFunction::~TestNotifyPassFunction() = default;

ExtensionFunction::ResponseAction TestNotifyPassFunction::Run() {
  TestApiObserverRegistry::GetInstance()->NotifyTestPassed(browser_context());
  return RespondNow(NoArguments());
}

TestNotifyFailFunction::~TestNotifyFailFunction() = default;

ExtensionFunction::ResponseAction TestNotifyFailFunction::Run() {
  std::optional<NotifyFail::Params> params = NotifyFail::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);
  TestApiObserverRegistry::GetInstance()->NotifyTestFailed(
      browser_context(), params->message);
  return RespondNow(NoArguments());
}

TestLogFunction::~TestLogFunction() = default;

ExtensionFunction::ResponseAction TestLogFunction::Run() {
  std::optional<Log::Params> params = Log::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);
  VLOG(1) << params->message;
  return RespondNow(NoArguments());
}

TestOpenFileUrlFunction::~TestOpenFileUrlFunction() = default;

ExtensionFunction::ResponseAction TestOpenFileUrlFunction::Run() {
  std::optional<api::test::OpenFileUrl::Params> params =
      api::test::OpenFileUrl::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);
  GURL file_url(params->url);
  EXTENSION_FUNCTION_VALIDATE(file_url.is_valid());
  EXTENSION_FUNCTION_VALIDATE(file_url.SchemeIsFile());

  ExtensionsAPIClient::Get()->OpenFileUrlForTesting(file_url,
                                                    browser_context());
  return RespondNow(NoArguments());
}

TestSendMessageFunction::TestSendMessageFunction() = default;

ExtensionFunction::ResponseAction TestSendMessageFunction::Run() {
  std::optional<PassMessage::Params> params =
      PassMessage::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);
  bool listener_will_respond =
      TestApiObserverRegistry::GetInstance()->NotifyTestMessage(
          this, params->message);
  // If none of the listeners intend to respond, or one has already responded,
  // finish the function. We always reply to the message, even if it's just an
  // empty string.
  if (!listener_will_respond || response_) {
    if (!response_) {
      response_.emplace(WithArguments(std::string()));
    }
    return RespondNow(std::move(*response_));
  }
  // Otherwise, wait for a reply.
  waiting_ = true;
  return RespondLater();
}

TestSendMessageFunction::~TestSendMessageFunction() = default;

void TestSendMessageFunction::Reply(const std::string& message) {
  DCHECK(!response_);
  response_.emplace(WithArguments(message));
  if (waiting_)
    Respond(std::move(*response_));
}

void TestSendMessageFunction::ReplyWithError(const std::string& error) {
  DCHECK(!response_);
  response_.emplace(Error(error));
  if (waiting_)
    Respond(std::move(*response_));
}

TestSendScriptResultFunction::TestSendScriptResultFunction() = default;
TestSendScriptResultFunction::~TestSendScriptResultFunction() = default;

ExtensionFunction::ResponseAction TestSendScriptResultFunction::Run() {
  std::optional<api::test::SendScriptResult::Params> params =
      api::test::SendScriptResult::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);

  TestApiObserverRegistry::GetInstance()->NotifyScriptResult(params->result);
  return RespondNow(NoArguments());
}

// static
void TestGetConfigFunction::set_test_config_state(base::Value::Dict* value) {
  TestConfigState* test_config_state = TestConfigState::GetInstance();
  test_config_state->set_config_state(value);
}

TestGetConfigFunction::TestConfigState::TestConfigState()
    : config_state_(nullptr) {}

// static
TestGetConfigFunction::TestConfigState*
TestGetConfigFunction::TestConfigState::GetInstance() {
  return base::Singleton<TestConfigState>::get();
}

TestGetConfigFunction::~TestGetConfigFunction() = default;

ExtensionFunction::ResponseAction TestGetConfigFunction::Run() {
  TestConfigState* test_config_state = TestConfigState::GetInstance();
  if (!test_config_state->config_state())
    return RespondNow(Error(kNoTestConfigDataError));
  return RespondNow(WithArguments(test_config_state->config_state()->Clone()));
}

TestWaitForRoundTripFunction::~TestWaitForRoundTripFunction() = default;

ExtensionFunction::ResponseAction TestWaitForRoundTripFunction::Run() {
  std::optional<WaitForRoundTrip::Params> params =
      WaitForRoundTrip::Params::Create(args());
  return RespondNow(WithArguments(params->message));
}

}  // namespace extensions