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
getString(int id)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
getString(int id, Object... formatArgs)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
getConfiguration()126         public Configuration getConfiguration() {
127             Configuration config = new Configuration();
128             config.locale = Locale.getDefault();
129             return config;
130         }
131 
132         @Override
getDisplayMetrics()133         public DisplayMetrics getDisplayMetrics(){
134             DisplayMetrics metrics = new DisplayMetrics();
135             metrics.density = 2.0f;
136             return metrics;
137         }
138     }
139 
createTimeInMillis(int second, int minute, int hour, int monthDay, int month, int year)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 
createTimeInMillis(int second, int minute, int hour, int monthDay, int month, int year, String timezone)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 
setTimezone(String tz)154     private void setTimezone(String tz) {
155         timezoneUtils.setTimeZone(dbUtils.getContext(), tz);
156     }
157 
158     @Override
setUp()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
tearDown()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
testGetWeeksSinceEpochFromJulianDay()193     public void testGetWeeksSinceEpochFromJulianDay() {
194         for (int i = 0; i < JULIAN_DAYS.length; i++) {
195             assertEquals(EXPECTED_WEEK_MONDAY_START[i],
196                     Utils.getWeeksSinceEpochFromJulianDay(JULIAN_DAYS[i], Time.MONDAY));
197             assertEquals(EXPECTED_WEEK_SUNDAY_START[i],
198                     Utils.getWeeksSinceEpochFromJulianDay(JULIAN_DAYS[i], Time.SUNDAY));
199             assertEquals(EXPECTED_WEEK_SATURDAY_START[i],
200                     Utils.getWeeksSinceEpochFromJulianDay(JULIAN_DAYS[i], Time.SATURDAY));
201         }
202     }
203 
204     @Smoke
205     @SmallTest
testGetJulianMondayFromWeeksSinceEpoch()206     public void testGetJulianMondayFromWeeksSinceEpoch() {
207         for (int i = 0; i < WEEKS_FOR_JULIAN_MONDAYS.length; i++) {
208             assertEquals(EXPECTED_JULIAN_MONDAYS[i],
209                     Utils.getJulianMondayFromWeeksSinceEpoch(WEEKS_FOR_JULIAN_MONDAYS[i]));
210         }
211     }
212 
213     // Helper function to create test events for BusyBits testing
buildTestEvent(int startTime, int endTime, boolean allDay, int startDay, int endDay)214     Event buildTestEvent(int startTime, int endTime, boolean allDay, int startDay, int endDay) {
215         Event e = new Event();
216         e.startTime = startTime;
217         e.endTime = endTime;
218         e.allDay = allDay;
219         e.startDay = startDay;
220         e.endDay = endDay;
221         e.startMillis = e.startDay * 1000L * 3600L * 24L + e.startTime * 60L * 1000L;
222         e.endMillis = e.endDay * 1000L * 3600L * 24L + e.endTime * 60L * 1000L;
223         return e;
224     }
225 
226     @SmallTest
testGetDisplayedDatetime_differentYear()227     public void testGetDisplayedDatetime_differentYear() {
228         // 4/12/2000 5pm - 4/12/2000 6pm
229         long start = createTimeInMillis(0, 0, 17, 12, 3, 2000);
230         long end = createTimeInMillis(0, 0, 18, 12, 3, 2000);
231         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
232                 false, dbUtils.getContext());
233         assertEquals("Wednesday, April 12, 2000, 5:00 \u2013 6:00 PM", result);
234 
235         // 12/31/2012 5pm - 1/1/2013 6pm
236         start = createTimeInMillis(0, 0, 17, 31, 11, 2012);
237         end = createTimeInMillis(0, 0, 18, 1, 0, 2013);
238         result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
239                 false, dbUtils.getContext());
240         assertEquals("Mon, Dec 31, 2012, 5:00 PM – Tue, Jan 1, 2013, 6:00 PM", result);
241     }
242 
243     @SmallTest
testGetDisplayedDatetime_sameYear()244     public void testGetDisplayedDatetime_sameYear() {
245         // 4/12/2012 5pm - 4/12/2012 6pm
246         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012);
247         long end = createTimeInMillis(0, 0, 18, 12, 3, 2012);
248         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
249                 false, dbUtils.getContext());
250         assertEquals("Thursday, April 12, 2012, 5:00 \u2013 6:00 PM", result);
251     }
252 
253     @SmallTest
testGetDisplayedDatetime_today()254     public void testGetDisplayedDatetime_today() {
255         // 4/10/2012 5pm - 4/10/2012 6pm
256         long start = createTimeInMillis(0, 0, 17, NOW_DAY, NOW_MONTH, NOW_YEAR);
257         long end = createTimeInMillis(0, 0, 18, NOW_DAY, NOW_MONTH, NOW_YEAR);
258         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
259                 false, dbUtils.getContext());
260         assertEquals("Today at 5:00 \u2013 6:00 PM", result);
261     }
262 
263     @SmallTest
testGetDisplayedDatetime_todayMidnight()264     public void testGetDisplayedDatetime_todayMidnight() {
265         // 4/10/2012 5pm - 4/11/2012 12am
266         long start = createTimeInMillis(0, 0, 17, NOW_DAY, NOW_MONTH, NOW_YEAR);
267         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
268         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
269                 false, dbUtils.getContext());
270         assertEquals("Today at 5:00 PM \u2013 12:00 AM", result);
271     }
272 
273     @SmallTest
testGetDisplayedDatetime_tomorrow()274     public void testGetDisplayedDatetime_tomorrow() {
275         // 4/11/2012 12:01AM - 4/11/2012 11:59pm
276         long start = createTimeInMillis(0, 1, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
277         long end = createTimeInMillis(0, 59, 23, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
278         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
279                 false, dbUtils.getContext());
280         assertEquals("Tomorrow at 12:01 AM \u2013 11:59 PM", result);
281     }
282 
283     @SmallTest
testGetDisplayedDatetime_yesterday()284     public void testGetDisplayedDatetime_yesterday() {
285         // 4/9/2012 5pm - 4/9/2012 6pm
286         long start = createTimeInMillis(0, 0, 17, 9, 3, 2012);
287         long end = createTimeInMillis(0, 0, 18, 9, 3, 2012);
288         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
289                 false, dbUtils.getContext());
290         assertEquals("Monday, April 9, 2012, 5:00 \u2013 6:00 PM", result);
291     }
292 
293     @SmallTest
testGetDisplayedDatetime_multiDay()294     public void testGetDisplayedDatetime_multiDay() {
295         // 4/10/2012 12:01AM - 4/11/2012 12:01AM
296         long start = createTimeInMillis(0, 1, 0, NOW_DAY, NOW_MONTH, NOW_YEAR);
297         long end = createTimeInMillis(0, 1, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR);
298         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
299                 false, dbUtils.getContext());
300         assertEquals("Tue, Apr 10, 2012, 12:01 AM \u2013 Wed, Apr 11, 2012, 12:01 AM", result);
301     }
302 
303     @SmallTest
testGetDisplayedDatetime_allDay()304     public void testGetDisplayedDatetime_allDay() {
305         // 4/2/2012 12:00AM - 4/3/2012 12:00AM
306         long start = createTimeInMillis(0, 0, 0, 2, 3, NOW_YEAR, Time.TIMEZONE_UTC);
307         long end = createTimeInMillis(0, 0, 0, 3, 3, NOW_YEAR, Time.TIMEZONE_UTC);
308         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
309                 true, dbUtils.getContext());
310         assertEquals("Monday, April 2, 2012", result);
311     }
312 
313     @SmallTest
testGetDisplayedDatetime_allDayToday()314     public void testGetDisplayedDatetime_allDayToday() {
315         // 4/10/2012 12:00AM - 4/11/2012 12:00AM
316         long start = createTimeInMillis(0, 0, 0, NOW_DAY, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
317         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
318         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
319                 true, dbUtils.getContext());
320         assertEquals("Today", result);
321     }
322 
323     @SmallTest
testGetDisplayedDatetime_allDayMultiday()324     public void testGetDisplayedDatetime_allDayMultiday() {
325         // 4/10/2012 12:00AM - 4/13/2012 12:00AM
326         long start = createTimeInMillis(0, 0, 0, NOW_DAY, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
327         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 3, NOW_MONTH, NOW_YEAR, Time.TIMEZONE_UTC);
328         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, DEFAULT_TIMEZONE,
329                 true, dbUtils.getContext());
330         assertEquals("Tuesday, April 10 \u2013 Thursday, April 12, 2012", result);
331     }
332 
333     @SmallTest
testGetDisplayedDatetime_differentTimezone()334     public void testGetDisplayedDatetime_differentTimezone() {
335         String localTz = "America/New_York";
336         String eventTz = "America/Los_Angeles";
337         setTimezone(localTz);
338 
339         // 4/12/2012 5pm - 4/12/2012 6pm (Pacific)
340         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012, eventTz);
341         long end = createTimeInMillis(0, 0, 18, 12, 3, 2012, eventTz);
342         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, false,
343                 dbUtils.getContext());
344         assertEquals("Thursday, April 12, 2012, 8:00 \u2013 9:00 PM", result);
345     }
346 
347     @SmallTest
testGetDisplayedDatetime_allDayDiffTimezone()348     public void testGetDisplayedDatetime_allDayDiffTimezone() {
349         String localTz = "America/New_York";
350         setTimezone(localTz);
351 
352         // 4/2/2012 12:00AM - 4/3/2012 12:00AM
353         long start = createTimeInMillis(0, 0, 0, 2, 3, NOW_YEAR, Time.TIMEZONE_UTC);
354         long end = createTimeInMillis(0, 0, 0, 3, 3, NOW_YEAR, Time.TIMEZONE_UTC);
355         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, true,
356                 dbUtils.getContext());
357         assertEquals("Monday, April 2, 2012", result);
358     }
359 
360     @SmallTest
testGetDisplayedDatetime_allDayTomorrowDiffTimezone()361     public void testGetDisplayedDatetime_allDayTomorrowDiffTimezone() {
362         String localTz = "America/New_York";
363         setTimezone(localTz);
364 
365         // 4/2/2012 12:00AM - 4/3/2012 12:00AM
366         long start = createTimeInMillis(0, 0, 0, NOW_DAY + 1, NOW_MONTH, NOW_YEAR,
367                 Time.TIMEZONE_UTC);
368         long end = createTimeInMillis(0, 0, 0, NOW_DAY + 2, NOW_MONTH, NOW_YEAR,
369                 Time.TIMEZONE_UTC);
370         String result = Utils.getDisplayedDatetime(start, end, NOW_TIME, localTz, true,
371                 dbUtils.getContext());
372         assertEquals("Tomorrow", result);
373     }
374 
375     // TODO: add tests for army time.
376 
377     @SmallTest
testGetDisplayedTimezone_sameTimezone()378     public void testGetDisplayedTimezone_sameTimezone() {
379         String localTz = "America/New_York";
380         setTimezone(localTz);
381 
382         // 4/12/2012 5pm
383         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012, localTz);
384         assertNull(Utils.getDisplayedTimezone(start, localTz, localTz));
385     }
386 
387     @SmallTest
testGetDisplayedTimezone_differentTimezone()388     public void testGetDisplayedTimezone_differentTimezone() {
389         String localTz = "America/New_York";
390         String eventTz = "America/Los_Angeles";
391         setTimezone(localTz);
392 
393         // 1/12/2012 5pm (not daylight savings)
394         long start = createTimeInMillis(0, 0, 17, 12, 0, 2012, eventTz);
395         assertEquals("EST", Utils.getDisplayedTimezone(start, localTz, eventTz));
396     }
397 
398     @SmallTest
testGetDisplayedTimezone_differentTimezoneDst()399     public void testGetDisplayedTimezone_differentTimezoneDst() {
400         String localTz = "America/New_York";
401         String eventTz = "America/Los_Angeles";
402         setTimezone(localTz);
403 
404         // 4/12/2012 5pm (daylight savings)
405         long start = createTimeInMillis(0, 0, 17, 12, 3, 2012, eventTz);
406         assertEquals("EDT", Utils.getDisplayedTimezone(start, localTz, eventTz));
407     }
408 }
409