Browse Source

[2370] defined MasterLexer and its Token classes, added main methods and tests

JINMEI Tatuya 12 years ago
parent
commit
a54864927b

+ 3 - 0
src/lib/dns/Makefile.am

@@ -95,6 +95,7 @@ libb10_dns___la_SOURCES += edns.h edns.cc
 libb10_dns___la_SOURCES += exceptions.h exceptions.cc
 libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
 libb10_dns___la_SOURCES += masterload.h masterload.cc
+libb10_dns___la_SOURCES += master_lexer.h
 libb10_dns___la_SOURCES += message.h message.cc
 libb10_dns___la_SOURCES += messagerenderer.h messagerenderer.cc
 libb10_dns___la_SOURCES += name.h name.cc
@@ -145,6 +146,8 @@ libdns___include_HEADERS = \
 	exceptions.h \
 	labelsequence.h \
 	message.h \
+	master_lexer.h \
+	masterload.h \
 	messagerenderer.h \
 	name.h \
 	question.h \

+ 101 - 0
src/lib/dns/master_lexer.h

@@ -0,0 +1,101 @@
+// 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 MASTER_LEXER_H
+#define MASTER_LEXER_H 1
+
+#include <exceptions/exceptions.h>
+
+#include <string>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dns {
+
+class MasterLexer {
+public:
+    class Token {
+    public:
+        enum Type {
+            ERROR,
+            END_OF_LINE,
+            END_OF_FILE,
+            INITIAL_WS,
+            STRING,
+            QSTRING,
+            NUMBER
+        };
+
+        struct StringRegion {
+            const char* beg;
+            size_t len;
+        };
+
+        explicit Token(Type type) : type_(type) {
+            if (type >= STRING) {
+                isc_throw(InvalidParameter, "Token per-type constructor "
+                          "called with invalid type: " << type);
+            }
+        }
+        Token(const char* str_beg, size_t str_len, bool quoted = false) :
+            type_(quoted ? QSTRING : STRING)
+        {
+            val_.str_region_.beg = str_beg;
+            val_.str_region_.len = str_len;
+        }
+        explicit Token(uint32_t number) : type_(NUMBER) {
+            val_.number_ = number;
+        }
+
+        Type getType() const { return (type_); }
+        std::string getString() const {
+            if (type_ != STRING && type_ != QSTRING) {
+                isc_throw(InvalidOperation,
+                          "Token::getString() for non string-variant type");
+            }
+            return (std::string(val_.str_region_.beg,
+                                val_.str_region_.beg + val_.str_region_.len));
+        }
+        const StringRegion& getStringRegion() const {
+            if (type_ != STRING && type_ != QSTRING) {
+                isc_throw(InvalidOperation,
+                          "Token::getString() for non string-variant type");
+            }
+            return (val_.str_region_);
+        }
+        uint32_t getNumber() const {
+            if (type_ != NUMBER) {
+                isc_throw(InvalidOperation,
+                          "Token::getNumber() for non number type");
+            }
+            return (val_.number_);
+        }
+
+    private:
+        Type type_;
+        union {
+            StringRegion str_region_;
+            uint32_t number_;
+        } val_;
+    };
+};
+
+} // namespace dns
+} // namespace isc
+#endif  // MASTER_LEXER_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 1 - 0
src/lib/dns/tests/Makefile.am

@@ -24,6 +24,7 @@ run_unittests_SOURCES = unittest_util.h unittest_util.cc
 run_unittests_SOURCES += edns_unittest.cc
 run_unittests_SOURCES += labelsequence_unittest.cc
 run_unittests_SOURCES += messagerenderer_unittest.cc
+run_unittests_SOURCES += master_lexer_token_unittest.cc
 run_unittests_SOURCES += name_unittest.cc
 run_unittests_SOURCES += nsec3hash_unittest.cc
 run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc

+ 110 - 0
src/lib/dns/tests/master_lexer_token_unittest.cc

