123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- // Copyright (C) 2014, 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/opaque_data_tuple.h>
- #include <util/buffer.h>
- #include <gtest/gtest.h>
- #include <algorithm>
- #include <sstream>
- #include <vector>
- using namespace isc;
- using namespace isc::dhcp;
- using namespace isc::util;
- namespace {
- // This test checks that when the default constructor is called, the data buffer
- // is empty.
- TEST(OpaqueDataTuple, constructor) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // There should be no data in the tuple.
- EXPECT_EQ(0, tuple.getLength());
- EXPECT_TRUE(tuple.getData().empty());
- EXPECT_TRUE(tuple.getText().empty());
- }
- // Test that the constructor which takes the buffer as argument parses the
- // wire data.
- TEST(OpaqueDataTuple, constructorParse1Byte) {
- const char wire_data[] = {
- 0x0B, // Length is 11
- 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
- 0x77, 0x6F, 0x72, 0x6C, 0x64 // world
- };
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE, wire_data,
- wire_data + sizeof(wire_data));
- EXPECT_EQ(11, tuple.getLength());
- EXPECT_EQ("Hello world", tuple.getText());
- }
- // Test that the constructor which takes the buffer as argument parses the
- // wire data.
- TEST(OpaqueDataTuple, constructorParse2Bytes) {
- const char wire_data[] = {
- 0x00, 0x0B, // Length is 11
- 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
- 0x77, 0x6F, 0x72, 0x6C, 0x64 // world
- };
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES, wire_data,
- wire_data + sizeof(wire_data));
- EXPECT_EQ(11, tuple.getLength());
- EXPECT_EQ("Hello world", tuple.getText());
- }
- // This test checks that it is possible to set the tuple data using raw buffer.
- TEST(OpaqueDataTuple, assignData) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initially the tuple buffer should be empty.
- OpaqueDataTuple::Buffer buf = tuple.getData();
- ASSERT_TRUE(buf.empty());
- // Prepare some input data and assign to the tuple.
- const uint8_t data1[] = {
- 0xCA, 0xFE, 0xBE, 0xEF
- };
- tuple.assign(data1, sizeof(data1));
- // Tuple should now hold the data we assigned.
- ASSERT_EQ(sizeof(data1), tuple.getLength());
- buf = tuple.getData();
- EXPECT_TRUE(std::equal(buf.begin(), buf.end(), data1));
- // Prepare the other set of data and assign to the tuple.
- const uint8_t data2[] = {
- 1, 2, 3, 4, 5, 6
- };
- tuple.assign(data2, sizeof(data2));
- // The new data should have replaced the old data.
- ASSERT_EQ(sizeof(data2), tuple.getLength());
- buf = tuple.getData();
- EXPECT_TRUE(std::equal(buf.begin(), buf.end(), data2));
- }
- // This test checks that it is possible to append the data to the tuple using
- // raw buffer.
- TEST(OpaqueDataTuple, appendData) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initially the tuple buffer should be empty.
- OpaqueDataTuple::Buffer buf = tuple.getData();
- ASSERT_TRUE(buf.empty());
- // Prepare some input data and append to the empty tuple.
- const uint8_t data1[] = {
- 0xCA, 0xFE, 0xBE, 0xEF
- };
- tuple.append(data1, sizeof(data1));
- // The tuple should now hold only the data we appended.
- ASSERT_EQ(sizeof(data1), tuple.getLength());
- buf = tuple.getData();
- EXPECT_TRUE(std::equal(buf.begin(), buf.end(), data1));
- // Prepare the new set of data and append.
- const uint8_t data2[] = {
- 1, 2, 3, 4, 5, 6
- };
- tuple.append(data2, sizeof(data2));
- // We expect that the tuple now has both sets of data we appended. In order
- // to verify that, we have to concatenate the input data1 and data2.
- std::vector<uint8_t> data12(data1, data1 + sizeof(data1));
- data12.insert(data12.end(), data2, data2 + sizeof(data2));
- // The size of the tuple should be a sum of data1 and data2 lengths.
- ASSERT_EQ(sizeof(data1) + sizeof(data2), tuple.getLength());
- buf = tuple.getData();
- EXPECT_TRUE(std::equal(buf.begin(), buf.end(), data12.begin()));
- }
- // This test checks that it is possible to assign the string to the tuple.
- TEST(OpaqueDataTuple, assignString) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initially, the tuple should be empty.
- ASSERT_EQ(0, tuple.getLength());
- // Assign some string data.
- tuple.assign("Some string");
- // Verify that the data has been assigned.
- EXPECT_EQ(11, tuple.getLength());
- EXPECT_EQ("Some string", tuple.getText());
- // Assign some other string.
- tuple.assign("Different string");
- // The new string should have replaced the old string.
- EXPECT_EQ(16, tuple.getLength());
- EXPECT_EQ("Different string", tuple.getText());
- }
- // This test checks that it is possible to append the string to the tuple.
- TEST(OpaqueDataTuple, appendString) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initially the tuple should be empty.
- ASSERT_EQ(0, tuple.getLength());
- // Append the string to it.
- tuple.append("First part");
- ASSERT_EQ(10, tuple.getLength());
- ASSERT_EQ("First part", tuple.getText());
- // Now append the other string.
- tuple.append(" and second part");
- EXPECT_EQ(26, tuple.getLength());
- // The resulting data in the tuple should be a concatenation of both
- // strings.
- EXPECT_EQ("First part and second part", tuple.getText());
- }
- // This test verifies that equals function correctly checks that the tuple
- // holds a given string but it doesn't hold the other. This test also
- // checks the assignment operator for the tuple.
- TEST(OpaqueDataTuple, equals) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Tuple is supposed to be empty so it is not equal xyz.
- EXPECT_FALSE(tuple.equals("xyz"));
- // Assign xyz.
- EXPECT_NO_THROW(tuple = "xyz");
- // The tuple should be equal xyz, but not abc.
- EXPECT_FALSE(tuple.equals("abc"));
- EXPECT_TRUE(tuple.equals("xyz"));
- // Assign abc to the tuple.
- EXPECT_NO_THROW(tuple = "abc");
- // It should be now opposite.
- EXPECT_TRUE(tuple.equals("abc"));
- EXPECT_FALSE(tuple.equals("xyz"));
- }
- // This test checks that the conversion of the data in the tuple to the string
- // is performed correctly.
- TEST(OpaqueDataTuple, getText) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initially the tuple should be empty.
- ASSERT_TRUE(tuple.getText().empty());
- // ASCII representation of 'Hello world'.
- const char as_ascii[] = {
- 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
- 0x77, 0x6F, 0x72, 0x6C, 0x64 // world
- };
- // Assign it to the tuple.
- tuple.assign(as_ascii, sizeof(as_ascii));
- // Conversion to string should give as the original text.
- EXPECT_EQ("Hello world", tuple.getText());
- }
- // This test verifies the behavior of (in)equality and assignment operators.
- TEST(OpaqueDataTuple, operators) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Tuple should be empty initially.
- ASSERT_EQ(0, tuple.getLength());
- // Check assignment.
- EXPECT_NO_THROW(tuple = "Hello World");
- EXPECT_EQ(11, tuple.getLength());
- EXPECT_TRUE(tuple == "Hello World");
- EXPECT_TRUE(tuple != "Something else");
- // Assign something else to make sure it affects the tuple.
- EXPECT_NO_THROW(tuple = "Something else");
- EXPECT_EQ(14, tuple.getLength());
- EXPECT_TRUE(tuple == "Something else");
- EXPECT_TRUE(tuple != "Hello World");
- }
- // This test verifies that the tuple is inserted in the textual format to the
- // output stream.
- TEST(OpaqueDataTuple, operatorOutputStream) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // The tuple should be empty initially.
- ASSERT_EQ(0, tuple.getLength());
- // The tuple is empty, so assigning its content to the output stream should
- // be no-op and result in the same text in the stream.
- std::ostringstream s;
- s << "Some text";
- EXPECT_NO_THROW(s << tuple);
- EXPECT_EQ("Some text", s.str());
- // Now, let's assign some text to the tuple and call operator again.
- // The new text should be added to the stream.
- EXPECT_NO_THROW(tuple = " and some other text");
- EXPECT_NO_THROW(s << tuple);
- EXPECT_EQ(s.str(), "Some text and some other text");
- }
- // This test verifies that the value of the tuple can be initialized from the
- // input stream.
- TEST(OpaqueDataTuple, operatorInputStream) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // The tuple should be empty initially.
- ASSERT_EQ(0, tuple.getLength());
- // The input stream has some text. This text should be appended to the
- // tuple.
- std::istringstream s;
- s.str("Some text");
- EXPECT_NO_THROW(s >> tuple);
- EXPECT_EQ("Some text", tuple.getText());
- // Now, let's assign some other text to the stream. This new text should be
- // assigned to the tuple.
- s.str("And some other");
- EXPECT_NO_THROW(s >> tuple);
- EXPECT_EQ("And some other", tuple.getText());
- }
- // This test checks that the tuple is correctly encoded in the wire format when
- // the size of the length field is 1 byte.
- TEST(OpaqueDataTuple, pack1Byte) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
- // Initially, the tuple should be empty.
- ASSERT_EQ(0, tuple.getLength());
- // The empty data doesn't make much sense, so the pack() should not
- // allow it.
- OutputBuffer out_buf(10);
- EXPECT_THROW(tuple.pack(out_buf), OpaqueDataTupleError);
- // Set the data for tuple.
- std::vector<uint8_t> data;
- for (uint8_t i = 0; i < 100; ++i) {
- data.push_back(i);
- }
- tuple.assign(data.begin(), data.size());
- // The pack should now succeed.
- ASSERT_NO_THROW(tuple.pack(out_buf));
- // The rendered buffer should be 101 bytes long - 1 byte for length,
- // 100 bytes for the actual data.
- ASSERT_EQ(101, out_buf.getLength());
- // Get the rendered data into the vector for convenience.
- std::vector<uint8_t>
- render_data(static_cast<const uint8_t*>(out_buf.getData()),
- static_cast<const uint8_t*>(out_buf.getData()) + 101);
- // The first byte is a length byte. It should hold the length of 100.
- EXPECT_EQ(100, render_data[0]);
- // Verify that the rendered data is correct.
- EXPECT_TRUE(std::equal(render_data.begin() + 1, render_data.end(),
- data.begin()));
- // Reset the output buffer for another test.
- out_buf.clear();
- // Fill in the tuple buffer so as it reaches maximum allowed length. The
- // maximum length is 255 when the size of the length field is one byte.
- for (uint8_t i = 100; i < 255; ++i) {
- data.push_back(i);
- }
- ASSERT_EQ(255, data.size());
- tuple.assign(data.begin(), data.size());
- // The pack() should be successful again.
- ASSERT_NO_THROW(tuple.pack(out_buf));
- // The rendered buffer should be 256 bytes long. The first byte holds the
- // opaque data length, the remaining bytes hold the actual data.
- ASSERT_EQ(256, out_buf.getLength());
- // Check that the data is correct.
- render_data.assign(static_cast<const uint8_t*>(out_buf.getData()),
- static_cast<const uint8_t*>(out_buf.getData()) + 256);
- EXPECT_EQ(255, render_data[0]);
- EXPECT_TRUE(std::equal(render_data.begin() + 1, render_data.end(),
- data.begin()));
- // Clear output buffer for another test.
- out_buf.clear();
- // Add one more value to the tuple. Now, the resulting buffer should exceed
- // the maximum length. An attempt to pack() should fail.
- data.push_back(255);
- tuple.assign(data.begin(), data.size());
- EXPECT_THROW(tuple.pack(out_buf), OpaqueDataTupleError);
- }
- // This test checks that the tuple is correctly encoded in the wire format when
- // the size of the length field is 2 bytes.
- TEST(OpaqueDataTuple, pack2Bytes) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initially, the tuple should be empty.
- ASSERT_EQ(0, tuple.getLength());
- // The empty data doesn't make much sense, so the pack() should not
- // allow it.
- OutputBuffer out_buf(10);
- EXPECT_THROW(tuple.pack(out_buf), OpaqueDataTupleError);
- // Set the data for tuple.
- std::vector<uint8_t> data;
- for (unsigned i = 0; i < 512; ++i) {
- data.push_back(i & 0xff);
- }
- tuple.assign(data.begin(), data.size());
- // The pack should now succeed.
- ASSERT_NO_THROW(tuple.pack(out_buf));
- // The rendered buffer should be 514 bytes long - 2 bytes for length,
- // 512 bytes for the actual data.
- ASSERT_EQ(514, out_buf.getLength());
- // Get the rendered data into the vector for convenience.
- std::vector<uint8_t>
- render_data(static_cast<const uint8_t*>(out_buf.getData()),
- static_cast<const uint8_t*>(out_buf.getData()) + 514);
- // The first two bytes hold the length of 512.
- uint16_t len = (render_data[0] << 8) + render_data[1];
- EXPECT_EQ(512, len);
- // Verify that the rendered data is correct.
- EXPECT_TRUE(std::equal(render_data.begin() + 2, render_data.end(),
- data.begin()));
- // Without clearing the output buffer, try to do it again. The pack should
- // append the data to the current buffer.
- ASSERT_NO_THROW(tuple.pack(out_buf));
- EXPECT_EQ(1028, out_buf.getLength());
- // Check that we can render the buffer of the maximal allowed size.
- data.assign(65535, 1);
- ASSERT_NO_THROW(tuple.assign(data.begin(), data.size()));
- ASSERT_NO_THROW(tuple.pack(out_buf));
- out_buf.clear();
- // Append one additional byte. The total length of the tuple now exceeds
- // the maximal value. An attempt to render it should throw an exception.
- data.assign(1, 1);
- ASSERT_NO_THROW(tuple.append(data.begin(), data.size()));
- EXPECT_THROW(tuple.pack(out_buf), OpaqueDataTupleError);
- }
- // This test verifies that the tuple is decoded from the wire format.
- TEST(OpaqueDataTuple, unpack1Byte) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
- const char wire_data[] = {
- 0x0B, // Length is 11
- 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
- 0x77, 0x6F, 0x72, 0x6C, 0x64 // world
- };
- ASSERT_NO_THROW(tuple.unpack(wire_data, wire_data + sizeof(wire_data)));
- EXPECT_EQ(11, tuple.getLength());
- EXPECT_EQ("Hello world", tuple.getText());
- }
- // This test verifies that the tuple having a length of 0, is decoded from
- // the wire format.
- TEST(OpaqueDataTuple, unpack1ByteZeroLength) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
- EXPECT_NO_THROW(tuple = "Hello world");
- ASSERT_NE(tuple.getLength(), 0);
- const char wire_data[] = {
- 0
- };
- ASSERT_NO_THROW(tuple.unpack(wire_data, wire_data + sizeof(wire_data)));
- EXPECT_EQ(0, tuple.getLength());
- }
- // This test verfifies that exception is thrown if the empty buffer is being
- // parsed.
- TEST(OpaqueDataTuple, unpack1ByteEmptyBuffer) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
- const char wire_data[] = {
- 1, 2, 3
- };
- EXPECT_THROW(tuple.unpack(wire_data, wire_data), OpaqueDataTupleError);
- }
- // This test verifies that exception is thrown when parsing truncated buffer.
- TEST(OpaqueDataTuple, unpack1ByteTruncatedBuffer) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
- const char wire_data[] = {
- 10, 2, 3
- };
- EXPECT_THROW(tuple.unpack(wire_data, wire_data + sizeof(wire_data)),
- OpaqueDataTupleError);
- }
- // This test verifies that the tuple is decoded from the wire format.
- TEST(OpaqueDataTuple, unpack2Byte) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- std::vector<uint8_t> wire_data;
- // Set tuple length to 400 (0x190).
- wire_data.push_back(1);
- wire_data.push_back(0x90);
- // Fill in the buffer with some data.
- for (int i = 0; i < 400; ++i) {
- wire_data.push_back(i);
- }
- // The unpack shoud succeed.
- ASSERT_NO_THROW(tuple.unpack(wire_data.begin(), wire_data.end()));
- // The decoded length should be 400.
- ASSERT_EQ(400, tuple.getLength());
- // And the data should match.
- EXPECT_TRUE(std::equal(wire_data.begin() + 2, wire_data.end(),
- tuple.getData().begin()));
- }
- // This test verifies that the tuple having a length of 0, is decoded from
- // the wire format.
- TEST(OpaqueDataTuple, unpack2ByteZeroLength) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Set some data for the tuple.
- EXPECT_NO_THROW(tuple = "Hello world");
- ASSERT_NE(tuple.getLength(), 0);
- // The buffer holds just a length field with the value of 0.
- const char wire_data[] = {
- 0, 0
- };
- // The empty tuple should be successfully decoded.
- ASSERT_NO_THROW(tuple.unpack(wire_data, wire_data + sizeof(wire_data)));
- // The data should be replaced with an empty buffer.
- EXPECT_EQ(0, tuple.getLength());
- }
- // This test verifies that exception is thrown if the empty buffer is being
- // parsed.
- TEST(OpaqueDataTuple, unpack2ByteEmptyBuffer) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Initialize the input buffer with some data, just to avoid initializing
- // empty array.
- const char wire_data[] = {
- 1, 2, 3
- };
- // Pass empty buffer (first iterator equal to second iterator).
- // This should not be accepted.
- EXPECT_THROW(tuple.unpack(wire_data, wire_data), OpaqueDataTupleError);
- }
- // This test verifies that exception if thrown when parsing truncated buffer.
- TEST(OpaqueDataTuple, unpack2ByteTruncatedBuffer) {
- OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- // Specify the data with the length of 10, but limit the buffer size to
- // 2 bytes.
- const char wire_data[] = {
- 0, 10, 2, 3
- };
- // This should fail because the buffer is truncated.
- EXPECT_THROW(tuple.unpack(wire_data, wire_data + sizeof(wire_data)),
- OpaqueDataTupleError);
- }
- } // anonymous namespace
|