BIND 10 trac2512, updated. a5d2806bff9656a3ea7900c8dba4101bf3c86ca8 [2512] Add CAA::getValue()

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Feb 11 07:50:21 UTC 2014


The branch, trac2512 has been updated
       via  a5d2806bff9656a3ea7900c8dba4101bf3c86ca8 (commit)
       via  7606f0759b4ae96e49edad0e46316d8d1784aaff (commit)
       via  cb1407f6e846eaa57940be4d13ff03d25c1728c8 (commit)
      from  79defea75c875181597598e880ee20af3016167f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a5d2806bff9656a3ea7900c8dba4101bf3c86ca8
Author: Mukund Sivaraman <muks at isc.org>
Date:   Tue Feb 11 13:18:50 2014 +0530

    [2512] Add CAA::getValue()

commit 7606f0759b4ae96e49edad0e46316d8d1784aaff
Author: Mukund Sivaraman <muks at isc.org>
Date:   Tue Feb 11 13:14:00 2014 +0530

    [2512] Simplify CAA implementation using CharStringData type

commit cb1407f6e846eaa57940be4d13ff03d25c1728c8
Author: Mukund Sivaraman <muks at isc.org>
Date:   Tue Feb 11 13:13:01 2014 +0530

    [2512] Add a CharStringData type (with no length byte prefix)

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dns/rdata/generic/caa_257.cc               |   75 ++++----
 src/lib/dns/rdata/generic/caa_257.h                |    1 +
 src/lib/dns/rdata/generic/detail/char_string.cc    |   78 ++++++++
 src/lib/dns/rdata/generic/detail/char_string.h     |   37 ++++
 src/lib/dns/tests/Makefile.am                      |    1 +
 src/lib/dns/tests/rdata_caa_unittest.cc            |   17 +-
 .../dns/tests/rdata_char_string_data_unittest.cc   |  187 ++++++++++++++++++++
 7 files changed, 351 insertions(+), 45 deletions(-)
 create mode 100644 src/lib/dns/tests/rdata_char_string_data_unittest.cc

-----------------------------------------------------------------------
diff --git a/src/lib/dns/rdata/generic/caa_257.cc b/src/lib/dns/rdata/generic/caa_257.cc
index ecaf559..a031ab1 100644
--- a/src/lib/dns/rdata/generic/caa_257.cc
+++ b/src/lib/dns/rdata/generic/caa_257.cc
@@ -37,19 +37,20 @@ using namespace isc::util;
 struct CAAImpl {
     // straightforward representation of CAA RDATA fields
     CAAImpl(uint8_t flags, const std::string& tag,
-            const std::vector<uint8_t>& value) :
+            const detail::CharStringData& value) :
         flags_(flags),
         tag_(tag),
         value_(value)
-    {}
+    {
+        if ((sizeof(flags) + 1 + tag_.size() + value_.size()) > 65535) {
+            isc_throw(InvalidRdataLength,
+                      "CAA Value field is too large: " << value_.size());
+        }
+    }
 
     uint8_t flags_;
     const std::string tag_;
-
-    // The first byte of this vector contains the length of the rest of
-    // the vector. This byte is actually unused and is skipped when
-    // reading the vector.
-    const detail::CharString value_;
+    const detail::CharStringData value_;
 };
 
 // helper function for string and lexer constructors
@@ -73,15 +74,12 @@ CAA::constructFromLexer(MasterLexer& lexer) {
     }
 
     // Value field may be empty.
-    std::vector<uint8_t> value;
+    detail::CharStringData value;
     MasterToken token = lexer.getNextToken(MasterToken::QSTRING, true);
     if ((token.getType() != MasterToken::END_OF_FILE) &&
         (token.getType() != MasterToken::END_OF_LINE))
     {
-        detail::stringToCharString(token.getStringRegion(), value);
-    } else {
-        // Convert it into a CharString.
-        value.push_back(0);
+        detail::stringToCharStringData(token.getStringRegion(), value);
     }
 
     return (new CAAImpl(flags, tag, value));
