123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- // Copyright (C) 2012, 2015 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 <config.h>
- #include <dhcp/dhcp6.h>
- #include <dhcp/option.h>
- #include <dhcp/option6_iaaddr.h>
- #include <dhcp/option_int_array.h>
- #include <util/buffer.h>
- #include <boost/pointer_cast.hpp>
- #include <gtest/gtest.h>
- using namespace std;
- using namespace isc;
- using namespace isc::dhcp;
- using namespace isc::asiolink;
- using namespace isc::util;
- namespace {
- /// @brief OptionIntArray test class.
- class OptionIntArrayTest : public ::testing::Test {
- public:
- /// @brief Constructor.
- ///
- /// Initializes the option buffer with some data.
- OptionIntArrayTest(): buf_(255), out_buf_(255) {
- for (unsigned i = 0; i < 255; i++) {
- buf_[i] = 255 - i;
- }
- }
- /// @brief Test parsing buffer into array of int8_t or uint8_t values.
- ///
- /// @warning this function does not perform type check. Make
- /// sure that only int8_t or uint8_t type is used.
- ///
- /// @param u universe (v4 or V6).
- /// @tparam T int8_t or uint8_t.
- template<typename T>
- void bufferToIntTest8(const Option::Universe u) {
- // Create option that conveys array of multiple uint8_t or int8_t values.
- // In fact there is no need to use this template class for array
- // of uint8_t values because Option class is sufficient - it
- // returns the buffer which is actually the array of uint8_t.
- // However, since we allow using uint8_t types with this template
- // class we have to test it here.
- boost::shared_ptr<OptionIntArray<T> > opt;
- const int opt_len = 10;
- const uint16_t opt_code = 80;
- // Constructor throws exception if provided buffer is empty.
- EXPECT_THROW(
- OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
- isc::OutOfRange
- );
- // Provided buffer is not empty so it should not throw exception.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<
- OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
- buf_.begin() + opt_len))
- );
- EXPECT_EQ(u, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- // Option should return the collection of int8_t or uint8_t values that
- // we can match with the buffer we used to create the option.
- std::vector<T> values = opt->getValues();
- // We need to copy values from the buffer to apply sign if signed
- // type is used.
- std::vector<T> reference_values;
- for (int i = 0; i < opt_len; ++i) {
- // Values have been read from the buffer in network
- // byte order. We put them back in the same order here.
- reference_values.push_back(static_cast<T>(buf_[i]));
- }
- // Compare the values against the reference buffer.
- ASSERT_EQ(opt_len, values.size());
- EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
- + opt_len, values.begin()));
- // test for pack()
- opt->pack(out_buf_);
- // Data length is 10 bytes.
- EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(opt_code, opt->getType());
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- if (u == Option::V4) {
- // The total length is 10 bytes for data and 2 bytes for a header.
- ASSERT_EQ(12, out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint8());
- // if option length is correct
- EXPECT_EQ(10, out.readUint8());
- } else {
- // The total length is 10 bytes for data and 4 bytes for a header.
- ASSERT_EQ(14, out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint16());
- // if option length is correct
- EXPECT_EQ(10, out.readUint16());
- }
- // if data is correct
- std::vector<uint8_t> out_data;
- ASSERT_NO_THROW(out.readVector(out_data, opt_len));
- ASSERT_EQ(opt_len, out_data.size());
- EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
- }
- /// @brief Test parsing buffer into array of int16_t or uint16_t values.
- ///
- /// @warning this function does not perform type check. Make
- /// sure that only int16_t or uint16_t type is used.
- ///
- /// @param u universe (V4 or V6).
- /// @tparam T int16_t or uint16_t.
- template<typename T>
- void bufferToIntTest16(const Option::Universe u) {
- // Create option that conveys array of multiple uint16_t or int16_t values.
- boost::shared_ptr<OptionIntArray<T> > opt;
- const int opt_len = 20;
- const uint16_t opt_code = 81;
- // Constructor throws exception if provided buffer is empty.
- EXPECT_THROW(
- OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
- isc::OutOfRange
- );
- // Constructor throws exception if provided buffer's length is not
- // multiple of 2-bytes.
- EXPECT_THROW(
- OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 5),
- isc::OutOfRange
- );
- // Now the buffer length is correct.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<
- OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
- buf_.begin() + opt_len))
- );
- EXPECT_EQ(u, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- // Option should return vector of uint16_t values which should be
- // constructed from the buffer we provided.
- std::vector<T> values = opt->getValues();
- ASSERT_EQ(opt_len, values.size() * sizeof(T));
- // Create reference values from the buffer so as we can
- // simply compare two vectors.
- std::vector<T> reference_values;
- for (int i = 0; i < opt_len; i += 2) {
- reference_values.push_back((buf_[i] << 8) |
- buf_[i + 1]);
- }
- EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
- values.begin()));
- // Test for pack()
- opt->pack(out_buf_);
- // Data length is 20 bytes.
- EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(opt_code, opt->getType());
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- if (u == Option::V4) {
- // The total length is 20 bytes for data and 2 bytes for a header.
- ASSERT_EQ(22, out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint8());
- // if option length is correct
- EXPECT_EQ(20, out.readUint8());
- } else {
- // The total length is 20 bytes for data and 4 bytes for a header.
- ASSERT_EQ(24, out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint16());
- // if option length is correct
- EXPECT_EQ(20, out.readUint16());
- }
- // if data is correct
- std::vector<uint8_t> out_data;
- ASSERT_NO_THROW(out.readVector(out_data, opt_len));
- ASSERT_EQ(opt_len, out_data.size());
- EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
- }
- /// @brief Test parsing buffer into array of int32_t or uint32_t values.
- ///
- /// @warning this function does not perform type check. Make
- /// sure that only int32_t or uint32_t type is used.
- ///
- /// @param u universe (V4 or V6)
- /// @tparam T int32_t or uint32_t.
- template<typename T>
- void bufferToIntTest32(const Option::Universe u) {
- // Create option that conveys array of multiple uint16_t values.
- boost::shared_ptr<OptionIntArray<T> > opt;
- const int opt_len = 40;
- const uint16_t opt_code = 82;
- // Constructor throws exception if provided buffer is empty.
- EXPECT_THROW(
- OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
- isc::OutOfRange
- );
- // Constructor throws exception if provided buffer's length is not
- // multiple of 4-bytes.
- EXPECT_THROW(
- OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 9),
- isc::OutOfRange
- );
- // Now the buffer length is correct.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<
- OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
- buf_.begin() + opt_len))
- );
- EXPECT_EQ(u, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- // Option should return vector of uint32_t values which should be
- // constructed from the buffer we provided.
- std::vector<T> values = opt->getValues();
- ASSERT_EQ(opt_len, values.size() * sizeof(T));
- // Create reference values from the buffer so as we can
- // simply compare two vectors.
- std::vector<T> reference_values;
- for (int i = 0; i < opt_len; i += 4) {
- reference_values.push_back((buf_[i] << 24) |
- (buf_[i + 1] << 16 & 0x00FF0000) |
- (buf_[i + 2] << 8 & 0xFF00) |
- (buf_[i + 3] & 0xFF));
- }
- EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
- values.begin()));
- // Test for pack()
- opt->pack(out_buf_);
- // Data length is 40 bytes.
- EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(opt_code, opt->getType());
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- if (u == Option::V4) {
- // The total length is 40 bytes for data and 2 bytes for a header.
- ASSERT_EQ(42, out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint8());
- // if option length is correct
- EXPECT_EQ(40, out.readUint8());
- } else {
- // The total length is 40 bytes for data and 4 bytes for a header.
- ASSERT_EQ(44, out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint16());
- // if option length is correct
- EXPECT_EQ(40, out.readUint16());
- }
- // if data is correct
- std::vector<uint8_t> out_data;
- ASSERT_NO_THROW(out.readVector(out_data, opt_len));
- ASSERT_EQ(opt_len, out_data.size());
- EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
- }
- /// @brief Test ability to set all values.
- ///
- /// @tparam T numeric type to perform the test for.
- template<typename T>
- void setValuesTest() {
- const uint16_t opt_code = 100;
- // Create option with empty vector of values.
- boost::shared_ptr<OptionIntArray<T> >
- opt(new OptionIntArray<T>(Option::V6, opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<T> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<uint8_t>::max() - i);
- }
- opt->setValues(values);
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<T> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
- }
- /// @brief Test ability to add values one by one.
- ///
- /// @tparam T numeric type to perform the test for.
- template<typename T>
- void addValuesTest() {
- const uint16_t opt_code = 100;
- // Create option with empty vector of values.
- boost::shared_ptr<OptionIntArray<T> >
- opt(new OptionIntArray<T>(Option::V6, opt_code));
- // Initialize vector with some data and add the same data
- // to the option.
- std::vector<T> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<T>::max() - i);
- opt->addValue(numeric_limits<T>::max() - i);
- }
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<T> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
- }
- OptionBuffer buf_; ///< Option buffer
- OutputBuffer out_buf_; ///< Output buffer
- };
- /// @todo: below, there is a bunch of tests for options that
- /// convey unsigned values. We should maybe extend these tests for
- /// signed types too.
- TEST_F(OptionIntArrayTest, useInvalidType) {
- const uint16_t opt_code = 80;
- EXPECT_THROW(
- boost::scoped_ptr<
- OptionIntArray<bool> >(new OptionIntArray<bool>(Option::V6, opt_code,
- OptionBuffer(5))),
- InvalidDataType
- );
- EXPECT_THROW(
- boost::scoped_ptr<
- OptionIntArray<int64_t> >(new OptionIntArray<int64_t>(Option::V6,
- opt_code,
- OptionBuffer(10))),
- InvalidDataType
- );
- }
- TEST_F(OptionIntArrayTest, bufferToUint8V4) {
- bufferToIntTest8<uint8_t>(Option::V4);
- }
- TEST_F(OptionIntArrayTest, bufferToUint8V6) {
- bufferToIntTest8<uint8_t>(Option::V6);
- }
- TEST_F(OptionIntArrayTest, bufferToInt8V4) {
- bufferToIntTest8<int8_t>(Option::V4);
- }
- TEST_F(OptionIntArrayTest, bufferToInt8V6) {
- bufferToIntTest8<int8_t>(Option::V6);
- }
- TEST_F(OptionIntArrayTest, bufferToUint16V4) {
- bufferToIntTest16<uint16_t>(Option::V4);
- }
- TEST_F(OptionIntArrayTest, bufferToUint16V6) {
- bufferToIntTest16<uint16_t>(Option::V6);
- }
- TEST_F(OptionIntArrayTest, bufferToInt16V4) {
- bufferToIntTest16<int16_t>(Option::V4);
- }
- TEST_F(OptionIntArrayTest, bufferToInt16V6) {
- bufferToIntTest16<int16_t>(Option::V6);
- }
- TEST_F(OptionIntArrayTest, bufferToUint32V4) {
- bufferToIntTest32<uint32_t>(Option::V4);
- }
- TEST_F(OptionIntArrayTest, bufferToUint32V6) {
- bufferToIntTest32<uint32_t>(Option::V6);
- }
- TEST_F(OptionIntArrayTest, bufferToInt32V4) {
- bufferToIntTest32<int32_t>(Option::V4);
- }
- TEST_F(OptionIntArrayTest, bufferToInt32V6) {
- bufferToIntTest32<int32_t>(Option::V6);
- }
- TEST_F(OptionIntArrayTest, setValuesUint8) {
- setValuesTest<uint8_t>();
- }
- TEST_F(OptionIntArrayTest, setValuesInt8) {
- setValuesTest<int8_t>();
- }
- TEST_F(OptionIntArrayTest, setValuesUint16) {
- setValuesTest<uint16_t>();
- }
- TEST_F(OptionIntArrayTest, setValuesInt16) {
- setValuesTest<int16_t>();
- }
- TEST_F(OptionIntArrayTest, setValuesUint32) {
- setValuesTest<uint16_t>();
- }
- TEST_F(OptionIntArrayTest, setValuesInt32) {
- setValuesTest<int16_t>();
- }
- TEST_F(OptionIntArrayTest, addValuesUint8) {
- addValuesTest<uint8_t>();
- }
- TEST_F(OptionIntArrayTest, addValuesInt8) {
- addValuesTest<int8_t>();
- }
- TEST_F(OptionIntArrayTest, addValuesUint16) {
- addValuesTest<uint16_t>();
- }
- TEST_F(OptionIntArrayTest, addValuesInt16) {
- addValuesTest<int16_t>();
- }
- TEST_F(OptionIntArrayTest, addValuesUint32) {
- addValuesTest<uint16_t>();
- }
- TEST_F(OptionIntArrayTest, addValuesInt32) {
- addValuesTest<int16_t>();
- }
- // This test checks that the option is correctly converted into
- // the textual format.
- TEST_F(OptionIntArrayTest, toText) {
- OptionUint32Array option(Option::V4, 128);
- option.addValue(1);
- option.addValue(32);
- option.addValue(324);
- EXPECT_EQ("type=128, len=012: 1(uint32) 32(uint32) 324(uint32)",
- option.toText());
- }
- // This test checks that the option holding multiple uint8 values
- // is correctly converted to the textual format.
- TEST_F(OptionIntArrayTest, toTextUint8) {
- OptionUint8Array option(Option::V4, 128);
- option.addValue(1);
- option.addValue(7);
- option.addValue(15);
- EXPECT_EQ("type=128, len=003: 1(uint8) 7(uint8) 15(uint8)",
- option.toText());
- }
- } // anonymous namespace
|