// Copyright (c) 2017 The Chromium Embedded Framework 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 "tests/ceftests/extensions/extension_test_handler.h"

#include "include/cef_request_context_handler.h"
#include "tests/ceftests/test_suite.h"
#include "tests/ceftests/test_util.h"

ExtensionTestHandler::ExtensionTestHandler(
    RequestContextType request_context_type)
    : request_context_type_(request_context_type), create_main_browser_(true) {
  // Verify supported flag combinations.
  if (request_context_on_disk()) {
    EXPECT_TRUE(request_context_is_custom());
  }
  if (request_context_load_with_handler()) {
    EXPECT_FALSE(request_context_load_without_handler());
  }
  if (request_context_load_without_handler()) {
    EXPECT_TRUE(request_context_with_handler());
    EXPECT_FALSE(request_context_load_with_handler());
  }
}

ExtensionTestHandler::~ExtensionTestHandler() {
  if (!request_context_temp_dir_.IsEmpty()) {
    // Delete temporary directories on shutdown.
    CefTestSuite::GetInstance()->RegisterTempDirectory(
        request_context_temp_dir_.Take());
  }
}

void ExtensionTestHandler::RunTest() {
  if (create_main_browser_)
    OnAddMainBrowserResources();

  CefRefPtr<CefRequestContextHandler> rc_handler;
  if (request_context_with_handler()) {
    class Handler : public CefRequestContextHandler {
     public:
      explicit Handler(ExtensionTestHandler* test_handler)
          : test_handler_(test_handler) {}

      void OnRequestContextInitialized(
          CefRefPtr<CefRequestContext> request_context) override {
        if (test_handler_->create_main_browser()) {
          // Load extensions after the RequestContext has been initialized by
          // creation of the main browser.
          test_handler_->OnLoadExtensions();
        }
      }

     private:
      ExtensionTestHandler* test_handler_;

      IMPLEMENT_REFCOUNTING(Handler);
    };
    rc_handler = new Handler(this);
  }

  if (request_context_is_custom()) {
    CefRequestContextSettings settings;

    if (request_context_on_disk()) {
      // Create a new temporary directory.
      EXPECT_TRUE(request_context_temp_dir_.CreateUniqueTempDir());
      CefString(&settings.cache_path) = request_context_temp_dir_.GetPath();
    }

    request_context_ = CefRequestContext::CreateContext(settings, rc_handler);
  } else {
    request_context_ = CefRequestContext::CreateContext(
        CefRequestContext::GetGlobalContext(), rc_handler);
  }

  if (request_context_load_with_handler()) {
    class Handler : public CefRequestContextHandler {
     public:
      Handler() {}

     private:
      IMPLEMENT_REFCOUNTING(Handler);
    };
    loader_request_context_ =
        CefRequestContext::CreateContext(request_context_, new Handler());
  } else if (request_context_load_without_handler()) {
    loader_request_context_ =
        CefRequestContext::CreateContext(request_context_, nullptr);
  } else {
    loader_request_context_ = request_context_;
  }

  if (create_main_browser_) {
    OnCreateMainBrowser();
  } else {
    // Creation of the extension browser will trigger initialization of the
    // RequestContext, so just load the extensions now.
    OnLoadExtensions();
  }

  // Time out the test after a reasonable period of time.
  SetTestTimeout();
}

void ExtensionTestHandler::DestroyTest() {
  OnDestroyTest();
  ReleaseRequestContexts();
  RoutingTestHandler::DestroyTest();
}

void ExtensionTestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  RoutingTestHandler::OnAfterCreated(browser);

  if (create_main_browser() && !request_context_with_handler() &&
      GetBrowserId() == browser->GetIdentifier()) {
    // When the RequestContext doesn't have a handler we won't get a
    // notification for RequestContext initialization. Instead use main browser
    // creation to indicate that the RequestContext has been initialized.
    OnLoadExtensions();
  }
}

void ExtensionTestHandler::OnExtensionLoadFailed(cef_errorcode_t result) {
  EXPECT_TRUE(CefCurrentlyOn(TID_UI));
  EXPECT_TRUE(false);  // Not reached.
}

