]> granicus.if.org Git - icu/commitdiff
ICU-10855 fix handling of partial match leniency to not falsely pass literals that...
authorScott Russell <DTownSMR@gmail.com>
Fri, 16 May 2014 17:38:08 +0000 (17:38 +0000)
committerScott Russell <DTownSMR@gmail.com>
Fri, 16 May 2014 17:38:08 +0000 (17:38 +0000)
X-SVN-Rev: 35720

icu4c/source/i18n/smpdtfmt.cpp
icu4c/source/i18n/unicode/smpdtfmt.h
icu4c/source/test/intltest/dtfmrgts.cpp
icu4c/source/test/intltest/dtfmrgts.h

index 4752de5e8a9a37ccee06a479578d49ed9d7aed86..b6e50b932973831c54a207a821f551f79eba8317 100644 (file)
@@ -29,7 +29,6 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-
 #include "unicode/smpdtfmt.h"
 #include "unicode/dtfmtsym.h"
 #include "unicode/ures.h"
@@ -1723,6 +1722,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
     int32_t pos = parsePos.getIndex();
     int32_t start = pos;
 
+
     UBool ambiguousYear[] = { FALSE };
     int32_t saveHebrewMonth = -1;
     int32_t count = 0;
@@ -1872,7 +1872,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
 
             abutPat = -1; // End of any abutting fields
             
-            if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status))) {
+            if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status), isLenient())) {
                 status = U_PARSE_ERROR;
                 goto ExitParse;
             }
@@ -2155,12 +2155,13 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
                                       const UnicodeString &text,
                                       int32_t &textOffset,
                                       UBool whitespaceLenient,
-                                      UBool partialMatchLenient)
+                                      UBool partialMatchLenient,
+                                      UBool oldLeniency)
 {
     UBool inQuote = FALSE;
-    UnicodeString literal;
+    UnicodeString literal;    
     int32_t i = patternOffset;
-    
+       
     // scan pattern looking for contiguous literal characters
     for ( ; i < pattern.length(); i += 1) {
         UChar ch = pattern.charAt(i);
@@ -2234,7 +2235,6 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
                 break;
             }
         }
-        
         if (t >= text.length() || literal.charAt(p) != text.charAt(t)) {
             // Ran out of text, or found a non-matching character:
             // OK in lenient mode, an error in strict mode.
@@ -2246,16 +2246,20 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
                     ++t;
                     continue;  // Do not update p.
                 }
-                // if it is actual whitespace and we're whitespace lenient it's OK
+                // if it is actual whitespace and we're whitespace lenient it's OK                
+                
                 UChar wsc = text.charAt(t);
-                if(PatternProps::isWhiteSpace(wsc))
-                    break;
+                if(PatternProps::isWhiteSpace(wsc)) {
+                    // Lenient mode and it's just whitespace we skip it
+                    ++t;
+                    continue;  // Do not update p.
+                }
             } 
-            // or if we're partial match lenient it's OK
-            if(partialMatchLenient) {                                
+            // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for paritial matches
+            if(partialMatchLenient && oldLeniency) {                             
                 break;
             }
-
+            
             return FALSE;
         }
         ++p;
index 1e54dc3248835895a13b0049ae01162e446e990a..efdb6471f047b1663a6e28633902901dc8699531 100644 (file)
@@ -1334,12 +1334,13 @@ private:
      *                   will be set to the offset of the character after the match
      * @param whitespaceLenient <code>TRUE</code> if whitespace parse is lenient, <code>FALSE</code> otherwise.
      * @param partialMatchLenient <code>TRUE</code> if partial match parse is lenient, <code>FALSE</code> otherwise.
