master_lexer_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright (C) 2012 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 <exceptions/exceptions.h>
  15. #include <dns/master_lexer.h>
  16. #include <dns/master_lexer_state.h>
  17. #include <gtest/gtest.h>
  18. #include <boost/lexical_cast.hpp>
  19. #include <boost/function.hpp>
  20. #include <boost/scoped_ptr.hpp>
  21. #include <boost/bind.hpp>
  22. #include <string>
  23. #include <sstream>
  24. using namespace isc::dns;
  25. using std::string;
  26. using std::stringstream;
  27. using boost::lexical_cast;
  28. using boost::scoped_ptr;
  29. using master_lexer_internal::State;
  30. namespace {
  31. class MasterLexerTest : public ::testing::Test {
  32. protected:
  33. MasterLexerTest() :
  34. expected_stream_name("stream-" + lexical_cast<string>(&ss))
  35. {}
  36. MasterLexer lexer;
  37. stringstream ss;
  38. const string expected_stream_name;
  39. };
  40. // Commonly used check case where the input sources stack is empty.
  41. void
  42. checkEmptySource(const MasterLexer& lexer) {
  43. EXPECT_TRUE(lexer.getSourceName().empty());
  44. EXPECT_EQ(0, lexer.getSourceLine());
  45. }
  46. TEST_F(MasterLexerTest, preOpen) {
  47. // Initially sources stack is empty.
  48. checkEmptySource(lexer);
  49. }
  50. TEST_F(MasterLexerTest, pushStream) {
  51. lexer.pushSource(ss);
  52. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  53. // From the point of view of this test, we only have to check (though
  54. // indirectly) getSourceLine calls InputSource::getCurrentLine. It should
  55. // return 1 initially.
  56. EXPECT_EQ(1, lexer.getSourceLine());
  57. // By popping it the stack will be empty again.
  58. lexer.popSource();
  59. checkEmptySource(lexer);
  60. }
  61. TEST_F(MasterLexerTest, pushFile) {
  62. // We use zone file (-like) data, but in this test that actually doesn't
  63. // matter.
  64. EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt"));
  65. EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
  66. EXPECT_EQ(1, lexer.getSourceLine());
  67. lexer.popSource();
  68. checkEmptySource(lexer);
  69. // If we give a non NULL string pointer, its content will be intact
  70. // if pushSource succeeds.
  71. std::string error_txt = "dummy";
  72. EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt",
  73. &error_txt));
  74. EXPECT_EQ("dummy", error_txt);
  75. }
  76. TEST_F(MasterLexerTest, pushBadFileName) {
  77. EXPECT_THROW(lexer.pushSource(NULL), isc::InvalidParameter);
  78. }
  79. TEST_F(MasterLexerTest, pushFileFail) {
  80. // The file to be pushed doesn't exist. pushSource() fails and
  81. // some non empty error string should be set.
  82. std::string error_txt;
  83. EXPECT_TRUE(error_txt.empty());
  84. EXPECT_FALSE(lexer.pushSource("no-such-file", &error_txt));
  85. EXPECT_FALSE(error_txt.empty());
  86. // It's safe to pass NULL error_txt (either explicitly or implicitly as
  87. // the default)
  88. EXPECT_FALSE(lexer.pushSource("no-such-file", NULL));
  89. EXPECT_FALSE(lexer.pushSource("no-such-file"));
  90. }
  91. TEST_F(MasterLexerTest, nestedPush) {
  92. lexer.pushSource(ss);
  93. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  94. // We can push another source without popping the previous one.
  95. lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt");
  96. EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
  97. // popSource() works on the "topmost" (last-pushed) source
  98. lexer.popSource();
  99. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  100. lexer.popSource();
  101. EXPECT_TRUE(lexer.getSourceName().empty());
  102. }
  103. TEST_F(MasterLexerTest, invalidPop) {
  104. // popSource() cannot be called if the sources stack is empty.
  105. EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);
  106. }
  107. // Test it is not possible to get token when no source is available.
  108. TEST_F(MasterLexerTest, noSource) {
  109. EXPECT_THROW(lexer.getNextToken(), isc::InvalidOperation);
  110. }
  111. // Test getting some tokens
  112. TEST_F(MasterLexerTest, getNextToken) {
  113. ss << "\n \n\"STRING\"\n";
  114. lexer.pushSource(ss);
  115. // First, the newline should get out.
  116. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  117. // Then the whitespace, if we specify the option.
  118. EXPECT_EQ(MasterToken::INITIAL_WS,
  119. lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
  120. // The newline
  121. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  122. // The (quoted) string
  123. EXPECT_EQ(MasterToken::QSTRING,
  124. lexer.getNextToken(MasterLexer::QSTRING).getType());
  125. // And the end of line and file
  126. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  127. EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
  128. }
  129. // Test we correctly find end of file.
  130. TEST_F(MasterLexerTest, eof) {
  131. // Let the ss empty.
  132. lexer.pushSource(ss);
  133. // The first one is found to be EOF
  134. EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
  135. // And it stays on EOF for any following attempts
  136. EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
  137. // And we can step back one token, but that is the EOF too.
  138. lexer.ungetToken();
  139. EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
  140. }
  141. // Check we properly return error when there's an opened parentheses and no
  142. // closing one
  143. TEST_F(MasterLexerTest, getUnbalancedParen) {
  144. ss << "(\"string\"";
  145. lexer.pushSource(ss);
  146. // The string gets out first
  147. EXPECT_EQ(MasterToken::STRING, lexer.getNextToken().getType());
  148. // Then an unbalanced parenthesis
  149. EXPECT_EQ(MasterToken::UNBALANCED_PAREN,
  150. lexer.getNextToken().getErrorCode());
  151. // And then EOF
  152. EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
  153. }
  154. // Check we properly return error when there's an opened quoted string and no
  155. // closing one
  156. TEST_F(MasterLexerTest, getUnbalancedString) {
  157. ss << "\"string";
  158. lexer.pushSource(ss);
  159. // Then an unbalanced qstring (reported as an unexpected end)
  160. EXPECT_EQ(MasterToken::UNEXPECTED_END,
  161. lexer.getNextToken(MasterLexer::QSTRING).getErrorCode());
  162. // And then EOF
  163. EXPECT_EQ(MasterToken::END_OF_FILE, lexer.getNextToken().getType());
  164. }
  165. // Test ungetting tokens works
  166. TEST_F(MasterLexerTest, ungetToken) {
  167. ss << "\n (\"string\"\n) more";
  168. lexer.pushSource(ss);
  169. // Try getting the newline
  170. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  171. // Return it and get again
  172. lexer.ungetToken();
  173. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  174. // Get the string and return it back
  175. EXPECT_EQ(MasterToken::QSTRING,
  176. lexer.getNextToken(MasterLexer::QSTRING).getType());
  177. lexer.ungetToken();
  178. // But if we change the options, it honors them
  179. EXPECT_EQ(MasterToken::INITIAL_WS,
  180. lexer.getNextToken(MasterLexer::QSTRING |
  181. MasterLexer::INITIAL_WS).getType());
  182. // Get to the "more" string
  183. EXPECT_EQ(MasterToken::QSTRING,
  184. lexer.getNextToken(MasterLexer::QSTRING).getType());
  185. EXPECT_EQ(MasterToken::STRING,
  186. lexer.getNextToken(MasterLexer::QSTRING).getType());
  187. // Return it back. It should get inside the parentheses.
  188. // Upon next attempt to get it again, the newline inside the parentheses
  189. // should be still ignored.
  190. lexer.ungetToken();
  191. EXPECT_EQ(MasterToken::STRING,
  192. lexer.getNextToken(MasterLexer::QSTRING).getType());
  193. }
  194. // Check ungetting token without overriding the start method. We also
  195. // check it works well with changing options between the calls.
  196. TEST_F(MasterLexerTest, ungetRealOptions) {
  197. ss << "\n \n";
  198. lexer.pushSource(ss);
  199. // Skip the first newline
  200. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  201. // If we call it the usual way, it skips up to the newline and returns
  202. // it
  203. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  204. // Now we return it. If we call it again, but with different options,
  205. // we get the initial whitespace.
  206. lexer.ungetToken();
  207. EXPECT_EQ(MasterToken::INITIAL_WS,
  208. lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
  209. }
  210. // Test only one token can be ungotten
  211. TEST_F(MasterLexerTest, ungetTwice) {
  212. ss << "\n";
  213. lexer.pushSource(ss);
  214. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  215. // Unget the token. It can be done once
  216. lexer.ungetToken();
  217. // But not twice
  218. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  219. }
  220. // Test we can't unget a token before we get one
  221. TEST_F(MasterLexerTest, ungetBeforeGet) {
  222. lexer.pushSource(ss); // Just to eliminate the missing source problem
  223. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  224. }
  225. // Test we can't unget a token after a source switch, even when we got
  226. // something before.
  227. TEST_F(MasterLexerTest, ungetAfterSwitch) {
  228. ss << "\n\n";
  229. lexer.pushSource(ss);
  230. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  231. // Switch the source
  232. std::stringstream ss2;
  233. ss2 << "\n\n";
  234. lexer.pushSource(ss2);
  235. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  236. // We can get from the new source
  237. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  238. // And when we drop the current source, we can't unget again
  239. lexer.popSource();
  240. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  241. }
  242. // Common checks regarding expected/unexpected end-of-line
  243. void
  244. eolCheck(MasterLexer& lexer, MasterToken::Type expect) {
  245. // If EOL is found and eol_ok is true, we get it.
  246. EXPECT_EQ(MasterToken::END_OF_LINE,
  247. lexer.getNextToken(expect, true).getType());
  248. // We'll see the second '\n'; by default it will fail.
  249. EXPECT_THROW(lexer.getNextToken(expect), MasterLexer::LexerError);
  250. // Same if eol_ok is explicitly set to false. This also checks the
  251. // offending '\n' was "ungotten".
  252. EXPECT_THROW(lexer.getNextToken(expect, false), MasterLexer::LexerError);
  253. // And also check the error token set in the exception object.
  254. bool thrown = false;
  255. try {
  256. lexer.getNextToken(expect);
  257. } catch (const MasterLexer::LexerError& error) {
  258. EXPECT_EQ(MasterToken::UNEXPECTED_END, error.token_.getErrorCode());
  259. thrown = true;
  260. }
  261. EXPECT_TRUE(thrown);
  262. }
  263. // Common checks regarding expected/unexpected end-of-file
  264. void
  265. eofCheck(MasterLexer& lexer, MasterToken::Type expect) {
  266. EXPECT_EQ(MasterToken::END_OF_FILE,
  267. lexer.getNextToken(expect, true).getType());
  268. EXPECT_THROW(lexer.getNextToken(expect), MasterLexer::LexerError);
  269. EXPECT_THROW(lexer.getNextToken(expect, false), MasterLexer::LexerError);
  270. }
  271. TEST_F(MasterLexerTest, getNextTokenString) {
  272. ss << "normal-string\n";
  273. ss << "\n";
  274. ss << "another-string";
  275. lexer.pushSource(ss);
  276. // Normal successful case: Expecting a string and get one.
  277. EXPECT_EQ("normal-string",
  278. lexer.getNextToken(MasterToken::STRING).getString());
  279. eolCheck(lexer, MasterToken::STRING);
  280. // Skip the 2nd '\n'
  281. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  282. // Same set of tests but for end-of-file
  283. EXPECT_EQ("another-string",
  284. lexer.getNextToken(MasterToken::STRING, true).getString());
  285. eofCheck(lexer, MasterToken::STRING);
  286. }
  287. TEST_F(MasterLexerTest, getNextTokenQString) {
  288. ss << "\"quoted-string\"\n";
  289. ss << "\n";
  290. ss << "normal-string";
  291. lexer.pushSource(ss);
  292. // Expecting a quoted string and get one.
  293. EXPECT_EQ("quoted-string",
  294. lexer.getNextToken(MasterToken::QSTRING).getString());
  295. eolCheck(lexer, MasterToken::QSTRING);
  296. // Skip the 2nd '\n'
  297. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  298. // Expecting a quoted string but see a normal string. It's okay.
  299. EXPECT_EQ("normal-string",
  300. lexer.getNextToken(MasterToken::QSTRING).getString());
  301. eofCheck(lexer, MasterToken::QSTRING);
  302. }
  303. TEST_F(MasterLexerTest, getNextTokenNumber) {
  304. ss << "3600\n";
  305. ss << "\n";
  306. ss << "86400";
  307. lexer.pushSource(ss);
  308. // Expecting a number string and get one.
  309. EXPECT_EQ(3600,
  310. lexer.getNextToken(MasterToken::NUMBER).getNumber());
  311. eolCheck(lexer, MasterToken::NUMBER);
  312. // Skip the 2nd '\n'
  313. EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
  314. // Unless we specify NUMBER, decimal number string should be recognized
  315. // as a string.
  316. EXPECT_EQ("86400",
  317. lexer.getNextToken(MasterToken::STRING).getString());
  318. eofCheck(lexer, MasterToken::NUMBER);
  319. }
  320. }