Commit 936342b0 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

merged from the jinmei-dnsrrset branch


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@939 e5f2f494-b856-4b98-b285-d166d9295462
parents 83ac742f 87a9c552
......@@ -568,7 +568,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/lib/cc/cpp ../src/lib/config/cpp
INPUT = ../src/lib/cc/cpp ../src/lib/config/cpp ../src/lib/dns/cpp
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
......@@ -65,6 +65,7 @@ public:
class Rdata;
typedef boost::shared_ptr<Rdata> RdataPtr;
typedef boost::shared_ptr<const Rdata> ConstRdataPtr;
/// Abstract RDATA class
class Rdata {
......
......@@ -46,16 +46,20 @@ AbstractRRset::toText() const
string s;
RdataIteratorPtr it = getRdataIterator();
for (it->first(); !it->isLast(); it->next()) {
s += getName().toText() + " " +
getTTL().toText() + " " +
getClass().toText() + " " +
getType().toText() + " " +
it->getCurrent().toText() + "\n";
it->first();
if (it->isLast()) {
dns_throw(EmptyRRset, "ToText() is attempted for an empty RRset");
}
do {
s += getName().toText() + " " + getTTL().toText() + " " +
getClass().toText() + " " + getType().toText() + " " +
it->getCurrent().toText() + "\n";
it->next();
} while (!it->isLast());
return (s);
}
}
namespace {
template <typename T>
......@@ -65,9 +69,14 @@ rrsetToWire(const AbstractRRset& rrset, T& output)
unsigned int n = 0;
RdataIteratorPtr it = rrset.getRdataIterator();
it->first();
if (it->isLast()) {
dns_throw(EmptyRRset, "ToWire() is attempted for an empty RRset");
}
// sort the set of Rdata based on rrset-order and sortlist, and possible
// other options. Details to be considered.
for (it->first(); !it->isLast(); it->next(), ++n) {
do {
rrset.getName().toWire(output);
rrset.getType().toWire(output);
rrset.getClass().toWire(output);
......@@ -77,7 +86,10 @@ rrsetToWire(const AbstractRRset& rrset, T& output)
output.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
it->getCurrent().toWire(output);
output.writeUint16At(output.getLength() - pos - sizeof(uint16_t), pos);
}
it->next();
++n;
} while (!it->isLast());
return (n);
}
......@@ -102,7 +114,10 @@ operator<<(ostream& os, const AbstractRRset& rrset)
return (os);
}
struct BasicRRsetImpl {
/// \brief This encapsulates the actual implementation of the \c BasicRRset
/// class. It's hidden from applications.
class BasicRRsetImpl {
public:
BasicRRsetImpl(const Name& name, const RRClass& rrclass,
const RRType& rrtype, const RRTTL& ttl) :
name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {}
......@@ -110,7 +125,10 @@ struct BasicRRsetImpl {
RRClass rrclass_;
RRType rrtype_;
RRTTL ttl_;
vector<RdataPtr> rdatalist_;
// XXX: "list" is not a good name: It in fact isn't a list; more conceptual
// name than a data structure name is generally better. But since this
// is only used in the internal implementation we'll live with it.
vector<ConstRdataPtr> rdatalist_;
};
BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass,
......@@ -125,11 +143,17 @@ BasicRRset::~BasicRRset()
}
void
BasicRRset::addRdata(const RdataPtr rdata)
BasicRRset::addRdata(ConstRdataPtr rdata)
{
impl_->rdatalist_.push_back(rdata);
}
void
BasicRRset::addRdata(const Rdata& rdata)
{
AbstractRRset::addRdata(rdata);
}
unsigned int
BasicRRset::getRdataCount() const
{
......@@ -160,18 +184,42 @@ BasicRRset::getTTL() const
return (impl_->ttl_);
}
void
BasicRRset::setName(const Name& name)
{
impl_->name_ = name;
}
void
BasicRRset::setTTL(const RRTTL& ttl)
{
impl_->ttl_ = ttl;
}
string
BasicRRset::toText() const
{
return (AbstractRRset::toText());
}
unsigned int
BasicRRset::toWire(OutputBuffer& buffer) const
{
return (AbstractRRset::toWire(buffer));
}
unsigned int
BasicRRset::toWire(MessageRenderer& renderer) const
{
return (AbstractRRset::toWire(renderer));
}
namespace {
class BasicRdataIterator : public RdataIterator {
private:
BasicRdataIterator() {}
public:
BasicRdataIterator(const std::vector<rdata::RdataPtr>& datavector) :
BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) :
datavector_(&datavector) {}
~BasicRdataIterator() {}
virtual void first() { it_ = datavector_->begin(); }
......@@ -179,8 +227,8 @@ public:
virtual const rdata::Rdata& getCurrent() const { return (**it_); }
virtual bool isLast() const { return (it_ == datavector_->end()); }
private:
const std::vector<rdata::RdataPtr>* datavector_;
std::vector<rdata::RdataPtr>::const_iterator it_;
const std::vector<rdata::ConstRdataPtr>* datavector_;
std::vector<rdata::ConstRdataPtr>::const_iterator it_;
};
}
......
This diff is collapsed.
......@@ -14,6 +14,8 @@
// $Id$
#include <stdexcept>
#include "buffer.h"
#include "messagerenderer.h"
#include "name.h"
......@@ -42,9 +44,16 @@ protected:
test_domain("example.com"),
test_nsname("ns.example.com"),
rrset_a(test_name, RRClass::IN(), RRType::A(), RRTTL(3600)),
rrset_a_empty(test_name, RRClass::IN(), RRType::A(),
RRTTL(3600)),
rrset_ns(test_domain, RRClass::IN(), RRType::NS(),
RRTTL(86400))
{}
RRTTL(86400)),
rrset_ch_txt(test_domain, RRClass::CH(), RRType::TXT(),
RRTTL(0))
{
rrset_a.addRdata(in::A("192.0.2.1"));
rrset_a.addRdata(in::A("192.0.2.2"));
}
OutputBuffer buffer;
MessageRenderer renderer;
......@@ -52,44 +61,157 @@ protected:
Name test_domain;
Name test_nsname;
RRset rrset_a;
RRset rrset_a_empty;
RRset rrset_ns;
RRset rrset_ch_txt;
std::vector<unsigned char> wiredata;
// max number of Rdata objects added to a test RRset object.
// this is an arbitrary chosen limit, but should be sufficiently large
// in practice and reasonable even as an extreme test case.
static const int MAX_RDATA_COUNT = 100;
};
TEST_F(RRsetTest, addRdata)
TEST_F(RRsetTest, getRdataCount)
{
for (int i = 0; i < MAX_RDATA_COUNT; ++i) {
EXPECT_EQ(i, rrset_a_empty.getRdataCount());
rrset_a_empty.addRdata(in::A("192.0.2.1"));
}
}
TEST_F(RRsetTest, getName)
{
rrset_a.addRdata(in::A("192.0.2.1"));
rrset_a.addRdata(in::A("192.0.2.2"));
EXPECT_EQ(test_name, rrset_a.getName());
EXPECT_EQ(test_domain, rrset_ns.getName());
}
TEST_F(RRsetTest, getClass)
{
EXPECT_EQ(RRClass("IN"), rrset_a.getClass());
EXPECT_EQ(RRClass("CH"), rrset_ch_txt.getClass());
}
RdataIteratorPtr it = rrset_a.getRdataIterator();
TEST_F(RRsetTest, getType)
{
EXPECT_EQ(RRType("A"), rrset_a.getType());
EXPECT_EQ(RRType("NS"), rrset_ns.getType());
EXPECT_EQ(RRType("TXT"), rrset_ch_txt.getType());
}
TEST_F(RRsetTest, getTTL)
{
EXPECT_EQ(RRTTL(3600), rrset_a.getTTL());
EXPECT_EQ(RRTTL(86400), rrset_ns.getTTL());
EXPECT_EQ(RRTTL(0), rrset_ch_txt.getTTL());
}
TEST_F(RRsetTest, setTTL)
{
rrset_a.setTTL(RRTTL(86400));
EXPECT_EQ(RRTTL(86400), rrset_a.getTTL());
rrset_a.setTTL(RRTTL(0));
EXPECT_EQ(RRTTL(0), rrset_a.getTTL());
}
TEST_F(RRsetTest, setName)
{
rrset_a.setName(test_nsname);
EXPECT_EQ(test_nsname, rrset_a.getName());
}
void
addRdataTestCommon(const RRset& rrset)
{
EXPECT_EQ(2, rrset.getRdataCount());
RdataIteratorPtr it = rrset.getRdataIterator();
it->first();
EXPECT_FALSE(it->isLast());
EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1")));
it->next();
EXPECT_FALSE(it->isLast());
EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.2")));
it->next();
EXPECT_TRUE(it->isLast());
}
TEST_F(RRsetTest, addRdata)
{
addRdataTestCommon(rrset_a);
// Reference version of addRdata() doesn't allow to add a different
// type of Rdata.
EXPECT_THROW(rrset_a.addRdata(generic::NS(test_nsname)), std::bad_cast);
}
TEST_F(RRsetTest, addRdataPtr)
{
rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(),
rrset_a_empty.getClass(),
"192.0.2.1"));
rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(),
rrset_a_empty.getClass(),
"192.0.2.2"));
addRdataTestCommon(rrset_a);
// Pointer version of addRdata() doesn't type check and does allow to
//add a different type of Rdata as a result.
rrset_a_empty.addRdata(createRdata(RRType::NS(), RRClass::IN(),
"ns.example.com"));
EXPECT_EQ(3, rrset_a_empty.getRdataCount());
}
TEST_F(RRsetTest, iterator)
{
// Iterator for an empty RRset.
RdataIteratorPtr it = rrset_a_empty.getRdataIterator();
it->first();
EXPECT_TRUE(it->isLast());
// Normal case (already tested, but do it again just in case)
rrset_a_empty.addRdata(in::A("192.0.2.1"));
rrset_a_empty.addRdata(in::A("192.0.2.2"));
addRdataTestCommon(rrset_a_empty);
// Rewind test: should be repeat the iteration by calling first().
for (int i = 0; i < 2; ++i) {
it = rrset_a_empty.getRdataIterator();
it->first();
EXPECT_FALSE(it->isLast());
it->next();
EXPECT_FALSE(it->isLast());
it->next();
EXPECT_TRUE(it->isLast());
}
}
TEST_F(RRsetTest, toText)
{
EXPECT_EQ("test.example.com. 3600 IN A 192.0.2.1\n"
"test.example.com. 3600 IN A 192.0.2.2\n", rrset_a.toText());
"test.example.com. 3600 IN A 192.0.2.2\n",
rrset_a.toText());
// toText() cannot be performed for an empty RRset.
EXPECT_THROW(rrset_a_empty.toText(), EmptyRRset);
}
TEST_F(RRsetTest, toWireBuffer)
{
rrset_a.addRdata(in::A("192.0.2.1"));
rrset_a.addRdata(in::A("192.0.2.2"));
rrset_a.toWire(buffer);
UnitTestUtil::readWireData("testdata/rrset_toWire1", wiredata);
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
buffer.getLength(), &wiredata[0], wiredata.size());
// toWire() cannot be performed for an empty RRset.
buffer.clear();
EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset);
}
TEST_F(RRsetTest, toWireRenderer)
{
rrset_a.addRdata(in::A("192.0.2.1"));
rrset_a.addRdata(in::A("192.0.2.2"));
rrset_ns.addRdata(generic::NS(test_nsname));
rrset_a.toWire(renderer);
......@@ -98,6 +220,17 @@ TEST_F(RRsetTest, toWireRenderer)
UnitTestUtil::readWireData("testdata/rrset_toWire2", wiredata);
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
buffer.getLength(), &wiredata[0], wiredata.size());
// toWire() cannot be performed for an empty RRset.
renderer.clear();
EXPECT_THROW(rrset_a_empty.toWire(renderer), EmptyRRset);
}
// test operator<<. We simply confirm it appends the result of toText().
TEST_F(RRsetTest, LeftShiftOperator)
{
ostringstream oss;
oss << rrset_a;
EXPECT_EQ(rrset_a.toText(), oss.str());
}
}
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