Browse Source

Merge branch 'trac1140'

Conflicts:
	ChangeLog
Dima Volodin 13 years ago
parent
commit
8eb6232b00

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+297.	[func]		dvv
+	Implement the SPF rrtype according to RFC4408.
+	(Trac #1140, git 146934075349f94ee27f23bf9ff01711b94e369e)
+
 296.	[build]		jreed
 296.	[build]		jreed
 	Do not install the unittest libraries. At this time, they
 	Do not install the unittest libraries. At this time, they
 	are not useful without source tree (and they may or may
 	are not useful without source tree (and they may or may

+ 54 - 2
src/lib/dns/rdata/generic/detail/txt_like.h

@@ -23,8 +23,24 @@
 using namespace std;
 using namespace std;
 using namespace isc::util;
 using namespace isc::util;
 
 
+/// \brief \c rdata::TXTLikeImpl class represents the TXT-like RDATA for TXT
+/// and SPF types.
+///
+/// This class implements the basic interfaces inherited by the TXT and SPF
+/// classes from the abstract \c rdata::Rdata class, and provides trivial
+/// accessors to TXT-like RDATA.
 template<class Type, uint16_t typeCode>class TXTLikeImpl {
 template<class Type, uint16_t typeCode>class TXTLikeImpl {
 public:
 public:
+    /// \brief Constructor from wire-format data.
+    ///
+    /// \param buffer A buffer storing the wire format data.
+    /// \param rdata_len The length of the RDATA in bytes, normally expected
+    /// to be the value of the RDLENGTH field of the corresponding RR.
+    ///
+    /// <b>Exceptions</b>
+    ///
+    /// \c InvalidRdataLength is thrown if rdata_len exceeds the maximum.
+    /// \c DNSMessageFORMERR is thrown if the RR is misformed.
     TXTLikeImpl(InputBuffer& buffer, size_t rdata_len) {
     TXTLikeImpl(InputBuffer& buffer, size_t rdata_len) {
         if (rdata_len > MAX_RDLENGTH) {
         if (rdata_len > MAX_RDLENGTH) {
             isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
             isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
@@ -52,6 +68,14 @@ public:
         } while (rdata_len > 0);
         } while (rdata_len > 0);
     }
     }
 
 
+    /// \brief Constructor from string.
+    ///
+    /// <b>Exceptions</b>
+    ///
+    /// \c CharStringTooLong is thrown if the parameter string length exceeds
+    /// maximum.
+    /// \c InvalidRdataText is thrown if the method cannot process the
+    /// parameter data.
     explicit TXTLikeImpl(const std::string& txtstr) {
     explicit TXTLikeImpl(const std::string& txtstr) {
         // TBD: this is a simple, incomplete implementation that only supports
         // TBD: this is a simple, incomplete implementation that only supports
         // a single character-string.
         // a single character-string.
@@ -86,10 +110,17 @@ public:
         string_list_.push_back(data);
         string_list_.push_back(data);
     }
     }
 
 
+    /// \brief The copy constructor.
+    ///
+    /// Trivial for now, we could've used the default one.
     TXTLikeImpl(const TXTLikeImpl& other) :
     TXTLikeImpl(const TXTLikeImpl& other) :
         string_list_(other.string_list_)
         string_list_(other.string_list_)
     {}
     {}
 
 
+    /// \brief Render the TXT-like data in the wire format to an OutputBuffer
+    /// object.
+    ///
+    /// \param buffer An output buffer to store the wire data.
     void
     void
     toWire(OutputBuffer& buffer) const {
     toWire(OutputBuffer& buffer) const {
         for (vector<vector<uint8_t> >::const_iterator it =
         for (vector<vector<uint8_t> >::const_iterator it =
@@ -101,6 +132,11 @@ public:
         }
         }
     }
     }
 
 
+    /// \brief Render the TXT-like data in the wire format to an
+    /// AbstractMessageRenderer object.
+    ///
+    /// \param buffer An output AbstractMessageRenderer to send the wire data
+    /// to.
     void
     void
     toWire(AbstractMessageRenderer& renderer) const {
     toWire(AbstractMessageRenderer& renderer) const {
         for (vector<vector<uint8_t> >::const_iterator it =
         for (vector<vector<uint8_t> >::const_iterator it =
@@ -112,6 +148,9 @@ public:
         }
         }
     }
     }
 
 
+    /// \brief Convert the TXT-like data to a string.
+    ///
+    /// \return A \c string object that represents the TXT-like data.
     string
     string
     toText() const {
     toText() const {
         string s;
         string s;
@@ -134,20 +173,33 @@ public:
         return (s);
         return (s);
     }
     }
 
 
+    /// \brief Compare two instances of TXT-like RDATA.
+    ///
+    /// It is up to the caller to make sure that \c other is an object of the
+    /// same \c TXTLikeImpl class.
+    ///
+    /// \param other the right-hand operand to compare against.
+    /// \return < 0 if \c this would be sorted before \c other.
+    /// \return 0 if \c this is identical to \c other in terms of sorting
+    /// order.
+    /// \return > 0 if \c this would be sorted after \c other.
     int
     int
     compare(const TXTLikeImpl& other) const {
     compare(const TXTLikeImpl& other) const {
         // This implementation is not efficient.  Revisit this (TBD).
         // This implementation is not efficient.  Revisit this (TBD).
         OutputBuffer this_buffer(0);
         OutputBuffer this_buffer(0);
         toWire(this_buffer);
         toWire(this_buffer);
+        uint8_t const* const this_data = (uint8_t const*)this_buffer.getData();
         size_t this_len = this_buffer.getLength();
         size_t this_len = this_buffer.getLength();
 
 
         OutputBuffer other_buffer(0);
         OutputBuffer other_buffer(0);
         other.toWire(other_buffer);
         other.toWire(other_buffer);
+        uint8_t const* const other_data
+                                      = (uint8_t const*)other_buffer.getData();
         const size_t other_len = other_buffer.getLength();
         const size_t other_len = other_buffer.getLength();
 
 
         const size_t cmplen = min(this_len, other_len);
         const size_t cmplen = min(this_len, other_len);
-        const int cmp = memcmp(this_buffer.getData(), other_buffer.getData(),
-                               cmplen);
+        const int cmp = memcmp(this_data, other_data, cmplen);
+
         if (cmp != 0) {
         if (cmp != 0) {
             return (cmp);
             return (cmp);
         } else {
         } else {

+ 44 - 0
src/lib/dns/rdata/generic/spf_99.cc

@@ -30,8 +30,17 @@ using namespace isc::util;
 // BEGIN_ISC_NAMESPACE
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
 
+/// This class implements the basic interfaces inherited from the abstract
+/// \c rdata::Rdata class. The semantics of the class is provided by
+/// a copy of instantiated TXTLikeImpl class common to both TXT and SPF.
+
 #include <dns/rdata/generic/detail/txt_like.h>
 #include <dns/rdata/generic/detail/txt_like.h>
 
 
+/// \brief The assignment operator
+///
+/// It internally allocates a resource, and if it fails a corresponding
+/// standard exception will be thrown.
+/// This method never throws an exception otherwise.
 SPF&
 SPF&
 SPF::operator=(const SPF& source) {
 SPF::operator=(const SPF& source) {
     if (impl_ == source.impl_) {
     if (impl_ == source.impl_) {
@@ -45,37 +54,72 @@ SPF::operator=(const SPF& source) {
     return (*this);
     return (*this);
 }
 }
 
 
+/// \brief The destructor
 SPF::~SPF() {
 SPF::~SPF() {
     delete impl_;
     delete impl_;
 }
 }
 
 
+/// \brief Constructor from wire-format data.
+///
+/// It internally allocates a resource, and if it fails a corresponding
+/// standard exception will be thrown.
 SPF::SPF(InputBuffer& buffer, size_t rdata_len) :
 SPF::SPF(InputBuffer& buffer, size_t rdata_len) :
     impl_(new SPFImpl(buffer, rdata_len))
     impl_(new SPFImpl(buffer, rdata_len))
 {}
 {}
 
 
+/// \brief Constructor from string.
+///
+/// It internally allocates a resource, and if it fails a corresponding
+/// standard exception will be thrown.
 SPF::SPF(const std::string& txtstr) :
 SPF::SPF(const std::string& txtstr) :
     impl_(new SPFImpl(txtstr))
     impl_(new SPFImpl(txtstr))
 {}
 {}
 
 
+/// \brief Copy constructor
+///
+/// It internally allocates a resource, and if it fails a corresponding
+/// standard exception will be thrown.
 SPF::SPF(const SPF& other) :
 SPF::SPF(const SPF& other) :
     Rdata(), impl_(new SPFImpl(*other.impl_))
     Rdata(), impl_(new SPFImpl(*other.impl_))
 {}
 {}
 
 
+/// \brief Render the \c SPF in the wire format to a OutputBuffer object
+///
+/// \return is the return of the corresponding implementation method.
 void
 void
 SPF::toWire(OutputBuffer& buffer) const {
 SPF::toWire(OutputBuffer& buffer) const {
     impl_->toWire(buffer);
     impl_->toWire(buffer);
 }
 }
 
 
+/// \brief Render the \c SPF in the wire format to an AbstractMessageRenderer
+/// object
+///
+/// \return is the return of the corresponding implementation method.
 void
 void
 SPF::toWire(AbstractMessageRenderer& renderer) const {
 SPF::toWire(AbstractMessageRenderer& renderer) const {
     impl_->toWire(renderer);
     impl_->toWire(renderer);
 }
 }
 
 
+/// \brief Convert the \c SPF to a string.
+///
+/// \return is the return of the corresponding implementation method.
 string
 string
 SPF::toText() const {
 SPF::toText() const {
     return (impl_->toText());
     return (impl_->toText());
 }
 }
 
 
+/// \brief Compare two instances of \c SPF RDATA.
+///
+/// This method compares \c this and the \c other \c SPF objects.
+///
+/// This method is expected to be used in a polymorphic way, and the
+/// parameter to compare against is therefore of the abstract \c Rdata class.
+/// However, comparing two \c Rdata objects of different RR types
+/// is meaningless, and \c other must point to a \c SPF object;
+/// otherwise, the standard \c bad_cast exception will be thrown.
+///
+/// \param other the right-hand operand to compare against.
+/// \return is the return of the corresponding implementation method.
 int
 int
 SPF::compare(const Rdata& other) const {
 SPF::compare(const Rdata& other) const {
     const SPF& other_txt = dynamic_cast<const SPF&>(other);
     const SPF& other_txt = dynamic_cast<const SPF&>(other);

+ 26 - 0
src/lib/dns/rdata/generic/spf_99.h

@@ -30,14 +30,40 @@
 
 
 template<class Type, uint16_t typeCode> class TXTLikeImpl;
 template<class Type, uint16_t typeCode> class TXTLikeImpl;
 
 
+/// \brief \c rdata::SPF class represents the SPF RDATA as defined %in
+/// RFC4408.
+///
+/// This class implements the basic interfaces inherited from the abstract
+/// \c rdata::Rdata class. The semantics of the class is provided by
+/// a copy of instantiated TXTLikeImpl class common to both TXT and SPF.
 class SPF : public Rdata {
 class SPF : public Rdata {
 public:
 public:
     // BEGIN_COMMON_MEMBERS
     // BEGIN_COMMON_MEMBERS
     // END_COMMON_MEMBERS
     // END_COMMON_MEMBERS
 
 
+    /// \brief Assignment operator.
+    ///
+    /// It internally allocates a resource, and if it fails a corresponding
+    /// standard exception will be thrown.
+    /// This operator never throws an exception otherwise.
+    ///
+    /// This operator provides the strong exception guarantee: When an
+    /// exception is thrown the content of the assignment target will be
+    /// intact.
     SPF& operator=(const SPF& source);
     SPF& operator=(const SPF& source);
+
+    /// \brief The destructor.
     ~SPF();
     ~SPF();
 
 
+    ///
+    /// Specialized methods
+    ///
+
+    /// \brief Return a reference to the data strings
+    ///
+    /// This method never throws an exception.
+    const std::vector<std::vector<uint8_t> >& getString() const;
+
 private:
 private:
     typedef TXTLikeImpl<SPF, 99> SPFImpl;
     typedef TXTLikeImpl<SPF, 99> SPFImpl;
     SPFImpl* impl_;
     SPFImpl* impl_;

+ 2 - 1
src/lib/dns/tests/Makefile.am

@@ -29,7 +29,8 @@ run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc
 run_unittests_SOURCES += rdatafields_unittest.cc
 run_unittests_SOURCES += rdatafields_unittest.cc
 run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
 run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
 run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
 run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
-run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc
+run_unittests_SOURCES += rdata_txt_like_unittest.cc
+run_unittests_SOURCES += rdata_mx_unittest.cc
 run_unittests_SOURCES += rdata_ptr_unittest.cc rdata_cname_unittest.cc
 run_unittests_SOURCES += rdata_ptr_unittest.cc rdata_cname_unittest.cc
 run_unittests_SOURCES += rdata_dname_unittest.cc
 run_unittests_SOURCES += rdata_dname_unittest.cc
 run_unittests_SOURCES += rdata_afsdb_unittest.cc
 run_unittests_SOURCES += rdata_afsdb_unittest.cc

+ 261 - 0
src/lib/dns/tests/rdata_txt_like_unittest.cc

@@ -0,0 +1,261 @@
+// Copyright (C) 2011  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.
+
+// This is the common code for TXT and SPF tests.
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/rdataclass.h>
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <dns/tests/rdata_unittest.h>
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::dns::rdata;
+
+
+template<class T>
+class RRTYPE : public RRType {
+public:
+    RRTYPE();
+};
+
+template<> RRTYPE<generic::TXT>::RRTYPE() : RRType(RRType::TXT()) {}
+template<> RRTYPE<generic::SPF>::RRTYPE() : RRType(RRType::SPF()) {}
+
+namespace {
+const uint8_t wiredata_txt_like[] = {
+    sizeof("Test String") - 1,
+    'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+};
+
+const uint8_t wiredata_nulltxt[] = { 0 };
+vector<uint8_t> wiredata_longesttxt(256, 'a');
+
+template<class TXT_LIKE>
+class Rdata_TXT_LIKE_Test : public RdataTest {
+protected:
+    Rdata_TXT_LIKE_Test() {
+        wiredata_longesttxt[0] = 255; // adjust length
+    }
+
+    static const TXT_LIKE rdata_txt_like;
+    static const TXT_LIKE rdata_txt_like_empty;
+    static const TXT_LIKE rdata_txt_like_quoted;
+};
+
+template<class TXT_LIKE>
+const TXT_LIKE Rdata_TXT_LIKE_Test<TXT_LIKE>::rdata_txt_like("Test String");
+
+template<class TXT_LIKE>
+const TXT_LIKE Rdata_TXT_LIKE_Test<TXT_LIKE>::rdata_txt_like_empty("");
+
+template<class TXT_LIKE>
+const TXT_LIKE Rdata_TXT_LIKE_Test<TXT_LIKE>::rdata_txt_like_quoted
+                                                          ("\"Test String\"");
+
+// The list of types we want to test.
+typedef testing::Types<generic::TXT, generic::SPF> Implementations;
+
+TYPED_TEST_CASE(Rdata_TXT_LIKE_Test, Implementations);
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createFromText) {
+    // normal case is covered in toWireBuffer.
+
+    // surrounding double-quotes shouldn't change the result.
+    EXPECT_EQ(0, this->rdata_txt_like.compare(this->rdata_txt_like_quoted));
+
+    // Null character-string.
+    this->obuffer.clear();
+    TypeParam(string("")).toWire(this->obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        this->obuffer.getData(),
+                        this->obuffer.getLength(),
+                        wiredata_nulltxt, sizeof(wiredata_nulltxt));
+
+    // Longest possible character-string.
+    this->obuffer.clear();
+    TypeParam(string(255, 'a')).toWire(this->obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        this->obuffer.getData(),
+                        this->obuffer.getLength(),
+                        &wiredata_longesttxt[0], wiredata_longesttxt.size());
+
+    // Too long text for a valid character-string.
+    EXPECT_THROW(TypeParam(string(256, 'a')), CharStringTooLong);
+
+    // The escape character makes the double quote a part of character-string,
+    // so this is invalid input and should be rejected.
+    EXPECT_THROW(TypeParam("\"Test String\\\""), InvalidRdataText);
+
+    // Terminating double-quote is provided, so this is valid, but in this
+    // version of implementation we reject escaped characters.
+    EXPECT_THROW(TypeParam("\"Test String\\\"\""), InvalidRdataText);
+}
+
+void
+makeLargest(vector<uint8_t>& data) {
+    uint8_t ch = 0;
+
+    // create 255 sets of character-strings, each of which has the longest
+    // length (255bytes string + 1-byte length field)
+    for (int i = 0; i < 255; ++i, ++ch) {
+        data.push_back(255);
+        data.insert(data.end(), 255, ch);
+    }
+    // the last character-string should be 255 bytes (including the one-byte
+    // length field) in length so that the total length should be in the range
+    // of 16-bit integers.
+    data.push_back(254);
+    data.insert(data.end(), 254, ch);
+
+    assert(data.size() == 65535);
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, createFromWire) {
+    EXPECT_EQ(0, this->rdata_txt_like.compare(
+                  *rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+                                        "rdata_txt_fromWire1")));
+
+    // Empty character string
+    EXPECT_EQ(0, this->rdata_txt_like_empty.compare(
+                  *rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+                                        "rdata_txt_fromWire2.wire")));
+
+    // Multiple character strings
+    this->obuffer.clear();
+    rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+                         "rdata_txt_fromWire3.wire")->toWire(this->obuffer);
+    // the result should be 'wiredata_txt' repeated twice
+    vector<uint8_t> expected_data(wiredata_txt_like, wiredata_txt_like +
+                                  sizeof(wiredata_txt_like));
+    expected_data.insert(expected_data.end(), wiredata_txt_like,
+                         wiredata_txt_like + sizeof(wiredata_txt_like));
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        this->obuffer.getData(),
+                        this->obuffer.getLength(),
+                        &expected_data[0], expected_data.size());
+
+    // Largest length of data.  There's nothing special, but should be
+    // constructed safely, and the content should be identical to the original
+    // data.
+    vector<uint8_t> largest_txt_like_data;
+    makeLargest(largest_txt_like_data);
+    InputBuffer ibuffer(&largest_txt_like_data[0],
+                        largest_txt_like_data.size());
+    TypeParam largest_txt_like(ibuffer, largest_txt_like_data.size());
+    this->obuffer.clear();
+    largest_txt_like.toWire(this->obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        this->obuffer.getData(),
+                        this->obuffer.getLength(),
+                        &largest_txt_like_data[0],
+                        largest_txt_like_data.size());
+
+    // rdlen parameter is out of range.  This is a rare event because we'd
+    // normally call the constructor via a polymorphic wrapper, where the
+    // length is validated.  But this should be checked explicitly.
+    InputBuffer ibuffer2(&largest_txt_like_data[0],
+                         largest_txt_like_data.size());
+    EXPECT_THROW(TypeParam(ibuffer2, 65536), InvalidRdataLength);
+
+    // RDATA is empty, which is invalid for TXT_LIKE.
+    EXPECT_THROW(rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+                                      "rdata_txt_fromWire4.wire"),
+                 DNSMessageFORMERR);
+
+    // character-string length is too large, which could cause overrun.
+    EXPECT_THROW(rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
+                                      "rdata_txt_fromWire5.wire"),
+                 DNSMessageFORMERR);
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, toWireBuffer) {
+    this->rdata_txt_like.toWire(this->obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        this->obuffer.getData(),
+                        this->obuffer.getLength(),
+                        wiredata_txt_like, sizeof(wiredata_txt_like));
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, toWireRenderer) {
+    this->rdata_txt_like.toWire(this->renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        this->renderer.getData(),
+                        this->renderer.getLength(),
+                        wiredata_txt_like, sizeof(wiredata_txt_like));
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, toText) {
+    EXPECT_EQ("\"Test String\"", this->rdata_txt_like.toText());
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, assignment) {
+    TypeParam rdata1("assignment1");
+    TypeParam rdata2("assignment2");
+    rdata1 = rdata2;
+    EXPECT_EQ(0, rdata2.compare(rdata1));
+
+    // Check if the copied data is valid even after the original is deleted
+    TypeParam* rdata3 = new TypeParam(rdata1);
+    TypeParam rdata4("assignment3");
+    rdata4 = *rdata3;
+    delete rdata3;
+    EXPECT_EQ(0, rdata4.compare(rdata1));
+
+    // Self assignment
+    rdata2 = rdata2;
+    EXPECT_EQ(0, rdata2.compare(rdata1));
+}
+
+TYPED_TEST(Rdata_TXT_LIKE_Test, compare) {
+    string const txt1("aaaaaaaa");
+    string const txt2("aaaaaaaaaa");
+    string const txt3("bbbbbbbb");
+    string const txt4(129, 'a');
+    string const txt5(128, 'b');
+
+    EXPECT_EQ(TypeParam(txt1).compare(TypeParam(txt1)), 0);
+
+    EXPECT_LT(TypeParam("").compare(TypeParam(txt1)), 0);
+    EXPECT_GT(TypeParam(txt1).compare(TypeParam("")), 0);
+
+    EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt2)), 0);
+    EXPECT_GT(TypeParam(txt2).compare(TypeParam(txt1)), 0);
+
+    EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt3)), 0);
+    EXPECT_GT(TypeParam(txt3).compare(TypeParam(txt1)), 0);
+
+    // we're comparing the data raw, starting at the length octet, so a shorter
+    // string sorts before a longer one no matter the lexicopraphical order
+    EXPECT_LT(TypeParam(txt3).compare(TypeParam(txt2)), 0);
+    EXPECT_GT(TypeParam(txt2).compare(TypeParam(txt3)), 0);
+
+    // to make sure the length octet compares unsigned
+    EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt4)), 0);
+    EXPECT_GT(TypeParam(txt4).compare(TypeParam(txt1)), 0);
+
+    EXPECT_LT(TypeParam(txt5).compare(TypeParam(txt4)), 0);
+    EXPECT_GT(TypeParam(txt4).compare(TypeParam(txt5)), 0);
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(TypeParam(txt1).compare(*this->rdata_nomatch),
+                 bad_cast);
+}
+
+}

+ 0 - 166
src/lib/dns/tests/rdata_txt_unittest.cc

@@ -1,166 +0,0 @@
-// Copyright (C) 2010  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 <util/buffer.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-#include <gtest/gtest.h>
-
-#include <dns/tests/unittest_util.h>
-#include <dns/tests/rdata_unittest.h>
-
-using isc::UnitTestUtil;
-using namespace std;
-using namespace isc::dns;
-using namespace isc::util;
-using namespace isc::dns::rdata;
-
-namespace {
-const generic::TXT rdata_txt("Test String");
-const generic::TXT rdata_txt_empty("");
-const generic::TXT rdata_txt_quoated("\"Test String\"");
-const uint8_t wiredata_txt[] = {
-    sizeof("Test String") - 1,
-    'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
-};
-const uint8_t wiredata_nulltxt[] = { 0 };
-vector<uint8_t> wiredata_longesttxt(256, 'a');
-
-class Rdata_TXT_Test : public RdataTest {
-protected:
-    Rdata_TXT_Test() {
-        wiredata_longesttxt[0] = 255; // adjust length
-    }
-};
-
-TEST_F(Rdata_TXT_Test, createFromText) {
-    // normal case is covered in toWireBuffer.
-
-    // surrounding double-quotes shouldn't change the result.
-    EXPECT_EQ(0, rdata_txt.compare(rdata_txt_quoated));
-
-    // Null character-string.
-    obuffer.clear();
-    generic::TXT(string("")).toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_nulltxt, sizeof(wiredata_nulltxt));
-
-    // Longest possible character-string.
-    obuffer.clear();
-    generic::TXT(string(255, 'a')).toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        &wiredata_longesttxt[0], wiredata_longesttxt.size());
-
-    // Too long text for a valid character-string.
-    EXPECT_THROW(generic::TXT(string(256, 'a')), CharStringTooLong);
-
-    // The escape character makes the double quote a part of character-string,
-    // so this is invalid input and should be rejected.
-    EXPECT_THROW(generic::TXT("\"Test String\\\""), InvalidRdataText);
-
-    // Terminating double-quote is provided, so this is valid, but in this
-    // version of implementation we reject escaped characters.
-    EXPECT_THROW(generic::TXT("\"Test String\\\"\""), InvalidRdataText);
-}
-
-void
-makeLargest(vector<uint8_t>& data) {
-    uint8_t ch = 0;
-
-    // create 255 sets of character-strings, each of which has the longest
-    // length (255bytes string + 1-byte length field)
-    for (int i = 0; i < 255; ++i, ++ch) {
-        data.push_back(255);
-        data.insert(data.end(), 255, ch);
-    }
-    // the last character-string should be 255 bytes (including the one-byte
-    // length field) in length so that the total length should be in the range
-    // of 16-bit integers.
-    data.push_back(254);
-    data.insert(data.end(), 254, ch);
-
-    assert(data.size() == 65535);
-}
-
-TEST_F(Rdata_TXT_Test, createFromWire) {
-    EXPECT_EQ(0, rdata_txt.compare(
-                  *rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
-                                        "rdata_txt_fromWire1")));
-
-    // Empty character string
-    EXPECT_EQ(0, rdata_txt_empty.compare(
-                  *rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
-                                        "rdata_txt_fromWire2.wire")));
-
-    // Multiple character strings
-    obuffer.clear();
-    rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
-                         "rdata_txt_fromWire3.wire")->toWire(obuffer);
-    // the result should be 'wiredata_txt' repeated twice
-    vector<uint8_t> expected_data(wiredata_txt, wiredata_txt +
-                                  sizeof(wiredata_txt));
-    expected_data.insert(expected_data.end(), wiredata_txt,
-                         wiredata_txt + sizeof(wiredata_txt));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        &expected_data[0], expected_data.size());
-
-    // Largest length of data.  There's nothing special, but should be
-    // constructed safely, and the content should be identical to the original
-    // data.
-    vector<uint8_t> largest_txt_data;
-    makeLargest(largest_txt_data);
-    InputBuffer ibuffer(&largest_txt_data[0], largest_txt_data.size());
-    generic::TXT largest_txt(ibuffer, largest_txt_data.size());
-    obuffer.clear();
-    largest_txt.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        &largest_txt_data[0], largest_txt_data.size());
-
-    // rdlen parameter is out of range.  This is a rare event because we'd
-    // normally call the constructor via a polymorphic wrapper, where the
-    // length is validated.  But this should be checked explicitly.
-    InputBuffer ibuffer2(&largest_txt_data[0], largest_txt_data.size());
-    EXPECT_THROW(generic::TXT(ibuffer2, 65536), InvalidRdataLength);
-
-    // RDATA is empty, which is invalid for TXT.
-    EXPECT_THROW(rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
-                                      "rdata_txt_fromWire4.wire"),
-                 DNSMessageFORMERR);
-
-    // character-string length is too large, which could cause overrun.
-    EXPECT_THROW(rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
-                                      "rdata_txt_fromWire5.wire"),
-                 DNSMessageFORMERR);
-}
-
-TEST_F(Rdata_TXT_Test, toWireBuffer) {
-    rdata_txt.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_txt, sizeof(wiredata_txt));
-}
-
-TEST_F(Rdata_TXT_Test, toText) {
-    EXPECT_EQ("\"Test String\"", rdata_txt.toText());
-}
-}