// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc; using namespace isc::dhcp; using namespace isc::asiolink; // don't import the entire boost namespace. It will unexpectedly hide uint8_t // for some systems. using boost::scoped_ptr; namespace { // This is a workaround for strange linking problems with gtest: // libdhcp___unittests-duid_unittest.o: In function `Compare': // ~/gtest-1.6.0/include/gtest/gtest.h:1353: undefined reference to `isc::dhcp::ClientId::MAX_CLIENT_ID_LE'N // collect2: ld returned 1 exit status const size_t MAX_DUID_LEN = DUID::MAX_DUID_LEN; const size_t MAX_CLIENT_ID_LEN = DUID::MAX_DUID_LEN; // This test verifies if the constructors are working as expected // and process passed parameters. TEST(DuidTest, constructor) { uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6}; vector data2(data1, data1 + sizeof(data1)); scoped_ptr duid1(new DUID(data1, sizeof(data1))); scoped_ptr duid2(new DUID(data2)); vector vecdata = duid1->getDuid(); EXPECT_TRUE(data2 == vecdata); EXPECT_EQ(DUID::DUID_LLT, duid1->getType()); vecdata = duid2->getDuid(); EXPECT_TRUE(data2 == vecdata); EXPECT_EQ(DUID::DUID_LLT, duid2->getType()); } // This test verifies if DUID size restrictions are implemented // properly. TEST(DuidTest, size) { uint8_t data[MAX_DUID_LEN + 1]; vector data2; for (uint8_t i = 0; i < MAX_DUID_LEN + 1; ++i) { data[i] = i; if (i < MAX_DUID_LEN) data2.push_back(i); } ASSERT_EQ(data2.size(), MAX_DUID_LEN); scoped_ptr duidmaxsize1(new DUID(data, MAX_DUID_LEN)); scoped_ptr duidmaxsize2(new DUID(data2)); EXPECT_THROW( scoped_ptr toolarge1(new DUID(data, MAX_DUID_LEN + 1)), BadValue); // that's one too much data2.push_back(128); EXPECT_THROW( scoped_ptr toolarge2(new DUID(data2)), BadValue); // empty duids are not allowed vector empty; EXPECT_THROW( scoped_ptr emptyDuid(new DUID(empty)), BadValue); EXPECT_THROW( scoped_ptr emptyDuid2(new DUID(data, 0)), BadValue); } // This test verifies if the implementation supports all defined // DUID types. TEST(DuidTest, getType) { uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6}; uint8_t en[] = {0, 2, 2, 3, 4, 5, 6}; uint8_t ll[] = {0, 3, 2, 3, 4, 5, 6}; uint8_t uuid[] = {0, 4, 2, 3, 4, 5, 6}; uint8_t invalid[] = {0,55, 2, 3, 4, 5, 6}; scoped_ptr duid_llt(new DUID(llt, sizeof(llt))); scoped_ptr duid_en(new DUID(en, sizeof(en))); scoped_ptr duid_ll(new DUID(ll, sizeof(ll))); scoped_ptr duid_uuid(new DUID(uuid, sizeof(uuid))); scoped_ptr duid_invalid(new DUID(invalid, sizeof(invalid))); EXPECT_EQ(DUID::DUID_LLT, duid_llt->getType()); EXPECT_EQ(DUID::DUID_EN, duid_en->getType()); EXPECT_EQ(DUID::DUID_LL, duid_ll->getType()); EXPECT_EQ(DUID::DUID_UUID, duid_uuid->getType()); EXPECT_EQ(DUID::DUID_UNKNOWN, duid_invalid->getType()); } // This test checks that the DUID instance can be created from the textual // format and that error is reported if the textual format is invalid. TEST(DuidTest, fromText) { scoped_ptr duid; // DUID with only decimal digits. ASSERT_NO_THROW( duid.reset(new DUID(DUID::fromText("00:01:02:03:04:05:06"))) ); EXPECT_EQ("00:01:02:03:04:05:06", duid->toText()); // DUID with some hexadecimal digits (upper case and lower case). ASSERT_NO_THROW( duid.reset(new DUID(DUID::fromText("00:aa:bb:CD:ee:EF:ab"))) ); EXPECT_EQ("00:aa:bb:cd:ee:ef:ab", duid->toText()); // DUID with one digit for a particular byte. ASSERT_NO_THROW( duid.reset(new DUID(DUID::fromText("00:a:bb:D:ee:EF:ab"))) ); EXPECT_EQ("00:0a:bb:0d:ee:ef:ab", duid->toText()); // Repeated colon sign is not allowed. EXPECT_THROW( duid.reset(new DUID(DUID::fromText("00::bb:D:ee:EF:ab"))), isc::BadValue ); // DUID with excessive number of digits for one of the bytes. EXPECT_THROW( duid.reset(new DUID(DUID::fromText("00:01:021:03:04:05:06"))), isc::BadValue ); } // Test checks if the toText() returns valid texual representation TEST(DuidTest, toText) { uint8_t data1[] = {0, 1, 2, 3, 4, 0xff, 0xfe}; DUID duid(data1, sizeof(data1)); EXPECT_EQ("00:01:02:03:04:ff:fe", duid.toText()); } // This test checks if the comparison operators are sane. TEST(DuidTest, operators) { uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6}; uint8_t data2[] = {0, 1, 2, 3, 4}; uint8_t data3[] = {0, 1, 2, 3, 4, 5, 7}; // last digit different uint8_t data4[] = {0, 1, 2, 3, 4, 5, 6}; // the same as 1 scoped_ptr duid1(new DUID(data1, sizeof(data1))); scoped_ptr duid2(new DUID(data2, sizeof(data2))); scoped_ptr duid3(new DUID(data3, sizeof(data3))); scoped_ptr duid4(new DUID(data4, sizeof(data4))); EXPECT_TRUE(*duid1 == *duid4); EXPECT_FALSE(*duid1 == *duid2); EXPECT_FALSE(*duid1 == *duid3); EXPECT_FALSE(*duid1 != *duid4); EXPECT_TRUE(*duid1 != *duid2); EXPECT_TRUE(*duid1 != *duid3); } // This test verifies if the ClientId constructors are working properly // and passed parameters are used TEST(ClientIdTest, constructor) { IOAddress addr2("192.0.2.1"); IOAddress addr3("2001:db8:1::1"); uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6}; vector data2(data1, data1 + sizeof(data1)); // checks for C-style constructor (uint8_t * + len) scoped_ptr id1(new ClientId(data1, sizeof(data1))); vector vecdata = id1->getClientId(); EXPECT_TRUE(data2 == vecdata); // checks for vector-based constructor scoped_ptr id2(new ClientId(data2)); vecdata = id2->getClientId(); EXPECT_TRUE(data2 == vecdata); } // Check that client-id sizes are reasonable TEST(ClientIdTest, size) { uint8_t data[MAX_CLIENT_ID_LEN + 1]; vector data2; for (uint8_t i = 0; i < MAX_CLIENT_ID_LEN + 1; ++i) { data[i] = i; if (i < MAX_CLIENT_ID_LEN) data2.push_back(i); } ASSERT_EQ(data2.size(), MAX_CLIENT_ID_LEN); scoped_ptr duidmaxsize1(new ClientId(data, MAX_CLIENT_ID_LEN)); scoped_ptr duidmaxsize2(new ClientId(data2)); EXPECT_THROW( scoped_ptr toolarge1(new ClientId(data, MAX_CLIENT_ID_LEN + 1)), BadValue); // that's one too much data2.push_back(128); EXPECT_THROW( scoped_ptr toolarge2(new ClientId(data2)), BadValue); // empty client-ids are not allowed vector empty; EXPECT_THROW( scoped_ptr empty_client_id1(new ClientId(empty)), BadValue); EXPECT_THROW( scoped_ptr empty_client_id2(new ClientId(data, 0)), BadValue); // client-id must be at least 2 bytes long vector shorty(1,17); // just a single byte with value 17 EXPECT_THROW( scoped_ptr too_short_client_id1(new ClientId(shorty)), BadValue); EXPECT_THROW( scoped_ptr too_short_client_id1(new ClientId(data, 1)), BadValue); } // This test checks if the comparison operators are sane. TEST(ClientIdTest, operators) { uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6}; uint8_t data2[] = {0, 1, 2, 3, 4}; uint8_t data3[] = {0, 1, 2, 3, 4, 5, 7}; // last digit different uint8_t data4[] = {0, 1, 2, 3, 4, 5, 6}; // the same as 1 scoped_ptr id1(new ClientId(data1, sizeof(data1))); scoped_ptr id2(new ClientId(data2, sizeof(data2))); scoped_ptr id3(new ClientId(data3, sizeof(data3))); scoped_ptr id4(new ClientId(data4, sizeof(data4))); EXPECT_TRUE(*id1 == *id4); EXPECT_FALSE(*id1 == *id2); EXPECT_FALSE(*id1 == *id3); EXPECT_FALSE(*id1 != *id4); EXPECT_TRUE(*id1 != *id2); EXPECT_TRUE(*id1 != *id3); } // Test checks if the toText() returns valid texual representation TEST(ClientIdTest, toText) { uint8_t data1[] = {0, 1, 2, 3, 4, 0xff, 0xfe}; ClientId clientid(data1, sizeof(data1)); EXPECT_EQ("00:01:02:03:04:ff:fe", clientid.toText()); } // This test checks that the ClientId instance can be created from the textual // format and that error is reported if the textual format is invalid. TEST(ClientIdTest, fromText) { ClientIdPtr cid; // ClientId with only decimal digits. ASSERT_NO_THROW( cid = ClientId::fromText("00:01:02:03:04:05:06") ); EXPECT_EQ("00:01:02:03:04:05:06", cid->toText()); // ClientId with some hexadecimal digits (upper case and lower case). ASSERT_NO_THROW( cid = ClientId::fromText("00:aa:bb:CD:ee:EF:ab") ); EXPECT_EQ("00:aa:bb:cd:ee:ef:ab", cid->toText()); // ClientId with one digit for a particular byte. ASSERT_NO_THROW( cid = ClientId::fromText("00:a:bb:D:ee:EF:ab") ); EXPECT_EQ("00:0a:bb:0d:ee:ef:ab", cid->toText()); // ClientId without any colons is allowed. ASSERT_NO_THROW( cid = ClientId::fromText("0010abcdee"); ); EXPECT_EQ("00:10:ab:cd:ee", cid->toText()); // Repeated colon sign in the ClientId is not allowed. EXPECT_THROW( ClientId::fromText("00::bb:D:ee:EF:ab"), isc::BadValue ); // ClientId with excessive number of digits for one of the bytes. EXPECT_THROW( ClientId::fromText("00:01:021:03:04:05:06"), isc::BadValue ); // ClientId with two spaces between the colons should not be allowed. EXPECT_THROW( ClientId::fromText("00:01: :03:04:05:06"), isc::BadValue ); // ClientId with one space between the colons should not be allowed. EXPECT_THROW( ClientId::fromText("00:01: :03:04:05:06"), isc::BadValue ); // ClientId with three spaces between the colons should not be allowed. EXPECT_THROW( ClientId::fromText("00:01: :03:04:05:06"), isc::BadValue ); } } // end of anonymous namespace