root/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AssertEmptyPermission
  2. ParsePermissionJSON
  3. PermissionFromValue
  4. PermissionFromJSON
  5. CheckFormat
  6. CheckFormat
  7. CheckFormat
  8. CheckFormat
  9. CheckFormat
  10. TEST
  11. TEST
  12. TEST
  13. TEST
  14. TEST

// 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 <set>

#include "base/json/json_reader.h"
#include "base/pickle.h"
#include "base/values.h"
#include "extensions/common/api/sockets/sockets_manifest_permission.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/manifest_constants.h"
#include "ipc/ipc_message.h"
#include "testing/gtest/include/gtest/gtest.h"

using content::SocketPermissionRequest;

namespace extensions {

namespace {

const char kUdpBindPermission[] =
    "{ \"udp\": { \"bind\": [\"127.0.0.1:3007\", \"a.com:80\"] } }";

const char kUdpSendPermission[] =
    "{ \"udp\": { \"send\": [\"\", \"a.com:80\"] } }";

const char kTcpConnectPermission[] =
    "{ \"tcp\": { \"connect\": [\"127.0.0.1:80\", \"a.com:80\"] } }";

const char kTcpServerListenPermission[] =
    "{ \"tcpServer\": { \"listen\": [\"127.0.0.1:80\", \"a.com:80\"] } }";

static void AssertEmptyPermission(const SocketsManifestPermission* permission) {
  EXPECT_TRUE(permission);
  EXPECT_EQ(std::string(extensions::manifest_keys::kSockets), permission->id());
  EXPECT_EQ(permission->id(), permission->name());
  EXPECT_FALSE(permission->HasMessages());
  EXPECT_EQ(0u, permission->entries().size());
}

static scoped_ptr<base::Value> ParsePermissionJSON(const std::string& json) {
  scoped_ptr<base::Value> result(base::JSONReader::Read(json));
  EXPECT_TRUE(result) << "Invalid JSON string: " << json;
  return result.Pass();
}

static scoped_ptr<SocketsManifestPermission> PermissionFromValue(
    const base::Value& value) {
  base::string16 error16;
  scoped_ptr<SocketsManifestPermission> permission(
      SocketsManifestPermission::FromValue(value, &error16));
  EXPECT_TRUE(permission) << "Error parsing Value into permission: " << error16;
  return permission.Pass();
}

static scoped_ptr<SocketsManifestPermission> PermissionFromJSON(
    const std::string& json) {
  scoped_ptr<base::Value> value(ParsePermissionJSON(json));
  return PermissionFromValue(*value);
}

struct CheckFormatEntry {
  CheckFormatEntry(SocketPermissionRequest::OperationType operation_type,
                   std::string host_pattern)
      : operation_type(operation_type), host_pattern(host_pattern) {}

  // operators <, == are needed by container std::set and algorithms
  // std::set_includes and std::set_differences.
  bool operator<(const CheckFormatEntry& rhs) const {
    if (operation_type == rhs.operation_type)
      return host_pattern < rhs.host_pattern;

    return operation_type < rhs.operation_type;
  }

  bool operator==(const CheckFormatEntry& rhs) const {
    return operation_type == rhs.operation_type &&
           host_pattern == rhs.host_pattern;
  }