// CefMessageRouterBrowserSide::Handler methods:
bool ExtensionTestHandler::OnQuery(CefRefPtr<CefBrowser> browser,
                                   CefRefPtr<CefFrame> frame,
                                   int64 query_id,
                                   const CefString& request,
                                   bool persistent,
                                   CefRefPtr<Callback> callback) {
  if (OnMessage(browser, request))
    return true;

  EXPECT_FALSE(true) << "Unexpected message: " << request.ToString();
  return false;
}

// static
CefRefPtr<CefDictionaryValue> ExtensionTestHandler::CreateDefaultManifest(
    const std::vector<std::string>& api_permissions) {
  CefRefPtr<CefDictionaryValue> manifest = CefDictionaryValue::Create();
  manifest->SetString("name", "An extension");
  manifest->SetString("description", "An extension description");
  manifest->SetString("version", "1.0");
  manifest->SetInt("manifest_version", 2);

  CefRefPtr<CefListValue> permissions = CefListValue::Create();
  permissions->SetSize(api_permissions.size() + 2);
  size_t idx = 0;
  for (; idx < api_permissions.size(); ++idx)
    permissions->SetString(idx, api_permissions[idx]);

  // Allow access to all http/https origins.
  permissions->SetString(idx++, "http://*/*");
  permissions->SetString(idx++, "https://*/*");

  manifest->SetList("permissions", permissions);

  return manifest;
}

// static
std::string ExtensionTestHandler::GetMessageJS(const std::string& message) {
  EXPECT_TRUE(!message.empty());
  return "window.testQuery({request:'" + message + "'});";
}

// static
void ExtensionTestHandler::VerifyExtensionInContext(
    CefRefPtr<CefExtension> extension,
    CefRefPtr<CefRequestContext> context,
    bool has_access,
    bool is_loader) {
  const CefString& extension_id = extension->GetIdentifier();
  EXPECT_FALSE(extension_id.empty());

  if (has_access) {
    EXPECT_TRUE(context->DidLoadExtension(extension_id));
    EXPECT_TRUE(context->HasExtension(extension_id));
  } else {
    EXPECT_FALSE(context->DidLoadExtension(extension_id));
    EXPECT_FALSE(context->HasExtension(extension_id));
  }

  CefRefPtr<CefExtension> extension2 = context->GetExtension(extension_id);
  if (has_access) {
    EXPECT_TRUE(extension2);
    EXPECT_TRUE(extension->IsSame(extension2));
    TestDictionaryEqual(extension->GetManifest(), extension2->GetManifest());
  } else {
    EXPECT_FALSE(extension2);
  }

  std::vector<CefString> extension_ids;
  EXPECT_TRUE(context->GetExtensions(extension_ids));

  // Should be our test extension and possibly the builtin PDF extension if it
  // has finished loading (our extension may load first if the call to
  // LoadExtension initializes the request context).
  bool has_extension = false;
  for (size_t i = 0; i < extension_ids.size(); ++i) {
    if (extension_ids[i] == extension_id) {
      has_extension = true;
      break;
    }
  }
  if (has_access) {
    EXPECT_TRUE(has_extension);
  } else {
    EXPECT_FALSE(has_extension);
  }
}

void ExtensionTestHandler::LoadExtension(
    const std::string& extension_path,
    CefRefPtr<CefDictionaryValue> manifest) {
  EXPECT_TRUE(!extension_path.empty());
  loader_request_context_->LoadExtension(extension_path, manifest, this);
}

void ExtensionTestHandler::UnloadExtension(CefRefPtr<CefExtension> extension) {
  EXPECT_TRUE(extension);
  extension->Unload();
  EXPECT_FALSE(extension->IsLoaded());
  EXPECT_FALSE(extension->GetLoaderContext());
}

void ExtensionTestHandler::ReleaseRequestContexts() {
  request_context_ = nullptr;
  loader_request_context_ = nullptr;
}
