123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <exceptions/exceptions.h>
- #include <dns/master_lexer.h>
- #include <dns/master_lexer_state.h>
- #include <gtest/gtest.h>
- #include <boost/lexical_cast.hpp>
- #include <boost/function.hpp>
- #include <boost/scoped_ptr.hpp>
- #include <string>
- #include <sstream>
- using namespace isc::dns;
- using std::string;
- using std::stringstream;
- using boost::lexical_cast;
- using boost::scoped_ptr;
- using master_lexer_internal::State;
- namespace {
- // This acts like the normal MasterLexer. It, however, allows to mock the start()
- // method to return some given state instead of the auto-detected ones.
- class TestedMasterLexer : public MasterLexer {
- public:
- TestedMasterLexer() :
- fake_start_(NULL)
- {}
- // During the next call to start(), return the given state instead of the
- // auto-detected one.
- void pushFakeStart(const State* state) {
- fake_start_ = state;
- }
- protected:
- virtual const State* start() {
- if (fake_start_ != NULL) {
- // There's a fake start, so remove it (not to be used next time)
- // and return it.
- const State* result = fake_start_;
- fake_start_ = NULL;
- return (result);
- } else {
- // No fake start ready. So we act the usual way, by delegating it to
- // the parent class.
- return (MasterLexer::start());
- }
- }
- private:
- const State* fake_start_;
- };
- class MasterLexerTest : public ::testing::Test {
- protected:
- MasterLexerTest() :
- expected_stream_name("stream-" + lexical_cast<string>(&ss))
- {}
- TestedMasterLexer lexer;
- stringstream ss;
- const string expected_stream_name;
- };
- // Commonly used check case where the input sources stack is empty.
- void
- checkEmptySource(const MasterLexer& lexer) {
- EXPECT_TRUE(lexer.getSourceName().empty());
- EXPECT_EQ(0, lexer.getSourceLine());
- }
- TEST_F(MasterLexerTest, preOpen) {
- // Initially sources stack is empty.
- checkEmptySource(lexer);
- }
- TEST_F(MasterLexerTest, pushStream) {
- lexer.pushSource(ss);
- EXPECT_EQ(expected_stream_name, lexer.getSourceName());
- // From the point of view of this test, we only have to check (though
- // indirectly) getSourceLine calls InputSource::getCurrentLine. It should
- // return 1 initially.
- EXPECT_EQ(1, lexer.getSourceLine());
- // By popping it the stack will be empty again.
- lexer.popSource();
- checkEmptySource(lexer);
- }
- TEST_F(MasterLexerTest, pushFile) {
- // We use zone file (-like) data, but in this test that actually doesn't
- // matter.
- EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt"));
- EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
- EXPECT_EQ(1, lexer.getSourceLine());
- lexer.popSource();
- checkEmptySource(lexer);
- // If we give a non NULL string pointer, its content will be intact
- // if pushSource succeeds.
- std::string error_txt = "dummy";
- EXPECT_TRUE(lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt",
- &error_txt));
- EXPECT_EQ("dummy", error_txt);
- }
- TEST_F(MasterLexerTest, pushBadFileName) {
- EXPECT_THROW(lexer.pushSource(NULL), isc::InvalidParameter);
- }
- TEST_F(MasterLexerTest, pushFileFail) {
- // The file to be pushed doesn't exist. pushSource() fails and
- // some non empty error string should be set.
- std::string error_txt;
- EXPECT_TRUE(error_txt.empty());
- EXPECT_FALSE(lexer.pushSource("no-such-file", &error_txt));
- EXPECT_FALSE(error_txt.empty());
- // It's safe to pass NULL error_txt (either explicitly or implicitly as
- // the default)
- EXPECT_FALSE(lexer.pushSource("no-such-file", NULL));
- EXPECT_FALSE(lexer.pushSource("no-such-file"));
- }
- TEST_F(MasterLexerTest, nestedPush) {
- lexer.pushSource(ss);
- EXPECT_EQ(expected_stream_name, lexer.getSourceName());
- // We can push another source without popping the previous one.
- lexer.pushSource(TEST_DATA_SRCDIR "/masterload.txt");
- EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", lexer.getSourceName());
- // popSource() works on the "topmost" (last-pushed) source
- lexer.popSource();
- EXPECT_EQ(expected_stream_name, lexer.getSourceName());
- lexer.popSource();
- EXPECT_TRUE(lexer.getSourceName().empty());
- }
- TEST_F(MasterLexerTest, invalidPop) {
- // popSource() cannot be called if the sources stack is empty.
- EXPECT_THROW(lexer.popSource(), isc::InvalidOperation);
- }
- // Test it is not possible to get token when no source is available.
- TEST_F(MasterLexerTest, noSource) {
- EXPECT_THROW(lexer.getNextToken(), isc::InvalidOperation);
- }
- // Getting a token directly from the start() method.
- TEST_F(MasterLexerTest, tokenFromStart) {
- // A class that sets the token directly in start() and returns no
- // state. This is equivalent to the State::start() doing so.
- class StartLexer : public MasterLexer {
- public:
- StartLexer() :
- token_(MasterLexer::Token::END_OF_LINE)
- {}
- virtual const State* start() {
- // We don't have access directly inside the implementation.
- // We get the fake state, run it to install the token.
- // Then we just delete it ourself and return NULL.
- State* state(State::getFakeState(NULL, 0, &token_));
- state->handle(*this);
- delete state;
- return (NULL);
- }
- private:
- MasterLexer::Token token_;
- } lexer;
- lexer.pushSource(ss);
- // The token gets out.
- MasterLexer::Token generated(lexer.getNextToken());
- EXPECT_EQ(MasterLexer::Token::END_OF_LINE, generated.getType());
- }
- // Getting a token with a single iteration through the states.
- TEST_F(MasterLexerTest, simpleGetToken) {
- // Prepare the fake state.
- MasterLexer::Token token(MasterLexer::Token::END_OF_LINE);
- scoped_ptr<State> state(State::getFakeState(NULL, 3, &token));
- lexer.pushFakeStart(state.get());
- // Push some source inside.
- ss << "12345";
- lexer.pushSource(ss);
- // Get the token.
- MasterLexer::Token generated(lexer.getNextToken());
- // It is the same token (well, on a different address)
- // We can't compare directly, so compare types.
- EXPECT_EQ(token.getType(), generated.getType());
- // 3 characters were read from the source.
- // We test by extracting the rest and comparing.
- int rest;
- ss >> rest;
- EXPECT_EQ(rest, 45);
- }
- // A token that takes multiple states.
- //
- // The first state sets the token as well as the second. The second one should
- // survive and be returned.
- TEST_F(MasterLexerTest, chainGetToken) {
- // Build the states
- MasterLexer::Token t1(MasterLexer::Token::END_OF_LINE);
- MasterLexer::Token t2(MasterLexer::Token::INITIAL_WS);
- scoped_ptr<State> s2(State::getFakeState(NULL, 1, &t2));
- scoped_ptr<State> s1(State::getFakeState(s2.get(), 2, &t1));
- // Put something into the source
- ss << "12345";
- lexer.pushSource(ss);
- // Get the token.
- MasterLexer::Token generated(lexer.getNextToken());
- // It is the same token as the second one (well, on a different address)
- // We can't compare directly, so compare types.
- EXPECT_EQ(t2.getType(), generated.getType());
- // 3 characters were read from the source.
- // We test by extracting the rest and comparing.
- int rest;
- ss >> rest;
- EXPECT_EQ(rest, 45);
- }
- // Test getting a token without overriding the start() method (well, it
- // is overriden, but no fake state is set, so it refers to the real one).
- //
- // This also tests the real start() passes the options, otherwise we wouldn't
- // get the initial whitespace.
- TEST_F(MasterLexerTest, realStart) {
- ss << " \n42";
- lexer.pushSource(ss);
- // The correct one gets out.
- MasterLexer::Token generated(lexer.getNextToken());
- EXPECT_EQ(MasterLexer::Token::INITIAL_WS, generated.getType());
- }
- }
|