  SocketPermissionRequest::OperationType operation_type;
  std::string host_pattern;
};

static testing::AssertionResult CheckFormat(
    std::multiset<CheckFormatEntry> permissions,
    const std::string& json) {
  scoped_ptr<SocketsManifestPermission> permission(PermissionFromJSON(json));
  if (!permission)
    return testing::AssertionFailure() << "Invalid permission " << json;

  if (permissions.size() != permission->entries().size()) {
    return testing::AssertionFailure()
           << "Incorrect # of entries in json: " << json;
  }

  // Note: We use multiset because SocketsManifestPermission does not have to
  // store entries in the order found in the json message.
  std::multiset<CheckFormatEntry> parsed_permissions;
  for (SocketsManifestPermission::SocketPermissionEntrySet::const_iterator it =
           permission->entries().begin();
       it != permission->entries().end();
       ++it) {
    parsed_permissions.insert(
        CheckFormatEntry(it->pattern().type, it->GetHostPatternAsString()));
  }

  if (!std::equal(
          permissions.begin(), permissions.end(), parsed_permissions.begin())) {
    return testing::AssertionFailure() << "Incorrect socket operations.";
  }
  return testing::AssertionSuccess();
}

static testing::AssertionResult CheckFormat(const std::string& json) {
  return CheckFormat(std::multiset<CheckFormatEntry>(), json);
}

static testing::AssertionResult CheckFormat(const std::string& json,
                                            const CheckFormatEntry& op1) {
  CheckFormatEntry entries[] = {op1};
  return CheckFormat(
      std::multiset<CheckFormatEntry>(entries, entries + arraysize(entries)),
      json);
}

static testing::AssertionResult CheckFormat(const std::string& json,
                                            const CheckFormatEntry& op1,
                                            const CheckFormatEntry& op2) {
  CheckFormatEntry entries[] = {op1, op2};
  return CheckFormat(
      std::multiset<CheckFormatEntry>(entries, entries + arraysize(entries)),
      json);
}

static testing::AssertionResult CheckFormat(const std::string& json,
                                            const CheckFormatEntry& op1,
                                            const CheckFormatEntry& op2,
                                            const CheckFormatEntry& op3,
                                            const CheckFormatEntry& op4,
                                            const CheckFormatEntry& op5,
                                            const CheckFormatEntry& op6,
                                            const CheckFormatEntry& op7,
                                            const CheckFormatEntry& op8,
                                            const CheckFormatEntry& op9) {
  CheckFormatEntry entries[] = {op1, op2, op3, op4, op5, op6, op7, op8, op9};
  return CheckFormat(
      std::multiset<CheckFormatEntry>(entries, entries + arraysize(entries)),
      json);
}

}  // namespace

TEST(SocketsManifestPermissionTest, Empty) {
  // Construction
  scoped_ptr<SocketsManifestPermission> permission(
      new SocketsManifestPermission());
  AssertEmptyPermission(permission.get());

  // Clone()/Equal()
  scoped_ptr<SocketsManifestPermission> clone(
      static_cast<SocketsManifestPermission*>(permission->Clone()));
  AssertEmptyPermission(clone.get());

  EXPECT_TRUE(permission->Equal(clone.get()));

  // ToValue()/FromValue()
  scoped_ptr<const base::Value> value(permission->ToValue());
  EXPECT_TRUE(value.get());

  scoped_ptr<SocketsManifestPermission> permission2(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission2->FromValue(value.get()));
  AssertEmptyPermission(permission2.get());

  // Union/Diff/Intersection
  scoped_ptr<SocketsManifestPermission> diff_perm(
      static_cast<SocketsManifestPermission*>(permission->Diff(clone.get())));
  AssertEmptyPermission(diff_perm.get());

  scoped_ptr<SocketsManifestPermission> union_perm(
      static_cast<SocketsManifestPermission*>(permission->Union(clone.get())));
  AssertEmptyPermission(union_perm.get());

  scoped_ptr<SocketsManifestPermission> intersect_perm(
      static_cast<SocketsManifestPermission*>(
          permission->Intersect(clone.get())));
  AssertEmptyPermission(intersect_perm.get());

  // IPC
  scoped_ptr<SocketsManifestPermission> ipc_perm(
      new SocketsManifestPermission());
  scoped_ptr<SocketsManifestPermission> ipc_perm2(
      new SocketsManifestPermission());

  IPC::Message m;
  ipc_perm->Write(&m);
  PickleIterator iter(m);
  EXPECT_TRUE(ipc_perm2->Read(&m, &iter));
  AssertEmptyPermission(ipc_perm2.get());
}

TEST(SocketsManifestPermissionTest, JSONFormats) {
  EXPECT_TRUE(CheckFormat(
      "{\"udp\":{\"send\":\"\"}}",
      CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "*:*")));
  EXPECT_TRUE(CheckFormat("{\"udp\":{\"send\":[]}}"));
  EXPECT_TRUE(CheckFormat(
      "{\"udp\":{\"send\":[\"\"]}}",
      CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "*:*")));
  EXPECT_TRUE(CheckFormat(
      "{\"udp\":{\"send\":[\"a:80\", \"b:10\"]}}",
      CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "b:10")));

  EXPECT_TRUE(
      CheckFormat("{\"udp\":{\"bind\":\"\"}}",
                  CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "*:*")));
  EXPECT_TRUE(CheckFormat("{\"udp\":{\"bind\":[]}}"));
  EXPECT_TRUE(
      CheckFormat("{\"udp\":{\"bind\":[\"\"]}}",
                  CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "*:*")));
  EXPECT_TRUE(
      CheckFormat("{\"udp\":{\"bind\":[\"a:80\", \"b:10\"]}}",
                  CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "a:80"),
                  CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "b:10")));

  EXPECT_TRUE(CheckFormat(
      "{\"udp\":{\"multicastMembership\":\"\"}}",
      CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, "")));
  EXPECT_TRUE(CheckFormat("{\"udp\":{\"multicastMembership\":[]}}"));
  EXPECT_TRUE(CheckFormat(
      "{\"udp\":{\"multicastMembership\":[\"\"]}}",
      CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, "")));
  EXPECT_TRUE(CheckFormat(
      "{\"udp\":{\"multicastMembership\":[\"\", \"\"]}}",
      CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, "")));

  EXPECT_TRUE(CheckFormat(
      "{\"tcp\":{\"connect\":\"\"}}",
      CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "*:*")));
  EXPECT_TRUE(CheckFormat("{\"tcp\":{\"connect\":[]}}"));
  EXPECT_TRUE(CheckFormat(
      "{\"tcp\":{\"connect\":[\"\"]}}",
      CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "*:*")));
  EXPECT_TRUE(CheckFormat(
      "{\"tcp\":{\"connect\":[\"a:80\", \"b:10\"]}}",
      CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "b:10")));

  EXPECT_TRUE(CheckFormat(
      "{\"tcpServer\":{\"listen\":\"\"}}",
      CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "*:*")));
  EXPECT_TRUE(CheckFormat("{\"tcpServer\":{\"listen\":[]}}"));
  EXPECT_TRUE(CheckFormat(
      "{\"tcpServer\":{\"listen\":[\"\"]}}",
      CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "*:*")));
  EXPECT_TRUE(CheckFormat(
      "{\"tcpServer\":{\"listen\":[\"a:80\", \"b:10\"]}}",
      CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "b:10")));

  EXPECT_TRUE(CheckFormat(
      "{"
      "\"udp\":{"
      "\"send\":[\"a:80\", \"b:10\"],"
      "\"bind\":[\"a:80\", \"b:10\"],"
      "\"multicastMembership\":\"\""
      "},"
      "\"tcp\":{\"connect\":[\"a:80\", \"b:10\"]},"
      "\"tcpServer\":{\"listen\":[\"a:80\", \"b:10\"]}"
      "}",
      CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "b:10"),
      CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "b:10"),
      CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, ""),
      CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "b:10"),
      CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "a:80"),
      CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "b:10")));
}