+     * @param oldLeniency <code>TRUE</code> if old leniency control is lenient, <code>FALSE</code> otherwise.
      *
      * @return <code>TRUE</code> if the literal text could be matched, <code>FALSE</code> otherwise.
      */
     static UBool matchLiterals(const UnicodeString &pattern, int32_t &patternOffset,
                                const UnicodeString &text, int32_t &textOffset, 
-                               UBool whitespaceLenient, UBool partialMatchLenient);
+                               UBool whitespaceLenient, UBool partialMatchLenient, UBool oldLeniency);
     
     /**
      * Private member function that converts the parsed date strings into
index 992fd3d8ab8f94486db4afd5322a970b98808031..9c6c538f0f2eb4ec956ca71a40dbad22e78a7fb8 100644 (file)
@@ -7,7 +7,6 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-
 #include "dtfmrgts.h"
 
 #include "unicode/timezone.h"
@@ -59,6 +58,7 @@ DateFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char*
         CASE(28,TestParsing)
         CASE(29,TestT10334)
         CASE(30,TestT10619)
+        CASE(31,TestT10855)
         default: name = ""; break;
     }
 }
@@ -1530,10 +1530,12 @@ void DateFormatRegressionTest::TestParsing(void) {
 
 void DateFormatRegressionTest::TestT10334(void) {
     UErrorCode status = U_ZERO_ERROR;
-    UnicodeString pattern("'--: 'EEE-WW-MMMM-yyyy");
+    UnicodeString pattern("--: EEE-WW-MMMM-yyyy");
     UnicodeString text("--mon-02-march-2011");
     SimpleDateFormat format(pattern, status);
 
+    logln("pattern["+pattern+"] text["+text+"]");
+
     if (U_FAILURE(status)) {
         dataerrln("Fail creating SimpleDateFormat object - %s", u_errorName(status));
         return;
@@ -1600,24 +1602,15 @@ typedef struct {
 void DateFormatRegressionTest::TestT10619(void) {
     const UDate july022008 = 1215000001979.0;
     const TestDateFormatLeniencyItem items[] = {
-        /*
-            new TestDateFormatLeniencyItem(true,       "2008-Jan 02",     "yyyy-LLL. dd",         "2008-Jan. 02"),
-            new TestDateFormatLeniencyItem(false,      "2008-Jan 03",     "yyyy-LLL. dd",         null),
-            new TestDateFormatLeniencyItem(true,       "2008-Jan--04",    "yyyy-MMM' -- 'dd",     "2008-Jan -- 04"),
-            new TestDateFormatLeniencyItem(false,      "2008-Jan--05",    "yyyy-MMM' -- 'dd",     null),
-            new TestDateFormatLeniencyItem(true,       "2008-12-31",      "yyyy-mm-dd",           "2008-12-31"),
-            new TestDateFormatLeniencyItem(false,      "6 Jan 05 2008",   "eee MMM dd yyyy",      null),
-            new TestDateFormatLeniencyItem(true,       "6 Jan 05 2008",   "eee MMM dd yyyy",      "Sat Jan 05 2008"),
-        */
         //locale    leniency    parse String                    pattern                             expected result
         { "en",     true,       UnicodeString("2008-07 02"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("2008-July 02") },
-        { "en",     false,      UnicodeString("2008-07 02"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("") },
-        { "en",     true,       UnicodeString("2008-Jan 02"),   UnicodeString("yyyy-LLL. dd"),      UnicodeString("2008-Jan 02") },
-        { "en",     false,      UnicodeString("2008-Jan 02"),   UnicodeString("yyyy-LLL. dd"),      UnicodeString("") },
-        { "en",     true,       UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("2008-Jan 02") },
-        { "en",     false,      UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("") },
-        { "en",     true,       UnicodeString("6 Jan 05 2008"), UnicodeString("eee MMM dd yyyy"),   UnicodeString("Sat Jan 05 2008") },
-        { "en",     false,      UnicodeString("6 Jan 05 2008"), UnicodeString("eee MMM dd yyyy"),   UnicodeString("") },
+        { "en",     false,      UnicodeString("2008-07 03"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("") },
+        { "en",     true,       UnicodeString("2008-Jan. 04"),  UnicodeString("yyyy-LLL dd"),       UnicodeString("2008-Jan 04") },
+        { "en",     false,      UnicodeString("2008-Jan. 05"),  UnicodeString("yyyy-LLL dd"),       UnicodeString("") },
+        { "en",     true,       UnicodeString("2008-Jan--06"),  UnicodeString("yyyy-MMM -- dd"),    UnicodeString("2008-Jan 06") },
+        { "en",     false,      UnicodeString("2008-Jan--07"),  UnicodeString("yyyy-MMM -- dd"),    UnicodeString("") },
+        { "en",     true,       UnicodeString("6 Jan 08 2008"), UnicodeString("eee MMM dd yyyy"),   UnicodeString("Sat Jan 08 2008") },
+        { "en",     false,      UnicodeString("6 Jan 09 2008"), UnicodeString("eee MMM dd yyyy"),   UnicodeString("") },
         // terminator
         { NULL,     true,       UnicodeString(""),              UnicodeString(""),                  UnicodeString("") }                
     };
@@ -1638,9 +1631,12 @@ void DateFormatRegressionTest::TestT10619(void) {
                 dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
                 continue;
             }
+            logln("parsing " + itemPtr->parseString);
             sdmft->setLenient(itemPtr->leniency);
-            sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status);
-            /*UDate d = */sdmft->parse(itemPtr->parseString, pos);
+            sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status);
+            sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status);
+            sdmft->setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, itemPtr->leniency, status);
+            sdmft->parse(itemPtr->parseString, pos);
 
             delete sdmft;
             if(pos.getErrorIndex() > -1) {
@@ -1658,6 +1654,58 @@ void DateFormatRegressionTest::TestT10619(void) {
 
 }
 
+
+typedef struct {
+    UnicodeString text;
+    UnicodeString pattern;
+    int initialParsePos;
+} T10855Data;
+    
+void DateFormatRegressionTest::TestT10855(void) {
+    // NOTE: these should NOT parse
+    const T10855Data items[] = {
+        //parse String                          pattern                         initial parse pos
+        { UnicodeString("September 30, 1998"),  UnicodeString("MM-dd-yyyy"),    0},
+        { UnicodeString("123-73-1950"),         UnicodeString("MM-dd-yyyy"),    -1},
+        { UnicodeString("12-23-1950"),          UnicodeString("MM-dd-yyyy"),    -1},
+        // terminator
+        { UnicodeString(""),                    UnicodeString(""),              0}                
+    };
+    UErrorCode status = U_ZERO_ERROR;
+
+    int x = 0;
+    while(items[x].pattern.length() > 0)
+    {
+        status = U_ZERO_ERROR;
+        logln("Date to parse: \""+items[x].text+"\"");
+        logln("Starting Index: %d", items[x].initialParsePos);
+
+        SimpleDateFormat dateFmt(items[x].pattern, status);
+        if(U_FAILURE(status)) { 
+            errln(u_errorName(status)); 
+            ++x;
+            continue;
+        } 
+        status = U_ZERO_ERROR;  
+
+        dateFmt.setLenient(false);
+        dateFmt.setTimeZone(*TimeZone::getGMT());
+
+        ParsePosition position(items[x].initialParsePos);
+        logln("set position is now: %d", position.getIndex());
+        UDate d = dateFmt.parse(items[x].text, position);
+        if (position.getErrorIndex() != -1 || position.getIndex() == items[x].initialParsePos) {
+            logln("Parse Failed. ErrorIndex is %d - Index is %d", position.getErrorIndex(), position.getIndex());
+        } else {
+            errln("Parse Succeeded...should have failed. Index is %d - ErrorIndex is %d", position.getIndex(), position.getErrorIndex());
+        }
+        logln("Parsed date returns %d\n", d);
+
+        ++x;
+    }
+}
+
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
 
 //eof
index 63955103881a9bc7562a2b92418c8260a3c731ca..a445243560fef103c8f848761e521f00aaa89c33 100644 (file)
@@ -55,6 +55,7 @@ public:
     void TestParsing(void);
     void TestT10334(void);
     void TestT10619(void);
+    void TestT10855(void);
  };
 
 #endif /* #if !UCONFIG_NO_FORMATTING */