[california] Don't treat unadorned 3 or 4-digit nums as 24-hour time: Bug #734750



commit f594a822d2d7b4f6f090131a2099ee34dfd9c922
Author: Jim Nelson <jim yorba org>
Date:   Thu Aug 14 18:01:37 2014 -0700

    Don't treat unadorned 3 or 4-digit nums as 24-hour time: Bug #734750
    
    Allowing for "1900" to be treated as 7pm meant things like street
    numbers would be treated as time.

 src/calendar/calendar-wall-time.vala        |    6 +++
 src/component/component-details-parser.vala |   13 +++---
 src/tests/tests-quick-add.vala              |   55 ++++++++++++++++++++++++++-
 3 files changed, 66 insertions(+), 8 deletions(-)
---
diff --git a/src/calendar/calendar-wall-time.vala b/src/calendar/calendar-wall-time.vala
index c68d5c2..aaa8494 100644
--- a/src/calendar/calendar-wall-time.vala
+++ b/src/calendar/calendar-wall-time.vala
@@ -168,6 +168,7 @@ public class WallTime : BaseObject, Gee.Comparable<WallTime>, Gee.Hashable<WallT
         }
         
         // remove colon (can be present for 12- or 24-hour time)
+        bool has_colon = token.index_of(":") > 0;
         token = token.replace(":", "");
         int length = token.length;
         