@@ -172,23 +170,15 @@ CAA::CAA(InputBuffer& buffer, size_t rdata_len) {
     }
 
     vector<uint8_t> tag_vec;
-    tag_vec.resize(tag_length + 1);
-    tag_vec[0] = tag_length;
-    buffer.readData(&tag_vec[1], tag_length);
+    tag_vec.resize(tag_length);
+    buffer.readData(&tag_vec[0], tag_length);
+    std::string tag(tag_vec.begin(), tag_vec.end());
     rdata_len -= tag_length;
 
-    const std::string tag = detail::charStringToString(tag_vec);
-
-    if (rdata_len > 255) {
-        isc_throw(InvalidRdataLength,
-                  "CAA value field is too long: " << rdata_len);
-    }
-
-    vector<uint8_t> value;
-    value.resize(rdata_len + 1);
-    value[0] = rdata_len;
+    detail::CharStringData value;
+    value.resize(rdata_len);
     if (rdata_len > 0) {
-        buffer.readData(&value[1], rdata_len);
+        buffer.readData(&value[0], rdata_len);
     }
 
     impl_ = new CAAImpl(flags, tag, value);
@@ -205,14 +195,8 @@ CAA::CAA(uint8_t flags, const std::string& tag, const std::string& value) :
                   "CAA tag field is too large: " << tag.size());
     }
 
-    if (value.size() > 255) {
-        isc_throw(isc::InvalidParameter,
-                  "CAA value field is too long: " << value.size());
-    }
-
-    std::vector<uint8_t> value_vec;
-    value_vec.reserve(value.size() + 1);
-    value_vec.push_back(value.size());
+    detail::CharStringData value_vec;
+    value_vec.reserve(value.size());
     value_vec.insert(value_vec.end(), value.begin(), value.end());
 
     impl_ = new CAAImpl(flags, tag, value_vec);
