rdata_txt_like_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // This is the common code for TXT and SPF tests.
  15. #include <util/buffer.h>
  16. #include <dns/exceptions.h>
  17. #include <dns/rdataclass.h>
  18. #include <dns/tests/unittest_util.h>
  19. #include <dns/tests/rdata_unittest.h>
  20. #include <gtest/gtest.h>
  21. #include <boost/bind.hpp>
  22. #include <string>
  23. #include <sstream>
  24. #include <vector>
  25. using isc::UnitTestUtil;
  26. using namespace std;
  27. using namespace isc::dns;
  28. using namespace isc::util;
  29. using namespace isc::dns::rdata;
  30. namespace {
  31. template<class T>
  32. class RRTYPE : public RRType {
  33. public:
  34. RRTYPE();
  35. };
  36. template<> RRTYPE<generic::TXT>::RRTYPE() : RRType(RRType::TXT()) {}
  37. template<> RRTYPE<generic::SPF>::RRTYPE() : RRType(RRType::SPF()) {}
  38. const uint8_t wiredata_txt_like[] = {
  39. sizeof("Test-String") - 1,
  40. 'T', 'e', 's', 't', '-', 'S', 't', 'r', 'i', 'n', 'g'
  41. };
  42. const uint8_t wiredata_nulltxt[] = { 0 };
  43. // For lexer-based constructor
  44. void
  45. dummyCallback(const string&, size_t, const string&) {
  46. }
  47. template<class TXT_LIKE>
  48. class Rdata_TXT_LIKE_Test : public RdataTest {
  49. protected:
  50. Rdata_TXT_LIKE_Test() :
  51. callback(boost::bind(&dummyCallback, _1, _2, _3)),
  52. loader_cb(callback, callback),
  53. wiredata_longesttxt(256, 'a'),
  54. rdata_txt_like("Test-String"),
  55. rdata_txt_like_empty("\"\""),
  56. rdata_txt_like_quoted("\"Test-String\"")
  57. {
  58. wiredata_longesttxt[0] = 255; // adjust length
  59. }
  60. private:
  61. const MasterLoaderCallbacks::IssueCallback callback;
  62. protected:
  63. MasterLoaderCallbacks loader_cb;
  64. vector<uint8_t> wiredata_longesttxt;
  65. const TXT_LIKE rdata_txt_like;
  66. const TXT_LIKE rdata_txt_like_empty;
  67. const TXT_LIKE rdata_txt_like_quoted;
  68. };
  69. // The list of types we want to test.
  70. typedef testing::Types<generic::TXT, generic::SPF> Implementations;
  71. TYPED_TEST_CASE(Rdata_TXT_LIKE_Test, Implementations);
  72. TYPED_TEST(Rdata_TXT_LIKE_Test, createFromText) {
  73. // Below we check the behavior for the "from text" constructors, both
  74. // from std::string and with MasterLexer. The underlying implementation
  75. // is the same, so both should work exactly same, but we confirm both
  76. // cases.
  77. const std::string multi_line = "(\n \"Test-String\" )";
  78. const std::string escaped_txt = "Test\\045Strin\\g";
  79. // test input for the lexer version
  80. std::stringstream ss;
  81. ss << "Test-String\n";
  82. ss << "\"Test-String\"\n"; // explicitly surrounded by '"'s
  83. ss << multi_line << "\n"; // multi-line text with ()
  84. ss << escaped_txt << "\n"; // using the two types of escape with '\'
  85. ss << "\"\"\n"; // empty string (note: still valid char-str)
  86. ss << string(255, 'a') << "\n"; // Longest possible character-string.
  87. ss << string(256, 'a') << "\n"; // char-string too long
  88. ss << "\"Test-String\\\"\n"; // unbalanced quote
  89. ss << "\"Test-String\\\"\"\n";
  90. this->lexer.pushSource(ss);
  91. // commonly used Rdata to compare below, created from wire
  92. ConstRdataPtr const rdata =
  93. this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
  94. RRClass("IN"), "rdata_txt_fromWire1");
  95. // normal case is covered in toWireBuffer. First check the std::string
  96. // case, then with MasterLexer. For the latter, we need to read and skip
  97. // '\n'. These apply to most of the other cases below.
  98. EXPECT_EQ(0, this->rdata_txt_like.compare(*rdata));
  99. EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  100. this->loader_cb).compare(*rdata));
  101. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  102. // surrounding double-quotes shouldn't change the result.
  103. EXPECT_EQ(0, this->rdata_txt_like_quoted.compare(*rdata));
  104. EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  105. this->loader_cb).compare(*rdata));
  106. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  107. // multi-line input with ()
  108. EXPECT_EQ(0, TypeParam(multi_line).compare(*rdata));
  109. EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  110. this->loader_cb).compare(*rdata));
  111. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  112. // for the same data using escape
  113. EXPECT_EQ(0, TypeParam(escaped_txt).compare(*rdata));
  114. EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  115. this->loader_cb).compare(*rdata));
  116. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  117. // Null character-string.
  118. this->obuffer.clear();
  119. TypeParam(string("\"\"")).toWire(this->obuffer);
  120. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  121. this->obuffer.getData(), this->obuffer.getLength(),
  122. wiredata_nulltxt, sizeof(wiredata_nulltxt));
  123. this->obuffer.clear();
  124. TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS, this->loader_cb).
  125. toWire(this->obuffer);
  126. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  127. this->obuffer.getData(), this->obuffer.getLength(),
  128. wiredata_nulltxt, sizeof(wiredata_nulltxt));
  129. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  130. // Longest possible character-string.
  131. this->obuffer.clear();
  132. TypeParam(string(255, 'a')).toWire(this->obuffer);
  133. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  134. this->obuffer.getData(), this->obuffer.getLength(),
  135. &this->wiredata_longesttxt[0],
  136. this->wiredata_longesttxt.size());
  137. this->obuffer.clear();
  138. TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS, this->loader_cb).
  139. toWire(this->obuffer);
  140. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  141. this->obuffer.getData(), this->obuffer.getLength(),
  142. &this->wiredata_longesttxt[0],
  143. this->wiredata_longesttxt.size());
  144. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  145. // Too long text for a valid character-string.
  146. EXPECT_THROW(TypeParam(string(256, 'a')), CharStringTooLong);
  147. EXPECT_THROW(TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  148. this->loader_cb), CharStringTooLong);
  149. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  150. // The escape character makes the double quote a part of character-string,
  151. // so this is invalid input and should be rejected.
  152. EXPECT_THROW(TypeParam("\"Test-String\\\""), InvalidRdataText);
  153. EXPECT_THROW(TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  154. this->loader_cb), MasterLexer::LexerError);
  155. EXPECT_EQ(MasterToken::END_OF_LINE, this->lexer.getNextToken().getType());
  156. }
  157. TYPED_TEST(Rdata_TXT_LIKE_Test, createMultiStringsFromText) {
  158. // Tests for "from text" variants construction with various forms of
  159. // multi character-strings.
  160. std::vector<std::string > texts;
  161. texts.push_back("\"Test-String\" \"Test-String\""); // most common form
  162. texts.push_back("\"Test-String\"\"Test-String\""); // no space between'em
  163. texts.push_back("\"Test-String\" Test-String"); // no '"' for one
  164. texts.push_back("\"Test-String\"Test-String"); // and no space either
  165. texts.push_back("Test-String \"Test-String\""); // no '"' for the other
  166. // This one currently doesn't work
  167. //texts.push_back("Test-String\"Test-String\""); // and no space either
  168. std::stringstream ss;
  169. for (std::vector<std::string >::const_iterator it = texts.begin();
  170. it != texts.end(); ++it) {
  171. ss << *it << "\n";
  172. }
  173. this->lexer.pushSource(ss);
  174. // The corresponding Rdata built from wire to compare in the checks below.
  175. ConstRdataPtr const rdata =
  176. this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
  177. RRClass("IN"), "rdata_txt_fromWire3.wire");
  178. // Confirm we can construct the Rdata from the test text, both from
  179. // std::string and with lexer, and that matches the from-wire data.
  180. for (std::vector<std::string >::const_iterator it = texts.begin();
  181. it != texts.end(); ++it) {
  182. SCOPED_TRACE(*it);
  183. EXPECT_EQ(0, TypeParam(*it).compare(*rdata));
  184. EXPECT_EQ(0, TypeParam(this->lexer, NULL, MasterLoader::MANY_ERRORS,
  185. this->loader_cb).compare(*rdata));
  186. EXPECT_EQ(MasterToken::END_OF_LINE,
  187. this->lexer.getNextToken().getType());
  188. }
  189. }
  190. TYPED_TEST(Rdata_TXT_LIKE_Test, createFromTextExtra) {
  191. // This is for the std::string version only: the input must end with EOF;
  192. // an extra new-line will result in an exception.
  193. EXPECT_THROW(TypeParam("\"Test-String\"\n"), InvalidRdataText);
  194. // Same if there's a space before '\n'
  195. EXPECT_THROW(TypeParam("\"Test-String\" \n"), InvalidRdataText);
  196. }
  197. TYPED_TEST(Rdata_TXT_LIKE_Test, fromTextEmpty) {
  198. // If the input text doesn't contain any character-string, it should be
  199. // rejected
  200. EXPECT_THROW(TypeParam(""), InvalidRdataText);
  201. EXPECT_THROW(TypeParam(" "), InvalidRdataText); // even with a space
  202. EXPECT_THROW(TypeParam("(\n)"), InvalidRdataText); // or multi-line with ()
  203. }
  204. void
  205. makeLargest(vector<uint8_t>& data) {
  206. uint8_t ch = 0;
  207. // create 255 sets of character-strings, each of which has the longest
  208. // length (255bytes string + 1-byte length field)
  209. for (int i = 0; i < 255; ++i, ++ch) {
  210. data.push_back(255);
  211. data.insert(data.end(), 255, ch);
  212. }
  213. // the last character-string should be 255 bytes (including the one-byte
  214. // length field) in length so that the total length should be in the range
  215. // of 16-bit integers.
  216. data.push_back(254);
  217. data.insert(data.end(), 254, ch);
  218. assert(data.size() == 65535);
  219. }
  220. TYPED_TEST(Rdata_TXT_LIKE_Test, createFromWire) {
  221. EXPECT_EQ(0, this->rdata_txt_like.compare(
  222. *this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
  223. RRClass("IN"),
  224. "rdata_txt_fromWire1")));
  225. // Empty character string
  226. EXPECT_EQ(0, this->rdata_txt_like_empty.compare(
  227. *this->rdataFactoryFromFile(RRTYPE<TypeParam>(),
  228. RRClass("IN"),
  229. "rdata_txt_fromWire2.wire")));
  230. // Multiple character strings
  231. this->obuffer.clear();
  232. this->rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
  233. "rdata_txt_fromWire3.wire")->toWire(this->obuffer);
  234. // the result should be 'wiredata_txt' repeated twice
  235. vector<uint8_t> expected_data(wiredata_txt_like, wiredata_txt_like +
  236. sizeof(wiredata_txt_like));
  237. expected_data.insert(expected_data.end(), wiredata_txt_like,
  238. wiredata_txt_like + sizeof(wiredata_txt_like));
  239. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  240. this->obuffer.getData(),
  241. this->obuffer.getLength(),
  242. &expected_data[0], expected_data.size());
  243. // Largest length of data. There's nothing special, but should be
  244. // constructed safely, and the content should be identical to the original
  245. // data.
  246. vector<uint8_t> largest_txt_like_data;
  247. makeLargest(largest_txt_like_data);
  248. InputBuffer ibuffer(&largest_txt_like_data[0],
  249. largest_txt_like_data.size());
  250. TypeParam largest_txt_like(ibuffer, largest_txt_like_data.size());
  251. this->obuffer.clear();
  252. largest_txt_like.toWire(this->obuffer);
  253. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  254. this->obuffer.getData(),
  255. this->obuffer.getLength(),
  256. &largest_txt_like_data[0],
  257. largest_txt_like_data.size());
  258. // rdlen parameter is out of range. This is a rare event because we'd
  259. // normally call the constructor via a polymorphic wrapper, where the
  260. // length is validated. But this should be checked explicitly.
  261. InputBuffer ibuffer2(&largest_txt_like_data[0],
  262. largest_txt_like_data.size());
  263. EXPECT_THROW(TypeParam(ibuffer2, 65536), InvalidRdataLength);
  264. // RDATA is empty, which is invalid for TXT_LIKE.
  265. EXPECT_THROW(this->rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
  266. "rdata_txt_fromWire4.wire"),
  267. DNSMessageFORMERR);
  268. // character-string length is too large, which could cause overrun.
  269. EXPECT_THROW(this->rdataFactoryFromFile(RRTYPE<TypeParam>(), RRClass("IN"),
  270. "rdata_txt_fromWire5.wire"),
  271. DNSMessageFORMERR);
  272. }
  273. TYPED_TEST(Rdata_TXT_LIKE_Test, createFromLexer) {
  274. EXPECT_EQ(0, this->rdata_txt_like.compare(
  275. *test::createRdataUsingLexer(RRTYPE<TypeParam>(), RRClass::IN(),
  276. "Test-String")));
  277. }
  278. TYPED_TEST(Rdata_TXT_LIKE_Test, toWireBuffer) {
  279. this->rdata_txt_like.toWire(this->obuffer);
  280. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  281. this->obuffer.getData(),
  282. this->obuffer.getLength(),
  283. wiredata_txt_like, sizeof(wiredata_txt_like));
  284. }
  285. TYPED_TEST(Rdata_TXT_LIKE_Test, toWireRenderer) {
  286. this->rdata_txt_like.toWire(this->renderer);
  287. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  288. this->renderer.getData(),
  289. this->renderer.getLength(),
  290. wiredata_txt_like, sizeof(wiredata_txt_like));
  291. }
  292. TYPED_TEST(Rdata_TXT_LIKE_Test, toText) {
  293. EXPECT_EQ("\"Test-String\"", this->rdata_txt_like.toText());
  294. }
  295. TYPED_TEST(Rdata_TXT_LIKE_Test, assignment) {
  296. TypeParam rdata1("assignment1");
  297. TypeParam rdata2("assignment2");
  298. rdata1 = rdata2;
  299. EXPECT_EQ(0, rdata2.compare(rdata1));
  300. // Check if the copied data is valid even after the original is deleted
  301. TypeParam* rdata3 = new TypeParam(rdata1);
  302. TypeParam rdata4("assignment3");
  303. rdata4 = *rdata3;
  304. delete rdata3;
  305. EXPECT_EQ(0, rdata4.compare(rdata1));
  306. // Self assignment
  307. rdata2 = rdata2;
  308. EXPECT_EQ(0, rdata2.compare(rdata1));
  309. }
  310. TYPED_TEST(Rdata_TXT_LIKE_Test, compare) {
  311. string const txt1("aaaaaaaa");
  312. string const txt2("aaaaaaaaaa");
  313. string const txt3("bbbbbbbb");
  314. string const txt4(129, 'a');
  315. string const txt5(128, 'b');
  316. EXPECT_EQ(TypeParam(txt1).compare(TypeParam(txt1)), 0);
  317. EXPECT_LT(TypeParam("\"\"").compare(TypeParam(txt1)), 0);
  318. EXPECT_GT(TypeParam(txt1).compare(TypeParam("\"\"")), 0);
  319. EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt2)), 0);
  320. EXPECT_GT(TypeParam(txt2).compare(TypeParam(txt1)), 0);
  321. EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt3)), 0);
  322. EXPECT_GT(TypeParam(txt3).compare(TypeParam(txt1)), 0);
  323. // we're comparing the data raw, starting at the length octet, so a shorter
  324. // string sorts before a longer one no matter the lexicopraphical order
  325. EXPECT_LT(TypeParam(txt3).compare(TypeParam(txt2)), 0);
  326. EXPECT_GT(TypeParam(txt2).compare(TypeParam(txt3)), 0);
  327. // to make sure the length octet compares unsigned
  328. EXPECT_LT(TypeParam(txt1).compare(TypeParam(txt4)), 0);
  329. EXPECT_GT(TypeParam(txt4).compare(TypeParam(txt1)), 0);
  330. EXPECT_LT(TypeParam(txt5).compare(TypeParam(txt4)), 0);
  331. EXPECT_GT(TypeParam(txt4).compare(TypeParam(txt5)), 0);
  332. // comparison attempt between incompatible RR types should be rejected
  333. EXPECT_THROW(TypeParam(txt1).compare(*this->rdata_nomatch),
  334. bad_cast);
  335. }
  336. }