@@ -0,0 +1,110 @@
+// 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 <gtest/gtest.h>
+
+#include <string>
+
+using namespace isc::dns;
+
+namespace {
+
+const char TEST_STRING[] = "string token";
+
+class MasterLexerTokenTest : public ::testing::Test {
+public:
+    MasterLexerTokenTest() :
+        token_err(MasterLexer::Token::ERROR),
+        token_str(TEST_STRING, sizeof(TEST_STRING) - 1), // excluding ending 0
+        token_num(42)
+    {}
+
+    const MasterLexer::Token token_err;
+    const MasterLexer::Token token_str;
+    const MasterLexer::Token token_num;
+};
+
+
+TEST_F(MasterLexerTokenTest, strings) {
+    EXPECT_EQ(MasterLexer::Token::STRING, token_str.getType());
+    EXPECT_EQ(std::string("string token"), token_str.getString());
+    const MasterLexer::Token::StringRegion str_region =
+        token_str.getStringRegion();
+    EXPECT_EQ(TEST_STRING, str_region.beg);
+    EXPECT_EQ(sizeof(TEST_STRING) - 1, str_region.len);
+
+    // Construct type of qstring
+    EXPECT_EQ(MasterLexer::Token::QSTRING,
+              MasterLexer::Token(TEST_STRING, sizeof(TEST_STRING), true).
+              getType());
+    // if we explicitly set 'quoted' to false, it should be normal string
+    EXPECT_EQ(MasterLexer::Token::STRING,
+              MasterLexer::Token(TEST_STRING, sizeof(TEST_STRING), false).
+              getType());
+
+    // getString/StringRegion() aren't allowed for non string(-variant) types
+    EXPECT_THROW(token_err.getString(), isc::InvalidOperation);
+    EXPECT_THROW(token_num.getString(), isc::InvalidOperation);
+    EXPECT_THROW(token_err.getStringRegion(), isc::InvalidOperation);
+    EXPECT_THROW(token_num.getStringRegion(), isc::InvalidOperation);
+}
+
+TEST_F(MasterLexerTokenTest, numbers) {
+    EXPECT_EQ(42, token_num.getNumber());
+    EXPECT_EQ(MasterLexer::Token::NUMBER, token_num.getType());
+
+    // It's copyable and assignable.
+    MasterLexer::Token token(token_num);
+    EXPECT_EQ(42, token.getNumber());
+    EXPECT_EQ(MasterLexer::Token::NUMBER, token.getType());
+
+    token = token_num;
+    EXPECT_EQ(42, token.getNumber());
+    EXPECT_EQ(MasterLexer::Token::NUMBER, token.getType());
+
+    // it's okay to replace it with a different type of token
+    token = token_err;
+    EXPECT_EQ(MasterLexer::Token::ERROR, token.getType());
+
+    // Possible max value
+    token = MasterLexer::Token(0xffffffff);
+    EXPECT_EQ(4294967295u, token.getNumber());
+
+    // TBD: getNumber for other type
+    EXPECT_THROW(token_err.getNumber(), isc::InvalidOperation);
+}
+
+TEST_F(MasterLexerTokenTest, specials) {
+    // Just checking we can construct them and getType() returns correct value.
+    EXPECT_EQ(MasterLexer::Token::ERROR, token_err.getType());
+    EXPECT_EQ(MasterLexer::Token::END_OF_LINE,
+              MasterLexer::Token(MasterLexer::Token::END_OF_LINE).getType());
+    EXPECT_EQ(MasterLexer::Token::END_OF_FILE,
+              MasterLexer::Token(MasterLexer::Token::END_OF_FILE).getType());
+    EXPECT_EQ(MasterLexer::Token::INITIAL_WS,
+              MasterLexer::Token(MasterLexer::Token::INITIAL_WS).getType());
+
+    // Special types of tokens cannot have value-based types
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::STRING),
+                 isc::InvalidParameter);
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::QSTRING),
+                 isc::InvalidParameter);
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::NUMBER),
+                 isc::InvalidParameter);
+}
+}