master_lexer_unittest.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 <string>
  22. #include <sstream>
  23. using namespace isc::dns;
  24. using std::string;
  25. using std::stringstream;
  26. using boost::lexical_cast;
  27. using boost::scoped_ptr;
  28. using master_lexer_internal::State;
  29. namespace {
  30. // This acts like the normal MasterLexer. It, however, allows to mock the start()
  31. // method to return some given state instead of the auto-detected ones.
  32. class TestedMasterLexer : public MasterLexer {
  33. public:
  34. TestedMasterLexer() :
  35. fake_start_(NULL)
  36. {}
  37. // During the next call to start(), return the given state instead of the
  38. // auto-detected one.
  39. void pushFakeStart(const State* state) {
  40. fake_start_ = state;
  41. }
  42. protected:
  43. virtual const State* start() {
  44. if (fake_start_ != NULL) {
  45. // There's a fake start, so remove it (not to be used next time)
  46. // and return it.
  47. const State* result = fake_start_;
  48. fake_start_ = NULL;
  49. return (result);
  50. } else {
  51. // No fake start ready. So we act the usual way, by delegating it to
  52. // the parent class.
  53. return (MasterLexer::start());
  54. }
  55. }
  56. private:
  57. const State* fake_start_;
  58. };
  59. class MasterLexerTest : public ::testing::Test {
  60. protected:
  61. MasterLexerTest() :
  62. expected_stream_name("stream-" + lexical_cast<string>(&ss))
  63. {}
  64. TestedMasterLexer lexer;
  65. stringstream ss;
  66. const string expected_stream_name;
  67. };
  68. // Commonly used check case where the input sources stack is empty.
  69. void
  70. checkEmptySource(const MasterLexer& lexer) {
  71. EXPECT_TRUE(lexer.getSourceName().empty());
  72. EXPECT_EQ(0, lexer.getSourceLine());
  73. }
  74. TEST_F(MasterLexerTest, preOpen) {
  75. // Initially sources stack is empty.
  76. checkEmptySource(lexer);
  77. }
  78. TEST_F(MasterLexerTest, pushStream) {
  79. lexer.pushSource(ss);
  80. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  81. // From the point of view of this test, we only have to check (though
  82. // indirectly) getSourceLine calls InputSource::getCurrentLine. It should
  83. // return 1 initially.
  84. EXPECT_EQ(1, lexer.getSourceLine());
  85. // By popping it the stack will be empty again.
  86. lexer.popSource();
  87. checkEmptySource(lexer);
  88. }
  89. TEST_F(MasterLexerTest, pushFile) {
  90. // We use zone file (-like) data, but in this test that actually doesn't
  91. // matter.
  92. EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt"));
  93. EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
  94. EXPECT_EQ(1, lexer.getSourceLine());
  95. lexer.popSource();
  96. checkEmptySource(lexer);
  97. // If we give a non NULL string pointer, its content will be intact
  98. // if pushSource succeeds.
  99. std::string error_txt = "dummy";
  100. EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt",
  101. &error_txt));
  102. EXPECT_EQ("dummy", error_txt);
  103. }
  104. TEST_F(MasterLexerTest, pushBadFileName) {
  105. EXPECT_THROW(lexer.pushSource(NULL), isc::InvalidParameter);
  106. }
  107. TEST_F(MasterLexerTest, pushFileFail) {
  108. // The file to be pushed doesn't exist. pushSource() fails and
  109. // some non empty error string should be set.
  110. std::string error_txt;
  111. EXPECT_TRUE(error_txt.empty());
  112. EXPECT_FALSE(lexer.pushSource("no-such-file", &error_txt));
  113. EXPECT_FALSE(error_txt.empty());
  114. // It's safe to pass NULL error_txt (either explicitly or implicitly as
  115. // the default)
  116. EXPECT_FALSE(lexer.pushSource("no-such-file", NULL));
  117. EXPECT_FALSE(lexer.pushSource("no-such-file"));
  118. }
  119. TEST_F(MasterLexerTest, nestedPush) {
  120. lexer.pushSource(ss);
  121. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  122. // We can push another source without popping the previous one.
  123. lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt");
  124. EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
  125. // popSource() works on the "topmost" (last-pushed) source
  126. lexer.popSource();
  127. EXPECT_EQ(expected_stream_name, lexer.getSourceName());
  128. lexer.popSource();
  129. EXPECT_TRUE(lexer.getSourceName().empty());
  130. }
  131. TEST_F(MasterLexerTest, invalidPop) {
  132. // popSource() cannot be called if the sources stack is empty.
  133. EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);
  134. }
  135. // Test it is not possible to get token when no source is available.
  136. TEST_F(MasterLexerTest, noSource) {
  137. EXPECT_THROW(lexer.getNextToken(), isc::InvalidOperation);
  138. }
  139. // Getting a token directly from the start() method.
  140. TEST_F(MasterLexerTest, tokenFromStart) {
  141. // A class that sets the token directly in start() and returns no
  142. // state. This is equivalent to the State::start() doing so.
  143. class StartLexer : public MasterLexer {
  144. public:
  145. StartLexer() :
  146. token_(MasterLexer::Token::END_OF_LINE)
  147. {}
  148. virtual const State* start() {
  149. // We don't have access directly inside the implementation.
  150. // We get the fake state, run it to install the token.
  151. // Then we just delete it ourself and return NULL.
  152. State* state(State::getFakeState(NULL, 0, &token_));
  153. state->handle(*this);
  154. delete state;
  155. return (NULL);
  156. }
  157. private:
  158. MasterLexer::Token token_;
  159. } lexer;
  160. lexer.pushSource(ss);
  161. // The token gets out.
  162. MasterLexer::Token generated(lexer.getNextToken());
  163. EXPECT_EQ(MasterLexer::Token::END_OF_LINE, generated.getType());
  164. }
  165. // Getting a token with a single iteration through the states.
  166. TEST_F(MasterLexerTest, simpleGetToken) {
  167. // Prepare the fake state.
  168. MasterLexer::Token token(MasterLexer::Token::END_OF_LINE);
  169. scoped_ptr<State> state(State::getFakeState(NULL, 3, &token));
  170. lexer.pushFakeStart(state.get());
  171. // Push some source inside.
  172. ss << "12345";
  173. lexer.pushSource(ss);
  174. // Get the token.
  175. MasterLexer::Token generated(lexer.getNextToken());
  176. // It is the same token (well, on a different address)
  177. // We can't compare directly, so compare types.
  178. EXPECT_EQ(token.getType(), generated.getType());
  179. // 3 characters were read from the source.
  180. // We test by extracting the rest and comparing.
  181. int rest;
  182. ss >> rest;
  183. EXPECT_EQ(rest, 45);
  184. }
  185. // A token that takes multiple states.
  186. //
  187. // The first state sets the token as well as the second. The second one should
  188. // survive and be returned.
  189. TEST_F(MasterLexerTest, chainGetToken) {
  190. // Build the states
  191. MasterLexer::Token t1(MasterLexer::Token::END_OF_LINE);
  192. MasterLexer::Token t2(MasterLexer::Token::INITIAL_WS);
  193. scoped_ptr<State> s2(State::getFakeState(NULL, 1, &t2));
  194. scoped_ptr<State> s1(State::getFakeState(s2.get(), 2, &t1));
  195. // Put something into the source
  196. ss << "12345";
  197. lexer.pushSource(ss);
  198. // Get the token.
  199. MasterLexer::Token generated(lexer.getNextToken());
  200. // It is the same token as the second one (well, on a different address)
  201. // We can't compare directly, so compare types.
  202. EXPECT_EQ(t2.getType(), generated.getType());
  203. // 3 characters were read from the source.
  204. // We test by extracting the rest and comparing.
  205. int rest;
  206. ss >> rest;
  207. EXPECT_EQ(rest, 45);
  208. }
  209. // Test getting a token without overriding the start() method (well, it
  210. // is overriden, but no fake state is set, so it refers to the real one).
  211. //
  212. // This also tests the real start() passes the options, otherwise we wouldn't
  213. // get the initial whitespace.
  214. TEST_F(MasterLexerTest, realStart) {
  215. ss << " \n42";
  216. lexer.pushSource(ss);
  217. // The correct one gets out.
  218. MasterLexer::Token generated(lexer.getNextToken());
  219. EXPECT_EQ(MasterLexer::Token::INITIAL_WS, generated.getType());
  220. }
  221. }