message_reader_unittest.cc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. #include <algorithm>
  15. #include <string>
  16. #include <gtest/gtest.h>
  17. #include <log/log_messages.h>
  18. #include <log/message_dictionary.h>
  19. #include <log/message_exception.h>
  20. #include <log/message_reader.h>
  21. using namespace isc;
  22. using namespace isc::log;
  23. using namespace std;
  24. class MessageReaderTest : public ::testing::Test {
  25. protected:
  26. MessageReaderTest() : dictionary_(), reader_()
  27. {
  28. dictionary_ = new MessageDictionary();
  29. reader_.setDictionary(dictionary_);
  30. }
  31. ~MessageReaderTest() {
  32. delete dictionary_;
  33. }
  34. MessageDictionary* dictionary_; // Dictionary to add messages to
  35. MessageReader reader_; // Default reader object
  36. };
  37. // Check the get/set dictionary calls (using a local reader and dictionary).
  38. TEST_F(MessageReaderTest, GetSetDictionary) {
  39. MessageReader reader;
  40. EXPECT_TRUE(reader.getDictionary() == NULL);
  41. MessageDictionary dictionary;
  42. reader.setDictionary(&dictionary);
  43. EXPECT_EQ(&dictionary, reader.getDictionary());
  44. }
  45. // Check for parsing blank lines and comments. These should not add to the
  46. // dictionary and each parse should return success.
  47. TEST_F(MessageReaderTest, BlanksAndComments) {
  48. // Ensure that the dictionary is empty.
  49. EXPECT_EQ(0, dictionary_->size());
  50. // Add a number of blank lines and comments and check that (a) they are
  51. // parsed successfully ...
  52. EXPECT_NO_THROW(reader_.processLine(""));
  53. EXPECT_NO_THROW(reader_.processLine(" "));
  54. EXPECT_NO_THROW(reader_.processLine(" \n "));
  55. EXPECT_NO_THROW(reader_.processLine("# This is a comment"));
  56. EXPECT_NO_THROW(reader_.processLine("\t\t # Another comment"));
  57. EXPECT_NO_THROW(reader_.processLine(" A description line"));
  58. EXPECT_NO_THROW(reader_.processLine("# A comment"));
  59. EXPECT_NO_THROW(reader_.processLine(" +# A description line"));
  60. // ... and (b) nothing gets added to either the map or the not-added section.
  61. EXPECT_EQ(0, dictionary_->size());
  62. vector<string> not_added = reader_.getNotAdded();
  63. EXPECT_EQ(0, not_added.size());
  64. }
  65. // Local test to check that processLine generates the right exception.
  66. void
  67. processLineException(MessageReader& reader, const char* what,
  68. const MessageID& expected) {
  69. try {
  70. reader.processLine(what);
  71. FAIL() << "MessageReader::processLine() should throw an exception " <<
  72. " with message ID " << expected << " for '" << what << "'\n";
  73. } catch (MessageException& e) {
  74. EXPECT_EQ(boost::lexical_cast<string>(expected),
  75. boost::lexical_cast<string>(e.id()));
  76. } catch (...) {
  77. FAIL() << "Unknown exception thrown by MessageReader::processLine()\n";
  78. }
  79. }
  80. // Check that it recognises invalid directives
  81. TEST_F(MessageReaderTest, InvalidDirectives) {
  82. // Check that a "$" with nothing else generates an error
  83. processLineException(reader_, "$", LOG_UNRECOGNISED_DIRECTIVE);
  84. processLineException(reader_, "$xyz", LOG_UNRECOGNISED_DIRECTIVE);
  85. }
  86. // Check that it can parse a prefix
  87. TEST_F(MessageReaderTest, Prefix) {
  88. // Check that no $PREFIX is present
  89. EXPECT_EQ(string(""), reader_.getPrefix());
  90. // Check that a $PREFIX directive with no argument is OK
  91. EXPECT_NO_THROW(reader_.processLine("$PREFIX"));
  92. // Check a $PREFIX with multiple arguments is invalid
  93. processLineException(reader_, "$prefix A B", LOG_PREFIX_EXTRA_ARGS);
  94. // Prefixes should be alphanumeric (with underscores) and not start
  95. // with a number.
  96. processLineException(reader_, "$prefix ab[cd", LOG_PREFIX_INVALID_ARG);
  97. processLineException(reader_, "$prefix 123", LOG_PREFIX_INVALID_ARG);
  98. processLineException(reader_, "$prefix 1ABC", LOG_PREFIX_INVALID_ARG);
  99. // A valid prefix should be accepted
  100. EXPECT_NO_THROW(reader_.processLine("$PREFIX dlm__"));
  101. EXPECT_EQ(string("dlm__"), reader_.getPrefix());
  102. // And check that the parser fails on invalid prefixes...
  103. processLineException(reader_, "$prefix 1ABC", LOG_PREFIX_INVALID_ARG);
  104. // Check that we can clear the prefix as well
  105. reader_.clearPrefix();
  106. EXPECT_EQ(string(""), reader_.getPrefix());
  107. EXPECT_NO_THROW(reader_.processLine("$PREFIX dlm__"));
  108. EXPECT_EQ(string("dlm__"), reader_.getPrefix());
  109. EXPECT_NO_THROW(reader_.processLine("$PREFIX"));
  110. EXPECT_EQ(string(""), reader_.getPrefix());
  111. }
  112. // Check that it can parse a namespace
  113. TEST_F(MessageReaderTest, Namespace) {
  114. // Check that no $NAMESPACE is present
  115. EXPECT_EQ(string(""), reader_.getNamespace());
  116. // Check that a $NAMESPACE directive with no argument generates an error.
  117. processLineException(reader_, "$NAMESPACE", LOG_NAMESPACE_NO_ARGS);
  118. // Check a $NAMESPACE with multiple arguments is invalid
  119. processLineException(reader_, "$namespace A B", LOG_NAMESPACE_EXTRA_ARGS);
  120. // Namespaces should be alphanumeric (with underscores and colons)
  121. processLineException(reader_, "$namespace ab[cd", LOG_NAMESPACE_INVALID_ARG);
  122. // A valid $NAMESPACE should be accepted
  123. EXPECT_NO_THROW(reader_.processLine("$NAMESPACE isc"));
  124. EXPECT_EQ(string("isc"), reader_.getNamespace());
  125. // (Check that we can clear the namespace)
  126. reader_.clearNamespace();
  127. EXPECT_EQ(string(""), reader_.getNamespace());
  128. // Check that a valid namespace can include colons
  129. EXPECT_NO_THROW(reader_.processLine("$NAMESPACE isc::log"));
  130. EXPECT_EQ(string("isc::log"), reader_.getNamespace());
  131. // Check that the indication of the anonymous namespace will be recognised.
  132. reader_.clearNamespace();
  133. EXPECT_NO_THROW(reader_.processLine("$NAMESPACE ::"));
  134. EXPECT_EQ(string("::"), reader_.getNamespace());
  135. // ... and that another $NAMESPACE is rejected
  136. processLineException(reader_, "$NAMESPACE ABC", LOG_DUPLICATE_NAMESPACE);
  137. }
  138. // Check that it can parse a line
  139. TEST_F(MessageReaderTest, ValidMessageAddDefault) {
  140. // Add a couple of valid messages
  141. reader_.processLine("% GLOBAL1\t\tthis is message global one\n");
  142. reader_.processLine("%GLOBAL2 this is message global two");
  143. // ... and check them
  144. EXPECT_EQ(string("this is message global one"),
  145. dictionary_->getText("GLOBAL1"));
  146. EXPECT_EQ(string("this is message global two"),
  147. dictionary_->getText("GLOBAL2"));
  148. EXPECT_EQ(2, dictionary_->size());
  149. // ... and ensure no messages were not added
  150. vector<string> not_added = reader_.getNotAdded();
  151. EXPECT_EQ(0, not_added.size());
  152. }
  153. TEST_F(MessageReaderTest, ValidMessageAdd) {
  154. // Add a couple of valid messages
  155. reader_.processLine("%GLOBAL1\t\tthis is message global one\n",
  156. MessageReader::ADD);
  157. reader_.processLine("% GLOBAL2 this is message global two",
  158. MessageReader::ADD);
  159. // ... and check them
  160. EXPECT_EQ(string("this is message global one"),
  161. dictionary_->getText("GLOBAL1"));
  162. EXPECT_EQ(string("this is message global two"),
  163. dictionary_->getText("GLOBAL2"));
  164. EXPECT_EQ(2, dictionary_->size());
  165. // ... and ensure no messages were not added
  166. vector<string> not_added = reader_.getNotAdded();
  167. EXPECT_EQ(0, not_added.size());
  168. }
  169. TEST_F(MessageReaderTest, ValidMessageReplace) {
  170. dictionary_->add("GLOBAL1", "original global1 message");
  171. dictionary_->add("GLOBAL2", "original global2 message");
  172. // Replace a couple of valid messages
  173. reader_.processLine("% GLOBAL1\t\tthis is message global one\n",
  174. MessageReader::REPLACE);
  175. reader_.processLine("% GLOBAL2 this is message global two",
  176. MessageReader::REPLACE);
  177. // ... and check them
  178. EXPECT_EQ(string("this is message global one"),
  179. dictionary_->getText("GLOBAL1"));
  180. EXPECT_EQ(string("this is message global two"),
  181. dictionary_->getText("GLOBAL2"));
  182. EXPECT_EQ(2, dictionary_->size());
  183. // ... and ensure no messages were not added
  184. vector<string> not_added = reader_.getNotAdded();
  185. EXPECT_EQ(0, not_added.size());
  186. }
  187. // Do checks on overflows, although this essentially duplicates the checks
  188. // in MessageDictionary.
  189. TEST_F(MessageReaderTest, Overflows) {
  190. // Add a couple of valid messages
  191. reader_.processLine("% GLOBAL1\t\tthis is message global one\n");
  192. reader_.processLine("% GLOBAL2 this is message global two");
  193. // Add a duplicate in ADD mode.
  194. reader_.processLine("% GLOBAL1\t\tthis is a replacement for global one");
  195. // Replace a non-existent one in REPLACE mode
  196. reader_.processLine("% LOCAL\t\tthis is a new message",
  197. MessageReader::REPLACE);
  198. // Check what is in the dictionary.
  199. EXPECT_EQ(string("this is message global one"),
  200. dictionary_->getText("GLOBAL1"));
  201. EXPECT_EQ(string("this is message global two"),
  202. dictionary_->getText("GLOBAL2"));
  203. EXPECT_EQ(2, dictionary_->size());
  204. // ... and ensure no overflows
  205. vector<string> not_added = reader_.getNotAdded();
  206. ASSERT_EQ(2, not_added.size());
  207. sort(not_added.begin(), not_added.end());
  208. EXPECT_EQ(string("GLOBAL1"), not_added[0]);
  209. EXPECT_EQ(string("LOCAL"), not_added[1]);
  210. }