Home | History | Annotate | Download | only in calendar
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.calendar;
     18 
     19 import com.android.calendar.Utils;
     20 import com.android.calendar.CalendarUtils.TimeZoneUtils;
     21 
     22 import android.content.Context;
     23 import android.content.res.Configuration;
     24 import android.content.res.Resources;
     25 import android.content.res.Resources.NotFoundException;
     26 import android.database.MatrixCursor;
     27 import android.provider.CalendarContract.CalendarCache;
     28 import android.test.mock.MockResources;
     29 import android.test.suitebuilder.annotation.SmallTest;
     30 import android.test.suitebuilder.annotation.Smoke;
     31 import android.text.Spannable;
     32 import android.text.SpannableString;
     33 import android.text.format.Time;
     34 import android.text.style.URLSpan;
     35 import android.util.DisplayMetrics;
     36 import android.util.Log;
     37 import android.view.Display;
     38 import android.view.View;
     39 import android.view.WindowManager;
     40 import android.view.ViewGroup.LayoutParams;
     41 import android.widget.TextView;
     42 
     43 import java.util.ArrayList;
     44 import java.util.Arrays;
     45 import java.util.HashMap;
     46 import java.util.Iterator;
     47 import java.util.Locale;
     48 
     49 import junit.framework.TestCase;
     50 
     51 /**
     52  * Test class for verifying helper functions in Calendar's Utils
     53  *
     54  * You can run these tests with the following command:
     55  * "adb shell am instrument -w -e class com.android.calendar.UtilsTests
     56  *          com.android.calendar.tests/android.test.InstrumentationTestRunner"
     57  */
     58 public class UtilsTests extends TestCase {
     59     HashMap<String, Boolean> mIsDuplicateName;
     60     HashMap<String, Boolean> mIsDuplicateNameExpected;
     61     MatrixCursor mDuplicateNameCursor;
     62     private DbTestUtils dbUtils;
     63     private final TimeZoneUtils timezoneUtils = new TimeZoneUtils(Utils.SHARED_PREFS_NAME);
     64 
     65     private static final int NAME_COLUMN = 0;
     66     private static final String[] DUPLICATE_NAME_COLUMNS = new String[] { "name" };
     67     private static final String[][] DUPLICATE_NAMES = new String[][] {
     68         {"Pepper Pots"},
     69         {"Green Goblin"},
     70         {"Pepper Pots"},
     71         {"Peter Parker"},
     72         {"Silver Surfer"},
     73         {"John Jameson"},
     74         {"John Jameson"},
     75         {"Pepper Pots"}
     76     };
     77     // First date is Thursday, Jan 1st, 1970.
     78     private static final int[] JULIAN_DAYS = {2440588, 2440589, 2440590, 2440591, 2440592, 2440593,
     79             2440594, 2440595, 2440596, 2440597, 2440598, 2440599, 2440600, 2440601
     80     };
     81     private static final int[] EXPECTED_WEEK_MONDAY_START = {
     82             0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 };
     83     private static final int[] EXPECTED_WEEK_SUNDAY_START = {
     84             0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 };
     85     private static final int[] EXPECTED_WEEK_SATURDAY_START = {
     86             0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
     87     private static final int[] WEEKS_FOR_JULIAN_MONDAYS = {1, 2};
     88     private static final int[] EXPECTED_JULIAN_MONDAYS = {2440592, 2440599};
     89 
     90     private static final int NOW_MONTH = 3; // April
     91     private static final int NOW_DAY = 10;
     92     private static final int NOW_YEAR = 2012;
     93     private static final long NOW_TIME = createTimeInMillis(5, 5, 5, NOW_DAY, NOW_MONTH, NOW_YEAR);
     94     private static final String DEFAULT_TIMEZONE = Time.getCurrentTimezone();
     95 
     96     /**
     97      * Mock resources.  Add translation strings for test here.
     98      */
     99     private static class ResourcesForTest extends MockResources {
    100         @Override
    101         public String getString(int id) {
    102             if (id == R.string.today) {
    103                 return "Today";
    104             }
    105             if (id == R.string.tomorrow) {
    106                 return "Tomorrow";
    107             }
    108             throw new IllegalArgumentException("unexpected resource ID: " + id);
    109         }
    110 
    111         @Override
    112         public String getString(int id, Object... formatArgs) {
    113             if (id == R.string.today_at_time_fmt) {
    114                 return String.format("Today at %s", formatArgs);
    115             }
    116             if (id == R.string.tomorrow_at_time_fmt) {
    117                 return String.format("Tomorrow at %s", formatArgs);
    118             }
    119             if (id == R.string.date_time_fmt) {
    120                 return String.format("%s, %s", formatArgs);
    121             }
    122             throw new IllegalArgumentException("unexpected resource ID: " + id);
    123         }
    124 
    125         @Override
    126         public Configuration getConfiguration() {
    127             Configuration config = new Configuration();
    128             config.locale = Locale.getDefault();
    129             return config;
    130         }
    131 
    132         @Override
    133         public DisplayMetrics getDisplayMetrics(){
    134             DisplayMetrics metrics = new DisplayMetrics();
    135             metrics.density = 2.0f;
    136             return metrics;
    137         }
    138     }
    139 
    140     private static long createTimeInMillis(int second, int minute, int hour, int monthDay,
    141             int month, int year) {
    142         return createTimeInMillis(second, minute, hour, monthDay, month, year,
    143                 Time.getCurrentTimezone());
    144     }
    145 
    146     private static long createTimeInMillis(int second, int minute, int hour, int monthDay,
    147             int month, int year, String timezone) {
    148         Time t = new Time(timezone);
    149         t.set(second, minute, hour, monthDay, month, year);
    150         t.normalize(false);
    151         return t.toMillis(false);
    152     }
    153 
    154     private void setTimezone(String tz) {
    155         timezoneUtils.setTimeZone(dbUtils.getContext(), tz);
    156     }
    157 
    158     @Override
    159     public void setUp() {
    160         mIsDuplicateName = new HashMap<String, Boolean> ();
    161         mDuplicateNameCursor = new MatrixCursor(DUPLICATE_NAME_COLUMNS);
    162         for (int i = 0; i < DUPLICATE_NAMES.length; i++) {
    163             mDuplicateNameCursor.addRow(DUPLICATE_NAMES[i]);
    164         }
    165 
    166         mIsDuplicateNameExpected = new HashMap<String, Boolean> ();
    167         mIsDuplicateNameExpected.put("Pepper Pots", true);
    168         mIsDuplicateNameExpected.put("Green Goblin", false);
    169         mIsDuplicateNameExpected.put("Peter Parker", false);
    170         mIsDuplicateNameExpected.put("Silver Surfer", false);
    171         mIsDuplicateNameExpected.put("John Jameson", true);
    172 
    173         // Set up fake db.
    174         dbUtils = new DbTestUtils(new ResourcesForTest());
    175         dbUtils.getContentResolver().addProvider("settings", dbUtils.getContentProvider());
    176         dbUtils.getContentResolver().addProvider(CalendarCache.URI.getAuthority(),
    177                 dbUtils.getContentProvider());
    178 
    179         setTimezone(DEFAULT_TIMEZONE);
    180     }
    181 
    182     @Override
    183     public void tearDown() {
    184         mDuplicateNameCursor.close();
    185 
    186         // Must reset the timezone here, because even though the fake provider will be
    187         // recreated/cleared, TimeZoneUtils statically holds on to a cached value.
    188         setTimezone(Time.getCurrentTimezone());
    189     }
    190 
    191     @Smoke
    192     @SmallTest
    193     public void testCheckForDuplicateNames() {
    194         Utils.checkForDuplicateNames(mIsDuplicateName, mDuplicateNameCursor, NAME_COLUMN);
    195         assertEquals(mIsDuplicateNameExpected, mIsDuplicateName);
    196     }
    197 
    198     @Smoke
    199     @SmallTest
    200     public void testGetWeeksSinceEpochFromJulianDay() {
    201         for (int i = 0; i < JULIAN_DAYS.length; i++) {
    202             assertEquals(EXPECTED_WEEK_MONDAY_START[i],
    203                     Utils.getWeeksSinceEpochFromJulianDay(JULIAN_DAYS[i], Time.MONDAY));
    204             assertEquals(EXPECTED_WEEK_SUNDAY_START[i],
    205                     Utils.getWeeksSinceEpochFromJulianDay(JULIAN_DAYS[i], Time.SUNDAY));
    206             assertEquals(EXPECTED_WEEK_SATURDAY_START[i],
    207                     Utils.getWeeksSinceEpochFromJulianDay(JULIAN_DAYS[i], Time.SATURDAY));
    208         }
    209     }
    210 
    211     @Smoke
    212     @SmallTest
    213     public void testGetJulianMondayFromWeeksSinceEpoch() {
    214         for (int i = 0; i < WEEKS_FOR_JULIAN_MONDAYS.length; i++) {
    215             assertEquals(EXPECTED_JULIAN_MONDAYS[i],
    216                     Utils.getJulianMondayFromWeeksSinceEpoch(WEEKS_FOR_JULIAN_MONDAYS[i]));
    217         }
    218     }
    219 
    220     @Smoke
    221     @SmallTest
    222     public void testEquals() {
    223         assertTrue(Utils.equals(null, null));
    224         assertFalse(Utils.equals("", null));
    225         assertFalse(Utils.equals(null, ""));
    226         assertTrue(Utils.equals("",""));
    227 
    228         Integer int1 = new Integer(1);
    229         Integer int2 = new Integer(1);
    230         assertTrue(Utils.equals(int1, int2));
    231     }
    232 
    233 
    234     // Helper function to create test events for BusyBits testing
    235     Event buildTestEvent(int startTime, int endTime, boolean allDay, int startDay, int endDay) {
    236         Event e = new Event();
    237         e.startTime = startTime;
    238         e.endTime = endTime;
    239         e.allDay = allDay;
    240         e.startDay = startDay;
    241         e.endDay = endDay;
    242         e.startMillis = e.startDay * 1000L * 3600L * 24L + e.startTime * 60L * 1000L;
    243         e.endMillis = e.endDay * 1000L * 3600L * 24L + e.endTime * 60L * 1000L;
    244         return e;
    245     }
    246 
    247     @Smoke
    248     @SmallTest
    249     public void testCreateBusyBitSegments() {
    250 
    251   /*      ArrayList<Event> events = new ArrayList<Event>();
    252 
    253         // Test cases that should return null
    254         // Empty events list
    255         assertEquals(null, Utils.createBusyBitSegments(10, 30, 100, 200, 0, events));
    256         // No events list
    257         assertEquals(null, Utils.createBusyBitSegments(10, 30, 100, 200, 0, null));
    258 
    259         events.add(buildTestEvent(100, 130, false, 1, 1));
    260         events.add(buildTestEvent(1000, 1030, false, 1, 1));
    261         // Illegal pixel positions
    262         assertEquals(null, Utils.createBusyBitSegments(30, 10, 100, 200, 1, events));
    263         // Illegal start and end times
    264         assertEquals(null, Utils.createBusyBitSegments(10, 30, 200, 100, 1, events));
    265         assertEquals(null, Utils.createBusyBitSegments(10, 30, -10, 100, 1, events));
    266         assertEquals(null, Utils.createBusyBitSegments(10, 30, 24 * 60 + 100, 24 * 60 + 200, 1,
    267                 events));
    268         assertEquals(null, Utils.createBusyBitSegments(10, 30, 200, 24 * 60 + 100, 1, events));
    269         assertEquals(null, Utils.createBusyBitSegments(10, 30, 200, -100, 1, events));
    270         // No Events in time frame
    271         assertEquals(null, Utils.createBusyBitSegments(10, 30, 500, 900, 1, events));
    272 
    273         // Test event that spans over the day
    274         events.clear();
    275         events.add(buildTestEvent(100, 300, false, 1, 5));
    276         ArrayList<BusyBitsSegment> segments = new ArrayList<BusyBitsSegment>();
    277         assertEquals(null, Utils.createBusyBitSegments(0, 250, 200, 1200, 3, events));
    278 
    279         // test zero times events, events that are partially in the time span
    280         // and all day events
    281         events.clear();
    282         events.add(buildTestEvent(100, 300, false, 1, 1));
    283         events.add(buildTestEvent(1100, 1300, false, 1, 1));
    284         events.add(buildTestEvent(500, 600, true, 1, 1));
    285         events.add(buildTestEvent(700, 700, false, 1, 1));
    286         segments.clear();
    287         segments.add(new BusyBitsSegment(0, 10, false));
    288         segments.add(new BusyBitsSegment(90, 100, false));
    289         assertEquals(segments, Utils.createBusyBitSegments(0, 100, 200, 1200, 1, events));
    290 
    291         // Test event that spans over 2 days but start and end time do not
    292         // overlap fully with tested time span
    293 
    294         events.clear();
    295         events.add(buildTestEvent(23 * 60, 120, false, 1, 2));
    296         segments.clear();
    297         segments.add(new BusyBitsSegment(0, 120, false));
    298         assertEquals(segments, Utils.createBusyBitSegments(0, 240, 60, 180, 2, events));
    299 
    300         // Test overlapped events (two draw sizes)
    301         events.clear();
    302         events.add(buildTestEvent(10, 200, false, 1, 1));
    303         events.add(buildTestEvent(150, 250, false, 1, 1));
    304         events.add(buildTestEvent(150, 250, false, 1, 1));
    305         events.add(buildTestEvent(200, 400, false, 1, 1));
    306         events.add(buildTestEvent(500, 700, false, 1, 1));
    307         events.add(buildTestEvent(550, 600, false, 1, 1));
    308         events.add(buildTestEvent(550, 580, false, 1, 1));
    309         events.add(buildTestEvent(560, 570, false, 1, 1));
    310         events.add(buildTestEvent(600, 700, false, 1, 1));
    311         events.add(buildTestEvent(620, 700, false, 1, 1));
    312         events.add(buildTestEvent(650, 700, false, 1, 1));
    313         events.add(buildTestEvent(800, 900, false, 1, 1));
    314         events.add(buildTestEvent(800, 900, false, 1, 1));
    315         events.add(buildTestEvent(800, 850, false, 1, 1));
    316         events.add(buildTestEvent(1000, 1200, false, 1, 1));
    317         events.add(buildTestEvent(1000, 1200, false, 1, 1));
    318         segments.clear();
    319         segments.add(new BusyBitsSegment(100, 149, false));
    320         segments.add(new BusyBitsSegment(150, 250, true));
    321         segments.add(new BusyBitsSegment(251, 400, false));
    322         segments.add(new BusyBitsSegment(500, 549, false));
    323         segments.add(new BusyBitsSegment(550, 700, true));
    324         segments.add(new BusyBitsSegment(800, 900, true));
    325         segments.add(new BusyBitsSegment(1000, 1100, true));
    326         assertEquals(segments, Utils.createBusyBitSegments(100, 1100, 100, 1100, 1, events));
    327         segments.clear();
    328         segments.add(new BusyBitsSegment(100, 111, false));
    329         segments.add(new BusyBitsSegment(112, 137, true));
    330         segments.add(new BusyBitsSegment(138, 175, false));
    331         segments.add(new BusyBitsSegment(200, 211, false));
    332         segments.add(new BusyBitsSegment(212, 250, true));
    333         segments.add(new BusyBitsSegment(275, 300, true));
    334         segments.add(new BusyBitsSegment(325, 350, true));
    335         assertEquals(segments, Utils.createBusyBitSegments(100, 350, 100, 1100, 1, events));
    336 */
    337     }
    338 
    339     /**
    340      * Tests the findNanpPhoneNumbers function.
    341      */
    342     @SmallTest
    343     public void testFindNanpPhoneNumber() {
    344         final String[] NO_NUMBERS = new String[] {};
    345 
    346         findPhoneNumber("", NO_NUMBERS);
    347         findPhoneNumber("               ", NO_NUMBERS);
    348         findPhoneNumber("123", NO_NUMBERS);
    349         findPhoneNumber("how much wood", NO_NUMBERS);
    350         findPhoneNumber("abc1-650-555-1212", NO_NUMBERS);
    351         findPhoneNumber("abc 5551212 def", new String[] { "5551212" });
    352         findPhoneNumber("1234567", NO_NUMBERS);
    353         findPhoneNumber(" 2345678 ", new String[] { "2345678" });
    354         findPhoneNumber("1234567890", NO_NUMBERS);
    355         findPhoneNumber("12345678901", new String[] { "12345678901" });
    356         findPhoneNumber("123456789012", NO_NUMBERS);
    357         findPhoneNumber("+1-555-1212", NO_NUMBERS);
    358         findPhoneNumber("+1 (650) 555-1212", new String[] { "+1 (650) 555-1212" });
    359         findPhoneNumber("(650) 555-1212, (650) 555-1213",
    360                 new String[] { "(650) 555-1212", "(650) 555-1213" });
    361         findPhoneNumber("Call 555-1212, 555-1213 and also 555-1214.",
    362                 new String[] { "555-1212", "555-1213", "555-1214." });
    363         findPhoneNumber("555-1212,555-1213,555-1214", new String[] { "555-1212" });
    364         findPhoneNumber("123 (650) 555-1212", new String[] { "(650) 555-1212" });
    365         findPhoneNumber("1-650-555-1212", new String[] { "1-650-555-1212" });
    366         findPhoneNumber("1650-555-1212", new String[] { "1650-555-1212" });
    367         findPhoneNumber("1650 555-1212", new String[] { "1650 555-1212" });
    368         findPhoneNumber("1650/555-1212", NO_NUMBERS);
    369         findPhoneNumber("1650-555 1212", NO_NUMBERS);
    370         findPhoneNumber("8-650-555-1212", NO_NUMBERS);
    371         findPhoneNumber("8 650-555-1212", new String[] { "650-555-1212" });
    372         findPhoneNumber("650.555.1212", new String[] { "650.555.1212" });
    373         findPhoneNumber(" *#650.555.1212#*!", new String[] { "*#650.555.1212#*" });
    374         findPhoneNumber("555.1212", new String[] { "555.1212" });
    375         findPhoneNumber("6505551212 x123, 555-1212", new String[] { "6505551212", "555-1212" });
    376         findPhoneNumber("6505551212x123", new String[] { "6505551212" });
    377         findPhoneNumber("http://example.com/6505551212/", NO_NUMBERS);
    378         findPhoneNumber("Mountain View, CA 94043 (650) 555-1212", new String[]{ "(650) 555-1212" });
    379         findPhoneNumber("New York, NY 10001-0001", NO_NUMBERS);
    380     }
    381 
    382     /**
    383      * Finds the numbers in a block of text, and checks to see if the positions of the numbers
    384      * match the expected values.
    385      *
    386      * @param text The text to search.
    387      * @param matches Pairs of start/end positions.
    388      */
    389     private static void findPhoneNumber(String text, String[] matches) {
    390         int[] results = Utils.findNanpPhoneNumbers(text);
    391 
    392         assertEquals(0, results.length % 2);
    393 
    394         if (results.length / 2 != matches.length) {
    395             fail("Text '" + text + "': expected " + matches.length
    396                     + " matches, found " + results.length / 2);
    397         }
    398 
    399         for (int i = 0; i < results.length / 2; i++) {
    400             CharSequence seq = text.subSequence(results[i*2], results[i*2 + 1]);
    401             assertEquals(matches[i], seq);
    402         }
    403     }
    404 
    405     /**
    406      * Tests the linkify section of event locations.
    407      */
    408     @SmallTest
    409     public void testExtendedLinkify() {
    410         final URLSpan[] NO_LINKS = new URLSpan[] {};
    411         URLSpan span_tel01 = new URLSpan("tel:6505551234");
    412         URLSpan span_tel02 = new URLSpan("tel:5555678");
    413         URLSpan span_tel03 = new URLSpan("tel:+16505551234");
    414         URLSpan span_tel04 = new URLSpan("tel:16505551234");
    415         URLSpan span_web = new URLSpan("http://www.google.com");
    416         URLSpan span_geo01 =
    417                 new URLSpan("geo:0,0?q=1600+Amphitheatre+Parkway%2C+Mountain+View+CA+94043");
    418         URLSpan span_geo02 =
    419                 new URLSpan("geo:0,0?q=37.422081, -122.084576");
    420         URLSpan span_geo03 =
    421                 new URLSpan("geo:0,0?q=37.422081,-122.084576");
    422         URLSpan span_geo04 =
    423                 new URLSpan("geo:0,0?q=+3725'19.49\", -1225'4.47\"");
    424         URLSpan span_geo05 =
    425                 new URLSpan("geo:0,0?q=3725'19.49\"N, 1225'4.47\"W");
    426         URLSpan span_geo06 =
    427                 new URLSpan("geo:0,0?q=N 37 25' 19.49\",  W 122 5' 4.47\"");
    428         URLSpan span_geo07 = new URLSpan("geo:0,0?q=non-specified address");
    429 
    430 
    431         // First test without the last-ditch geo attempt.
    432         // Phone spans.
    433         findLinks("", NO_LINKS, false);
    434         findLinks("(650) 555-1234", new URLSpan[]{span_tel01}, false);
    435         findLinks("94043", NO_LINKS, false);
    436         findLinks("123456789012", NO_LINKS, false);
    437         findLinks("+1 (650) 555-1234", new URLSpan[]{span_tel03}, false);
    438         findLinks("(650) 555 1234", new URLSpan[]{span_tel01}, false);
    439         findLinks("1-650-555-1234", new URLSpan[]{span_tel04}, false);
    440         findLinks("*#650.555.1234#*!", new URLSpan[]{span_tel01}, false);
    441         findLinks("555.5678", new URLSpan[]{span_tel02}, false);
    442 
    443         // Web spans.
    444         findLinks("http://www.google.com", new URLSpan[]{span_web}, false);
    445 
    446         // Geo spans.
    447         findLinks("1600 Amphitheatre Parkway, Mountain View CA 94043",
    448                 new URLSpan[]{span_geo01}, false);
    449         findLinks("37.422081, -122.084576", new URLSpan[]{span_geo02}, false);
    450         findLinks("37.422081,-122.084576", new URLSpan[]{span_geo03}, false);
    451         findLinks("+3725'19.49\", -1225'4.47\"", new URLSpan[]{span_geo04}, false);
    452         findLinks("3725'19.49\"N, 1225'4.47\"W", new URLSpan[]{span_geo05}, false);
    453         findLinks("N 37 25' 19.49\",  W 122 5' 4.47\"", new URLSpan[]{span_geo06}, false);
    454 
    455         // Multiple spans.
    456         findLinks("(650) 555-1234 1600 Amphitheatre Parkway, Mountain View CA 94043",
    457                 new URLSpan[]{span_tel01, span_geo01}, false);
    458         findLinks("(650) 555-1234, 555-5678", new URLSpan[]{span_tel01, span_tel02}, false);
    459 
    460 
    461         // Now test using the last-ditch geo attempt.
    462         findLinks("", NO_LINKS, true);
    463         findLinks("(650) 555-1234", new URLSpan[]{span_tel01}, true);
    464         findLinks("http://www.google.com", new URLSpan[]{span_web}, true);
    465         findLinks("1600 Amphitheatre Parkway, Mountain View CA 94043",
    466                 new URLSpan[]{span_geo01}, true);
    467         findLinks("37.422081, -122.084576", new URLSpan[]{span_geo02}, true);
    468         findLinks("37.422081,-122.084576", new URLSpan[]{span_geo03}, true);
    469         findLinks("+3725'19.49\", -1225'4.47\"", new URLSpan[]{span_geo04}, true);
    470         findLinks("3725'19.49\"N, 1225'4.47\"W", new URLSpan[]{span_geo05}, true);
    471         findLinks("N 37 25' 19.49\",  W 122 5' 4.47\"", new URLSpan[]{span_geo06}, true);
    472         findLinks("non-specified address", new URLSpan[]{span_geo07}, true);
    473     }
    474 
    475     private static void findLinks(String text, URLSpan[] matches, boolean lastDitchGeo) {
    476         Spannable spanText = Utils.extendedLinkify(text, lastDitchGeo);
    477         URLSpan[] spansFound = spanText.getSpans(0, spanText.length(), URLSpan.class);
    478         assertEquals(matches.length, spansFound.length);
    479 
    480         // Make sure the expected matches list of URLs is the same as that returned by linkify.
    481         ArrayList<URLSpan> matchesArrayList = new ArrayList<URLSpan>(Arrays.asList(matches));
    482         for (URLSpan spanFound : spansFound) {
    483             Iterator<URLSpan> matchesIt = matchesArrayList.iterator();
    484             boolean removed = false;
    485             while (matchesIt.hasNext()) {
    486                 URLSpan match = matchesIt.next();
    487                 if (match.getURL().equals(spanFound.getURL())) {
    488                     matchesIt.remove();
    489                     removed = true;
    490                     break;
    491                 }
    492             }
    493             if (!removed) {
    494                 // If a match was not found for the current spanFound, the lists aren't equal.
    495                 fail("No match found for span: "+spanFound.getURL());
    496             }
    497         }
    498 
    499         // As a sanity check, ensure the matches list is empty, as each item should have been
    500         // removed by going through the spans returned by linkify.
    501         assertTrue(matchesArrayList.isEmpty());
    502     }
    503 
    504     @SmallTest
    505     public void testGetDisplayedDatetime_differentYear() {
    506         // 4/12/2000 5pm - 4/12/2000 6pm
    507         long start = createTimeInMillis(0, 0, 17, 12, 3, 2000);
    508         long end = createTimeInMillis(0, 0, 18, 12, 3, 2000);
    509         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    510                 false, dbUtils.getContext());
    511         assertEquals("Wednesday, April 12, 2000, 5:00PM \u2013 6:00PM", result);
    512 
    513         // 12/31/2012 5pm - 1/1/2013 6pm
    514         start = createTimeInMillis(0, 0, 17, 31, 11, 2012);
    515         end = createTimeInMillis(0, 0, 18, 1, 0, 2013);
    516         result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    517                 false, dbUtils.getContext());
    518         assertEquals("Mon, Dec 31, 2012, 5:00PM  Tue, Jan 1, 2013, 6:00PM", result);
    519     }
    520 
    521     @SmallTest
    522     public void testGetDisplayedDatetime_sameYear() {
    523         // 4/12/2012 5pm - 4/12/2012 6pm
    524         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012);
    525         long end = createTimeInMillis(0, 0, 18, 12, 3, 2012);
    526         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    527                 false, dbUtils.getContext());
    528         assertEquals("Thursday, April 12, 2012, 5:00PM \u2013 6:00PM", result);
    529     }
    530 
    531     @SmallTest
    532     public void testGetDisplayedDatetime_today() {
    533         // 4/10/2012 5pm - 4/10/2012 6pm
    534         long start = createTimeInMillis(0, 0, 17, NOW_DAY, NOW_MONTH, NOW_YEAR);
    535         long end = createTimeInMillis(0, 0, 18, NOW_DAY, NOW_MONTH, NOW_YEAR);
    536         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    537                 false, dbUtils.getContext());
    538         assertEquals("Today at 5:00PM \u2013 6:00PM", result);
    539     }
    540 
    541     @SmallTest
    542     public void testGetDisplayedDatetime_todayMidnight() {
    543         // 4/10/2012 5pm - 4/11/2012 12am
    544         long start = createTimeInMillis(0, 0, 17, NOW_DAY, NOW_MONTH, NOW_YEAR);
    545         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
    546         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    547                 false, dbUtils.getContext());
    548         assertEquals("Today at 5:00PM \u2013 midnight", result);
    549     }
    550 
    551     @SmallTest
    552     public void testGetDisplayedDatetime_tomorrow() {
    553         // 4/11/2012 12:01AM - 4/11/2012 11:59pm
    554         long start = createTimeInMillis(0, 1, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
    555         long end = createTimeInMillis(0, 59, 23, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
    556         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    557                 false, dbUtils.getContext());
    558         assertEquals("Tomorrow at 12:01AM \u2013 11:59PM", result);
    559     }
    560 
    561     @SmallTest
    562     public void testGetDisplayedDatetime_yesterday() {
    563         // 4/9/2012 5pm - 4/9/2012 6pm
    564         long start = createTimeInMillis(0, 0, 17, 9, 3, 2012);
    565         long end = createTimeInMillis(0, 0, 18, 9, 3, 2012);
    566         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    567                 false, dbUtils.getContext());
    568         assertEquals("Monday, April 9, 2012, 5:00PM \u2013 6:00PM", result);
    569     }
    570 
    571     @SmallTest
    572     public void testGetDisplayedDatetime_multiDay() {
    573         // 4/10/2012 12:01AM - 4/11/2012 12:01AM
    574         long start = createTimeInMillis(0, 1, 0, NOW_DAY, NOW_MONTH, NOW_YEAR);
    575         long end = createTimeInMillis(0, 1, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
    576         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    577                 false, dbUtils.getContext());
    578         assertEquals("Tue, Apr 10, 2012, 12:01AM \u2013 Wed, Apr 11, 2012, 12:01AM", result);
    579     }
    580 
    581     @SmallTest
    582     public void testGetDisplayedDatetime_allDay() {
    583         // 4/2/2012 12:00AM - 4/3/2012 12:00AM
    584         long start = createTimeInMillis(0, 0, 0, 2, 3, NOW_YEAR, Time.TIMEZONE_UTC);
    585         long end = createTimeInMillis(0, 0, 0, 3, 3, NOW_YEAR, Time.TIMEZONE_UTC);
    586         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    587                 true, dbUtils.getContext());
    588         assertEquals("Monday, April 2, 2012", result);
    589     }
    590 
    591     @SmallTest
    592     public void testGetDisplayedDatetime_allDayToday() {
    593         // 4/10/2012 12:00AM - 4/11/2012 12:00AM
    594         long start = createTimeInMillis(0, 0, 0, NOW_DAY, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
    595         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
    596         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    597                 true, dbUtils.getContext());
    598         assertEquals("Today", result);
    599     }
    600 
    601     @SmallTest
    602     public void testGetDisplayedDatetime_allDayMultiday() {
    603         // 4/10/2012 12:00AM - 4/13/2012 12:00AM
    604         long start = createTimeInMillis(0, 0, 0, NOW_DAY, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
    605         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 3, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
    606         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
    607                 true, dbUtils.getContext());
    608         assertEquals("Tuesday, April 10, 2012 \u2013 Thursday, April 12, 2012", result);
    609     }
    610 
    611     @SmallTest
    612     public void testGetDisplayedDatetime_differentTimezone() {
    613         String localTz = "America/New_York";
    614         String eventTz = "America/Los_Angeles";
    615         setTimezone(localTz);
    616 
    617         // 4/12/2012 5pm - 4/12/2012 6pm (Pacific)
    618         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012, eventTz);
    619         long end = createTimeInMillis(0, 0, 18, 12, 3, 2012, eventTz);
    620         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, false,
    621                 dbUtils.getContext());
    622         assertEquals("Thursday, April 12, 2012, 8:00PM \u2013 9:00PM", result);
    623     }
    624 
    625     @SmallTest
    626     public void testGetDisplayedDatetime_allDayDiffTimezone() {
    627         String localTz = "America/New_York";
    628         setTimezone(localTz);
    629 
    630         // 4/2/2012 12:00AM - 4/3/2012 12:00AM
    631         long start = createTimeInMillis(0, 0, 0, 2, 3, NOW_YEAR, Time.TIMEZONE_UTC);
    632         long end = createTimeInMillis(0, 0, 0, 3, 3, NOW_YEAR, Time.TIMEZONE_UTC);
    633         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, true,
    634                 dbUtils.getContext());
    635         assertEquals("Monday, April 2, 2012", result);
    636     }
    637 
    638     @SmallTest
    639     public void testGetDisplayedDatetime_allDayTomorrowDiffTimezone() {
    640         String localTz = "America/New_York";
    641         setTimezone(localTz);
    642 
    643         // 4/2/2012 12:00AM - 4/3/2012 12:00AM
    644         long start = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR,
    645                 Time.TIMEZONE_UTC);
    646         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 2, NOW_MONTH, NOW_YEAR,
    647                 Time.TIMEZONE_UTC);
    648         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, true,
    649                 dbUtils.getContext());
    650         assertEquals("Tomorrow", result);
    651     }
    652 
    653     // TODO: add tests for army time.
    654 
    655     @SmallTest
    656     public void testGetDisplayedTimezone_sameTimezone() {
    657         String localTz = "America/New_York";
    658         setTimezone(localTz);
    659 
    660         // 4/12/2012 5pm
    661         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012, localTz);
    662         assertNull(Utils.getDisplayedTimezone(start, localTz, localTz));
    663     }
    664 
    665     @SmallTest
    666     public void testGetDisplayedTimezone_differentTimezone() {
    667         String localTz = "America/New_York";
    668         String eventTz = "America/Los_Angeles";
    669         setTimezone(localTz);
    670 
    671         // 1/12/2012 5pm (not daylight savings)
    672         long start = createTimeInMillis(0, 0, 17, 12, 0, 2012, eventTz);
    673         assertEquals("EST", Utils.getDisplayedTimezone(start, localTz, eventTz));
    674     }
    675 
    676     @SmallTest
    677     public void testGetDisplayedTimezone_differentTimezoneDst() {
    678         String localTz = "America/New_York";
    679         String eventTz = "America/Los_Angeles";
    680         setTimezone(localTz);
    681 
    682         // 4/12/2012 5pm (daylight savings)
    683         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012, eventTz);
    684         assertEquals("EDT", Utils.getDisplayedTimezone(start, localTz, eventTz));
    685     }
    686 }
    687