TEST(SocketsManifestPermissionTest, FromToValue) {
  scoped_ptr<base::Value> udp_send(ParsePermissionJSON(kUdpBindPermission));
  scoped_ptr<base::Value> udp_bind(ParsePermissionJSON(kUdpSendPermission));
  scoped_ptr<base::Value> tcp_connect(
      ParsePermissionJSON(kTcpConnectPermission));
  scoped_ptr<base::Value> tcp_server_listen(
      ParsePermissionJSON(kTcpServerListenPermission));

  // FromValue()
  scoped_ptr<SocketsManifestPermission> permission1(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission1->FromValue(udp_send.get()));
  EXPECT_EQ(2u, permission1->entries().size());

  scoped_ptr<SocketsManifestPermission> permission2(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission2->FromValue(udp_bind.get()));
  EXPECT_EQ(2u, permission2->entries().size());

  scoped_ptr<SocketsManifestPermission> permission3(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission3->FromValue(tcp_connect.get()));
  EXPECT_EQ(2u, permission3->entries().size());

  scoped_ptr<SocketsManifestPermission> permission4(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission4->FromValue(tcp_server_listen.get()));
  EXPECT_EQ(2u, permission4->entries().size());

  // ToValue()
  scoped_ptr<base::Value> value1 = permission1->ToValue();
  EXPECT_TRUE(value1);
  scoped_ptr<SocketsManifestPermission> permission1_1(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission1_1->FromValue(value1.get()));
  EXPECT_TRUE(permission1->Equal(permission1_1.get()));

  scoped_ptr<base::Value> value2 = permission2->ToValue();
  EXPECT_TRUE(value2);
  scoped_ptr<SocketsManifestPermission> permission2_1(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission2_1->FromValue(value2.get()));
  EXPECT_TRUE(permission2->Equal(permission2_1.get()));

  scoped_ptr<base::Value> value3 = permission3->ToValue();
  EXPECT_TRUE(value3);
  scoped_ptr<SocketsManifestPermission> permission3_1(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission3_1->FromValue(value3.get()));
  EXPECT_TRUE(permission3->Equal(permission3_1.get()));

  scoped_ptr<base::Value> value4 = permission4->ToValue();
  EXPECT_TRUE(value4);
  scoped_ptr<SocketsManifestPermission> permission4_1(
      new SocketsManifestPermission());
  EXPECT_TRUE(permission4_1->FromValue(value4.get()));
  EXPECT_TRUE(permission4->Equal(permission4_1.get()));
}

