]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Implement Parser::Tokenizer::int64 and unit tests
authorFrancesco Chemolli <kinkie@squid-cache.org>
Mon, 26 May 2014 13:04:01 +0000 (15:04 +0200)
committerFrancesco Chemolli <kinkie@squid-cache.org>
Mon, 26 May 2014 13:04:01 +0000 (15:04 +0200)
src/parser/Tokenizer.cc
src/parser/Tokenizer.h
src/parser/testTokenizer.cc
src/parser/testTokenizer.h

index 469d0b62c68f3b9d1f003b0e9dbce6e1de1206f6..5fef29850867692e6a4f19f5770152e756c7c43f 100644 (file)
@@ -60,36 +60,23 @@ Parser::Tokenizer::skip(const char tokenChar)
 bool
 Parser::Tokenizer::int64 (int64_t & result, int base)
 {
-    //register uint64_t acc;
-    register uint64_t cutoff;
-    bool neg = false;
-    static SBuf zerox("0x"), zero("0");
-
     if (buf_.isEmpty())
         return false;
 
-    if (buf_[0] == '-') {
-        neg = true;
-        buf_.consume(1);
-    }
-    if (buf_[0] == '+')
-        buf_.consume(1);
-    if (base == 0) {
-        if (buf_.startsWith(zerox))
-            base = 16;
-        else if (buf_.startsWith(zero))
-            base = 8;
-        else
-            base = 10;
-    }
-    if (base != 8 && base != 10 && base != 16)
+    // API mismatch with strtoll: we don't eat leading space.
+    if (xisspace(buf_[0]))
         return false;
 
-    // TODO: finish
-    cutoff = neg ? -(uint64_t) INT64_MIN : INT64_MAX;
+    char *eon;
+    errno = 0; // reset errno
 
-    // dummy to keep compiler happy. Remove before continuing
-    if (neg) result = cutoff;
+    int64_t rv = strtoll(buf_.rawContent(), &eon, base);
+
+    if (errno != 0)
+        return false;
+
+    buf_.consume(eon - buf_.rawContent()); // consume the parsed chunk
+    result = rv;
+    return true;
 
-    return false;
 }
index 0296a7221d44be54192f0bee30ab365a42778970..84db031342158e8abeb1df995bd61863eb0a1ffe 100644 (file)
@@ -21,6 +21,9 @@ class Tokenizer {
 public:
    explicit Tokenizer(const SBuf &inBuf) : buf_(inBuf) {}
 
+   // return a copy the current contents of the parse buffer
+   const SBuf buf() const { return buf_; }
+
    /// whether the end of the buffer has been reached
    bool atEnd() const { return buf_.isEmpty(); }
 
@@ -66,7 +69,7 @@ public:
 
    /** parse an unsigned int64_t at the beginning of the buffer
     *
-    * strtoull(3)-alike function: tries to parse unsigned 64-bit integer
+    * strtoll(3)-alike function: tries to parse unsigned 64-bit integer
     * at the beginning of the parse buffer, in the base specified by the user
     * or guesstimated; consumes the parsed characters.
     *
@@ -76,9 +79,7 @@ public:
     *   the base
     * \return true if the parsing was successful
     */
-   bool uint64 (uint64_t & result, int base);
-
-   bool int64 (int64_t &result, int base);
+   bool int64 (int64_t &result, int base = 0);
 
 private:
    SBuf buf_; ///< yet unparsed input
index a329853632e1ae8fe0ab45f119862a5427c5a307..5308c91de783e1bce63a0103e4bb8108ca8605b5 100644 (file)
@@ -102,3 +102,80 @@ testTokenizer::testCharacterSet()
 {
 
 }
+
+void
+testTokenizer::testTokenizerInt64()
+{
+    int64_t rv;
+
+    // successful parse in base 10
+    {
+        Parser::Tokenizer t(SBuf("1234"));
+        const int64_t benchmark = 1234;
+        CPPUNIT_ASSERT(t.int64(rv, 10));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+    }
+
+    // successful parse, autodetect base
+    {
+        Parser::Tokenizer t(SBuf("1234"));
+        const int64_t benchmark = 1234;
+        CPPUNIT_ASSERT(t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+    }
+
+    // successful parse, autodetect base
+    {
+        Parser::Tokenizer t(SBuf("01234"));
+        const int64_t benchmark = 01234;
+        CPPUNIT_ASSERT(t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+    }
+
+    // successful parse, autodetect base
+    {
+        Parser::Tokenizer t(SBuf("0x12f4"));
+        const int64_t benchmark = 0x12f4;
+        CPPUNIT_ASSERT(t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+    }
+
+    // API mismatch: don't eat leading space
+    {
+        Parser::Tokenizer t(SBuf(" 1234"));
+        CPPUNIT_ASSERT(!t.int64(rv));
+    }
+
+    // API mismatch: don't eat multiple leading spaces
+    {
+        Parser::Tokenizer t(SBuf("  1234"));
+        CPPUNIT_ASSERT(!t.int64(rv));
+    }
+
+    // trailing spaces
+    {
+        Parser::Tokenizer t(SBuf("1234  foo"));
+        const int64_t benchmark = 1234;
+        CPPUNIT_ASSERT(t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT_EQUAL(SBuf("  foo"), t.buf());
+    }
+
+    // trailing nonspaces
+    {
+        Parser::Tokenizer t(SBuf("1234foo"));
+        const int64_t benchmark = 1234;
+        CPPUNIT_ASSERT(t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT_EQUAL(SBuf("foo"), t.buf());
+    }
+
+    // trailing nonspaces
+    {
+        Parser::Tokenizer t(SBuf("0x1234foo"));
+        const int64_t benchmark = 0x1234f;
+        CPPUNIT_ASSERT(t.int64(rv));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT_EQUAL(SBuf("oo"), t.buf());
+    }
+}
index 22ff87d9dac4a545a13593e87d5d21dd029d77bb..9089aa75ccfe477d71009a2d96272e9ef44f9c34 100644 (file)
@@ -10,6 +10,7 @@ class testTokenizer : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST ( testTokenizerPrefix );
     CPPUNIT_TEST ( testTokenizerSkip );
     CPPUNIT_TEST ( testTokenizerToken );
+    CPPUNIT_TEST ( testTokenizerInt64 );
     CPPUNIT_TEST_SUITE_END();
 
 protected:
@@ -17,6 +18,7 @@ protected:
     void testTokenizerSkip();
     void testTokenizerToken();
     void testCharacterSet();
+    void testTokenizerInt64();
 };
 
 #endif /* SQUID_TESTTOKENIZER_H_ */