// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; using isc::UnitTestUtil; using isc::util::unittests::matchWireData; namespace { class Rdata_CAA_Test : public RdataTest { protected: Rdata_CAA_Test() : caa_txt("0 issue \"ca.example.net\""), rdata_caa(caa_txt) {} void checkFromText_None(const string& rdata_str) { checkFromText( rdata_str, rdata_caa, false, false); } void checkFromText_InvalidText(const string& rdata_str) { checkFromText( rdata_str, rdata_caa, true, true); } void checkFromText_LexerError(const string& rdata_str) { checkFromText ( rdata_str, rdata_caa, true, true); } void checkFromText_BadString(const string& rdata_str) { checkFromText ( rdata_str, rdata_caa, true, false); } const string caa_txt; const generic::CAA rdata_caa; }; const uint8_t rdata_caa_wiredata[] = { // flags 0x00, // tag length 0x5, // tag 'i', 's', 's', 'u', 'e', // value 'c', 'a', '.', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'n', 'e', 't' }; TEST_F(Rdata_CAA_Test, createFromText) { // Basic test checkFromText_None(caa_txt); // With different spacing checkFromText_None("0 issue \"ca.example.net\""); // Combination of lowercase and uppercase checkFromText_None("0 IssUE \"ca.example.net\""); // string constructor throws if there's extra text, // but lexer constructor doesn't checkFromText_BadString(caa_txt + "\n" + caa_txt); // Missing value field EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue")); } TEST_F(Rdata_CAA_Test, fields) { // Some of these may not be RFC conformant, but we relax the check // in our code to work with other field values that may show up in // the future. EXPECT_NO_THROW(const generic::CAA rdata_caa2("1 issue \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("2 issue \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("3 issue \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("128 issue \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("255 issue \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 foo \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 bar \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 12345 \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 w0x1y2z3 \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 relaxed-too \"ca.example.net\"")); EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 RELAXED.too \"ca.example.net\"")); // No value (this is redundant to the last test case in the // .createFromText test EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue")); // > 255 would be broken EXPECT_THROW(const generic::CAA rdata_caa2("256 issue \"ca.example.net\""), InvalidRdataText); // Missing tag causes the value to be parsed as the tag field. As // the tag field does not allow quoted strings, this throws. EXPECT_THROW(const generic::CAA rdata_caa2("0 \"ca.example.net\""), InvalidRdataText); // Tag is too long const std::string tag(256, 'a'); const std::string rdata_txt("0 " + tag + " \"ca.example.net\""); EXPECT_THROW(const generic::CAA rdata_caa2(rdata_txt), InvalidRdataText); } TEST_F(Rdata_CAA_Test, characterStringValue) { const generic::CAA rdata_caa_unquoted("0 issue ca.example.net"); EXPECT_EQ(0, rdata_caa_unquoted.compare(rdata_caa)); const generic::CAA rdata_caa_escape_X("0 issue ca.e\\xample.net"); EXPECT_EQ(0, rdata_caa_escape_X.compare(rdata_caa)); const generic::CAA rdata_caa_escape_DDD("0 issue ca.e\\120ample.net"); EXPECT_EQ(0, rdata_caa_escape_DDD.compare(rdata_caa)); const generic::CAA rdata_caa_multiline("0 issue (\nca.example.net)"); EXPECT_EQ(0, rdata_caa_multiline.compare(rdata_caa)); } TEST_F(Rdata_CAA_Test, badText) { checkFromText_LexerError("0"); checkFromText_LexerError("ZERO issue \"ca.example.net\""); EXPECT_THROW(const generic::CAA rdata_caa2(caa_txt + " extra text"), InvalidRdataText); // Yes, this is redundant to the last test cases in the .fields test checkFromText_InvalidText("2345 issue \"ca.example.net\""); // negative values are trapped in the lexer rather than the // constructor checkFromText_LexerError("-2 issue \"ca.example.net\""); } TEST_F(Rdata_CAA_Test, copyAndAssign) { // Copy construct generic::CAA rdata_caa2(rdata_caa); EXPECT_EQ(0, rdata_caa.compare(rdata_caa2)); // Assignment, mainly to confirm it doesn't cause disruption. rdata_caa2 = rdata_caa; EXPECT_EQ(0, rdata_caa.compare(rdata_caa2)); } TEST_F(Rdata_CAA_Test, createFromWire) { // Basic test EXPECT_EQ(0, rdata_caa.compare( *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire1.wire"))); // Combination of lowercase and uppercase EXPECT_EQ(0, rdata_caa.compare( *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire2.wire"))); // Value field is empty EXPECT_NO_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire3.wire")); // Tag field is empty EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire4.wire"), InvalidRdataText); // Value field is shorter than rdata len EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire5"), InvalidBufferPosition); // all RDATA is missing EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire6"), InvalidBufferPosition); } TEST_F(Rdata_CAA_Test, createFromParams) { const generic::CAA rdata_caa2(0, "issue", "ca.example.net"); EXPECT_EQ(0, rdata_caa2.compare(rdata_caa)); const generic::CAA rdata_caa4(0, "issue", "ca.e\\xample.net"); EXPECT_EQ(0, rdata_caa4.compare(rdata_caa)); const generic::CAA rdata_caa5(0, "issue", "ca.e\\120ample.net"); EXPECT_EQ(0, rdata_caa5.compare(rdata_caa)); // Tag is empty EXPECT_THROW(const generic::CAA rdata_caa3(0, "", "ca.example.net"), isc::InvalidParameter); // Tag is too long const std::string tag(256, 'a'); EXPECT_THROW(const generic::CAA rdata_caa3(0, tag, "ca.example.net"), isc::InvalidParameter); // Value is too long const std::string value(65536, 'a'); EXPECT_THROW(const generic::CAA rdata_caa3(0, "issue", value), InvalidRdataLength); } TEST_F(Rdata_CAA_Test, toText) { EXPECT_TRUE(boost::iequals(caa_txt, rdata_caa.toText())); const string caa_txt2("1 issue \"\""); const generic::CAA rdata_caa2(caa_txt2); EXPECT_TRUE(boost::iequals(caa_txt2, rdata_caa2.toText())); } TEST_F(Rdata_CAA_Test, toWire) { obuffer.clear(); rdata_caa.toWire(obuffer); matchWireData(rdata_caa_wiredata, sizeof(rdata_caa_wiredata), obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_CAA_Test, compare) { // Equality test is repeated from createFromWire tests above. EXPECT_EQ(0, rdata_caa.compare( *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire1.wire"))); const generic::CAA rdata_caa2("1 issue \"ca.example.net\""); EXPECT_EQ(1, rdata_caa2.compare(rdata_caa)); EXPECT_EQ(-1, rdata_caa.compare(rdata_caa2)); } TEST_F(Rdata_CAA_Test, getFlags) { EXPECT_EQ(0, rdata_caa.getFlags()); } 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& value = rdata_caa.getValue(); matchWireData(value_data, sizeof(value_data), &value[0], value.size()); } TEST_F(Rdata_CAA_Test, emptyValueFromWire) { const uint8_t rdf_wiredata[] = { // flags 0x00, // tag length 0x5, // tag 'i', 's', 's', 'u', 'e' }; const generic::CAA rdf = dynamic_cast (*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), "rdata_caa_fromWire3.wire")); EXPECT_EQ(0, rdf.getFlags()); EXPECT_EQ("issue", rdf.getTag()); obuffer.clear(); rdf.toWire(obuffer); matchWireData(rdf_wiredata, sizeof(rdf_wiredata), obuffer.getData(), obuffer.getLength()); } TEST_F(Rdata_CAA_Test, emptyValueFromString) { const generic::CAA rdata_caa2("0 issue"); const uint8_t rdata_caa2_wiredata[] = { // flags 0x00, // tag length 0x5, // tag 'i', 's', 's', 'u', 'e' }; EXPECT_EQ(0, rdata_caa2.getFlags()); EXPECT_EQ("issue", rdata_caa2.getTag()); obuffer.clear(); rdata_caa2.toWire(obuffer); matchWireData(rdata_caa2_wiredata, sizeof(rdata_caa2_wiredata), obuffer.getData(), obuffer.getLength()); } }