@@ -248,9 +232,9 @@ CAA::toWire(OutputBuffer& buffer) const {
     buffer.writeUint8(impl_->tag_.size());
     buffer.writeData(&impl_->tag_[0], impl_->tag_.size());
 
-    if (impl_->value_.size() > 1) {
-        buffer.writeData(&impl_->value_[1],
-                         impl_->value_.size() - 1);
+    if (!impl_->value_.empty()) {
+        buffer.writeData(&impl_->value_[0],
+                         impl_->value_.size());
     }
 }
 
@@ -263,9 +247,9 @@ CAA::toWire(AbstractMessageRenderer& renderer) const {
     renderer.writeUint8(impl_->tag_.size());
     renderer.writeData(&impl_->tag_[0], impl_->tag_.size());
 
-    if (impl_->value_.size() > 1) {
-        renderer.writeData(&impl_->value_[1],
-                           impl_->value_.size() - 1);
+    if (!impl_->value_.empty()) {
+        renderer.writeData(&impl_->value_[0],
+                           impl_->value_.size());
     }
 }
 
@@ -275,7 +259,7 @@ CAA::toText() const {
 
     result = lexical_cast<std::string>(static_cast<int>(impl_->flags_));
     result += " " + impl_->tag_;
-    result += " \"" + detail::charStringToString(impl_->value_) + "\"";
+    result += " \"" + detail::charStringDataToString(impl_->value_) + "\"";
 
     return (result);
 }
@@ -297,8 +281,8 @@ CAA::compare(const Rdata& other) const {
         return (result);
     }
 
-    return (detail::compareCharStrings(impl_->value_,
-                                       other_caa.impl_->value_));
+    return (detail::compareCharStringDatas(impl_->value_,
+                                           other_caa.impl_->value_));
 }
 
 uint8_t
@@ -311,5 +295,10 @@ CAA::getTag() const {
     return (impl_->tag_);
 }
 
+const std::vector<uint8_t>&
+CAA::getValue() const {
+    return (impl_->value_);
+}
+
 // END_RDATA_NAMESPACE
 // END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/caa_257.h b/src/lib/dns/rdata/generic/caa_257.h
index 69e3936..e06b250 100644
--- a/src/lib/dns/rdata/generic/caa_257.h
+++ b/src/lib/dns/rdata/generic/caa_257.h
@@ -45,6 +45,7 @@ public:
     ///
     uint8_t getFlags() const;
     const std::string& getTag() const;
+    const std::vector<uint8_t>& getValue() const;
 
 private:
     CAAImpl* constructFromLexer(MasterLexer& lexer);
diff --git a/src/lib/dns/rdata/generic/detail/char_string.cc b/src/lib/dns/rdata/generic/detail/char_string.cc
index 4c8965a..16b281d 100644
--- a/src/lib/dns/rdata/generic/detail/char_string.cc
+++ b/src/lib/dns/rdata/generic/detail/char_string.cc
@@ -93,6 +93,33 @@ stringToCharString(const MasterToken::StringRegion& str_region,
     result[0] = result.size() - 1;
 }
 
+void
+stringToCharStringData(const MasterToken::StringRegion& str_region,
+                       CharStringData& result)
+{
+    bool escape = false;
+    const char* s = str_region.beg;
+    const char* const s_end = str_region.beg + str_region.len;
+
+    for (size_t n = str_region.len; n != 0; --n, ++s) {
+        int c = (*s & 0xff);
+        if (escape && std::isdigit(c) != 0) {
+            c = decimalToNumber(s, s_end);
+            assert(n >= 3);
+            n -= 2;
+            s += 2;
+        } else if (!escape && c == '\\') {
+            escape = true;
+            continue;
+        }
+        escape = false;
+        result.push_back(c);
+    }
+    if (escape) {               // terminated by non-escaped '\'
+        isc_throw(InvalidRdataText, "character-string ends with '\\'");
+    }
+}
+
 std::string
 charStringToString(const CharString& char_string) {
     std::string s;
@@ -116,6 +143,29 @@ charStringToString(const CharString& char_string) {
     return (s);
 }
 
+std::string
+charStringDataToString(const CharStringData& char_string) {
+    std::string s;
+    for (CharString::const_iterator it = char_string.begin();
+         it != char_string.end(); ++it) {
+        const uint8_t ch = *it;
+        if ((ch < 0x20) || (ch >= 0x7f)) {
+            // convert to escaped \xxx (decimal) format
+            s.push_back('\\');
+            s.push_back('0' + ((ch / 100) % 10));
+            s.push_back('0' + ((ch / 10) % 10));
+            s.push_back('0' + (ch % 10));
+            continue;
+        }
+        if ((ch == '"') || (ch == ';') || (ch == '\\')) {
+            s.push_back('\\');
+        }
+        s.push_back(ch);
+    }
+
+    return (s);
+}
+
 int compareCharStrings(const detail::CharString& self,
                        const detail::CharString& other) {
     if (self.size() == 0 && other.size() == 0) {
@@ -144,6 +194,34 @@ int compareCharStrings(const detail::CharString& self,
     }
 }
 
+int compareCharStringDatas(const detail::CharStringData& self,
+                           const detail::CharStringData& other) {
+    if (self.size() == 0 && other.size() == 0) {
+        return (0);
+    }
+    if (self.size() == 0) {
+        return (-1);
+    }
+    if (other.size() == 0) {
+        return (1);
+    }
+    const size_t self_len = self.size();
+    const size_t other_len = other.size();
+    const size_t cmp_len = std::min(self_len, other_len);
+    const int cmp = std::memcmp(&self[0], &other[0], cmp_len);
+    if (cmp < 0) {
+        return (-1);
+    } else if (cmp > 0) {
+        return (1);
+    } else if (self_len < other_len) {
+        return (-1);
+    } else if (self_len > other_len) {
+        return (1);
+    } else {
+        return (0);
+    }
+}
+
 size_t
 bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
                    CharString& target) {
diff --git a/src/lib/dns/rdata/generic/detail/char_string.h b/src/lib/dns/rdata/generic/detail/char_string.h
index 8e3e294..01fccad 100644
--- a/src/lib/dns/rdata/generic/detail/char_string.h
+++ b/src/lib/dns/rdata/generic/detail/char_string.h
@@ -34,6 +34,9 @@ namespace detail {
 /// be the bare char basis.
 typedef std::vector<uint8_t> CharString;
 
+/// \brief Type for DNS character string without the length prefix.
+typedef std::vector<uint8_t> CharStringData;
+
 /// \brief Convert a DNS character-string into corresponding binary data.
 ///
 /// This helper function takes a string object that is expected to be a
@@ -53,6 +56,20 @@ typedef std::vector<uint8_t> CharString;
 void stringToCharString(const MasterToken::StringRegion& str_region,
                         CharString& result);
 
+/// \brief Convert a DNS character-string into corresponding binary data.
+///
+/// This method functions similar to \c stringToCharString() except it
+/// does not include the 1-octet length prefix in the \c result, and the
+/// result is not limited to MAX_CHARSTRING_LEN octets.
+///
+/// \throw InvalidRdataText Upon syntax errors.
+///
+/// \brief str_region A string that represents a character-string.
+/// \brief result A placeholder vector where the resulting data are to be
+/// stored.  Expected to be empty, but it's not checked.
+void stringToCharStringData(const MasterToken::StringRegion& str_region,
+                            CharStringData& result);
+
 /// \brief Convert a CharString into a textual DNS character-string.
 ///
 /// This method converts a binary 8-bit representation of a DNS
@@ -67,6 +84,15 @@ void stringToCharString(const MasterToken::StringRegion& str_region,
 /// \return A string representation of \c char_string.
 std::string charStringToString(const CharString& char_string);
 
+/// \brief Convert a CharStringData into a textual DNS character-string.
+///
+/// Reverse of \c stringToCharStringData(). See \c stringToCharString()
+/// vs. \c stringToCharStringData().
+///
+/// \param char_string The \c CharStringData to convert.
+/// \return A string representation of \c char_string.
+std::string charStringDataToString(const CharStringData& char_string);
+
 /// \brief Compare two CharString objects
 ///
 /// \param self The CharString field to compare
@@ -77,6 +103,17 @@ std::string charStringToString(const CharString& char_string);
 ///          0 if \c self and \c other are equal
 int compareCharStrings(const CharString& self, const CharString& other);
 
+/// \brief Compare two CharStringData objects
+///
+/// \param self The CharStringData field to compare
+/// \param other The CharStringData field to compare to
+///
+/// \return -1 if \c self would be sorted before \c other
+///          1 if \c self would be sorted after \c other
+///          0 if \c self and \c other are equal
+int compareCharStringDatas(const CharStringData& self,
+                           const CharStringData& other);
+
 /// \brief Convert a buffer containing a character-string to CharString
 ///
 /// This method reads one character-string from the given buffer (in wire
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index 46fcfb1..01773e0 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -39,6 +39,7 @@ run_unittests_SOURCES += rcode_unittest.cc
 run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc
 run_unittests_SOURCES += rdatafields_unittest.cc
 run_unittests_SOURCES += rdata_char_string_unittest.cc
+run_unittests_SOURCES += rdata_char_string_data_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_txt_like_unittest.cc
diff --git a/src/lib/dns/tests/rdata_caa_unittest.cc b/src/lib/dns/tests/rdata_caa_unittest.cc
index 579cba9..8968f46 100644
--- a/src/lib/dns/tests/rdata_caa_unittest.cc
+++ b/src/lib/dns/tests/rdata_caa_unittest.cc
@@ -203,9 +203,9 @@ TEST_F(Rdata_CAA_Test, createFromParams) {
                  isc::InvalidParameter);
 
     // Value is too long
-    const std::string value(256, 'a');
+    const std::string value(65536, 'a');
     EXPECT_THROW(const generic::CAA rdata_caa3(0, "issue", value),
-                 isc::InvalidParameter);
+                 InvalidRdataLength);
 }
 
 TEST_F(Rdata_CAA_Test, toText) {
@@ -249,6 +249,19 @@ TEST_F(Rdata_CAA_Test, getTag) {
     EXPECT_EQ("issue", rdata_caa.getTag());
 }
 
+TEST_F(Rdata_CAA_Test, getValue) {
+    const uint8_t value_data[] = {
+        'c', 'a', '.',
+        'e', 'x', 'a', 'm', 'p', 'l', 'e', '.',
+        'n', 'e', 't'
+    };
+
+    const std::vector<uint8_t>& value = rdata_caa.getValue();
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        &value[0], value.size(),
+                        value_data, sizeof(value_data));
+}
+
 TEST_F(Rdata_CAA_Test, emptyValueFromWire) {
     const uint8_t rdf_wiredata[] = {
         // flags
diff --git a/src/lib/dns/tests/rdata_char_string_data_unittest.cc b/src/lib/dns/tests/rdata_char_string_data_unittest.cc
new file mode 100644
index 0000000..6f05936
--- /dev/null
+++ b/src/lib/dns/tests/rdata_char_string_data_unittest.cc
@@ -0,0 +1,187 @@
+// Copyright (C) 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 <util/unittests/wiredata.h>
+
+#include <dns/exceptions.h>
+#include <dns/rdata.h>
+#include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::dns::rdata::generic::detail::CharStringData;
+using isc::dns::rdata::generic::detail::stringToCharStringData;
+using isc::dns::rdata::generic::detail::charStringDataToString;
+using isc::dns::rdata::generic::detail::compareCharStringDatas;
+using isc::util::unittests::matchWireData;
+
+namespace {
+const uint8_t test_charstr[] = {
+    'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+};
+
+class CharStringDataTest : public ::testing::Test {
+protected:
+    CharStringDataTest() :
+        // char-string representation for test data using two types of escape
+        // ('r' = 114)
+        test_str("Test\\ St\\114ing")
+    {
+        str_region.beg = &test_str[0];
+        str_region.len = test_str.size();
+    }
+    CharStringData chstr;           // place holder
+    const std::string test_str;
+    MasterToken::StringRegion str_region;
+};
+
+MasterToken::StringRegion
+createStringRegion(const std::string& str) {
+    MasterToken::StringRegion region;
+    region.beg = &str[0]; // note std ensures this works even if str is empty
+    region.len = str.size();
+    return (region);
+}
+
+TEST_F(CharStringDataTest, normalConversion) {
+    uint8_t tmp[3];             // placeholder for expected sequence
+
+    stringToCharStringData(str_region, chstr);
+    matchWireData(test_charstr, sizeof(test_charstr), &chstr[0], chstr.size());
+
+    // Empty string
+    chstr.clear();
+    stringToCharStringData(createStringRegion(""), chstr);
+    EXPECT_TRUE(chstr.empty());
+
+    // Possible largest char string
+    chstr.clear();
+    std::string long_str(255, 'x');
+    stringToCharStringData(createStringRegion(long_str), chstr);
+    std::vector<uint8_t> expected;
+    expected.insert(expected.end(), long_str.begin(), long_str.end());
+    matchWireData(&expected[0], expected.size(), &chstr[0], chstr.size());
+
+    // Escaped '\'
+    chstr.clear();
+    tmp[0] = '\\';
+    stringToCharStringData(createStringRegion("\\\\"), chstr);
+    matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+    // Boundary values for \DDD
+    chstr.clear();
+    tmp[0] = 0;
+    stringToCharStringData(createStringRegion("\\000"), chstr);
+    matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+    chstr.clear();
+    stringToCharStringData(createStringRegion("\\255"), chstr);
+    tmp[0] = 255;
+    matchWireData(tmp, 1, &chstr[0], chstr.size());
+
+    // Another digit follows DDD; it shouldn't cause confusion
+    chstr.clear();
+    stringToCharStringData(createStringRegion("\\2550"), chstr);
+    tmp[1] = '0';
+    matchWireData(tmp, 2, &chstr[0], chstr.size());
+}
+
+TEST_F(CharStringDataTest, badConversion) {
+    // input string ending with (non escaped) '\'
+    chstr.clear();
+    EXPECT_THROW(stringToCharStringData(createStringRegion("foo\\"), chstr),
+                 InvalidRdataText);
+}
+
+TEST_F(CharStringDataTest, badDDD) {
+    // Check various type of bad form of \DDD
+
+    // Not a number
+    EXPECT_THROW(stringToCharStringData(createStringRegion("\\1a2"), chstr),
+                 InvalidRdataText);
+    EXPECT_THROW(stringToCharStringData(createStringRegion("\\12a"), chstr),
+                 InvalidRdataText);
+
+    // Not in the range of uint8_t
+    EXPECT_THROW(stringToCharStringData(createStringRegion("\\256"), chstr),
+                 InvalidRdataText);
+
+    // Short buffer
+    EXPECT_THROW(stringToCharStringData(createStringRegion("\\42"), chstr),
+                 InvalidRdataText);
+}
+
+const struct TestData {
+    const char *data;
+    const char *expected;
+} conversion_data[] = {
+    {"Test\"Test", "Test\\\"Test"},
+    {"Test;Test", "Test\\;Test"},
+    {"Test\\Test", "Test\\\\Test"},
+    {"Test\x1fTest", "Test\\031Test"},
+    {"Test ~ Test", "Test ~ Test"},
+    {"Test\x7fTest", "Test\\127Test"},
+    {NULL, NULL}
+};
+
+TEST_F(CharStringDataTest, charStringDataToString) {
+    for (const TestData* cur = conversion_data; cur->data != NULL; ++cur) {
+        uint8_t idata[32];
+        size_t length = std::strlen(cur->data);
+        assert(sizeof(idata) >= length);
+        std::memcpy(idata, cur->data, length);
+        const CharStringData test_data(idata, idata + length);
+        EXPECT_EQ(cur->expected, charStringDataToString(test_data));
+    }
+}
+
+TEST_F(CharStringDataTest, compareCharStringData) {
+    CharStringData charstr;
+    CharStringData charstr2;
+    CharStringData charstr_small1;
+    CharStringData charstr_small2;
+    CharStringData charstr_large1;
+    CharStringData charstr_large2;
+    CharStringData charstr_empty;
+
+    stringToCharStringData(createStringRegion("test string"), charstr);
+    stringToCharStringData(createStringRegion("test string"), charstr2);
+    stringToCharStringData(createStringRegion("test strin"), charstr_small1);
+    stringToCharStringData(createStringRegion("test strina"), charstr_small2);
+    stringToCharStringData(createStringRegion("test stringa"), charstr_large1);
+    stringToCharStringData(createStringRegion("test strinz"), charstr_large2);
+
+    EXPECT_EQ(0, compareCharStringDatas(charstr, charstr2));
+    EXPECT_EQ(0, compareCharStringDatas(charstr2, charstr));
+    EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small1));
+    EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_small2));
+    EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large1));
+    EXPECT_EQ(-1, compareCharStringDatas(charstr, charstr_large2));
+    EXPECT_EQ(-1, compareCharStringDatas(charstr_small1, charstr));
+    EXPECT_EQ(-1, compareCharStringDatas(charstr_small2, charstr));
+    EXPECT_EQ(1, compareCharStringDatas(charstr_large1, charstr));
+    EXPECT_EQ(1, compareCharStringDatas(charstr_large2, charstr));
+
+    EXPECT_EQ(-1, compareCharStringDatas(charstr_empty, charstr));
+    EXPECT_EQ(1, compareCharStringDatas(charstr, charstr_empty));
+    EXPECT_EQ(0, compareCharStringDatas(charstr_empty, charstr_empty));
+}
+
+} // unnamed namespace



More information about the bind10-changes mailing list