TEST(SocketAddress, SetFromSocketIPv4) {
  TSocketAddress serverBindAddr("0.0.0.0", 0);
  TSocketAddress clientBindAddr("0.0.0.0", 0);
  TSocketAddress listenAddr;
  TSocketAddress acceptAddr;
  TSocketAddress serverAddr;
  TSocketAddress serverPeerAddr;
  TSocketAddress clientAddr;
  TSocketAddress clientPeerAddr;

  testSetFromSocket(&serverBindAddr, &clientBindAddr,
                    &listenAddr, &acceptAddr,
                    &serverAddr, &serverPeerAddr,
                    &clientAddr, &clientPeerAddr);

  // The server socket's local address should have the same port as the listen
  // address.  The IP will be different, since the listening socket is
  // listening on INADDR_ANY, but the server socket will have a concrete IP
  // address assigned to it.
  EXPECT_EQ(serverAddr.getPort(), listenAddr.getPort());

  // The client's peer address should always be the same as the server
  // socket's address.
  EXPECT_EQ(clientPeerAddr, serverAddr);
  // The address returned by getpeername() on the server socket should
  // be the same as the address returned by accept()
  EXPECT_EQ(serverPeerAddr, acceptAddr);
  EXPECT_EQ(serverPeerAddr, clientAddr);
  EXPECT_EQ(acceptAddr, clientAddr);
}
TEST(SocketAddress, SetFromStrings) {
  TSocketAddress addr;

  // Set from a numeric port string
  addr.setFromLocalPort("1234");
  EXPECT_EQ(addr.getPort(), 1234);

  // setFromLocalPort() should not accept service names
  EXPECT_THROW(addr.setFromLocalPort("http"), TTransportException);

  // Call setFromLocalIpPort() with just a port, no IP
  addr.setFromLocalIpPort("80");
  EXPECT_EQ(addr.getPort(), 80);

  // Call setFromLocalIpPort() with an IP and port.
  addr.setFromLocalIpPort("127.0.0.1:4321");
  EXPECT_EQ(addr.getAddressStr(), "127.0.0.1");
  EXPECT_EQ(addr.getPort(), 4321);

  // setFromIpPort() without an address should fail
  EXPECT_THROW(addr.setFromIpPort("4321"), TTransportException);

  // Call setFromIpPort() with an IPv6 address and port
  addr.setFromIpPort("2620:0:1cfe:face:b00c::3:65535");
  EXPECT_EQ(addr.getFamily(), AF_INET6);
  EXPECT_EQ(addr.getAddressStr(), "2620:0:1cfe:face:b00c::3");
  EXPECT_EQ(addr.getPort(), 65535);

  // Call setFromIpPort() with an IPv4 address and port
  addr.setFromIpPort("1.2.3.4:9999");
  EXPECT_EQ(addr.getFamily(), AF_INET);
  EXPECT_EQ(addr.getAddressStr(), "1.2.3.4");
  EXPECT_EQ(addr.getPort(), 9999);
}
TEST(SocketAddress, SetFromIpv4) {
  TSocketAddress addr;
  addr.setFromIpPort("255.254.253.252", 8888);
  EXPECT_EQ(addr.getFamily(), AF_INET);
  EXPECT_EQ(addr.getAddressStr(), "255.254.253.252");
  EXPECT_EQ(addr.getPort(), 8888);
  sockaddr_storage addrStorage;
  addr.getAddress(&addrStorage);
  const sockaddr_in* inaddr = reinterpret_cast<sockaddr_in*>(&addrStorage);
  EXPECT_EQ(inaddr->sin_addr.s_addr, htonl(0xfffefdfc));
  EXPECT_EQ(inaddr->sin_port, htons(8888));
}
std::string
HeaderServerChannel::getTransportDebugString(TAsyncTransport* transport) {
  if (!transport) {
    return std::string();
  }

  auto ret = folly::to<std::string>("(transport ",
                                    folly::demangle(typeid(*transport)));

  try {
    TSocketAddress addr;
    transport->getPeerAddress(&addr);
    folly::toAppend(", address ", addr.getAddressStr(),
                    ", port ", addr.getPort(),
                    &ret);
  } catch (const TTransportException& e) {
  }

  ret += ')';
  return std::move(ret);
}
TEST(SocketAddress, Unix) {
  TSocketAddress addr;

  // Test a small path
  addr.setFromPath("foo");
  EXPECT_EQ(addr.getFamily(), AF_UNIX);
  EXPECT_EQ(addr.describe(), "foo");
  EXPECT_THROW(addr.getAddressStr(), TTransportException);
  EXPECT_THROW(addr.getPort(), TTransportException);
  EXPECT_TRUE(addr.isPrivateAddress());
  EXPECT_TRUE(addr.isLoopbackAddress());

  // Test a path that is too large
  const char longPath[] =
    "abcdefghijklmnopqrstuvwxyz0123456789"
    "abcdefghijklmnopqrstuvwxyz0123456789"
    "abcdefghijklmnopqrstuvwxyz0123456789"
    "abcdefghijklmnopqrstuvwxyz0123456789";
  EXPECT_THROW(addr.setFromPath(longPath), TTransportException);
  // The original address should still be the same
  EXPECT_EQ(addr.getFamily(), AF_UNIX);
  EXPECT_EQ(addr.describe(), "foo");

  // Test a path that exactly fits in sockaddr_un
  // (not including the NUL terminator)
  const char exactLengthPath[] =
    "abcdefghijklmnopqrstuvwxyz0123456789"
    "abcdefghijklmnopqrstuvwxyz0123456789"
    "abcdefghijklmnopqrstuvwxyz0123456789";
  addr.setFromPath(exactLengthPath);
  EXPECT_EQ(addr.describe(), exactLengthPath);

  // Test converting a unix socket address to an IPv4 one, then back
  addr.setFromHostPort("127.0.0.1", 1234);
  EXPECT_EQ(addr.getFamily(), AF_INET);
  EXPECT_EQ(addr.describe(), "127.0.0.1:1234");
  addr.setFromPath("/i/am/a/unix/address");
  EXPECT_EQ(addr.getFamily(), AF_UNIX);
  EXPECT_EQ(addr.describe(), "/i/am/a/unix/address");

  // Test copy constructor and assignment operator
  {
    TSocketAddress copy(addr);
    EXPECT_EQ(copy, addr);
    copy.setFromPath("/abc");
    EXPECT_NE(copy, addr);
    copy = addr;
    EXPECT_EQ(copy, addr);
    copy.setFromIpPort("127.0.0.1", 80);
    EXPECT_NE(copy, addr);
    copy = addr;
    EXPECT_EQ(copy, addr);
  }

  {
    TSocketAddress copy(addr);
    EXPECT_EQ(copy, addr);
    EXPECT_EQ(copy.describe(), "/i/am/a/unix/address");
    EXPECT_EQ(copy.getPath(), "/i/am/a/unix/address");

    TSocketAddress other("127.0.0.1", 80);
    EXPECT_NE(other, addr);
    other = copy;
    EXPECT_EQ(other, copy);
    EXPECT_EQ(other, addr);
    EXPECT_EQ(copy, addr);
  }

#if __GXX_EXPERIMENTAL_CXX0X__
  {
    TSocketAddress copy;
    {
      // move a unix address into a non-unix address
      TSocketAddress tmpCopy(addr);
      copy = std::move(tmpCopy);
    }
    EXPECT_EQ(copy, addr);

    copy.setFromPath("/another/path");
    {
      // move a unix address into a unix address
      TSocketAddress tmpCopy(addr);
      copy = std::move(tmpCopy);
    }
    EXPECT_EQ(copy, addr);

    {
      // move a non-unix address into a unix address
      TSocketAddress tmp("127.0.0.1", 80);
      copy = std::move(tmp);
    }
    EXPECT_EQ(copy.getAddressStr(), "127.0.0.1");
    EXPECT_EQ(copy.getPort(), 80);

    copy = addr;
    // move construct a unix address
    TSocketAddress other(std::move(copy));
    EXPECT_EQ(other, addr);
    EXPECT_EQ(other.getPath(), addr.getPath());
  }
#endif
}