master_lexer_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. // This acts like the normal MasterLexer. It, however, allows to mock the start()
  32. // method to return some given state instead of the auto-detected ones.
  33. class TestedMasterLexer : public MasterLexer {
  34. public:
  35. TestedMasterLexer() :
  36. fake_start_(NULL)
  37. {}
  38. // During the next call to start(), return the given state instead of the
  39. // auto-detected one.
  40. void pushFakeStart(const State* state) {
  41. fake_start_ = state;
  42. }
  43. protected:
  44. virtual const State* start(Options options) {
  45. if (fake_start_ != NULL) {
  46. // There's a fake start, so remove it (not to be used next time)
  47. // and return it.
  48. const State* result = fake_start_;
  49. fake_start_ = NULL;
  50. return (result);
  51. } else {
  52. // No fake start ready. So we act the usual way, by delegating it to
  53. // the parent class.
  54. return (MasterLexer::start(options));
  55. }
  56. }
  57. private:
  58. const State* fake_start_;
  59. };
  60. class MasterLexerTest : public ::testing::Test {
  61. protected:
  62. MasterLexerTest() :
  63. expected_stream_name("stream-" + lexical_cast<string>(&ss))
  64. {}
  65. TestedMasterLexer lexer;
  66. stringstream ss;
  67. const string expected_stream_name;
  68. };
  69. // Commonly used check case where the input sources stack is empty.
  70. void
  71. checkEmptySource(const MasterLexer& lexer) {
  72. EXPECT_TRUE(lexer.getSourceName().empty());
  73. EXPECT_EQ(0, lexer.getSourceLine());
  74. }
  75. TEST_F(MasterLexerTest, preOpen) {
  76. // Initially sources stack is empty.
  77. checkEmptySource(lexer);
  78. }
  79. TEST_F(MasterLexerTest, pushStream) {
  80. lexer.pushSource(ss);
  81. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  82. // From the point of view of this test, we only have to check (though
  83. // indirectly) getSourceLine calls InputSource::getCurrentLine. It should
  84. // return 1 initially.
  85. EXPECT_EQ(1, lexer.getSourceLine());
  86. // By popping it the stack will be empty again.
  87. lexer.popSource();
  88. checkEmptySource(lexer);
  89. }
  90. TEST_F(MasterLexerTest, pushFile) {
  91. // We use zone file (-like) data, but in this test that actually doesn't
  92. // matter.
  93. EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt"));
  94. EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
  95. EXPECT_EQ(1, lexer.getSourceLine());
  96. lexer.popSource();
  97. checkEmptySource(lexer);
  98. // If we give a non NULL string pointer, its content will be intact
  99. // if pushSource succeeds.
  100. std::string error_txt = "dummy";
  101. EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt",
  102. &error_txt));
  103. EXPECT_EQ("dummy", error_txt);
  104. }
  105. TEST_F(MasterLexerTest, pushBadFileName) {
  106. EXPECT_THROW(lexer.pushSource(NULL), isc::InvalidParameter);
  107. }
  108. TEST_F(MasterLexerTest, pushFileFail) {
  109. // The file to be pushed doesn't exist. pushSource() fails and
  110. // some non empty error string should be set.
  111. std::string error_txt;
  112. EXPECT_TRUE(error_txt.empty());
  113. EXPECT_FALSE(lexer.pushSource("no-such-file", &error_txt));
  114. EXPECT_FALSE(error_txt.empty());
  115. // It's safe to pass NULL error_txt (either explicitly or implicitly as
  116. // the default)
  117. EXPECT_FALSE(lexer.pushSource("no-such-file", NULL));
  118. EXPECT_FALSE(lexer.pushSource("no-such-file"));
  119. }
  120. TEST_F(MasterLexerTest, nestedPush) {
  121. lexer.pushSource(ss);
  122. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  123. // We can push another source without popping the previous one.
  124. lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt");
  125. EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
  126. // popSource() works on the "topmost" (last-pushed) source
  127. lexer.popSource();
  128. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  129. lexer.popSource();
  130. EXPECT_TRUE(lexer.getSourceName().empty());
  131. }
  132. TEST_F(MasterLexerTest, invalidPop) {
  133. // popSource() cannot be called if the sources stack is empty.
  134. EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);
  135. }
  136. // Test it is not possible to get token when no source is available.
  137. TEST_F(MasterLexerTest, noSource) {
  138. EXPECT_THROW(lexer.getNextToken(), isc::InvalidOperation);
  139. }
  140. // Getting a token directly from the start() method.
  141. TEST_F(MasterLexerTest, tokenFromStart) {
  142. // A class that sets the token directly in start() and returns no
  143. // state. This is equivalent to the State::start() doing so.
  144. class StartLexer : public MasterLexer {
  145. public:
  146. StartLexer() :
  147. token_(MasterLexer::Token::END_OF_LINE)
  148. {}
  149. virtual const State* start(Options) {
  150. // We don't have access directly inside the implementation.
  151. // We get the fake state, run it to install the token.
  152. // Then we just delete it ourself and return NULL.
  153. State* state(State::getFakeState(NULL, 0, &token_));
  154. state->handle(*this);
  155. delete state;
  156. return (NULL);
  157. }
  158. private:
  159. MasterLexer::Token token_;
  160. } lexer;
  161. lexer.pushSource(ss);
  162. // The token gets out.
  163. MasterLexer::Token generated(lexer.getNextToken());
  164. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, generated.getType());
  165. }
  166. // Getting a token with a single iteration through the states.
  167. TEST_F(MasterLexerTest, simpleGetToken) {
  168. // Prepare the fake state.
  169. MasterLexer::Token token(MasterLexer::Token::END_OF_LINE);
  170. scoped_ptr<State> state(State::getFakeState(NULL, 3, &token));
  171. lexer.pushFakeStart(state.get());
  172. // Push some source inside.
  173. ss << "12345";
  174. lexer.pushSource(ss);
  175. // Get the token.
  176. MasterLexer::Token generated(lexer.getNextToken());
  177. // It is the same token (well, on a different address)
  178. // We can't compare directly, so compare types.
  179. EXPECT_EQ(token.getType(), generated.getType());
  180. // 3 characters were read from the source.
  181. // We test by extracting the rest and comparing.
  182. int rest;
  183. ss >> rest;
  184. EXPECT_EQ(45, rest);
  185. }
  186. // A token that takes multiple states.
  187. //
  188. // The first state sets the token as well as the second. The second one should
  189. // survive and be returned.
  190. TEST_F(MasterLexerTest, chainGetToken) {
  191. // Build the states
  192. MasterLexer::Token t1(MasterLexer::Token::END_OF_LINE);
  193. MasterLexer::Token t2(MasterLexer::Token::INITIAL_WS);
  194. scoped_ptr<State> s2(State::getFakeState(NULL, 1, &t2));
  195. scoped_ptr<State> s1(State::getFakeState(s2.get(), 2, &t1));
  196. lexer.pushFakeStart(s1.get());
  197. // Put something into the source
  198. ss << "12345";
  199. lexer.pushSource(ss);
  200. // Get the token.
  201. MasterLexer::Token generated(lexer.getNextToken());
  202. // It is the same token as the second one (well, on a different address)
  203. // We can't compare directly, so compare types.
  204. EXPECT_EQ(t2.getType(), generated.getType());
  205. // 3 characters were read from the source.
  206. // We test by extracting the rest and comparing.
  207. int rest;
  208. ss >> rest;
  209. EXPECT_EQ(45, rest);
  210. }
  211. // Test getting a token without overriding the start() method (well, it
  212. // is overriden, but no fake state is set, so it refers to the real one).
  213. //
  214. // This also tests the real start() passes the options, otherwise we wouldn't
  215. // get the initial whitespace.
  216. TEST_F(MasterLexerTest, realStart) {
  217. ss << "\n \n";
  218. lexer.pushSource(ss);
  219. // First, the newline should get out.
  220. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  221. // Then the whitespace, if we specify the option.
  222. EXPECT_EQ(MasterLexer::Token::INITIAL_WS,
  223. lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
  224. }
  225. // Test we correctly find end of file. Then, upon more attempts to produce
  226. // tokens past the end, it throws.
  227. TEST_F(MasterLexerTest, eof) {
  228. // Let the ss empty.
  229. lexer.pushSource(ss);
  230. // The first one is found to be EOF
  231. EXPECT_EQ(MasterLexer::Token::END_OF_FILE, lexer.getNextToken().getType());
  232. // And it is not allowed to use this one any more.
  233. EXPECT_THROW(lexer.getNextToken(), isc::InvalidOperation);
  234. }
  235. void
  236. checkInput(const std::string& expected, const std::string& received) {
  237. EXPECT_EQ(expected, received);
  238. }
  239. // Check ungetting a token, which should get to the previous state. We do
  240. // so with changing the state a little bit.
  241. TEST_F(MasterLexerTest, ungetSimple) {
  242. ss << "12345";
  243. lexer.pushSource(ss);
  244. const bool true_value = true, false_value = false;
  245. // Make sure we change the state to non-default, so we return to previous
  246. // not default state.
  247. MasterLexer::Token t0(MasterLexer::Token::INITIAL_WS);
  248. scoped_ptr<State> s0(State::getFakeState(NULL, 1, &t0, 1, &true_value));
  249. lexer.pushFakeStart(s0.get());
  250. EXPECT_EQ(MasterLexer::Token::INITIAL_WS, lexer.getNextToken().getType());
  251. // Prepare the token to get and return
  252. const std::string expected = "234";
  253. MasterLexer::Token token(MasterLexer::Token::END_OF_LINE);
  254. // Change the internal state with it too. So we can check it is retured.
  255. scoped_ptr<State> state(State::getFakeState(NULL, 3, &token, 1,
  256. &false_value,
  257. boost::bind(&checkInput,
  258. expected, _1)));
  259. lexer.pushFakeStart(state.get());
  260. // Check the internal state before getting the token
  261. // We access the lexer through any state, so use the one we have.
  262. EXPECT_EQ(1, state->getParenCount(lexer));
  263. EXPECT_TRUE(state->wasLastEOL(lexer));
  264. // Now get the token and check the state changed
  265. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  266. EXPECT_EQ(2, state->getParenCount(lexer));
  267. EXPECT_FALSE(state->wasLastEOL(lexer));
  268. // Return the token back. Check the state is as it was before.
  269. lexer.ungetToken();
  270. EXPECT_EQ(1, state->getParenCount(lexer));
  271. EXPECT_TRUE(state->wasLastEOL(lexer));
  272. // By calling getToken again, we verify even the source got back to
  273. // original. We must push it as a fake start again so it is picked.
  274. lexer.pushFakeStart(state.get());
  275. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  276. EXPECT_EQ(2, state->getParenCount(lexer));
  277. EXPECT_FALSE(state->wasLastEOL(lexer));
  278. }
  279. // Check ungetting token without overriding the start method. We also
  280. // check it works well with changing options between the calls.
  281. TEST_F(MasterLexerTest, ungetRealOptions) {
  282. ss << "\n \n";
  283. lexer.pushSource(ss);
  284. // Skip the first newline
  285. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  286. // If we call it the usual way, it skips up to the newline and returns
  287. // it
  288. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  289. // Now we return it. If we call it again, but with different options,
  290. // we get the initial whitespace.
  291. lexer.ungetToken();
  292. EXPECT_EQ(MasterLexer::Token::INITIAL_WS,
  293. lexer.getNextToken(MasterLexer::INITIAL_WS).getType());
  294. }
  295. // Test only one token can be ungotten
  296. TEST_F(MasterLexerTest, ungetTwice) {
  297. ss << "\n";
  298. lexer.pushSource(ss);
  299. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  300. // Unget the token. It can be done once
  301. lexer.ungetToken();
  302. // But not twice
  303. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  304. }
  305. // Test we can't unget a token before we get one
  306. TEST_F(MasterLexerTest, ungetBeforeGet) {
  307. lexer.pushSource(ss); // Just to eliminate the missing source problem
  308. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  309. }
  310. // Test we can't unget a token after a source switch, even when we got
  311. // something before.
  312. TEST_F(MasterLexerTest, ungetAfterSwitch) {
  313. ss << "\n\n";
  314. lexer.pushSource(ss);
  315. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  316. // Switch the source
  317. std::stringstream ss2;
  318. ss2 << "\n\n";
  319. lexer.pushSource(ss2);
  320. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  321. // We can get from the new source
  322. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  323. // And when we drop the current source, we can't unget again
  324. lexer.popSource();
  325. EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
  326. }
  327. class TestException {};
  328. void
  329. doThrow(const std::string&) {
  330. throw TestException();
  331. }
  332. // Check the getNextToken provides at least the weak exception guarantee.
  333. TEST_F(MasterLexerTest, getTokenExceptions) {
  334. ss << "\n12345";
  335. lexer.pushSource(ss);
  336. // Prepare a chain that changes the internal state, reads something.
  337. // The next item in the chain will throw an exception (we explicitly
  338. // throw something not known to it, so we know it can handle anything).
  339. // Then the thing should get to the previous state and getting the
  340. // token the usual way without mock should work.
  341. const bool true_value = true;
  342. boost::scoped_ptr<State> s2(State::getFakeState(NULL, 3, NULL, 0, NULL,
  343. &doThrow));
  344. boost::scoped_ptr<State> s1(State::getFakeState(s2.get(), 3, NULL, 1,
  345. &true_value));
  346. lexer.pushFakeStart(s1.get());
  347. // Getting the token with the fake start should throw. But then, the
  348. // current state should be untouched.
  349. EXPECT_THROW(lexer.getNextToken(), TestException);
  350. EXPECT_EQ(0, s1->getParenCount(lexer));
  351. EXPECT_FALSE(s1->wasLastEOL(lexer));
  352. // It gets back to the original state, so getting the newline works.
  353. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, lexer.getNextToken().getType());
  354. }
  355. }