BIND 10 master, updated. 560a71919bda37ad20e54efed07183acc5413a8a Merge branch 'master' into trac2369
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Nov 7 08:31:42 UTC 2012
The branch, master has been updated
via 560a71919bda37ad20e54efed07183acc5413a8a (commit)
via dce5a5557d44d52455e9cfbafe2ad882e6b930db (commit)
via 24862b62d9a01d277ea5c5b99666f04b1951de64 (commit)
via 31745f2d5978086e2d0cc40524efc2e5a45b832b (commit)
via ff7cec44f4ee5c59593278558269bdd41a6e5719 (commit)
via 265fb98ba1f1daab43779b8eaeb6d7f8775dd772 (commit)
via 9af419deb6691876904d456faf0da731cb5c96b5 (commit)
via ccb0973459b702152f79ea23841269a379580850 (commit)
via 4d7d67838cb15ce75ceab0664e7b25e4b58d658a (commit)
via ed1a2ad7dfa4d0c87e9ab3fa446acdbc29f6cc24 (commit)
via 9f5232047b3a68299192a7885068430af6f8859b (commit)
via 80b227af0bf08ac9e7bdf645b11e8593b717add3 (commit)
via a2090f1d5702cbc00da7b52a2c1247bd37334ebc (commit)
via f142087f73411145565baf4a3280607413162e06 (commit)
via e32617d592d204e4c5c27ff3ecab77ea4e258cb7 (commit)
via eb92bed532b40a0904f8397ba108d96f152abbbf (commit)
via 5ac6e8b56caad02994fd9352e3427e975e72f44a (commit)
via 710bac35169ec02b73a82cab2c4ce31874a8e440 (commit)
via b27d601b91d09bbaa5c20805331c7efa95eac944 (commit)
via 6b8bf7d03e221e9a1802bcddda66b2b424930042 (commit)
via 6847454e58c65b33e61fe03b16b3aa5a63df8d8d (commit)
via 0dd898f80907bcb0180858a3a1b2811c803012a9 (commit)
via ba71154440e841836726bbc6b9088f095d14f7d1 (commit)
via 51e26dc96b447d4f60b6aa2c428bfcfe6e6a4d04 (commit)
via 9843e33b58ce12f13fc34fe27c7ef0e4042bd506 (commit)
via b5ca6ac342e49edb73ab75938de20c8fd3f6e8b8 (commit)
via 2c8d3ac2d8d62ef77c0f888a7c334689ebcd9b5b (commit)
via a6093a8ef88a556bb0c6094d11863e700ec8242f (commit)
via cb9e761c578cc1de9421eb5e5c1a45c3d9145239 (commit)
via 7fb91131cdfc5778e241cb247e3c2713dfe2ca3a (commit)
via 8aa5e22a0fc048058c3b45d1c2fc76065e0ac8bd (commit)
via 29ff6bebc9eef580849d063cfb58bc8e053a03e6 (commit)
from 36514ddc884c02a063e166d44319467ce6fb1d8f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 560a71919bda37ad20e54efed07183acc5413a8a
Merge: dce5a55 36514dd
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Nov 7 13:05:21 2012 +0530
Merge branch 'master' into trac2369
-----------------------------------------------------------------------
Summary of changes:
src/lib/dns/Makefile.am | 1 +
src/lib/dns/master_lexer_inputsource.cc | 154 ++++++++++
src/lib/dns/master_lexer_inputsource.h | 164 ++++++++++
src/lib/dns/tests/Makefile.am | 1 +
.../dns/tests/master_lexer_inputsource_unittest.cc | 325 ++++++++++++++++++++
5 files changed, 645 insertions(+)
create mode 100644 src/lib/dns/master_lexer_inputsource.cc
create mode 100644 src/lib/dns/master_lexer_inputsource.h
create mode 100644 src/lib/dns/tests/master_lexer_inputsource_unittest.cc
-----------------------------------------------------------------------
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 5cf0732..e81ef76 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 += master_lexer_inputsource.h master_lexer_inputsource.cc
libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
libb10_dns___la_SOURCES += masterload.h masterload.cc
libb10_dns___la_SOURCES += master_lexer.h master_lexer.cc
diff --git a/src/lib/dns/master_lexer_inputsource.cc b/src/lib/dns/master_lexer_inputsource.cc
new file mode 100644
index 0000000..e6d9cec
--- /dev/null
+++ b/src/lib/dns/master_lexer_inputsource.cc
@@ -0,0 +1,154 @@
+// 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 <dns/master_lexer_inputsource.h>
+
+#include <cerrno>
+#include <cstring>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+
+namespace { // unnamed namespace
+
+std::string
+createStreamName(const std::istream& input_stream) {
+ std::stringstream ss;
+ ss << "stream-" << &input_stream;
+ return (ss.str());
+}
+
+} // end of unnamed namespace
+
+InputSource::InputSource(std::istream& input_stream) :
+ at_eof_(false),
+ line_(1),
+ saved_line_(line_),
+ buffer_pos_(0),
+ name_(createStreamName(input_stream)),
+ input_(input_stream)
+{}
+
+InputSource::InputSource(const char* filename) :
+ at_eof_(false),
+ line_(1),
+ saved_line_(line_),
+ buffer_pos_(0),
+ name_(filename),
+ input_(file_stream_)
+{
+ errno = 0;
+ file_stream_.open(filename);
+ if (file_stream_.fail()) {
+ std::string error_txt("Error opening the input source file: ");
+ error_txt += filename;
+ if (errno != 0) {
+ error_txt += "; possible cause: ";
+ error_txt += std::strerror(errno);
+ }
+ isc_throw(OpenError, error_txt);
+ }
+}
+
+InputSource::~InputSource()
+{
+ if (file_stream_.is_open()) {
+ file_stream_.close();
+ }
+}
+
+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 (END_OF_STREAM);
+ }
+ // We are not yet at EOF. Read from the stream.
+ const 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_.eof()) {
+ at_eof_ = true;
+ return (END_OF_STREAM);
+ }
+ // This has to come after the .eof() check as some
+ // implementations seem to check the eofbit also in .fail().
+ if (input_.fail()) {
+ isc_throw(ReadError,
+ "Error reading from the input stream: " << getName());
+ }
+ buffer_.push_back(c);
+ }
+
+ const int c = buffer_[buffer_pos_];
+ ++buffer_pos_;
+ if (c == '\n') {
+ ++line_;
+ }
+
+ return (c);
+}
+
+void
+InputSource::ungetChar() {
+ if (at_eof_) {
+ at_eof_ = false;
+ } else if (buffer_pos_ == 0) {
+ isc_throw(UngetBeforeBeginning,
+ "Cannot skip before the start of buffer");
+ } else {
+ --buffer_pos_;
+ if (buffer_[buffer_pos_] == '\n') {
+ --line_;
+ }
+ }
+}
+
+void
+InputSource::ungetAll() {
+ buffer_pos_ = 0;
+ line_ = saved_line_;
+ at_eof_ = false;
+}
+
+void
+InputSource::saveLine() {
+ saved_line_ = line_;
+}
+
+void
+InputSource::compact() {
+ if (buffer_pos_ == buffer_.size()) {
+ buffer_.clear();
+ } else {
+ buffer_.erase(buffer_.begin(), buffer_.begin() + buffer_pos_);
+ }
+
+ buffer_pos_ = 0;
+}
+
+void
+InputSource::mark() {
+ saveLine();
+ compact();
+}
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/master_lexer_inputsource.h b/src/lib/dns/master_lexer_inputsource.h
new file mode 100644
index 0000000..33659d1
--- /dev/null
+++ b/src/lib/dns/master_lexer_inputsource.h
@@ -0,0 +1,164 @@
+// 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 <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+
+/// \brief An input source that is used internally by MasterLexer.
+///
+/// This is a helper internal class for MasterLexer, and represents
+/// state of a single source of the entire zone data to be
+/// parsed. Normally this means the master zone file, but MasterLexer
+/// can have multiple InputSources if $INCLUDE is used. The source can
+/// also be generic input stream (std::istream).
+///
+/// This class is not meant for public use. We also enforce that
+/// instances are non-copyable.
+class InputSource : boost::noncopyable {
+public:
+ /// \brief Returned by getChar() when end of stream is reached.
+ static const int END_OF_STREAM;
+
+ /// \brief Exception thrown when ungetChar() is made to go before
+ /// the start of buffer.
+ struct UngetBeforeBeginning : public OutOfRange {
+ UngetBeforeBeginning(const char* file, size_t line, const char* what) :
+ OutOfRange(file, line, what)
+ {}
+ };
+
+ /// \brief Exception thrown when we fail to read from the input
+ /// stream or file.
+ struct ReadError : public Unexpected {
+ ReadError(const char* file, size_t line, const char* what) :
+ Unexpected(file, line, what)
+ {}
+ };
+
+ /// \brief Exception thrown when we fail to open the input file.
+ struct OpenError : public Unexpected {
+ OpenError(const char* file, size_t line, const char* what) :
+ Unexpected(file, line, what)
+ {}
+ };
+
+ /// \brief Constructor which takes an input stream. The stream is
+ /// read-from, but it is not closed.
+ explicit InputSource(std::istream& input_stream);
+
+ /// \brief Constructor which takes a filename to read from. The
+ /// associated file stream is managed internally.
+ ///
+ /// \throws OpenError when opening the input file fails.
+ explicit InputSource(const char* filename);
+
+ /// \brief Destructor
+ ~InputSource();
+
+ /// \brief Returns a name for the InputSource. Typically this is the
+ /// filename, but if the InputSource was constructed for an
+ /// \c std::istream, it returns a name in the format "stream-%p".
+ const std::string& getName() const {
+ return (name_);
+ }
+
+ /// \brief Returns if the input source is at end of file.
+ bool atEOF() const {
+ return (at_eof_);
+ }
+
+ /// \brief Returns the current line number being read.
+ size_t getCurrentLine() const {
+ return (line_);
+ }
+
+ /// \brief Saves the current line being read. Later, when
+ /// \c ungetAll() is called, it skips back to the last-saved line.
+ ///
+ /// TODO: Please make this method private if it is unused after the
+ /// MasterLexer implementation is complete (and only \c mark() is
+ /// used instead).
+ void saveLine();
+
+ /// Removes buffered content before the current location in the
+ /// \c InputSource. It's not possible to \c ungetChar() after this,
+ /// unless we read more data using \c getChar().
+ ///
+ /// TODO: Please make this method private if it is unused after the
+ /// MasterLexer implementation is complete (and only \c mark() is
+ /// used instead).
+ void compact();
+
+ /// Calls \c saveLine() and \c compact() in sequence.
+ void mark();
+
+ /// \brief Returns a single character from the input source. If end
+ /// of file is reached, \c END_OF_STREAM is returned.
+ ///
+ /// \throws ReadError when reading from the input stream or file
+ /// fails.
+ int getChar();
+
+ /// \brief Skips backward a single character in the input
+ /// source. The last-read character is unget.
+ ///
+ /// \throws UngetBeforeBeginning if we go backwards past the start
+ /// of reading, or backwards past the last time compact() was
+ /// called.
+ void ungetChar();
+
+ /// Forgets what was read, and skips back to the position where
+ /// \c compact() was last called. If \c compact() was not called, it
+ /// skips back to where reading started. If \c saveLine() was called
+ /// previously, it sets the current line number to the line number
+ /// saved.
+ void ungetAll();
+
+private:
+ bool at_eof_;
+ size_t line_;
+ size_t saved_line_;
+
+ std::vector<char> buffer_;
+ size_t buffer_pos_;
+
+ const std::string name_;
+ std::ifstream file_stream_;
+ std::istream& input_;
+};
+
+const int InputSource::END_OF_STREAM = -1;
+
+} // 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 6df0e62..35d659c 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 += master_lexer_inputsource_unittest.cc
run_unittests_SOURCES += labelsequence_unittest.cc
run_unittests_SOURCES += messagerenderer_unittest.cc
run_unittests_SOURCES += master_lexer_token_unittest.cc
diff --git a/src/lib/dns/tests/master_lexer_inputsource_unittest.cc b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
new file mode 100644
index 0000000..db0cbec
--- /dev/null
+++ b/src/lib/dns/tests/master_lexer_inputsource_unittest.cc
@@ -0,0 +1,325 @@
+// 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 <dns/master_lexer_inputsource.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <string.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::master_lexer_internal;
+
+namespace {
+
+class InputSourceTest : public ::testing::Test {
+protected:
+ InputSourceTest() :
+ str_("Line1 to scan.\nLine2 to scan.\nLine3 to scan.\n"),
+ str_length_(strlen(str_)),
+ iss_(str_),
+ source_(iss_)
+ {}
+
+ const char* str_;
+ const size_t str_length_;
+ stringstream iss_;
+ InputSource source_;
+};
+
+// Test the default return values set during InputSource construction.
+TEST_F(InputSourceTest, defaults) {
+ EXPECT_EQ(1, source_.getCurrentLine());
+ EXPECT_FALSE(source_.atEOF());
+}
+
+// getName() on file and stream sources
+TEST_F(InputSourceTest, getName) {
+ EXPECT_EQ(0, source_.getName().find("stream-"));
+
+ // Use some file; doesn't really matter what.
+ InputSource source2(TEST_DATA_SRCDIR "/masterload.txt");
+ EXPECT_EQ(TEST_DATA_SRCDIR "/masterload.txt", source2.getName());
+}
+
+TEST_F(InputSourceTest, nonExistentFile) {
+ EXPECT_THROW({
+ InputSource source(TEST_DATA_SRCDIR "/does-not-exist");
+ }, InputSource::OpenError);
+}
+
+// getChar() should return characters from the input stream in
+// sequence. ungetChar() should skip backwards.
+void
+checkGetAndUngetChar(InputSource& source,
+ const char* str, const size_t str_length)
+{
+ 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(InputSource::END_OF_STREAM, 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(InputSource::END_OF_STREAM, 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) {
+ const 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(), InputSource::UngetBeforeBeginning);
+}
+
+TEST_F(InputSourceTest, stream) {
+ checkGetAndUngetChar(source_, str_, str_length_);
+}
+
+TEST_F(InputSourceTest, file) {
+ std::ifstream fs(TEST_DATA_SRCDIR "/masterload.txt");
+ const std::string str((std::istreambuf_iterator<char>(fs)),
+ std::istreambuf_iterator<char>());
+ fs.close();
+
+ InputSource source(TEST_DATA_SRCDIR "/masterload.txt");
+ checkGetAndUngetChar(source, str.c_str(), str.size());
+}
+
+// ungetAll() should skip back to the place where the InputSource
+// started at construction, or the last saved start of line.
+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_F(InputSourceTest, compact) {
+ // Compact at the start
+ source_.compact();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ 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(InputSource::END_OF_STREAM, source_.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // Compact again
+ source_.compact();
+
+ // We are still at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // Skip the EOF.
+ source_.ungetChar();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ EXPECT_EQ(InputSource::END_OF_STREAM, source_.getChar());
+ EXPECT_TRUE(source_.atEOF());
+}
+
+TEST_F(InputSourceTest, markDuring) {
+ // First, skip to line 2.
+ while (!source_.atEOF() &&
+ (source_.getCurrentLine() != 2)) {
+ source_.getChar();
+ }
+ EXPECT_FALSE(source_.atEOF());
+ EXPECT_EQ(2, source_.getCurrentLine());
+
+ // Now, unget a couple of characters. This should cause the
+ // buffer_pos_ to be not equal to the size of the buffer.
+ source_.ungetChar();
+ source_.ungetChar();
+
+ // Now "mark" the source, meaning that we save line number and also
+ // compact the internal buffer at this stage.
+ source_.mark();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ for (size_t i = 13; 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(InputSource::END_OF_STREAM, source_.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(source_.atEOF());
+
+ // Now, ungetAll() and check where it goes back.
+ source_.ungetAll();
+
+ // Ungetting here must throw.
+ EXPECT_THROW(source_.ungetChar(), InputSource::UngetBeforeBeginning);
+
+ for (size_t i = 13; 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(InputSource::END_OF_STREAM, source_.getChar());
+
+ // Now, EOF should be set.
+ EXPECT_TRUE(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 2 characters, skipping the last EOF and '\n'.
+ source_.ungetChar();
+ 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());
+
+ // Now check that line numbers are decremented properly (as much as
+ // possible using the available API).
+ while (!source_.atEOF()) {
+ source_.getChar();
+ }
+ line = source_.getCurrentLine();
+
+ // Now, we are at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, line);
+
+ EXPECT_THROW({
+ while (true) {
+ source_.ungetChar();
+ EXPECT_TRUE(((line == source_.getCurrentLine()) ||
+ ((line - 1) == source_.getCurrentLine())));
+ line = source_.getCurrentLine();
+ }
+ }, InputSource::UngetBeforeBeginning);
+
+ // Now we are back to where we started.
+ EXPECT_EQ(1, source_.getCurrentLine());
+}
+
+// ungetAll() after saveLine() should skip back to the last-saved place.
+TEST_F(InputSourceTest, saveLine) {
+ // First, skip to line 2.
+ while (!source_.atEOF() &&
+ (source_.getCurrentLine() != 2)) {
+ source_.getChar();
+ }
+ EXPECT_FALSE(source_.atEOF());
+ EXPECT_EQ(2, source_.getCurrentLine());
+
+ // Now, save the line.
+ source_.saveLine();
+
+ // Now, go to EOF
+ while (!source_.atEOF()) {
+ source_.getChar();
+ }
+
+ // Now, we are at EOF.
+ EXPECT_TRUE(source_.atEOF());
+ EXPECT_EQ(4, source_.getCurrentLine());
+
+ // Now, ungetAll() and check where it goes back.
+ source_.ungetAll();
+
+ // Now we are back to where we last-saved.
+ EXPECT_EQ(2, source_.getCurrentLine());
+ EXPECT_FALSE(source_.atEOF());
+}
+
+} // end namespace
More information about the bind10-changes
mailing list