From 23b8ec6d9a22b05d16d221bdce38c9083bc1bb35 Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Sat, 19 Mar 2022 19:03:18 +0200 Subject: [PATCH 1/5] Test ParseRFC822Date() with truncated time zone specifiers --- tests/datetime/datetimetest.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index bb1086eca9..6024b17ff9 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -1139,6 +1139,18 @@ void DateTimeTestCase::TestParseRFC822() false }, + { + "Sun 01 Jun 2008 16:39:10 +02", // truncated time zone + { 0 }, + false + }, + + { + "Sun 01 Jun 2008 16:39:10 G", // truncated time zone + { 0 }, + false + }, + { "Sat, 18 Dec 1999 10:48:30", // TZ missing { 0 }, From 4cf335340c9def1baea37097be8283bdc3e733aa Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Tue, 15 Mar 2022 21:16:31 +0200 Subject: [PATCH 2/5] Test the end iterator set by Parse{Date,Time,DateTime}() In other words, check that the unprocessed part of the input is what we expected. Also add some cases where a valid date or time is followed by something. --- tests/datetime/datetimetest.cpp | 78 ++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 6024b17ff9..5e490b590b 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -913,13 +913,33 @@ void DateTimeTestCase::TestTimeParse() wxDateTime dt; // Parsing standard formats should work. - CPPUNIT_ASSERT( dt.ParseTime("12:34:56") ); - CPPUNIT_ASSERT_EQUAL( "12:34:56", dt.FormatISOTime() ); + const char* end = dt.ParseTime("12:34:56"); + CPPUNIT_ASSERT( end ); + if ( end ) + { + CPPUNIT_ASSERT_EQUAL( "12:34:56", dt.FormatISOTime() ); + CPPUNIT_ASSERT_EQUAL( "", wxString(end) ); + } + dt.ResetTime(); + + // Valid, but followed by something. + end = dt.ParseTime("12:34:56 0123 something"); + CPPUNIT_ASSERT( end ); + if ( end ) + { + CPPUNIT_ASSERT_EQUAL( "12:34:56", dt.FormatISOTime() ); + CPPUNIT_ASSERT_EQUAL( " 0123 something", wxString(end) ); + } + dt.ResetTime(); // Parsing just hours should work too. - dt.ResetTime(); - CPPUNIT_ASSERT( dt.ParseTime("17") ); - CPPUNIT_ASSERT_EQUAL( "17:00:00", dt.FormatISOTime() ); + end = dt.ParseTime("17"); + CPPUNIT_ASSERT( end ); + if ( end ) + { + CPPUNIT_ASSERT_EQUAL( "17:00:00", dt.FormatISOTime() ); + CPPUNIT_ASSERT_EQUAL( "", wxString(end) ); + } // Parsing gibberish shouldn't work. CPPUNIT_ASSERT( !dt.ParseTime("bloordyblop") ); @@ -1219,13 +1239,18 @@ void DateTimeTestCase::TestDateParse() const char *str; Date date; // NB: this should be in UTC bool good; + const char* beyondEnd; // what remains unprocessed of the input } parseTestDates[] = { - { "21 Mar 2006", { 21, wxDateTime::Mar, 2006 }, true }, - { "29 Feb 1976", { 29, wxDateTime::Feb, 1976 }, true }, - { "Feb 29 1976", { 29, wxDateTime::Feb, 1976 }, true }, - { "31/03/06", { 31, wxDateTime::Mar, 6 }, true }, - { "31/03/2006", { 31, wxDateTime::Mar, 2006 }, true }, + { "21 Mar 2006", { 21, wxDateTime::Mar, 2006 }, true, ""}, + { "29 Feb 1976", { 29, wxDateTime::Feb, 1976 }, true, "" }, + { "Feb 29 1976", { 29, wxDateTime::Feb, 1976 }, true, "" }, + { "31/03/06", { 31, wxDateTime::Mar, 6 }, true, "" }, + { "31/03/2006", { 31, wxDateTime::Mar, 2006 }, true, "" }, + + // valid, but followed by something + { "Dec 31 1979 was the end of 70s", + { 31, wxDateTime::Dec, 1979 }, true, "was the end of 70s" }, // some invalid ones too { "29 Feb 2006" }, @@ -1255,6 +1280,7 @@ void DateTimeTestCase::TestDateParse() ); CPPUNIT_ASSERT_EQUAL( parseTestDates[n].date.DT(), dt ); + CPPUNIT_ASSERT_EQUAL( wxString(parseTestDates[n].beyondEnd), wxString(end) ); } else // failed to parse { @@ -1357,18 +1383,21 @@ void DateTimeTestCase::TestDateTimeParse() const char *str; Date date; // NB: this should be in UTC bool good; + const char *beyondEnd; // what remains unprocessed of the input } parseTestDates[] = { { "Thu 22 Nov 2007 07:40:00 PM", { 22, wxDateTime::Nov, 2007, 19, 40, 0 }, - true + true, + "" }, { "2010-01-04 14:30", { 4, wxDateTime::Jan, 2010, 14, 30, 0 }, - true + true, + "" }, { @@ -1381,15 +1410,33 @@ void DateTimeTestCase::TestDateTimeParse() { "bloordyblop", { 1, wxDateTime::Jan, 9999, 0, 0, 0}, - false + false, + "bloordyblop" + }, + + { + "2022-03-09 19:12:05 and some text after space", + { 9, wxDateTime::Mar, 2022, 19, 12, 5, -1 }, + true, + " and some text after space" + }, + + { + // something other than a space right after time + "2022-03-09 19:12:05AAaaaa", + { 9, wxDateTime::Mar, 2022, 19, 12, 5, -1 }, + true, + "AAaaaa" }, { "2012-01-01 10:12:05 +0100", { 1, wxDateTime::Jan, 2012, 10, 12, 5, -1 }, - true // ParseDateTime does know yet +0100, but - // ignoring that, parsing still succeeds + true, // ParseDateTime does know yet +0100, but + // ignoring that, parsing still succeeds + " +0100" }, + }; wxGCC_WARNING_RESTORE(missing-field-initializers) @@ -1412,6 +1459,7 @@ void DateTimeTestCase::TestDateTimeParse() ); CPPUNIT_ASSERT_EQUAL( parseTestDates[n].date.DT(), dt ); + CPPUNIT_ASSERT_EQUAL( wxString(parseTestDates[n].beyondEnd), wxString(end) ); } else // failed to parse { From 700d763ebc1afa89b752d63e12a5f61c890766bb Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Fri, 18 Mar 2022 19:15:02 +0200 Subject: [PATCH 3/5] Test ParseDate() with dates containing a weekday Test both a weekday that matches the date, and one that does not. --- tests/datetime/datetimetest.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 5e490b590b..ba44a83646 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -1247,6 +1247,8 @@ void DateTimeTestCase::TestDateParse() { "Feb 29 1976", { 29, wxDateTime::Feb, 1976 }, true, "" }, { "31/03/06", { 31, wxDateTime::Mar, 6 }, true, "" }, { "31/03/2006", { 31, wxDateTime::Mar, 2006 }, true, "" }, + { "Thu 20 Jun 2019", { 20, wxDateTime::Jun, 2019 }, true, "" }, + { "20 Jun 2019 Thu", { 20, wxDateTime::Jun, 2019 }, true, "" }, // valid, but followed by something { "Dec 31 1979 was the end of 70s", @@ -1255,6 +1257,8 @@ void DateTimeTestCase::TestDateParse() // some invalid ones too { "29 Feb 2006" }, { "31/04/06" }, + { "Sat 20 Jun 2019" }, // it was not a Saturday + { "20 Jun 2019 Sat" }, // it was not a Saturday { "bloordyblop" }, { "2 . . " }, { "14:30:15" }, From 945738042df5b11262ba16a236ef5b5f14b29fdf Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Fri, 18 Mar 2022 19:39:22 +0200 Subject: [PATCH 4/5] Fix ParseDate() for dates having day expressed as an ordinal Previously the year was left unparsed, and the current year was incorrectly used even when the input provided a year. --- src/common/datetimefmt.cpp | 4 ++-- tests/datetime/datetimetest.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/datetimefmt.cpp b/src/common/datetimefmt.cpp index 79993651cd..80682b5788 100644 --- a/src/common/datetimefmt.cpp +++ b/src/common/datetimefmt.cpp @@ -2033,9 +2033,9 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) { const wxString ord = wxGetTranslation(ordinals[n]); const size_t len = ord.length(); - if ( date.compare(p - pBegin, len, ord) == 0 ) + if ( date.compare(pCopy - pBegin, len, ord) == 0 ) { - p += len; + pCopy += len; break; } } diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index ba44a83646..7bf249d548 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -1249,6 +1249,7 @@ void DateTimeTestCase::TestDateParse() { "31/03/2006", { 31, wxDateTime::Mar, 2006 }, true, "" }, { "Thu 20 Jun 2019", { 20, wxDateTime::Jun, 2019 }, true, "" }, { "20 Jun 2019 Thu", { 20, wxDateTime::Jun, 2019 }, true, "" }, + { "Dec sixth 2017", { 6, wxDateTime::Dec, 2017 }, true, "" }, // valid, but followed by something { "Dec 31 1979 was the end of 70s", From 088e643d370d55c45bb796e75883efde60ce6734 Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Fri, 18 Mar 2022 15:01:17 +0200 Subject: [PATCH 5/5] Do not consume whitespace/delimiters after date in DateParse() Set the end iterator to the end of the actually parsed date, instead of consuming any ultimately unparsed whitespace/delimiters possibly following the date. --- src/common/datetimefmt.cpp | 16 +++++++++------- tests/datetime/datetimetest.cpp | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/common/datetimefmt.cpp b/src/common/datetimefmt.cpp index 80682b5788..9da429c7c8 100644 --- a/src/common/datetimefmt.cpp +++ b/src/common/datetimefmt.cpp @@ -1866,17 +1866,19 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) // tokenize the string while ( p != pEnd ) { - // skip white space and date delimiters - if ( wxStrchr(".,/-\t\r\n ", *p) ) - { - ++p; - continue; - } - // modify copy of the iterator as we're not sure if the next token is // still part of the date at all wxString::const_iterator pCopy = p; + // skip white space and date delimiters + while ( pCopy != pEnd && wxStrchr(".,/-\t\r\n ", *pCopy) ) + { + ++pCopy; + } + + if ( pCopy == pEnd ) + break; + // we can have either alphabetic or numeric token, start by testing if // it's the latter unsigned long val; diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 7bf249d548..6104d975fe 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -1253,7 +1253,7 @@ void DateTimeTestCase::TestDateParse() // valid, but followed by something { "Dec 31 1979 was the end of 70s", - { 31, wxDateTime::Dec, 1979 }, true, "was the end of 70s" }, + { 31, wxDateTime::Dec, 1979 }, true, " was the end of 70s" }, // some invalid ones too { "29 Feb 2006" },