/*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2014-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include <sys/types.h>
#include <string>
-#include <folly/Bits.h>
#include <folly/Format.h>
#include <folly/IPAddress.h>
#include <folly/MacAddress.h>
#include <folly/String.h>
+#include <folly/container/BitIterator.h>
#include <folly/detail/IPAddressSource.h>
+#include <folly/lang/Bits.h>
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>
struct IPAddressByteAccessorTest : TestWithParam<AddressData> {};
struct IPAddressBitAccessorTest : TestWithParam<AddressData> {};
+struct StringTestParam {
+ std::string in;
+ folly::Optional<std::string> out;
+ folly::Optional<std::string> out4;
+ folly::Optional<std::string> out6;
+};
+
+struct TryFromStringTest : TestWithParam<StringTestParam> {
+ static std::vector<StringTestParam> ipInOutProvider() {
+ const std::string lo6{"::1"};
+ const std::string lo6brackets{"[::1]"};
+ const std::string ip6{"1234::abcd"};
+ const std::string invalid6{"[::aaaR]"};
+
+ const std::string lo4{"127.0.0.1"};
+ const std::string ip4{"192.168.0.1"};
+ const std::string invalid4{"127.0.0.256"};
+
+ const static std::vector<StringTestParam> ret = {
+ {lo6, lo6, none, lo6},
+ {lo6brackets, lo6, none, lo6},
+ {ip6, ip6, none, ip6},
+ {invalid6, none, none, none},
+ {lo4, lo4, lo4, none},
+ {ip4, ip4, ip4, none},
+ {invalid4, none, none, none},
+ };
+
+ return ret;
+ }
+};
+
// tests code example
TEST(IPAddress, CodeExample) {
EXPECT_EQ(4, sizeof(IPAddressV4));
}
}
-TEST(IPAddress, CreateNetwork) {
+TEST(IPAddress, TryCreateNetwork) {
// test valid IPv4 network
{
- auto net = IPAddress::createNetwork("192.168.0.1/24");
+ auto net = IPAddress::tryCreateNetwork("192.168.0.1/24").value();
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.0", net.first.str());
EXPECT_EQ(24, net.second);
}
// test valid IPv4 network without applying mask
{
- auto net = IPAddress::createNetwork("192.168.0.1/24", -1, false);
+ auto net = IPAddress::tryCreateNetwork("192.168.0.1/24", -1, false).value();
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.1", net.first.str());
EXPECT_EQ(24, net.second);
}
// test valid IPv6 network
{
- auto net = IPAddress::createNetwork("1999::1/24");
+ auto net = IPAddress::tryCreateNetwork("1999::1/24").value();
ASSERT_TRUE(net.first.isV6());
EXPECT_EQ("1999::", net.first.str());
EXPECT_EQ(24, net.second);
}
// test valid IPv6 network without applying mask
{
- auto net = IPAddress::createNetwork("1999::1/24", -1, false);
+ auto net = IPAddress::tryCreateNetwork("1999::1/24", -1, false).value();
ASSERT_TRUE(net.first.isV6());
EXPECT_EQ("1999::1", net.first.str());
EXPECT_EQ(24, net.second);
EXPECT_EQ("1999::1/24", IPAddress::networkToString(net));
}
+
+ // test invalid default CIDR
+ EXPECT_EQ(
+ CIDRNetworkError::INVALID_DEFAULT_CIDR,
+ IPAddress::tryCreateNetwork("192.168.1.1", 300).error());
+
// test empty string
- EXPECT_THROW(IPAddress::createNetwork(""), IPAddressFormatException);
+ EXPECT_EQ(
+ CIDRNetworkError::INVALID_IP, IPAddress::tryCreateNetwork("").error());
+
// test multi slash string
- EXPECT_THROW(
- IPAddress::createNetwork("192.168.0.1/24/36"), IPAddressFormatException);
+ EXPECT_EQ(
+ CIDRNetworkError::INVALID_IP_SLASH_CIDR,
+ IPAddress::tryCreateNetwork("192.168.0.1/24/36").error());
+
// test no slash string with default IPv4
{
- auto net = IPAddress::createNetwork("192.168.0.1");
+ auto net = IPAddress::tryCreateNetwork("192.168.0.1").value();
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.1", net.first.str());
EXPECT_EQ(32, net.second); // auto-detected
}
// test no slash string with default IPv6
{
- auto net = IPAddress::createNetwork("1999::1");
+ auto net = IPAddress::tryCreateNetwork("1999::1").value();
ASSERT_TRUE(net.first.isV6());
EXPECT_EQ("1999::1", net.first.str());
EXPECT_EQ(128, net.second);
}
// test no slash string with invalid default
+ EXPECT_EQ(
+ CIDRNetworkError::CIDR_MISMATCH,
+ IPAddress::tryCreateNetwork("192.168.0.1", 33).error());
+}
+
+// test that throwing version actually throws
+TEST(IPAddress, CreateNetworkExceptions) {
+ // test invalid default CIDR
+ EXPECT_THROW(IPAddress::createNetwork("192.168.0.1", 300), std::range_error);
+ // test empty string
+ EXPECT_THROW(IPAddress::createNetwork(""), IPAddressFormatException);
+ // test multi slash string
+ EXPECT_THROW(
+ IPAddress::createNetwork("192.168.0.1/24/36"), IPAddressFormatException);
+ // test no slash string with invalid default
EXPECT_THROW(
IPAddress::createNetwork("192.168.0.1", 33), IPAddressFormatException);
}
}
}
+TEST_P(TryFromStringTest, IPAddress) {
+ auto param = GetParam();
+ auto maybeIp = IPAddress::tryFromString(param.in);
+ if (param.out) {
+ EXPECT_TRUE(maybeIp.hasValue());
+ EXPECT_EQ(param.out, maybeIp.value().str());
+ } else {
+ EXPECT_TRUE(maybeIp.hasError());
+ EXPECT_TRUE(
+ IPAddressFormatError::INVALID_IP == maybeIp.error() ||
+ IPAddressFormatError::UNSUPPORTED_ADDR_FAMILY == maybeIp.error());
+ }
+}
+
+TEST_P(TryFromStringTest, IPAddressV4) {
+ auto param = GetParam();
+ auto maybeIp = IPAddressV4::tryFromString(param.in);
+ if (param.out4) {
+ EXPECT_TRUE(maybeIp.hasValue());
+ EXPECT_EQ(param.out4, maybeIp.value().str());
+ } else {
+ EXPECT_TRUE(maybeIp.hasError());
+ EXPECT_EQ(IPAddressFormatError::INVALID_IP, maybeIp.error());
+ }
+}
+
+TEST_P(TryFromStringTest, IPAddressV6) {
+ auto param = GetParam();
+ auto maybeIp = IPAddressV6::tryFromString(param.in);
+ if (param.out6) {
+ EXPECT_TRUE(maybeIp.hasValue());
+ EXPECT_EQ(param.out6, maybeIp.value().str());
+ } else {
+ EXPECT_TRUE(maybeIp.hasError());
+ EXPECT_EQ(IPAddressFormatError::INVALID_IP, maybeIp.error());
+ }
+}
+
TEST(IPAddress, ToString) {
// Test with IPAddressV4
IPAddressV4 addr_10_0_0_1("10.0.0.1");
<< "should have thrown an IPAddressFormatException";
}
-// Test that invalid binary values throw an exception
+// Test that invalid binary values throw or return an exception
TEST_P(IPAddressCtorBinaryTest, InvalidBinary) {
auto bin = GetParam();
- EXPECT_THROW(
- IPAddress::fromBinary(ByteRange(&bin[0], bin.size())),
- IPAddressFormatException);
+ auto byteRange = ByteRange(&bin[0], bin.size());
+ // Throwing versions.
+ EXPECT_THROW(IPAddress::fromBinary(byteRange), IPAddressFormatException);
+ EXPECT_THROW(IPAddressV4::fromBinary(byteRange), IPAddressFormatException);
+ EXPECT_THROW(IPAddressV6::fromBinary(byteRange), IPAddressFormatException);
+ // Non-throwing versions.
+ EXPECT_TRUE(IPAddress::tryFromBinary(byteRange).hasError());
+ EXPECT_TRUE(IPAddressV4::tryFromBinary(byteRange).hasError());
+ EXPECT_TRUE(IPAddressV6::tryFromBinary(byteRange).hasError());
}
TEST(IPAddressSource, ToHex) {
addr2 = IPAddressV4::fromBinary(bytes);
EXPECT_EQ(fromStr, addr2);
+ auto maybeAddr3 = IPAddressV4::tryFromBinary(bytes);
+ EXPECT_TRUE(maybeAddr3.hasValue());
+ EXPECT_EQ(fromStr, maybeAddr3.value());
+
IPAddress genericAddr = IPAddress::fromBinary(bytes);
ASSERT_TRUE(genericAddr.isV4());
EXPECT_EQ(fromStr, genericAddr.asV4());
addr2 = IPAddressV6::fromBinary(bytes);
EXPECT_EQ(fromStr, addr2);
+ auto maybeAddr3 = IPAddressV6::tryFromBinary(bytes);
+ EXPECT_TRUE(maybeAddr3.hasValue());
+ EXPECT_EQ(fromStr, maybeAddr3.value());
+
IPAddress genericAddr = IPAddress::fromBinary(bytes);
ASSERT_TRUE(genericAddr.isV6());
EXPECT_EQ(fromStr, genericAddr.asV6());
EXPECT_FALSE(no_link_local_ip6.getMacAddressFromLinkLocal().hasValue());
}
+TEST(IPAddress, getMacAddressFromEUI64) {
+ IPAddressV6 ip6("2401:db00:3020:51dc:4a57:ddff:fe04:5643");
+ EXPECT_TRUE(ip6.getMacAddressFromEUI64().hasValue());
+ EXPECT_EQ("48:57:dd:04:56:43", ip6.getMacAddressFromEUI64()->toString());
+ ip6 = IPAddressV6("fe80::4a57:ddff:fe04:5643");
+ EXPECT_TRUE(ip6.getMacAddressFromEUI64().hasValue());
+ EXPECT_EQ("48:57:dd:04:56:43", ip6.getMacAddressFromEUI64()->toString());
+}
+
+TEST(IPAddress, getMacAddressFromEUI64_Negative) {
+ IPAddressV6 not_eui64_ip6("2401:db00:3020:51dc:face:0000:009a:0000");
+ EXPECT_FALSE(not_eui64_ip6.getMacAddressFromEUI64().hasValue());
+}
+
TEST(IPAddress, LongestCommonPrefix) {
IPAddress ip10("10.0.0.0");
IPAddress ip11("11.0.0.0");
IPAddress,
IPAddressBitAccessorTest,
::testing::ValuesIn(validAddressProvider));
+INSTANTIATE_TEST_CASE_P(
+ IPAddress,
+ TryFromStringTest,
+ ::testing::ValuesIn(TryFromStringTest::ipInOutProvider()));
TEST(IPAddressV4, fetchMask) {
struct X : private IPAddressV4 {