From 29ff6bebc9eef580849d063cfb58bc8e053a03e6 Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Fri, 26 Oct 2012 10:30:09 +0530 Subject: [PATCH] [2369] Add InputSource helper class (work-in-progress) --- src/lib/dns/Makefile.am | 1 + src/lib/dns/inputsource.cc | 74 +++++++++++ src/lib/dns/inputsource.h | 76 +++++++++++ src/lib/dns/tests/Makefile.am | 1 + src/lib/dns/tests/inputsource_unittest.cc | 147 ++++++++++++++++++++++ 5 files changed, 299 insertions(+) create mode 100644 src/lib/dns/inputsource.cc create mode 100644 src/lib/dns/inputsource.h create mode 100644 src/lib/dns/tests/inputsource_unittest.cc diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am index 977854d1e..02c38beb6 100644 --- a/src/lib/dns/Makefile.am +++ b/src/lib/dns/Makefile.am @@ -93,6 +93,7 @@ libb10_dns___la_LDFLAGS = -no-undefined -version-info 2:0:0 libb10_dns___la_SOURCES = libb10_dns___la_SOURCES += edns.h edns.cc libb10_dns___la_SOURCES += exceptions.h exceptions.cc +libb10_dns___la_SOURCES += inputsource.h inputsource.cc libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc libb10_dns___la_SOURCES += masterload.h masterload.cc libb10_dns___la_SOURCES += message.h message.cc diff --git a/src/lib/dns/inputsource.cc b/src/lib/dns/inputsource.cc new file mode 100644 index 000000000..a93993b24 --- /dev/null +++ b/src/lib/dns/inputsource.cc @@ -0,0 +1,74 @@ +// 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 +#include + +namespace isc { +namespace dns { +namespace master_lexer_internal { + +int +InputSource::getChar() { + if (buffer_pos_ == buffer_.size()) { + // We may have reached EOF at the last call to + // getChar(). at_eof_ will be set then. We then simply return + // early. + if (at_eof_) { + return -1; + } + // We are not yet at EOF. Read from the stream. + int c = input_.get(); + // Have we reached EOF now? If so, set at_eof_ and return early, + // but don't modify buffer_pos_ (which should still be equal to + // the size of buffer_). + if (!input_.good()) { + at_eof_ = true; + return -1; + } + buffer_.push_back(c); + } + + int c = buffer_[buffer_pos_++]; + if (c == '\n') { + line_++; + } + + return (c); +} + +void +InputSource::ungetChar() { + if (at_eof_) { + at_eof_ = false; + } else if (buffer_pos_ == 0) { + isc_throw(OutOfRange, "Cannot skip before the start of buffer"); + } else { + if (buffer_[buffer_pos_] == '\n') { + line_--; + } + buffer_pos_--; + } +} + +void +InputSource::ungetAll() { + buffer_pos_ = 0; + line_ = saved_line_; + at_eof_ = false; +} + +} // namespace master_lexer_internal +} // namespace dns +} // namespace isc diff --git a/src/lib/dns/inputsource.h b/src/lib/dns/inputsource.h new file mode 100644 index 000000000..6349ed1cd --- /dev/null +++ b/src/lib/dns/inputsource.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef DNS_INPUTSOURCE_H +#define DNS_INPUTSOURCE_H 1 + +#include +#include +#include + +namespace isc { +namespace dns { +namespace master_lexer_internal { + +class InputSource { +public: + InputSource(std::istream& input, const std::string& name) : + input_(input), + name_(name), + at_eof_(false), + line_(1), + saved_line_(line_), + buffer_pos_(buffer_.size()) + {} + + const std::string& getName() { + return (name_); + } + + bool atEOF() const { + return (at_eof_); + } + + size_t getCurrentLine() const { + return (line_); + } + + void saveLine() { + saved_line_ = line_; + } + + int getChar(); + void ungetChar(); + void ungetAll(); + +private: + std::istream& input_; + const std::string name_; + bool at_eof_; + size_t line_; + size_t saved_line_; + + std::vector buffer_; + size_t buffer_pos_; +}; + +} // namespace master_lexer_internal +} // namespace dns +} // namespace isc + +#endif // DNS_INPUTSOURCE_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am index e8cbe101f..49c6ddfe4 100644 --- a/src/lib/dns/tests/Makefile.am +++ b/src/lib/dns/tests/Makefile.am @@ -22,6 +22,7 @@ if HAVE_GTEST TESTS += run_unittests run_unittests_SOURCES = unittest_util.h unittest_util.cc run_unittests_SOURCES += edns_unittest.cc +run_unittests_SOURCES += inputsource_unittest.cc run_unittests_SOURCES += labelsequence_unittest.cc run_unittests_SOURCES += messagerenderer_unittest.cc run_unittests_SOURCES += name_unittest.cc diff --git a/src/lib/dns/tests/inputsource_unittest.cc b/src/lib/dns/tests/inputsource_unittest.cc new file mode 100644 index 000000000..274c16efc --- /dev/null +++ b/src/lib/dns/tests/inputsource_unittest.cc @@ -0,0 +1,147 @@ +// 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 +#include + +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace isc::dns; +using namespace isc::dns::master_lexer_internal; + +namespace { + +class InputSourceTest : public ::testing::Test { +protected: + InputSourceTest() : + name_("a90wjer"), + str_("Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n"), + str_length_(strlen(str_)), + iss_(str_), + source_(iss_, name_) + {} + + string name_; + const char* str_; + size_t str_length_; + stringstream iss_; + InputSource source_; +}; + +// Test the default return values set during InputSource construction. +TEST_F(InputSourceTest, defaults) { + EXPECT_EQ(name_, source_.getName()); + EXPECT_EQ(1, source_.getCurrentLine()); + EXPECT_FALSE(source_.atEOF()); +} + +// getChar() should return characters from the input stream in +// sequence. ungetChar() should skip backwards. +TEST_F(InputSourceTest, getAndUngetChar) { + for (size_t i = 0; i < str_length_; i++) { + EXPECT_EQ(str_[i], source_.getChar()); + EXPECT_FALSE(source_.atEOF()); + } + + // At this point, we still have not reached EOF. + EXPECT_FALSE(source_.atEOF()); + + // This should cause EOF to be set. + EXPECT_EQ(-1, source_.getChar()); + + // Now, EOF should be set. + EXPECT_TRUE(source_.atEOF()); + + // Now, let's go backwards. This should cause the EOF to be set to + // false. + source_.ungetChar(); + + // Now, EOF should be false. + EXPECT_FALSE(source_.atEOF()); + + // This should cause EOF to be set again. + EXPECT_EQ(-1, source_.getChar()); + + // Now, EOF should be set. + EXPECT_TRUE(source_.atEOF()); + + // Now, let's go backwards in a loop. Start by skipping the EOF. + source_.ungetChar(); + + for (size_t i = 0; i < str_length_; i++) { + size_t index = str_length_ - 1 - i; + // Skip one character. + source_.ungetChar(); + EXPECT_EQ(str_[index], source_.getChar()); + // Skip the character we received again. + source_.ungetChar(); + } + + // Skipping past the start of buffer should throw. + EXPECT_THROW(source_.ungetChar(), isc::OutOfRange); +} + +// ungetAll() should skip back to the place where the InputSource +// started at construction. +TEST_F(InputSourceTest, ungetAll) { + while (!source_.atEOF()) { + source_.getChar(); + } + + // Now, we are at EOF. + EXPECT_TRUE(source_.atEOF()); + EXPECT_EQ(4, source_.getCurrentLine()); + + source_.ungetAll(); + + // Now we are back to where we started. + EXPECT_EQ(1, source_.getCurrentLine()); + EXPECT_FALSE(source_.atEOF()); +} + + +// Test line counters. +TEST_F(InputSourceTest, lines) { + size_t line = 1; + while (!source_.atEOF()) { + if (source_.getChar() == '\n') { + line++; + } + EXPECT_EQ(line, source_.getCurrentLine()); + } + + // Now, we are at EOF. + EXPECT_TRUE(source_.atEOF()); + EXPECT_EQ(4, source_.getCurrentLine()); + + // Go backwards 1 character, skipping the last '\n'. + source_.ungetChar(); + EXPECT_FALSE(source_.atEOF()); + EXPECT_EQ(3, source_.getCurrentLine()); + + source_.ungetAll(); + + // Now we are back to where we started. + EXPECT_EQ(1, source_.getCurrentLine()); + EXPECT_FALSE(source_.atEOF()); +} + +} // end namespace -- GitLab