TEST(SocketsManifestPermissionTest, SetOperations) {
  scoped_ptr<SocketsManifestPermission> permission1(
      PermissionFromJSON(kUdpBindPermission));
  scoped_ptr<SocketsManifestPermission> permission2(
      PermissionFromJSON(kUdpSendPermission));
  scoped_ptr<SocketsManifestPermission> permission3(
      PermissionFromJSON(kTcpConnectPermission));
  scoped_ptr<SocketsManifestPermission> permission4(
      PermissionFromJSON(kTcpServerListenPermission));

  // Union
  scoped_ptr<SocketsManifestPermission> union_perm(
      static_cast<SocketsManifestPermission*>(
          permission1->Union(permission2.get())));
  EXPECT_TRUE(union_perm);
  EXPECT_EQ(4u, union_perm->entries().size());

  EXPECT_TRUE(union_perm->Contains(permission1.get()));
  EXPECT_TRUE(union_perm->Contains(permission2.get()));
  EXPECT_FALSE(union_perm->Contains(permission3.get()));
  EXPECT_FALSE(union_perm->Contains(permission4.get()));

  // Diff
  scoped_ptr<SocketsManifestPermission> diff_perm1(
      static_cast<SocketsManifestPermission*>(
          permission1->Diff(permission2.get())));
  EXPECT_TRUE(diff_perm1);
  EXPECT_EQ(2u, diff_perm1->entries().size());

  EXPECT_TRUE(permission1->Equal(diff_perm1.get()));
  EXPECT_TRUE(diff_perm1->Equal(permission1.get()));

  scoped_ptr<SocketsManifestPermission> diff_perm2(
      static_cast<SocketsManifestPermission*>(
          permission1->Diff(union_perm.get())));
  EXPECT_TRUE(diff_perm2);
  AssertEmptyPermission(diff_perm2.get());

  // Intersection
  scoped_ptr<SocketsManifestPermission> intersect_perm1(
      static_cast<SocketsManifestPermission*>(
          union_perm->Intersect(permission1.get())));
  EXPECT_TRUE(intersect_perm1);
  EXPECT_EQ(2u, intersect_perm1->entries().size());

  EXPECT_TRUE(permission1->Equal(intersect_perm1.get()));
  EXPECT_TRUE(intersect_perm1->Equal(permission1.get()));
}

TEST(SocketsManifestPermissionTest, IPC) {
  scoped_ptr<SocketsManifestPermission> permission(
      PermissionFromJSON(kUdpBindPermission));

  scoped_ptr<SocketsManifestPermission> ipc_perm(
      static_cast<SocketsManifestPermission*>(permission->Clone()));
  scoped_ptr<SocketsManifestPermission> ipc_perm2(
      new SocketsManifestPermission());

  IPC::Message m;
  ipc_perm->Write(&m);
  PickleIterator iter(m);
  EXPECT_TRUE(ipc_perm2->Read(&m, &iter));
  EXPECT_TRUE(permission->Equal(ipc_perm2.get()));
}

}  // namespace extensions

/* [<][>][^][v][top][bottom][index][help] */