Commit 57c61f2f authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

[2052] Add implementation and unit tests for dns::LabelSequence::compare()

parent 61fdb18f
......@@ -1260,6 +1260,9 @@ RBTree<T>::previousNode(RBTreeNodeChain<T>& node_path) const {
// already, which located the exact node. The rest of the function
// goes one domain left and returns it for us.
break;
default:
// This must not happen as Name::compare() never returns NONE.
isc_throw(isc::Unexpected, "Name::compare() returned unexpected result");
}
// So, the node_path now contains the path to a node we want previous for.
......
......@@ -71,6 +71,19 @@ LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
return (true);
}
NameComparisonResult
LabelSequence::compare(const LabelSequence& other,
bool case_sensitive) const {
if ((!isAbsolute()) || (!other.isAbsolute())) {
return (NameComparisonResult(0, 0, NameComparisonResult::NONE));
}
return (name_.partial_compare(other.name_,
first_label_,
other.first_label_,
case_sensitive));
}
void
LabelSequence::stripLeft(size_t i) {
if (i >= getLabelCount()) {
......
......@@ -85,10 +85,10 @@ public:
/// \return The length of the data of the label sequence in octets.
size_t getDataLength() const;
/// \brief Compares two label sequences.
/// \brief Compares two label sequences for equality.
///
/// Performs a (optionally case-insensitive) comparison between this
/// LabelSequence and another LabelSequence.
/// LabelSequence and another LabelSequence for equality.
///
/// \param other The LabelSequence to compare with
/// \param case_sensitive If true, comparison is case-insensitive
......@@ -96,6 +96,18 @@ public:
/// and contain the same data.
bool equals(const LabelSequence& other, bool case_sensitive = false) const;
/// \brief Compares two label sequences.
///
/// Performs a (optionally case-insensitive) comparison between this
/// LabelSequence and another LabelSequence.
///
/// \param other The LabelSequence to compare with
/// \param case_sensitive If true, comparison is case-insensitive
/// \return a <code>NameComparisonResult</code> object representing the
/// comparison result.
NameComparisonResult compare(const LabelSequence& other,
bool case_sensitive = false) const;
/// \brief Remove labels from the front of this LabelSequence
///
/// \note No actual memory is changed, this operation merely updates the
......
......@@ -507,13 +507,26 @@ Name::toText(bool omit_final_dot) const {
NameComparisonResult
Name::compare(const Name& other) const {
return (partial_compare(other, 0, 0));
}
NameComparisonResult
Name::partial_compare(const Name& other,
unsigned int first_label,
unsigned int first_label_other,
bool case_sensitive) const {
// Determine the relative ordering under the DNSSEC order relation of
// 'this' and 'other', and also determine the hierarchical relationship
// of the names.
if ((first_label > labelcount_) ||
(first_label_other > other.labelcount_)) {
isc_throw(BadValue, "Bad first label indices were passed");
}
unsigned int nlabels = 0;
unsigned int l1 = labelcount_;
unsigned int l2 = other.labelcount_;
int l1 = labelcount_ - first_label;
int l2 = other.labelcount_ - first_label_other;
int ldiff = (int)l1 - (int)l2;
unsigned int l = (ldiff < 0) ? l1 : l2;
......@@ -521,8 +534,8 @@ Name::compare(const Name& other) const {
--l;
--l1;
--l2;
size_t pos1 = offsets_[l1];
size_t pos2 = other.offsets_[l2];
size_t pos1 = offsets_[l1 + first_label];
size_t pos2 = other.offsets_[l2 + first_label_other];
unsigned int count1 = ndata_[pos1++];
unsigned int count2 = other.ndata_[pos2++];
......@@ -536,11 +549,17 @@ Name::compare(const Name& other) const {
while (count > 0) {
unsigned char label1 = ndata_[pos1];
unsigned char label2 = other.ndata_[pos2];
int chdiff;
if (case_sensitive) {
chdiff = (int)label1 - (int)label2;
} else {
chdiff = (int)maptolower[label1] - (int)maptolower[label2];
}
int chdiff = (int)maptolower[label1] - (int)maptolower[label2];
if (chdiff != 0) {
return (NameComparisonResult(chdiff, nlabels,
NameComparisonResult::COMMONANCESTOR));
NameComparisonResult::COMMONANCESTOR));
}
--count;
++pos1;
......
......@@ -142,7 +142,8 @@ public:
SUPERDOMAIN = 0,
SUBDOMAIN = 1,
EQUAL = 2,
COMMONANCESTOR = 3
COMMONANCESTOR = 3,
NONE = 4
};
///
......@@ -399,6 +400,29 @@ public:
/// comparison result.
NameComparisonResult compare(const Name& other) const;
private:
/// \brief Partially compare two <code>Name</code>s.
///
/// This method performs a partial comparison of the
/// <code>Name</code> and <code>other</code> and returns the result
/// in the form of a <code>NameComparisonResult</code> object.
///
/// This method never throws an exception.
///
/// \param other the right-hand operand to compare against.
/// \param first_label the leftmost label of <code>Name</code> to
/// begin comparing from.
/// \param first_label_other the leftmost label of
/// <code>other</code> to begin comparing from.
/// \param case_sensitive If true, comparison is case-insensitive
/// \return a <code>NameComparisonResult</code> object representing the
/// comparison result.
NameComparisonResult partial_compare(const Name& other,
unsigned int first_label,
unsigned int first_label_other,
bool case_sensitive = false) const;
public:
/// \brief Return true iff two names are equal.
///
/// Semantically this could be implemented based on the result of the
......
......@@ -125,6 +125,117 @@ TEST_F(LabelSequenceTest, equals_insensitive) {
EXPECT_FALSE(ls5.equals(ls7));
}
// Compare tests
TEST_F(LabelSequenceTest, compare) {
// "example.org." and "example.org.", case sensitive
NameComparisonResult result = ls1.compare(ls3, true);
EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
// "example.org." and "example.ORG.", case sensitive
result = ls3.compare(ls5, true);
EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
result.getRelation());
EXPECT_EQ(1, result.getCommonLabels());
// "example.org." and "example.ORG.", case in-sensitive
result = ls3.compare(ls5);
EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
Name na("a.example.org");
Name nb("b.example.org");
LabelSequence lsa(na);
LabelSequence lsb(nb);
// "a.example.org." and "b.example.org.", case in-sensitive
result = lsa.compare(lsb);
EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
// "example.org." and "b.example.org.", case in-sensitive
lsa.stripLeft(1);
result = lsa.compare(lsb);
EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
Name nc("g.f.e.d.c.example.org");
LabelSequence lsc(nc);
// "g.f.e.d.c.example.org." and "b.example.org" (no hierarchy), case
// in-sensitive
lsb.stripRight(1);
result = lsc.compare(lsb);
EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
result.getRelation());
EXPECT_EQ(0, result.getCommonLabels());
EXPECT_EQ(0, result.getOrder());
// "g.f.e.d.c.example.org." and "example.org.", case in-sensitive
result = lsc.compare(ls1);
EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
// "e.d.c.example.org." and "example.org.", case in-sensitive
lsc.stripLeft(2);
result = lsc.compare(ls1);
EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
// "example.org." and "example.org.", case in-sensitive
lsc.stripLeft(3);
result = lsc.compare(ls1);
EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
result.getRelation());
EXPECT_EQ(3, result.getCommonLabels());
// "." and "example.org.", case in-sensitive
lsc.stripLeft(2);
result = lsc.compare(ls1);
EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
result.getRelation());
EXPECT_EQ(1, result.getCommonLabels());
Name nd("a.b.c.isc.example.org");
LabelSequence lsd(nd);
Name ne("w.x.y.isc.EXAMPLE.org");
LabelSequence lse(ne);
// "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
// case sensitive
result = lsd.compare(lse, true);
EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
result.getRelation());
EXPECT_EQ(2, result.getCommonLabels());
// "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
// case in-sensitive
result = lsd.compare(lse);
EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
result.getRelation());
EXPECT_EQ(4, result.getCommonLabels());
// "isc.example.org." and "isc.EXAMPLE.org.", case sensitive
lsd.stripLeft(3);
lse.stripLeft(3);
result = lsd.compare(lse, true);
EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
result.getRelation());
EXPECT_EQ(2, result.getCommonLabels());
// "isc.example.org." and "isc.EXAMPLE.org.", case in-sensitive
result = lsd.compare(lse);
EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
result.getRelation());
EXPECT_EQ(4, result.getCommonLabels());
}
void
getDataCheck(const char* expected_data, size_t expected_len,
const LabelSequence& ls)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment