// Copyright (c) 2013 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 <string>

#include <vector>

#include "base/guid.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/signedin_devices/signedin_devices_api.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/device_info.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/sync/profile_sync_service_mock.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using extensions::Extension;
using extensions::TestExtensionPrefs;
using browser_sync::DeviceInfo;
using testing::Return;

namespace extensions {

namespace utils = extension_function_test_utils;

TEST(SignedinDevicesAPITest, GetSignedInDevices) {
  ProfileSyncServiceMock pss_mock;
  base::MessageLoop message_loop_;
  TestExtensionPrefs extension_prefs(
      message_loop_.message_loop_proxy().get());

  // Add a couple of devices and make sure we get back public ids for them.
  std::string extension_name = "test";
  scoped_refptr<Extension> extension_test =
      extension_prefs.AddExtension(extension_name);

  DeviceInfo device_info1(
      base::GenerateGUID(),
      "abc Device", "XYZ v1", "XYZ SyncAgent v1",
      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);

  DeviceInfo device_info2(
      base::GenerateGUID(),
      "def Device", "XYZ v2", "XYZ SyncAgent v2",
      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);

  std::vector<DeviceInfo*> devices;
  devices.push_back(&device_info1);
  devices.push_back(&device_info2);

  EXPECT_CALL(pss_mock, GetAllSignedinDevicesMock()).
              WillOnce(Return(&devices));

  ScopedVector<DeviceInfo> output1 = GetAllSignedinDevices(
      extension_test.get()->id(),
      &pss_mock,
      extension_prefs.prefs());

  std::string public_id1 = device_info1.public_id();
  std::string public_id2 = device_info2.public_id();

  EXPECT_FALSE(public_id1.empty());
  EXPECT_FALSE(public_id2.empty());
  EXPECT_NE(public_id1, public_id2);

  // Now clear output1 so its destructor will not destroy the pointers for
  // |device_info1| and |device_info2|.
  output1.weak_clear();

  // Add a third device and make sure the first 2 ids are retained and a new
  // id is generated for the third device.
  DeviceInfo device_info3(
      base::GenerateGUID(),
      "def Device", "jkl v2", "XYZ SyncAgent v2",
      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);

  devices.push_back(&device_info3);

  EXPECT_CALL(pss_mock, GetAllSignedinDevicesMock()).
              WillOnce(Return(&devices));

  ScopedVector<DeviceInfo> output2 = GetAllSignedinDevices(
      extension_test.get()->id(),
      &pss_mock,
      extension_prefs.prefs());

  EXPECT_EQ(device_info1.public_id(), public_id1);
  EXPECT_EQ(device_info2.public_id(), public_id2);

  std::string public_id3 = device_info3.public_id();
  EXPECT_FALSE(public_id3.empty());
  EXPECT_NE(public_id3, public_id1);
  EXPECT_NE(public_id3, public_id2);

  // Now clear output2 so that its destructor does not destroy the
  // |DeviceInfo| pointers.
  output2.weak_clear();
}

class ProfileSyncServiceMockForExtensionTests:
    public ProfileSyncServiceMock {
 public:
  ProfileSyncServiceMockForExtensionTests() {}
  ~ProfileSyncServiceMockForExtensionTests() {}
  MOCK_METHOD0(Shutdown, void());
};

BrowserContextKeyedService* CreateProfileSyncServiceMock(
    content::BrowserContext* profile) {
  return new ProfileSyncServiceMockForExtensionTests();
}

class ExtensionSignedinDevicesTest : public BrowserWithTestWindowTest {
 public:
  virtual void SetUp() {
    BrowserWithTestWindowTest::SetUp();

    ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
        profile(), CreateProfileSyncServiceMock);

    extension_ = utils::CreateEmptyExtensionWithLocation(
        extensions::Manifest::UNPACKED);

  }

  base::Value* RunFunctionWithExtension(
      UIThreadExtensionFunction* function,
      const std::string& args) {
    scoped_refptr<UIThreadExtensionFunction> delete_function(function);
    function->set_extension(extension_.get());
    return utils::RunFunctionAndReturnSingleResult(function, args, browser());
  }

  base::ListValue* RunFunctionAndReturnList(
      UIThreadExtensionFunction* function,
      const std::string& args) {
    base::Value* result = RunFunctionWithExtension(function, args);
    return result ? utils::ToList(result) : NULL;
  }

 protected:
  scoped_refptr<extensions::Extension> extension_;
};

DeviceInfo* CreateDeviceInfo(const DeviceInfo& device_info) {
  return new DeviceInfo(device_info.guid(),
                        device_info.client_name(),
                        device_info.chrome_version(),
                        device_info.sync_user_agent(),
                        device_info.device_type());
}

std::string GetPublicId(const base::DictionaryValue* dictionary) {
  std::string public_id;
  if (!dictionary->GetString("id", &public_id)) {
    ADD_FAILURE() << "Not able to find public id in the dictionary";
  }

  return public_id;
}

void VerifyDictionaryWithDeviceInfo(const base::DictionaryValue* actual_value,
                                    DeviceInfo* device_info) {
  std::string public_id = GetPublicId(actual_value);
  device_info->set_public_id(public_id);

  scoped_ptr<base::DictionaryValue> expected_value(device_info->ToValue());
  EXPECT_TRUE(expected_value->Equals(actual_value));
}

base::DictionaryValue* GetDictionaryFromList(int index,
                                             base::ListValue* value) {
  base::DictionaryValue* dictionary;
  if (!value->GetDictionary(index, &dictionary)) {
    ADD_FAILURE() << "Expected a list of dictionaries";
    return NULL;
  }
  return dictionary;
}

TEST_F(ExtensionSignedinDevicesTest, GetAll) {
  ProfileSyncServiceMockForExtensionTests* pss_mock =
      static_cast<ProfileSyncServiceMockForExtensionTests*>(
          ProfileSyncServiceFactory::GetForProfile(profile()));

  DeviceInfo device_info1(
      base::GenerateGUID(),
      "abc Device", "XYZ v1", "XYZ SyncAgent v1",
      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);

  DeviceInfo device_info2(
      base::GenerateGUID(),
      "def Device", "XYZ v2", "XYZ SyncAgent v2",
      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);

  std::vector<DeviceInfo*> devices;
  devices.push_back(CreateDeviceInfo(device_info1));
  devices.push_back(CreateDeviceInfo(device_info2));

  EXPECT_CALL(*pss_mock, GetAllSignedinDevicesMock()).
              WillOnce(Return(&devices));

  EXPECT_CALL(*pss_mock, Shutdown());

  scoped_ptr<base::ListValue> result(RunFunctionAndReturnList(
      new SignedinDevicesGetFunction(), "[null]"));

  // Ensure dictionary matches device info.
  VerifyDictionaryWithDeviceInfo(GetDictionaryFromList(0, result.get()),
                                 &device_info1);
  VerifyDictionaryWithDeviceInfo(GetDictionaryFromList(1, result.get()),
                                 &device_info2);

  // Ensure public ids are set and unique.
  std::string public_id1 = GetPublicId(GetDictionaryFromList(0, result.get()));
  std::string public_id2 = GetPublicId(GetDictionaryFromList(1, result.get()));

  EXPECT_FALSE(public_id1.empty());
  EXPECT_FALSE(public_id2.empty());
  EXPECT_NE(public_id1, public_id2);
}

}  // namespace extensions
