// 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/browser/extension_action_manager.h"

#include <memory>

#include "components/version_info/channel.h"
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_test.h"
#include "extensions/common/api/extension_action/action_info_test_util.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/value_builder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace extensions {

// TODO(devlin): This really seems like more of an ExtensionAction test than
// an ExtensionActionManager test.
class ExtensionActionManagerTest
    : public ExtensionsTest,
      public testing::WithParamInterface<ActionInfo::Type> {
 public:
  ExtensionActionManagerTest();

 protected:
  // ExtensionsTest:
  void SetUp() override;

  ExtensionActionManager* manager() { return manager_; }
  ExtensionRegistry* registry() { return registry_; }

 private:
  ExtensionRegistry* registry_;
  ExtensionActionManager* manager_;

  // Note: Instantiate the channel override, if any, before the rest of the
  // test environment gets set up in SetUp().
  std::unique_ptr<ScopedCurrentChannel> current_channel_;

  DISALLOW_COPY_AND_ASSIGN(ExtensionActionManagerTest);
};

ExtensionActionManagerTest::ExtensionActionManagerTest()
    : current_channel_(GetOverrideChannelForActionType(GetParam())) {}

void ExtensionActionManagerTest::SetUp() {
  ExtensionsTest::SetUp();
  registry_ = ExtensionRegistry::Get(browser_context());
  manager_ = ExtensionActionManager::Get(browser_context());
}

// Tests that if no icons are specified in the extension's action, values from
// the "icons" key are used instead.
TEST_P(ExtensionActionManagerTest, TestPopulateMissingValues_Icons) {
  // Test that the largest icon from the extension's "icons" key is chosen as a
  // replacement for missing action default_icons keys. "48" should not be
  // replaced because "128" can always be used in its place.
  scoped_refptr<const Extension> extension =
      ExtensionBuilder("Test Extension")
          .SetManifestKey("icons", DictionaryBuilder()
                                       .Set("48", "icon48.png")
                                       .Set("128", "icon128.png")
                                       .Build())
          .SetManifestKey(GetManifestKeyForActionType(GetParam()),
                          std::make_unique<base::DictionaryValue>())
          .Build();

  ASSERT_TRUE(extension);
  registry()->AddEnabled(extension);
  const ExtensionAction* action = manager()->GetExtensionAction(*extension);
  ASSERT_TRUE(action);
  ASSERT_EQ(GetParam(), action->action_type());

  ASSERT_TRUE(action->default_icon());
  // Since no icons are specified in the extension action, the product icons
  // (from the "icons" key) are used instead.
  EXPECT_EQ(action->default_icon()->map(),
            IconsInfo::GetIcons(extension.get()).map());
}

TEST_P(ExtensionActionManagerTest, TestPopulateMissingValues_Title) {
  scoped_refptr<const Extension> extension =
      ExtensionBuilder("Test Extension")
          .SetManifestKey(GetManifestKeyForActionType(GetParam()),
                          std::make_unique<base::DictionaryValue>())
          .Build();

  ASSERT_TRUE(extension);
  registry()->AddEnabled(extension);
  const ExtensionAction* action = manager()->GetExtensionAction(*extension);
  ASSERT_TRUE(action);
  ASSERT_EQ(GetParam(), action->action_type());

  EXPECT_EQ(extension->name(),
            action->GetTitle(ExtensionAction::kDefaultTabId));
}

// Tests that if defaults are provided in the extension action specification,
// those should be used.
TEST_P(ExtensionActionManagerTest, TestDontOverrideIfDefaultsProvided) {
  scoped_refptr<const Extension> extension =
      ExtensionBuilder("Test Extension")
          .SetManifestKey("icons",
                          DictionaryBuilder().Set("24", "icon24.png").Build())
          .SetManifestKey(
              GetManifestKeyForActionType(GetParam()),
              DictionaryBuilder()
                  .Set("default_icon",
                       DictionaryBuilder().Set("19", "icon19.png").Build())
                  .Set("default_title", "Action!")
                  .Build())
          .Build();

  ASSERT_TRUE(extension);
  registry()->AddEnabled(extension);
  const ExtensionAction* action = manager()->GetExtensionAction(*extension);
  ASSERT_TRUE(action);
  ASSERT_EQ(GetParam(), action->action_type());

  ASSERT_TRUE(action->default_icon());
  // Since there was at least one icon specified in the extension action, the
  // action icon should use that.
  EXPECT_THAT(action->default_icon()->map(),
              testing::UnorderedElementsAre(std::make_pair(19, "icon19.png")));

  // Since the default_title was specified, it should be used.
  EXPECT_EQ("Action!", action->GetTitle(ExtensionAction::kDefaultTabId));
}

INSTANTIATE_TEST_SUITE_P(All,
                         ExtensionActionManagerTest,
                         testing::Values(ActionInfo::TYPE_ACTION,
                                         ActionInfo::TYPE_BROWSER,
                                         ActionInfo::TYPE_PAGE));

}  // namespace extensions