@@ -177,6 +178,11 @@ public class WallTime : BaseObject, Gee.Comparable<WallTime>, Gee.Hashable<WallT
         
         // look for 24-hour time or a fully-detailed 12-hour time
         if ((length == 3 || length == 4)) {
+            // 3- and 4-digit time requires colon, otherwise it could be any 3- or 4-digit number
+            // (i.e. a street address)
+            if (!has_colon)
+                return null;
+            
             int h, m;
             if (length == 3) {
                 h = int.parse(token.slice(0, 1));
diff --git a/src/component/component-details-parser.vala b/src/component/component-details-parser.vala
index 6fa28f8..bda7631 100644
--- a/src/component/component-details-parser.vala
+++ b/src/component/component-details-parser.vala
@@ -220,7 +220,8 @@ public class DetailsParser : BaseObject {
                 continue;
             stack.restore();
             
-            // attempt to (strictly) parse into wall-clock time
+            // attempt to parse into wall-clock time, strictly if adding location (to prevent street
+            // numbers from being interpreted as 24-hour time)
             stack.mark();
             if (parse_time(token, true))
                 continue;
@@ -369,8 +370,9 @@ public class DetailsParser : BaseObject {
         if (date != null && add_date(date))
             return true;
         
-        // store locally so it can be modified w/o risk (tokens may be reused)
-        string specifier_casefolded = specifier.casefolded;
+        // store locally so it can be modified w/o risk (tokens may be reused) ... don't use
+        // casefolded because important punctuation has been stripped
+        string specifier_string = specifier.original;
         
         // if meridiem found in next token, append to specifier for WallTime.parse()
         bool found_meridiem = false;
@@ -379,7 +381,7 @@ public class DetailsParser : BaseObject {
             Token? meridiem = stack.pop();
             if (meridiem != null
                 && (meridiem.casefolded == Calendar.FMT_AM.casefold() || meridiem.casefolded == 
Calendar.FMT_PM.casefold())) {
-                specifier_casefolded += meridiem.casefolded;
+                specifier_string += meridiem.casefolded;
                 found_meridiem = true;
             }
         }
@@ -389,8 +391,7 @@ public class DetailsParser : BaseObject {
             stack.restore();
         
         bool strictly_parsed;
-        Calendar.WallTime? wall_time = Calendar.WallTime.parse(specifier_casefolded,
-            out strictly_parsed);
+        Calendar.WallTime? wall_time = Calendar.WallTime.parse(specifier_string, out strictly_parsed);
         if (wall_time != null && !strictly_parsed && strict)
             return false;
         
diff --git a/src/tests/tests-quick-add.vala b/src/tests/tests-quick-add.vala
index 193e62a..19efdce 100644
--- a/src/tests/tests-quick-add.vala
+++ b/src/tests/tests-quick-add.vala
@@ -18,6 +18,7 @@ private class QuickAdd : UnitTest.Harness {
         add_case("valid-no-summary", valid_no_summary);
         add_case("with-12hr-time", with_12hr_time);
         add_case("with-24hr-time", with_24hr_time);
+        add_case("with-24hr-time-no-preposition", with_24hr_time_no_preposition);
         add_case("with-day-of-week", with_day_of_week);
         add_case("with-delay", with_delay);
         add_case("with-duration", with_duration);
@@ -46,6 +47,9 @@ private class QuickAdd : UnitTest.Harness {
         add_case("numeric-dot", numeric_dot);
         add_case("numeric-dash", numeric_dash);
         add_case("numeric-leading-zeros", numeric_leading_zeroes);
+        add_case("street-address_3", street_address_3);
+        add_case("street-address_3a", street_address_3a);
+        add_case("street-address_4", street_address_4);
     }
     
     protected override void setup() throws Error {
@@ -130,16 +134,22 @@ private class QuickAdd : UnitTest.Harness {
     }
     
     private bool with_24hr_time() throws Error {
-        return with_time(new Component.DetailsParser("dinner at 1900 with Alice", null));
+        return with_time(new Component.DetailsParser("dinner at 19:00 with Alice", null));
     }
     
-    private bool with_time(Component.DetailsParser parser) {
+    private bool with_24hr_time_no_preposition(out string? dump) throws Error {
+        return with_time(new Component.DetailsParser("19:00 dinner with Alice", null), out dump);
+    }
+    
+    private bool with_time(Component.DetailsParser parser, out string? dump = null) {
         Calendar.ExactTime time = new Calendar.ExactTime(
             Calendar.System.timezone,
             Calendar.System.today,
             new Calendar.WallTime(19, 0, 0)
         );
         
+        dump = parser.event.source;
+        
         return parser.event.summary == "dinner with Alice"
             && parser.event.location == null
             && parser.event.exact_time_span.start_exact_time.equal_to(time)
@@ -525,6 +535,47 @@ private class QuickAdd : UnitTest.Harness {
             && parser.event.date_span.start_date.day_of_month.value == 2
             && parser.event.date_span.start_date.year.value == 2014;
     }
+    
+    private bool street_address_3(out string? dump) throws Error {
+        Component.DetailsParser parser = new Component.DetailsParser(
+            "6:30pm Alice at Burrito Shack, 450 Main", null);
+        
+        dump = parser.event.source;
+        
+        return parser.event.summary == "Alice at Burrito Shack, 450 Main"
+            && parser.event.location == "Burrito Shack, 450 Main"
+            && !parser.event.is_all_day
+            && parser.event.exact_time_span.start_exact_time.hour == 18
+            && parser.event.exact_time_span.start_exact_time.minute == 30;
+    }
+    
+    private bool street_address_3a(out string? dump) throws Error {
+        Component.DetailsParser parser = new Component.DetailsParser(
+            "Friday 6:30pm meet eric at 431 natoma", null);
+        
+        dump = parser.event.source;
+        
+        return parser.event.summary == "meet eric at 431 natoma"
+            && parser.event.location == "431 natoma"
+            && !parser.event.is_all_day
+            && parser.event.exact_time_span.start_exact_time.hour == 18
+            && parser.event.exact_time_span.start_exact_time.minute == 30
+            && parser.event.exact_time_span.start_date.day_of_week == Calendar.DayOfWeek.FRI
+            && parser.event.exact_time_span.duration.hours == 1;
+    }
+    
+    private bool street_address_4(out string? dump) throws Error {
+        Component.DetailsParser parser = new Component.DetailsParser(
+            "6:30pm Alice at Burrito Shack, 1235 Main", null);
+        
+        dump = parser.event.source;
+        
+        return parser.event.summary == "Alice at Burrito Shack, 1235 Main"
+            && parser.event.location == "Burrito Shack, 1235 Main"
+            && !parser.event.is_all_day
+            && parser.event.exact_time_span.start_exact_time.hour == 18
+            && parser.event.exact_time_span.start_exact_time.minute == 30;
+    }
 }
 
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]