1/* //device/content/providers/pim/RecurrenceProcessorTest.java
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18package com.android.calendarcommon2;
19
20import android.os.Debug;
21import android.test.suitebuilder.annotation.LargeTest;
22import android.test.suitebuilder.annotation.MediumTest;
23import android.test.suitebuilder.annotation.SmallTest;
24import android.text.TextUtils;
25import android.text.format.Time;
26import android.util.Log;
27import android.util.TimeFormatException;
28import junit.framework.TestCase;
29
30import java.util.TreeSet;
31
32public class RecurrenceProcessorTest extends TestCase {
33    private static final String TAG = "RecurrenceProcessorTest";
34    private static final boolean SPEW = true;
35    private static final boolean METHOD_TRACE = false;
36
37    private static String[] getFormattedDates(long[] dates, Time time) {
38        String[] out = new String[dates.length];
39        int i = 0;
40        for (long date : dates) {
41            time.set(date);
42            out[i] = time.format2445();
43            ++i;
44        }
45        return out;
46    }
47
48    private static void printLists(String[] expected, String[] out) {
49        Log.i(TAG, "        expected        out");
50        int i;
51        for (i = 0; i < expected.length && i < out.length; i++) {
52            Log.i(TAG, "  [" + i + "] " + expected[i]
53                    + "  " + out[i]);
54        }
55        for (; i < expected.length; i++) {
56            Log.i(TAG, "  [" + i + "] " + expected[i]);
57        }
58        for (; i < out.length; i++) {
59            Log.i(TAG, "  [" + i + "]                   " + out[i]);
60        }
61    }
62
63    public void verifyRecurrence(String dtstartStr, String rrule, String rdate, String exrule,
64            String exdate, String rangeStartStr, String rangeEndStr, String[] expected)
65            throws Exception {
66        verifyRecurrence(dtstartStr, rrule, rdate, exrule, exdate, rangeStartStr,
67                rangeEndStr, expected, expected[expected.length - 1]);
68    }
69
70    public void verifyRecurrence(String dtstartStr, String rrule, String rdate, String exrule,
71            String exdate, String rangeStartStr, String rangeEndStr, String[] expected,
72            String last) throws Exception {
73
74        // note that the zulu of all parameters here must be the same, expand
75        // doesn't work otherwise
76
77        if (SPEW) {
78            Log.i(TAG, "DTSTART:" + dtstartStr
79                    + " RRULE:" + rrule
80                    + " RDATE:" + rdate
81                    + " EXRULE:" + exrule
82                    + " EXDATE:" + exdate);
83        }
84
85        // we could use any timezone, incl. UTC, but we use a non-UTC
86        // timezone to make sure there are no UTC assumptions in the
87        // recurrence processing code.
88        String tz = "America/Los_Angeles";
89        Time dtstart = new Time(tz);
90        Time rangeStart = new Time(tz);
91        Time rangeEnd = new Time(tz);
92        Time outCal = new Time(tz);
93
94        dtstart.parse(dtstartStr);
95
96        rangeStart.parse(rangeStartStr);
97        rangeEnd.parse(rangeEndStr);
98
99        if (METHOD_TRACE) {
100            String fn = "/tmp/trace/" + this.getClass().getName().replace('$', '_');
101            String df = fn + ".data";
102            String kf = fn + ".key";
103            Debug.startMethodTracing(fn, 8 * 1024 * 1024);
104        }
105
106        RecurrenceProcessor rp = new RecurrenceProcessor();
107        RecurrenceSet recur = new RecurrenceSet(rrule, rdate, exrule, exdate);
108
109        long[] out = rp.expand(dtstart, recur, rangeStart.toMillis(false /* use isDst */),
110                rangeEnd.toMillis(false /* use isDst */));
111
112        if (METHOD_TRACE) {
113            Debug.stopMethodTracing();
114        }
115
116        int count = out.length;
117        String[] actual = getFormattedDates(out, outCal);
118
119        if (count != expected.length) {
120            if (SPEW) {
121                Log.i(TAG, "DTSTART:" + dtstartStr + " RRULE:" + rrule);
122                printLists(expected, actual);
123            }
124            throw new RuntimeException("result lengths don't match.  "
125                    + " expected=" + expected.length
126                    + " actual=" + count);
127        }
128
129        for (int i = 0; i < count; i++) {
130            String s = actual[i];
131            if (!s.equals(expected[i])) {
132                if (SPEW) {
133                    Log.i(TAG, "DTSTART:" + dtstartStr + " RRULE:" + rrule);
134                    printLists(expected, actual);
135                    Log.i(TAG, "i=" + i);
136                }
137                throw new RuntimeException("expected[" + i + "]="
138                        + expected[i] + " actual=" + actual[i]);
139            }
140        }
141
142        long lastOccur = rp.getLastOccurence(dtstart, rangeEnd, recur);
143        if (lastOccur == 0 && out.length == 0) {
144            // No occurrence found and 0 returned for lastOccur, this is ok.
145            return;
146        }
147        long lastMillis = -1;
148        long expectedMillis = -1;
149        String lastStr = "";
150        if (lastOccur != -1) {
151            outCal.set(lastOccur);
152            lastStr = outCal.format2445();
153            lastMillis = outCal.toMillis(true /* ignore isDst */);
154        }
155        if (last != null && last.length() > 0) {
156            Time expectedLast = new Time(tz);
157            expectedLast.parse(last);
158            expectedMillis = expectedLast.toMillis(true /* ignore isDst */);
159        }
160        if (lastMillis != expectedMillis) {
161            if (SPEW) {
162                Log.i(TAG, "DTSTART:" + dtstartStr + " RRULE:" + rrule);
163                Log.i(TAG, "Expected: " + last + "; Actual: " + lastStr);
164                printLists(expected, actual);
165            }
166
167            throw new RuntimeException("expected last occurrence date does not match."
168                    + " expected=" + last
169                    + " actual=" + lastStr);
170        }
171    }
172
173    @SmallTest
174    public void testMonthly0() throws Exception {
175        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;COUNT=3",
176                null /* rdate */, null /* exrule */, null /* exdate */,
177                "20060101T000000", "20080101T000000",
178                new String[]{
179                        "20060205T100000",
180                        "20060305T100000",
181                        "20060405T100000"
182                });
183    }
184
185    @SmallTest
186    public void testMonthly1() throws Exception {
187        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;INTERVAL=2;COUNT=3",
188                null /* rdate */, null /* exrule */, null /* exdate */,
189                "20060101T000000", "20080101T000000",
190                new String[]{
191                        "20060205T100000",
192                        "20060405T100000",
193                        "20060605T100000"
194                });
195    }
196
197    @SmallTest
198    public void testMonthly2() throws Exception {
199        // this tests wrapping the year when the interval isn't divisible
200        // by 12
201        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;INTERVAL=5;COUNT=5",
202                null /* rdate */, null /* exrule */, null /* exdate */,
203                "20060101T000000", "20080101T000000",
204                new String[]{
205                        "20060205T100000",
206                        "20060705T100000",
207                        "20061205T100000",
208                        "20070505T100000",
209                        "20071005T100000"
210                });
211    }
212
213    @SmallTest
214    public void testMonthly3() throws Exception {
215        // with a simple BYDAY, spanning two months
216        verifyRecurrence("20060104T123456",
217                "FREQ=MONTHLY;UNTIL=20060201T200000Z;BYDAY=TU,WE",
218                null /* rdate */, null /* exrule */, null /* exdate */,
219                "20060101T000000", "20080101T000000",
220                new String[]{
221                        "20060104T123456",
222                        "20060110T123456",
223                        "20060111T123456",
224                        "20060117T123456",
225                        "20060118T123456",
226                        "20060124T123456",
227                        "20060125T123456",
228                        "20060131T123456"
229                },
230                "20060201T120000");
231    }
232
233    @SmallTest
234    public void testMonthly4() throws Exception {
235        // with a BYDAY with +1 / etc., spanning two months and
236        // one day which isn't in the result
237        verifyRecurrence("20060101T123456",
238                "FREQ=MONTHLY;UNTIL=20060301T200000Z;BYDAY=+1SU,+2MO,+3TU,+4WE,+5MO,+5TU,+5WE,+6TH",
239                null /* rdate */, null /* exrule */, null /* exdate */,
240                "20060101T000000", "20080101T000000",
241                new String[]{
242                        "20060101T123456",
243                        "20060109T123456",
244                        "20060117T123456",
245                        "20060125T123456",
246                        "20060130T123456",
247                        "20060131T123456",
248                        "20060205T123456",
249                        "20060213T123456",
250                        "20060221T123456",
251                        "20060222T123456"
252                },
253                "20060301T120000");
254    }
255
256    @SmallTest
257    public void testMonthly5() throws Exception {
258        // with a BYDAY with -1 / etc.
259        verifyRecurrence("20060201T123456",
260                "FREQ=MONTHLY;UNTIL=20060301T200000Z;BYDAY=-1SU,-2MO,-3TU,-4TU,-4WE,-5MO,-5TU,-5WE,-6TH",
261                null /* rdate */, null /* exrule */, null /* exdate */,
262                "20060101T000000", "20080101T000000",
263                new String[]{
264                        "20060201T123456",
265                        "20060207T123456",
266                        "20060214T123456",
267                        "20060220T123456",
268                        "20060226T123456"
269                },
270                "20060301T120000");
271    }
272
273    @SmallTest
274    public void testMonthly6() throws Exception {
275        // With positive BYMONTHDAYs
276        verifyRecurrence("20060201T123456",
277                "FREQ=MONTHLY;UNTIL=20060301T200000Z;BYMONTHDAY=1,2,5,28,31",
278                null /* rdate */, null /* exrule */, null /* exdate */,
279                "20060101T000000", "20080101T000000",
280                new String[]{
281                        "20060201T123456",
282                        "20060202T123456",
283                        "20060205T123456",
284                        "20060228T123456"
285                },
286                "20060301T120000");
287    }
288
289    @SmallTest
290    public void testMonthly7() throws Exception {
291        // With negative BYMONTHDAYs
292        verifyRecurrence("20060201T123456",
293                "FREQ=MONTHLY;UNTIL=20060301T200000Z;BYMONTHDAY=-1,-5,-27,-28,-31",
294                null /* rdate */, null /* exrule */, null /* exdate */,
295                "20060101T000000", "20080101T000000",
296                new String[]{
297                        "20060201T123456",
298                        "20060202T123456",
299                        "20060224T123456",
300                        "20060228T123456"
301                },
302                "20060301T120000");
303    }
304
305    @SmallTest
306    public void testMonthly8() throws Exception {
307        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;COUNT=3",
308                "America/Los_Angeles;20060207T140000,20060307T160000,20060407T180000",
309                null /* exrule */, null /* exdate */,
310                "20060101T000000", "20080101T000000",
311                new String[]{
312                        "20060205T100000",
313                        "20060207T140000",
314                        "20060305T100000",
315                        "20060307T160000",
316                        "20060405T100000",
317                        "20060407T180000",
318                });
319    }
320
321    @SmallTest
322    public void testMonthly9() throws Exception {
323        verifyRecurrence("20060205T100000", null /* rrule */,
324                "America/Los_Angeles;20060207T140000,20060307T160000,20060407T180000",
325                null /* exrule */, null /* exdate */,
326                "20060101T000000", "20080101T000000",
327                new String[]{
328                        "20060207T140000",
329                        "20060307T160000",
330                        "20060407T180000",
331                });
332    }
333
334    @SmallTest
335    public void testMonthly10() throws Exception {
336        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;COUNT=3\nFREQ=WEEKLY;COUNT=2",
337                "America/Los_Angeles;20060207T140000,20060307T160000,20060407T180000",
338                null /* exrule */, null /* exdate */,
339                "20060101T000000", "20080101T000000",
340                new String[]{
341                        "20060205T100000",
342                        "20060207T140000",
343                        "20060212T100000",
344                        "20060305T100000",
345                        "20060307T160000",
346                        "20060405T100000",
347                        "20060407T180000",
348                });
349    }
350
351    @SmallTest
352    public void testMonthly11() throws Exception {
353        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;COUNT=3\nFREQ=WEEKLY;COUNT=2",
354                null /* rdate */,
355                "FREQ=MONTHLY;COUNT=2", null /* exdate */,
356                "20060101T000000", "20080101T000000",
357                new String[]{
358                        "20060212T100000",
359                        "20060405T100000",
360                });
361    }
362
363    @SmallTest
364    public void testMonthly12() throws Exception {
365        verifyRecurrence("20060205T100000", "FREQ=MONTHLY;COUNT=3\nFREQ=WEEKLY;COUNT=2",
366                null /* rdate */, null /* exrule */,
367                "20060212T180000Z,20060405T170000Z" /* exdate */,
368                "20060101T000000", "20080101T000000",
369                new String[]{
370                        "20060205T100000",
371                        "20060305T100000",
372                });
373    }
374
375    @SmallTest
376    public void testMonthly13() throws Exception {
377        verifyRecurrence("20060101T100000", "FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=10",
378                null /* rdate */, null /* exrule */, null /* exdate */,
379                "20060101T000000", "20101231T000000",
380                new String[]{
381                        "20060101T100000",
382                        "20060113T100000",
383                        "20061013T100000",
384                        "20070413T100000",
385                        "20070713T100000",
386                        "20080613T100000",
387                        "20090213T100000",
388                        "20090313T100000",
389                        "20091113T100000",
390                        "20100813T100000",
391                });
392    }
393
394    @SmallTest
395    public void testMonthly14() throws Exception {
396        verifyRecurrence("20110103T100000", "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1",
397                null /* rdate */, null /* exrule */, null /* exdate */,
398                "20110101T000000", "20110331T235959",
399                new String[]{
400                "20110103T100000",
401                "20110131T100000",
402                "20110201T100000",
403                "20110228T100000",
404                "20110301T100000",
405                "20110331T100000",
406                });
407    }
408
409    @SmallTest
410    public void testMonthly15() throws Exception {
411        verifyRecurrence("20110703T100000", "FREQ=MONTHLY;BYDAY=SA,SU;BYSETPOS=2,-2",
412                null /* rdate */, null /* exrule */, null /* exdate */,
413                "20110701T000000", "20110931T235959",
414                new String[]{
415                "20110703T100000",
416                "20110730T100000",
417                "20110807T100000",
418                "20110827T100000",
419                "20110904T100000",
420                "20110924T100000",
421                });
422    }
423
424    @SmallTest
425    public void testWeekly0() throws Exception {
426        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;COUNT=3",
427                null /* rdate */, null /* exrule */, null /* exdate */,
428                "20060101T000000", "20080101T000000",
429                new String[]{
430                        "20060215T100000",
431                        "20060222T100000",
432                        "20060301T100000"
433                });
434    }
435
436    @SmallTest
437    public void testWeekly1() throws Exception {
438        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060301T100000Z",
439                null /* rdate */, null /* exrule */, null /* exdate */,
440                "20060101T000000", "20080101T000000",
441                new String[]{
442                        "20060215T100000",
443                        "20060222T100000"
444                }, "20060301T020000");
445    }
446
447    @SmallTest
448    public void testWeekly2() throws Exception {
449        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060301T100001Z",
450                null /* rdate */, null /* exrule */, null /* exdate */,
451                "20060101T000000", "20080101T000000",
452                new String[]{
453                        "20060215T100000",
454                        "20060222T100000"
455                }, "20060301T020001");
456    }
457
458    @SmallTest
459    public void testWeekly3() throws Exception {
460        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060301T090000Z",
461                null /* rdate */, null /* exrule */, null /* exdate */,
462                "20060101T000000", "20080101T000000",
463                new String[]{
464                        "20060215T100000",
465                        "20060222T100000"
466                }, "20060301T010000");
467    }
468
469    @SmallTest
470    public void testWeekly4() throws Exception {
471        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060311T100001Z;BYDAY=TU",
472                null /* rdate */, null /* exrule */, null /* exdate */,
473                "20060101T000000", "20080101T000000",
474                new String[]{
475                        "20060215T100000",
476                        "20060221T100000",
477                        "20060228T100000",
478                        "20060307T100000"
479                }, "20060311T020001");
480    }
481
482    // until without "Z"
483    @SmallTest
484    public void testWeekly4a() throws Exception {
485        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060311T100001;BYDAY=TU",
486                null /* rdate */, null /* exrule */, null /* exdate */,
487                "20060101T000000", "20080101T000000",
488                new String[]{
489                        "20060215T100000",
490                        "20060221T100000",
491                        "20060228T100000",
492                        "20060307T100000"
493                }, "20060311T100001");
494    }
495
496    @SmallTest
497    public void testWeekly5() throws Exception {
498        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060311T100001Z;BYDAY=TH",
499                null /* rdate */, null /* exrule */, null /* exdate */,
500                "20060101T000000", "20080101T000000",
501                new String[]{
502                        "20060215T100000",
503                        "20060216T100000",
504                        "20060223T100000",
505                        "20060302T100000",
506                        "20060309T100000"
507                }, "20060311T020001");
508    }
509
510    @SmallTest
511    public void testWeekly6() throws Exception {
512        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060309T100001Z;BYDAY=WE,TH",
513                null /* rdate */, null /* exrule */, null /* exdate */,
514                "20060101T000000", "20080101T000000",
515                new String[]{
516                        "20060215T100000",
517                        "20060216T100000",
518                        "20060222T100000",
519                        "20060223T100000",
520                        "20060301T100000",
521                        "20060302T100000",
522                        "20060308T100000"
523                }, "20060309T020001");
524    }
525
526    @SmallTest
527    public void testWeekly7() throws Exception {
528        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060220T100001Z;BYDAY=SU",
529                null /* rdate */, null /* exrule */, null /* exdate */,
530                "20060101T000000", "20080101T000000",
531                new String[]{
532                        "20060215T100000",
533                        "20060219T100000"
534                }, "20060220T020001");
535    }
536
537    @SmallTest
538    public void testWeekly8() throws Exception {
539        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;COUNT=4;WKST=SU;BYDAY=TU,TH",
540                null /* rdate */, null /* exrule */, null /* exdate */,
541                "20060101T000000", "20080101T000000",
542                new String[]{
543                        "20060215T100000",
544                        "20060216T100000",
545                        "20060221T100000",
546                        "20060223T100000"
547                });
548    }
549
550    @SmallTest
551    public void testWeekly9() throws Exception {
552        verifyRecurrence("19970805T100000",
553                "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU",   // uses default WKST=MO
554                null /* rdate */, null /* exrule */, null /* exdate */,
555                "19970101T000000", "19980101T000000",
556                new String[]{
557                        "19970805T100000",
558                        "19970810T100000",
559                        "19970819T100000",
560                        "19970824T100000",
561                });
562    }
563
564    @SmallTest
565    public void testWeekly10() throws Exception {
566        verifyRecurrence("19970805T100000",
567                "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU",
568                null /* rdate */, null /* exrule */, null /* exdate */,
569                "19970101T000000", "19980101T000000",
570                new String[]{
571                        "19970805T100000",
572                        "19970817T100000",
573                        "19970819T100000",
574                        "19970831T100000",
575                });
576    }
577
578    // BUG 1658567: UNTIL=date
579    @SmallTest
580    public void testWeekly11() throws Exception {
581        verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=20060220;BYDAY=SU",
582                null /* rdate */, null /* exrule */, null /* exdate */,
583                "20060101T000000", "20080101T000000",
584                new String[]{
585                        "20060215T100000",
586                        "20060219T100000"
587                }, "20060220T000000");
588    }
589
590    @SmallTest
591    public void testWeekly12() throws Exception {
592        try {
593            verifyRecurrence("20060215T100000", "FREQ=WEEKLY;UNTIL=junk;BYDAY=SU",
594                    null /* rdate */, null /* exrule */, null /* exdate */,
595                    "20060101T000000", "20080101T000000",
596                    new String[]{
597                            "20060215T100000",
598                            "20060219T100000"
599                    }, "20060220T020001");
600            fail("Bad UNTIL string failed to throw exception");
601        } catch (TimeFormatException e) {
602            // expected
603        }
604    }
605
606    /**
607     * Test repeating weekly event with dtstart and dtend (only one occurrence)
608     * See bug #3267616
609     * @throws Exception
610     */
611    @SmallTest
612    public void testWeekly13() throws Exception {
613        verifyRecurrence("20101117T150000",
614                "FREQ=WEEKLY;BYDAY=WE",
615                null /* rdate */, null /* exrule */, null /* exdate */,
616                "20101117T150000", "20101117T160000",
617                new String[]{ "20101117T150000" });
618    }
619
620    @SmallTest
621    public void testWeekly14() throws Exception {
622        verifyRecurrence("19970805T100000",
623                "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=TH",
624                null /* rdate */, null /* exrule */, null /* exdate */,
625                "19970101T000000", "19980101T000000",
626                new String[]{
627                        "19970805T100000",
628                        "19970817T100000",
629                        "19970819T100000",
630                        "19970831T100000",
631                });
632    }
633
634    @SmallTest
635    public void testDaily0() throws Exception {
636        verifyRecurrence("20060215T100000", "FREQ=DAILY;COUNT=3",
637                null /* rdate */, null /* exrule */, null /* exdate */,
638                "20060101T000000", "20080101T000000",
639                new String[]{
640                        "20060215T100000",
641                        "20060216T100000",
642                        "20060217T100000"
643                });
644    }
645
646    @SmallTest
647    public void testDaily1() throws Exception {
648        verifyRecurrence("20060215T100000", "FREQ=DAILY;UNTIL=20060302T100001Z",
649                null /* rdate */, null /* exrule */, null /* exdate */,
650                "20060101T000000", "20080101T000000",
651                new String[]{
652                        "20060215T100000",
653                        "20060216T100000",
654                        "20060217T100000",
655                        "20060218T100000",
656                        "20060219T100000",
657                        "20060220T100000",
658                        "20060221T100000",
659                        "20060222T100000",
660                        "20060223T100000",
661                        "20060224T100000",
662                        "20060225T100000",
663                        "20060226T100000",
664                        "20060227T100000",
665                        "20060228T100000",
666                        "20060301T100000"
667                }, "20060302T100001Z");
668    }
669
670    @SmallTest
671    public void testDaily2() throws Exception {
672        verifyRecurrence("20060215T100000", "FREQ=DAILY;UNTIL=20060220T100001Z;BYDAY=SU",
673                null /* rdate */, null /* exrule */, null /* exdate */,
674                "20060101T000000", "20080101T000000",
675                new String[]{
676                        "20060215T100000",
677                        "20060219T100000"
678                }, "20060220T020001");
679    }
680
681    @SmallTest
682    public void testDaily3() throws Exception {
683        verifyRecurrence("20060219T100000",
684                "FREQ=DAILY;UNTIL=20060225T180304Z;BYDAY=SU,MO,SA;BYHOUR=5,10,22;BYMINUTE=3,59;BYSECOND=2,5",
685                null /* rdate */, null /* exrule */, null /* exdate */,
686                "20060101T000000", "20080101T000000",
687                new String[]{
688                        "20060219T100000",
689                        "20060219T100302",
690                        "20060219T100305",
691                        "20060219T105902",
692                        "20060219T105905",
693                        "20060219T220302",
694                        "20060219T220305",
695                        "20060219T225902",
696                        "20060219T225905",
697                        "20060220T050302",
698                        "20060220T050305",
699                        "20060220T055902",
700                        "20060220T055905",
701                        "20060220T100302",
702                        "20060220T100305",
703                        "20060220T105902",
704                        "20060220T105905",
705                        "20060220T220302",
706                        "20060220T220305",
707                        "20060220T225902",
708                        "20060220T225905",
709                        "20060225T050302",
710                        "20060225T050305",
711                        "20060225T055902",
712                        "20060225T055905",
713                        "20060225T100302"
714                }, "20060225T100304");
715    }
716
717    @MediumTest
718    public void testFromGoogleCalendar0() throws Exception {
719        // Tuesday, Thursday (10/2)
720        verifyRecurrence("20061002T050000",
721                "FREQ=WEEKLY;UNTIL=20071031T200000Z;INTERVAL=1;BYDAY=TU,TH;WKST=SU",
722                null /* rdate */, null /* exrule */, null /* exdate */,
723                "20060101T000000", "20090101T000000",
724                new String[]{
725                        "20061002T050000",
726                        "20061003T050000",
727                        "20061005T050000",
728                        "20061010T050000",
729                        "20061012T050000",
730                        "20061017T050000",
731                        "20061019T050000",
732                        "20061024T050000",
733                        "20061026T050000",
734                        "20061031T050000",
735                        "20061102T050000",
736                        "20061107T050000",
737                        "20061109T050000",
738                        "20061114T050000",
739                        "20061116T050000",
740                        "20061121T050000",
741                        "20061123T050000",
742                        "20061128T050000",
743                        "20061130T050000",
744                        "20061205T050000",
745                        "20061207T050000",
746                        "20061212T050000",
747                        "20061214T050000",
748                        "20061219T050000",
749                        "20061221T050000",
750                        "20061226T050000",
751                        "20061228T050000",
752                        "20070102T050000",
753                        "20070104T050000",
754                        "20070109T050000",
755                        "20070111T050000",
756                        "20070116T050000",
757                        "20070118T050000",
758                        "20070123T050000",
759                        "20070125T050000",
760                        "20070130T050000",
761                        "20070201T050000",
762                        "20070206T050000",
763                        "20070208T050000",
764                        "20070213T050000",
765                        "20070215T050000",
766                        "20070220T050000",
767                        "20070222T050000",
768                        "20070227T050000",
769                        "20070301T050000",
770                        "20070306T050000",
771                        "20070308T050000",
772                        "20070313T050000",
773                        "20070315T050000",
774                        "20070320T050000",
775                        "20070322T050000",
776                        "20070327T050000",
777                        "20070329T050000",
778                        "20070403T050000",
779                        "20070405T050000",
780                        "20070410T050000",
781                        "20070412T050000",
782                        "20070417T050000",
783                        "20070419T050000",
784                        "20070424T050000",
785                        "20070426T050000",
786                        "20070501T050000",
787                        "20070503T050000",
788                        "20070508T050000",
789                        "20070510T050000",
790                        "20070515T050000",
791                        "20070517T050000",
792                        "20070522T050000",
793                        "20070524T050000",
794                        "20070529T050000",
795                        "20070531T050000",
796                        "20070605T050000",
797                        "20070607T050000",
798                        "20070612T050000",
799                        "20070614T050000",
800                        "20070619T050000",
801                        "20070621T050000",
802                        "20070626T050000",
803                        "20070628T050000",
804                        "20070703T050000",
805                        "20070705T050000",
806                        "20070710T050000",
807                        "20070712T050000",
808                        "20070717T050000",
809                        "20070719T050000",
810                        "20070724T050000",
811                        "20070726T050000",
812                        "20070731T050000",
813                        "20070802T050000",
814                        "20070807T050000",
815                        "20070809T050000",
816                        "20070814T050000",
817                        "20070816T050000",
818                        "20070821T050000",
819                        "20070823T050000",
820                        "20070828T050000",
821                        "20070830T050000",
822                        "20070904T050000",
823                        "20070906T050000",
824                        "20070911T050000",
825                        "20070913T050000",
826                        "20070918T050000",
827                        "20070920T050000",
828                        "20070925T050000",
829                        "20070927T050000",
830                        "20071002T050000",
831                        "20071004T050000",
832                        "20071009T050000",
833                        "20071011T050000",
834                        "20071016T050000",
835                        "20071018T050000",
836                        "20071023T050000",
837                        "20071025T050000",
838                        "20071030T050000",
839                }, "20071031T130000");
840    }
841
842    @MediumTest
843    public void testFromGoogleCalendar1() throws Exception {
844        // Mon Wed Fri
845        verifyRecurrence("20061002T030000",
846                "FREQ=WEEKLY;UNTIL=20071025T180000Z;INTERVAL=1;BYDAY=MO,WE,FR;",
847                null /* rdate */, null /* exrule */, null /* exdate */,
848                "20060101T000000", "20090101T000000",
849                new String[]{
850                        "20061002T030000",
851                        "20061004T030000",
852                        "20061006T030000",
853                        "20061009T030000",
854                        "20061011T030000",
855                        "20061013T030000",
856                        "20061016T030000",
857                        "20061018T030000",
858                        "20061020T030000",
859                        "20061023T030000",
860                        "20061025T030000",
861                        "20061027T030000",
862                        "20061030T030000",
863                        "20061101T030000",
864                        "20061103T030000",
865                        "20061106T030000",
866                        "20061108T030000",
867                        "20061110T030000",
868                        "20061113T030000",
869                        "20061115T030000",
870                        "20061117T030000",
871                        "20061120T030000",
872                        "20061122T030000",
873                        "20061124T030000",
874                        "20061127T030000",
875                        "20061129T030000",
876                        "20061201T030000",
877                        "20061204T030000",
878                        "20061206T030000",
879                        "20061208T030000",
880                        "20061211T030000",
881                        "20061213T030000",
882                        "20061215T030000",
883                        "20061218T030000",
884                        "20061220T030000",
885                        "20061222T030000",
886                        "20061225T030000",
887                        "20061227T030000",
888                        "20061229T030000",
889                        "20070101T030000",
890                        "20070103T030000",
891                        "20070105T030000",
892                        "20070108T030000",
893                        "20070110T030000",
894                        "20070112T030000",
895                        "20070115T030000",
896                        "20070117T030000",
897                        "20070119T030000",
898                        "20070122T030000",
899                        "20070124T030000",
900                        "20070126T030000",
901                        "20070129T030000",
902                        "20070131T030000",
903                        "20070202T030000",
904                        "20070205T030000",
905                        "20070207T030000",
906                        "20070209T030000",
907                        "20070212T030000",
908                        "20070214T030000",
909                        "20070216T030000",
910                        "20070219T030000",
911                        "20070221T030000",
912                        "20070223T030000",
913                        "20070226T030000",
914                        "20070228T030000",
915                        "20070302T030000",
916                        "20070305T030000",
917                        "20070307T030000",
918                        "20070309T030000",
919                        "20070312T030000",
920                        "20070314T030000",
921                        "20070316T030000",
922                        "20070319T030000",
923                        "20070321T030000",
924                        "20070323T030000",
925                        "20070326T030000",
926                        "20070328T030000",
927                        "20070330T030000",
928                        "20070402T030000",
929                        "20070404T030000",
930                        "20070406T030000",
931                        "20070409T030000",
932                        "20070411T030000",
933                        "20070413T030000",
934                        "20070416T030000",
935                        "20070418T030000",
936                        "20070420T030000",
937                        "20070423T030000",
938                        "20070425T030000",
939                        "20070427T030000",
940                        "20070430T030000",
941                        "20070502T030000",
942                        "20070504T030000",
943                        "20070507T030000",
944                        "20070509T030000",
945                        "20070511T030000",
946                        "20070514T030000",
947                        "20070516T030000",
948                        "20070518T030000",
949                        "20070521T030000",
950                        "20070523T030000",
951                        "20070525T030000",
952                        "20070528T030000",
953                        "20070530T030000",
954                        "20070601T030000",
955                        "20070604T030000",
956                        "20070606T030000",
957                        "20070608T030000",
958                        "20070611T030000",
959                        "20070613T030000",
960                        "20070615T030000",
961                        "20070618T030000",
962                        "20070620T030000",
963                        "20070622T030000",
964                        "20070625T030000",
965                        "20070627T030000",
966                        "20070629T030000",
967                        "20070702T030000",
968                        "20070704T030000",
969                        "20070706T030000",
970                        "20070709T030000",
971                        "20070711T030000",
972                        "20070713T030000",
973                        "20070716T030000",
974                        "20070718T030000",
975                        "20070720T030000",
976                        "20070723T030000",
977                        "20070725T030000",
978                        "20070727T030000",
979                        "20070730T030000",
980                        "20070801T030000",
981                        "20070803T030000",
982                        "20070806T030000",
983                        "20070808T030000",
984                        "20070810T030000",
985                        "20070813T030000",
986                        "20070815T030000",
987                        "20070817T030000",
988                        "20070820T030000",
989                        "20070822T030000",
990                        "20070824T030000",
991                        "20070827T030000",
992                        "20070829T030000",
993                        "20070831T030000",
994                        "20070903T030000",
995                        "20070905T030000",
996                        "20070907T030000",
997                        "20070910T030000",
998                        "20070912T030000",
999                        "20070914T030000",
1000                        "20070917T030000",
1001                        "20070919T030000",
1002                        "20070921T030000",
1003                        "20070924T030000",
1004                        "20070926T030000",
1005                        "20070928T030000",
1006                        "20071001T030000",
1007                        "20071003T030000",
1008                        "20071005T030000",
1009                        "20071008T030000",
1010                        "20071010T030000",
1011                        "20071012T030000",
1012                        "20071015T030000",
1013                        "20071017T030000",
1014                        "20071019T030000",
1015                        "20071022T030000",
1016                        "20071024T030000",
1017                }, "20071025T110000");
1018    }
1019
1020    @SmallTest
1021    public void testFromGoogleCalendar2() throws Exception {
1022        // Monthly on day 2
1023        verifyRecurrence("20061002T070000",
1024                "FREQ=MONTHLY;INTERVAL=1;WKST=SU",
1025                null /* rdate */, null /* exrule */, null /* exdate */,
1026                "20060101T000000", "20090101T000000",
1027                new String[]{
1028                        "20061002T070000",
1029                        "20061102T070000",
1030                        "20061202T070000",
1031                        "20070102T070000",
1032                        "20070202T070000",
1033                        "20070302T070000",
1034                        "20070402T070000",
1035                        "20070502T070000",
1036                        "20070602T070000",
1037                        "20070702T070000",
1038                        "20070802T070000",
1039                        "20070902T070000",
1040                        "20071002T070000",
1041                        "20071102T070000",
1042                        "20071202T070000",
1043                        "20080102T070000",
1044                        "20080202T070000",
1045                        "20080302T070000",
1046                        "20080402T070000",
1047                        "20080502T070000",
1048                        "20080602T070000",
1049                        "20080702T070000",
1050                        "20080802T070000",
1051                        "20080902T070000",
1052                        "20081002T070000",
1053                        "20081102T070000",
1054                        "20081202T070000",
1055                }, "20081202T070000");
1056    }
1057
1058    @MediumTest
1059    public void testFromGoogleCalendar3() throws Exception {
1060        // Every Weekday
1061        verifyRecurrence("20061002T100000",
1062                "FREQ=WEEKLY;UNTIL=20070215T100000Z;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;",
1063                null /* rdate */, null /* exrule */, null /* exdate */,
1064                "20060101T000000", "20090101T000000",
1065                new String[]{
1066                        "20061002T100000",
1067                        "20061003T100000",
1068                        "20061004T100000",
1069                        "20061005T100000",
1070                        "20061006T100000",
1071                        "20061009T100000",
1072                        "20061010T100000",
1073                        "20061011T100000",
1074                        "20061012T100000",
1075                        "20061013T100000",
1076                        "20061016T100000",
1077                        "20061017T100000",
1078                        "20061018T100000",
1079                        "20061019T100000",
1080                        "20061020T100000",
1081                        "20061023T100000",
1082                        "20061024T100000",
1083                        "20061025T100000",
1084                        "20061026T100000",
1085                        "20061027T100000",
1086                        "20061030T100000",
1087                        "20061031T100000",
1088                        "20061101T100000",
1089                        "20061102T100000",
1090                        "20061103T100000",
1091                        "20061106T100000",
1092                        "20061107T100000",
1093                        "20061108T100000",
1094                        "20061109T100000",
1095                        "20061110T100000",
1096                        "20061113T100000",
1097                        "20061114T100000",
1098                        "20061115T100000",
1099                        "20061116T100000",
1100                        "20061117T100000",
1101                        "20061120T100000",
1102                        "20061121T100000",
1103                        "20061122T100000",
1104                        "20061123T100000",
1105                        "20061124T100000",
1106                        "20061127T100000",
1107                        "20061128T100000",
1108                        "20061129T100000",
1109                        "20061130T100000",
1110                        "20061201T100000",
1111                        "20061204T100000",
1112                        "20061205T100000",
1113                        "20061206T100000",
1114                        "20061207T100000",
1115                        "20061208T100000",
1116                        "20061211T100000",
1117                        "20061212T100000",
1118                        "20061213T100000",
1119                        "20061214T100000",
1120                        "20061215T100000",
1121                        "20061218T100000",
1122                        "20061219T100000",
1123                        "20061220T100000",
1124                        "20061221T100000",
1125                        "20061222T100000",
1126                        "20061225T100000",
1127                        "20061226T100000",
1128                        "20061227T100000",
1129                        "20061228T100000",
1130                        "20061229T100000",
1131                        "20070101T100000",
1132                        "20070102T100000",
1133                        "20070103T100000",
1134                        "20070104T100000",
1135                        "20070105T100000",
1136                        "20070108T100000",
1137                        "20070109T100000",
1138                        "20070110T100000",
1139                        "20070111T100000",
1140                        "20070112T100000",
1141                        "20070115T100000",
1142                        "20070116T100000",
1143                        "20070117T100000",
1144                        "20070118T100000",
1145                        "20070119T100000",
1146                        "20070122T100000",
1147                        "20070123T100000",
1148                        "20070124T100000",
1149                        "20070125T100000",
1150                        "20070126T100000",
1151                        "20070129T100000",
1152                        "20070130T100000",
1153                        "20070131T100000",
1154                        "20070201T100000",
1155                        "20070202T100000",
1156                        "20070205T100000",
1157                        "20070206T100000",
1158                        "20070207T100000",
1159                        "20070208T100000",
1160                        "20070209T100000",
1161                        "20070212T100000",
1162                        "20070213T100000",
1163                        "20070214T100000",
1164                }, "20070215T020000");
1165    }
1166
1167    @SmallTest
1168    public void testFromGoogleCalendar4() throws Exception {
1169        // Every 5 months on day 2
1170        verifyRecurrence("20061003T100000",
1171                "FREQ=MONTHLY;INTERVAL=5;WKST=SU",
1172                null /* rdate */, null /* exrule */, null /* exdate */,
1173                "20060101T000000", "20090101T000000",
1174                new String[]{
1175                        "20061003T100000",
1176                        "20070303T100000",
1177                        "20070803T100000",
1178                        "20080103T100000",
1179                        "20080603T100000",
1180                        "20081103T100000",
1181                }, "20081103T100000");
1182    }
1183
1184    @MediumTest
1185    public void testFromGoogleCalendar5() throws Exception {
1186        // Tuesday, Thursday (10/3)
1187        verifyRecurrence("20061003T040000",
1188                "FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH;WKST=SU",
1189                null /* rdate */, null /* exrule */, null /* exdate */,
1190                "20060101T000000", "20090101T000000",
1191                new String[]{
1192                        "20061003T040000",
1193                        "20061005T040000",
1194                        "20061010T040000",
1195                        "20061012T040000",
1196                        "20061017T040000",
1197                        "20061019T040000",
1198                        "20061024T040000",
1199                        "20061026T040000",
1200                        "20061031T040000",
1201                        "20061102T040000",
1202                        "20061107T040000",
1203                        "20061109T040000",
1204                        "20061114T040000",
1205                        "20061116T040000",
1206                        "20061121T040000",
1207                        "20061123T040000",
1208                        "20061128T040000",
1209                        "20061130T040000",
1210                        "20061205T040000",
1211                        "20061207T040000",
1212                        "20061212T040000",
1213                        "20061214T040000",
1214                        "20061219T040000",
1215                        "20061221T040000",
1216                        "20061226T040000",
1217                        "20061228T040000",
1218                        "20070102T040000",
1219                        "20070104T040000",
1220                        "20070109T040000",
1221                        "20070111T040000",
1222                        "20070116T040000",
1223                        "20070118T040000",
1224                        "20070123T040000",
1225                        "20070125T040000",
1226                        "20070130T040000",
1227                        "20070201T040000",
1228                        "20070206T040000",
1229                        "20070208T040000",
1230                        "20070213T040000",
1231                        "20070215T040000",
1232                        "20070220T040000",
1233                        "20070222T040000",
1234                        "20070227T040000",
1235                        "20070301T040000",
1236                        "20070306T040000",
1237                        "20070308T040000",
1238                        "20070313T040000",
1239                        "20070315T040000",
1240                        "20070320T040000",
1241                        "20070322T040000",
1242                        "20070327T040000",
1243                        "20070329T040000",
1244                        "20070403T040000",
1245                        "20070405T040000",
1246                        "20070410T040000",
1247                        "20070412T040000",
1248                        "20070417T040000",
1249                        "20070419T040000",
1250                        "20070424T040000",
1251                        "20070426T040000",
1252                        "20070501T040000",
1253                        "20070503T040000",
1254                        "20070508T040000",
1255                        "20070510T040000",
1256                        "20070515T040000",
1257                        "20070517T040000",
1258                        "20070522T040000",
1259                        "20070524T040000",
1260                        "20070529T040000",
1261                        "20070531T040000",
1262                        "20070605T040000",
1263                        "20070607T040000",
1264                        "20070612T040000",
1265                        "20070614T040000",
1266                        "20070619T040000",
1267                        "20070621T040000",
1268                        "20070626T040000",
1269                        "20070628T040000",
1270                        "20070703T040000",
1271                        "20070705T040000",
1272                        "20070710T040000",
1273                        "20070712T040000",
1274                        "20070717T040000",
1275                        "20070719T040000",
1276                        "20070724T040000",
1277                        "20070726T040000",
1278                        "20070731T040000",
1279                        "20070802T040000",
1280                        "20070807T040000",
1281                        "20070809T040000",
1282                        "20070814T040000",
1283                        "20070816T040000",
1284                        "20070821T040000",
1285                        "20070823T040000",
1286                        "20070828T040000",
1287                        "20070830T040000",
1288                        "20070904T040000",
1289                        "20070906T040000",
1290                        "20070911T040000",
1291                        "20070913T040000",
1292                        "20070918T040000",
1293                        "20070920T040000",
1294                        "20070925T040000",
1295                        "20070927T040000",
1296                        "20071002T040000",
1297                        "20071004T040000",
1298                        "20071009T040000",
1299                        "20071011T040000",
1300                        "20071016T040000",
1301                        "20071018T040000",
1302                        "20071023T040000",
1303                        "20071025T040000",
1304                        "20071030T040000",
1305                        "20071101T040000",
1306                        "20071106T040000",
1307                        "20071108T040000",
1308                        "20071113T040000",
1309                        "20071115T040000",
1310                        "20071120T040000",
1311                        "20071122T040000",
1312                        "20071127T040000",
1313                        "20071129T040000",
1314                        "20071204T040000",
1315                        "20071206T040000",
1316                        "20071211T040000",
1317                        "20071213T040000",
1318                        "20071218T040000",
1319                        "20071220T040000",
1320                        "20071225T040000",
1321                        "20071227T040000",
1322                        "20080101T040000",
1323                        "20080103T040000",
1324                        "20080108T040000",
1325                        "20080110T040000",
1326                        "20080115T040000",
1327                        "20080117T040000",
1328                        "20080122T040000",
1329                        "20080124T040000",
1330                        "20080129T040000",
1331                        "20080131T040000",
1332                        "20080205T040000",
1333                        "20080207T040000",
1334                        "20080212T040000",
1335                        "20080214T040000",
1336                        "20080219T040000",
1337                        "20080221T040000",
1338                        "20080226T040000",
1339                        "20080228T040000",
1340                        "20080304T040000",
1341                        "20080306T040000",
1342                        "20080311T040000",
1343                        "20080313T040000",
1344                        "20080318T040000",
1345                        "20080320T040000",
1346                        "20080325T040000",
1347                        "20080327T040000",
1348                        "20080401T040000",
1349                        "20080403T040000",
1350                        "20080408T040000",
1351                        "20080410T040000",
1352                        "20080415T040000",
1353                        "20080417T040000",
1354                        "20080422T040000",
1355                        "20080424T040000",
1356                        "20080429T040000",
1357                        "20080501T040000",
1358                        "20080506T040000",
1359                        "20080508T040000",
1360                        "20080513T040000",
1361                        "20080515T040000",
1362                        "20080520T040000",
1363                        "20080522T040000",
1364                        "20080527T040000",
1365                        "20080529T040000",
1366                        "20080603T040000",
1367                        "20080605T040000",
1368                        "20080610T040000",
1369                        "20080612T040000",
1370                        "20080617T040000",
1371                        "20080619T040000",
1372                        "20080624T040000",
1373                        "20080626T040000",
1374                        "20080701T040000",
1375                        "20080703T040000",
1376                        "20080708T040000",
1377                        "20080710T040000",
1378                        "20080715T040000",
1379                        "20080717T040000",
1380                        "20080722T040000",
1381                        "20080724T040000",
1382                        "20080729T040000",
1383                        "20080731T040000",
1384                        "20080805T040000",
1385                        "20080807T040000",
1386                        "20080812T040000",
1387                        "20080814T040000",
1388                        "20080819T040000",
1389                        "20080821T040000",
1390                        "20080826T040000",
1391                        "20080828T040000",
1392                        "20080902T040000",
1393                        "20080904T040000",
1394                        "20080909T040000",
1395                        "20080911T040000",
1396                        "20080916T040000",
1397                        "20080918T040000",
1398                        "20080923T040000",
1399                        "20080925T040000",
1400                        "20080930T040000",
1401                        "20081002T040000",
1402                        "20081007T040000",
1403                        "20081009T040000",
1404                        "20081014T040000",
1405                        "20081016T040000",
1406                        "20081021T040000",
1407                        "20081023T040000",
1408                        "20081028T040000",
1409                        "20081030T040000",
1410                        "20081104T040000",
1411                        "20081106T040000",
1412                        "20081111T040000",
1413                        "20081113T040000",
1414                        "20081118T040000",
1415                        "20081120T040000",
1416                        "20081125T040000",
1417                        "20081127T040000",
1418                        "20081202T040000",
1419                        "20081204T040000",
1420                        "20081209T040000",
1421                        "20081211T040000",
1422                        "20081216T040000",
1423                        "20081218T040000",
1424                        "20081223T040000",
1425                        "20081225T040000",
1426                        "20081230T040000",
1427                }, "20081230T040000");
1428    }
1429
1430    @MediumTest
1431    public void testFromGoogleCalendar6() throws Exception {
1432        // Weekly on all days
1433        verifyRecurrence("20061003T060000",
1434                "FREQ=WEEKLY;INTERVAL=1;BYDAY=SU,MO,TU,WE,TH,FR,SA;WKST=SU",
1435                null /* rdate */, null /* exrule */, null /* exdate */,
1436                "20060101T000000", "20071003T060000",
1437                new String[]{
1438                        "20061003T060000",
1439                        "20061004T060000",
1440                        "20061005T060000",
1441                        "20061006T060000",
1442                        "20061007T060000",
1443                        "20061008T060000",
1444                        "20061009T060000",
1445                        "20061010T060000",
1446                        "20061011T060000",
1447                        "20061012T060000",
1448                        "20061013T060000",
1449                        "20061014T060000",
1450                        "20061015T060000",
1451                        "20061016T060000",
1452                        "20061017T060000",
1453                        "20061018T060000",
1454                        "20061019T060000",
1455                        "20061020T060000",
1456                        "20061021T060000",
1457                        "20061022T060000",
1458                        "20061023T060000",
1459                        "20061024T060000",
1460                        "20061025T060000",
1461                        "20061026T060000",
1462                        "20061027T060000",
1463                        "20061028T060000",
1464                        "20061029T060000",
1465                        "20061030T060000",
1466                        "20061031T060000",
1467                        "20061101T060000",
1468                        "20061102T060000",
1469                        "20061103T060000",
1470                        "20061104T060000",
1471                        "20061105T060000",
1472                        "20061106T060000",
1473                        "20061107T060000",
1474                        "20061108T060000",
1475                        "20061109T060000",
1476                        "20061110T060000",
1477                        "20061111T060000",
1478                        "20061112T060000",
1479                        "20061113T060000",
1480                        "20061114T060000",
1481                        "20061115T060000",
1482                        "20061116T060000",
1483                        "20061117T060000",
1484                        "20061118T060000",
1485                        "20061119T060000",
1486                        "20061120T060000",
1487                        "20061121T060000",
1488                        "20061122T060000",
1489                        "20061123T060000",
1490                        "20061124T060000",
1491                        "20061125T060000",
1492                        "20061126T060000",
1493                        "20061127T060000",
1494                        "20061128T060000",
1495                        "20061129T060000",
1496                        "20061130T060000",
1497                        "20061201T060000",
1498                        "20061202T060000",
1499                        "20061203T060000",
1500                        "20061204T060000",
1501                        "20061205T060000",
1502                        "20061206T060000",
1503                        "20061207T060000",
1504                        "20061208T060000",
1505                        "20061209T060000",
1506                        "20061210T060000",
1507                        "20061211T060000",
1508                        "20061212T060000",
1509                        "20061213T060000",
1510                        "20061214T060000",
1511                        "20061215T060000",
1512                        "20061216T060000",
1513                        "20061217T060000",
1514                        "20061218T060000",
1515                        "20061219T060000",
1516                        "20061220T060000",
1517                        "20061221T060000",
1518                        "20061222T060000",
1519                        "20061223T060000",
1520                        "20061224T060000",
1521                        "20061225T060000",
1522                        "20061226T060000",
1523                        "20061227T060000",
1524                        "20061228T060000",
1525                        "20061229T060000",
1526                        "20061230T060000",
1527                        "20061231T060000",
1528                        "20070101T060000",
1529                        "20070102T060000",
1530                        "20070103T060000",
1531                        "20070104T060000",
1532                        "20070105T060000",
1533                        "20070106T060000",
1534                        "20070107T060000",
1535                        "20070108T060000",
1536                        "20070109T060000",
1537                        "20070110T060000",
1538                        "20070111T060000",
1539                        "20070112T060000",
1540                        "20070113T060000",
1541                        "20070114T060000",
1542                        "20070115T060000",
1543                        "20070116T060000",
1544                        "20070117T060000",
1545                        "20070118T060000",
1546                        "20070119T060000",
1547                        "20070120T060000",
1548                        "20070121T060000",
1549                        "20070122T060000",
1550                        "20070123T060000",
1551                        "20070124T060000",
1552                        "20070125T060000",
1553                        "20070126T060000",
1554                        "20070127T060000",
1555                        "20070128T060000",
1556                        "20070129T060000",
1557                        "20070130T060000",
1558                        "20070131T060000",
1559                        "20070201T060000",
1560                        "20070202T060000",
1561                        "20070203T060000",
1562                        "20070204T060000",
1563                        "20070205T060000",
1564                        "20070206T060000",
1565                        "20070207T060000",
1566                        "20070208T060000",
1567                        "20070209T060000",
1568                        "20070210T060000",
1569                        "20070211T060000",
1570                        "20070212T060000",
1571                        "20070213T060000",
1572                        "20070214T060000",
1573                        "20070215T060000",
1574                        "20070216T060000",
1575                        "20070217T060000",
1576                        "20070218T060000",
1577                        "20070219T060000",
1578                        "20070220T060000",
1579                        "20070221T060000",
1580                        "20070222T060000",
1581                        "20070223T060000",
1582                        "20070224T060000",
1583                        "20070225T060000",
1584                        "20070226T060000",
1585                        "20070227T060000",
1586                        "20070228T060000",
1587                        "20070301T060000",
1588                        "20070302T060000",
1589                        "20070303T060000",
1590                        "20070304T060000",
1591                        "20070305T060000",
1592                        "20070306T060000",
1593                        "20070307T060000",
1594                        "20070308T060000",
1595                        "20070309T060000",
1596                        "20070310T060000",
1597                        "20070311T060000",
1598                        "20070312T060000",
1599                        "20070313T060000",
1600                        "20070314T060000",
1601                        "20070315T060000",
1602                        "20070316T060000",
1603                        "20070317T060000",
1604                        "20070318T060000",
1605                        "20070319T060000",
1606                        "20070320T060000",
1607                        "20070321T060000",
1608                        "20070322T060000",
1609                        "20070323T060000",
1610                        "20070324T060000",
1611                        "20070325T060000",
1612                        "20070326T060000",
1613                        "20070327T060000",
1614                        "20070328T060000",
1615                        "20070329T060000",
1616                        "20070330T060000",
1617                        "20070331T060000",
1618                        "20070401T060000",
1619                        "20070402T060000",
1620                        "20070403T060000",
1621                        "20070404T060000",
1622                        "20070405T060000",
1623                        "20070406T060000",
1624                        "20070407T060000",
1625                        "20070408T060000",
1626                        "20070409T060000",
1627                        "20070410T060000",
1628                        "20070411T060000",
1629                        "20070412T060000",
1630                        "20070413T060000",
1631                        "20070414T060000",
1632                        "20070415T060000",
1633                        "20070416T060000",
1634                        "20070417T060000",
1635                        "20070418T060000",
1636                        "20070419T060000",
1637                        "20070420T060000",
1638                        "20070421T060000",
1639                        "20070422T060000",
1640                        "20070423T060000",
1641                        "20070424T060000",
1642                        "20070425T060000",
1643                        "20070426T060000",
1644                        "20070427T060000",
1645                        "20070428T060000",
1646                        "20070429T060000",
1647                        "20070430T060000",
1648                        "20070501T060000",
1649                        "20070502T060000",
1650                        "20070503T060000",
1651                        "20070504T060000",
1652                        "20070505T060000",
1653                        "20070506T060000",
1654                        "20070507T060000",
1655                        "20070508T060000",
1656                        "20070509T060000",
1657                        "20070510T060000",
1658                        "20070511T060000",
1659                        "20070512T060000",
1660                        "20070513T060000",
1661                        "20070514T060000",
1662                        "20070515T060000",
1663                        "20070516T060000",
1664                        "20070517T060000",
1665                        "20070518T060000",
1666                        "20070519T060000",
1667                        "20070520T060000",
1668                        "20070521T060000",
1669                        "20070522T060000",
1670                        "20070523T060000",
1671                        "20070524T060000",
1672                        "20070525T060000",
1673                        "20070526T060000",
1674                        "20070527T060000",
1675                        "20070528T060000",
1676                        "20070529T060000",
1677                        "20070530T060000",
1678                        "20070531T060000",
1679                        "20070601T060000",
1680                        "20070602T060000",
1681                        "20070603T060000",
1682                        "20070604T060000",
1683                        "20070605T060000",
1684                        "20070606T060000",
1685                        "20070607T060000",
1686                        "20070608T060000",
1687                        "20070609T060000",
1688                        "20070610T060000",
1689                        "20070611T060000",
1690                        "20070612T060000",
1691                        "20070613T060000",
1692                        "20070614T060000",
1693                        "20070615T060000",
1694                        "20070616T060000",
1695                        "20070617T060000",
1696                        "20070618T060000",
1697                        "20070619T060000",
1698                        "20070620T060000",
1699                        "20070621T060000",
1700                        "20070622T060000",
1701                        "20070623T060000",
1702                        "20070624T060000",
1703                        "20070625T060000",
1704                        "20070626T060000",
1705                        "20070627T060000",
1706                        "20070628T060000",
1707                        "20070629T060000",
1708                        "20070630T060000",
1709                        "20070701T060000",
1710                        "20070702T060000",
1711                        "20070703T060000",
1712                        "20070704T060000",
1713                        "20070705T060000",
1714                        "20070706T060000",
1715                        "20070707T060000",
1716                        "20070708T060000",
1717                        "20070709T060000",
1718                        "20070710T060000",
1719                        "20070711T060000",
1720                        "20070712T060000",
1721                        "20070713T060000",
1722                        "20070714T060000",
1723                        "20070715T060000",
1724                        "20070716T060000",
1725                        "20070717T060000",
1726                        "20070718T060000",
1727                        "20070719T060000",
1728                        "20070720T060000",
1729                        "20070721T060000",
1730                        "20070722T060000",
1731                        "20070723T060000",
1732                        "20070724T060000",
1733                        "20070725T060000",
1734                        "20070726T060000",
1735                        "20070727T060000",
1736                        "20070728T060000",
1737                        "20070729T060000",
1738                        "20070730T060000",
1739                        "20070731T060000",
1740                        "20070801T060000",
1741                        "20070802T060000",
1742                        "20070803T060000",
1743                        "20070804T060000",
1744                        "20070805T060000",
1745                        "20070806T060000",
1746                        "20070807T060000",
1747                        "20070808T060000",
1748                        "20070809T060000",
1749                        "20070810T060000",
1750                        "20070811T060000",
1751                        "20070812T060000",
1752                        "20070813T060000",
1753                        "20070814T060000",
1754                        "20070815T060000",
1755                        "20070816T060000",
1756                        "20070817T060000",
1757                        "20070818T060000",
1758                        "20070819T060000",
1759                        "20070820T060000",
1760                        "20070821T060000",
1761                        "20070822T060000",
1762                        "20070823T060000",
1763                        "20070824T060000",
1764                        "20070825T060000",
1765                        "20070826T060000",
1766                        "20070827T060000",
1767                        "20070828T060000",
1768                        "20070829T060000",
1769                        "20070830T060000",
1770                        "20070831T060000",
1771                        "20070901T060000",
1772                        "20070902T060000",
1773                        "20070903T060000",
1774                        "20070904T060000",
1775                        "20070905T060000",
1776                        "20070906T060000",
1777                        "20070907T060000",
1778                        "20070908T060000",
1779                        "20070909T060000",
1780                        "20070910T060000",
1781                        "20070911T060000",
1782                        "20070912T060000",
1783                        "20070913T060000",
1784                        "20070914T060000",
1785                        "20070915T060000",
1786                        "20070916T060000",
1787                        "20070917T060000",
1788                        "20070918T060000",
1789                        "20070919T060000",
1790                        "20070920T060000",
1791                        "20070921T060000",
1792                        "20070922T060000",
1793                        "20070923T060000",
1794                        "20070924T060000",
1795                        "20070925T060000",
1796                        "20070926T060000",
1797                        "20070927T060000",
1798                        "20070928T060000",
1799                        "20070929T060000",
1800                        "20070930T060000",
1801                        "20071001T060000",
1802                        "20071002T060000",
1803                }, "20071002T060000");
1804    }
1805
1806    @MediumTest
1807    public void testFromGoogleCalendar7() throws Exception {
1808        // Every 3 days
1809        verifyRecurrence("20061003T080000",
1810                "FREQ=DAILY;INTERVAL=3;WKST=SU",
1811                null /* rdate */, null /* exrule */, null /* exdate */,
1812                "20060101T000000", "20090101T000000",
1813                new String[]{
1814                        "20061003T080000",
1815                        "20061006T080000",
1816                        "20061009T080000",
1817                        "20061012T080000",
1818                        "20061015T080000",
1819                        "20061018T080000",
1820                        "20061021T080000",
1821                        "20061024T080000",
1822                        "20061027T080000",
1823                        "20061030T080000",
1824                        "20061102T080000",
1825                        "20061105T080000",
1826                        "20061108T080000",
1827                        "20061111T080000",
1828                        "20061114T080000",
1829                        "20061117T080000",
1830                        "20061120T080000",
1831                        "20061123T080000",
1832                        "20061126T080000",
1833                        "20061129T080000",
1834                        "20061202T080000",
1835                        "20061205T080000",
1836                        "20061208T080000",
1837                        "20061211T080000",
1838                        "20061214T080000",
1839                        "20061217T080000",
1840                        "20061220T080000",
1841                        "20061223T080000",
1842                        "20061226T080000",
1843                        "20061229T080000",
1844                        "20070101T080000",
1845                        "20070104T080000",
1846                        "20070107T080000",
1847                        "20070110T080000",
1848                        "20070113T080000",
1849                        "20070116T080000",
1850                        "20070119T080000",
1851                        "20070122T080000",
1852                        "20070125T080000",
1853                        "20070128T080000",
1854                        "20070131T080000",
1855                        "20070203T080000",
1856                        "20070206T080000",
1857                        "20070209T080000",
1858                        "20070212T080000",
1859                        "20070215T080000",
1860                        "20070218T080000",
1861                        "20070221T080000",
1862                        "20070224T080000",
1863                        "20070227T080000",
1864                        "20070302T080000",
1865                        "20070305T080000",
1866                        "20070308T080000",
1867                        "20070311T080000",
1868                        "20070314T080000",
1869                        "20070317T080000",
1870                        "20070320T080000",
1871                        "20070323T080000",
1872                        "20070326T080000",
1873                        "20070329T080000",
1874                        "20070401T080000",
1875                        "20070404T080000",
1876                        "20070407T080000",
1877                        "20070410T080000",
1878                        "20070413T080000",
1879                        "20070416T080000",
1880                        "20070419T080000",
1881                        "20070422T080000",
1882                        "20070425T080000",
1883                        "20070428T080000",
1884                        "20070501T080000",
1885                        "20070504T080000",
1886                        "20070507T080000",
1887                        "20070510T080000",
1888                        "20070513T080000",
1889                        "20070516T080000",
1890                        "20070519T080000",
1891                        "20070522T080000",
1892                        "20070525T080000",
1893                        "20070528T080000",
1894                        "20070531T080000",
1895                        "20070603T080000",
1896                        "20070606T080000",
1897                        "20070609T080000",
1898                        "20070612T080000",
1899                        "20070615T080000",
1900                        "20070618T080000",
1901                        "20070621T080000",
1902                        "20070624T080000",
1903                        "20070627T080000",
1904                        "20070630T080000",
1905                        "20070703T080000",
1906                        "20070706T080000",
1907                        "20070709T080000",
1908                        "20070712T080000",
1909                        "20070715T080000",
1910                        "20070718T080000",
1911                        "20070721T080000",
1912                        "20070724T080000",
1913                        "20070727T080000",
1914                        "20070730T080000",
1915                        "20070802T080000",
1916                        "20070805T080000",
1917                        "20070808T080000",
1918                        "20070811T080000",
1919                        "20070814T080000",
1920                        "20070817T080000",
1921                        "20070820T080000",
1922                        "20070823T080000",
1923                        "20070826T080000",
1924                        "20070829T080000",
1925                        "20070901T080000",
1926                        "20070904T080000",
1927                        "20070907T080000",
1928                        "20070910T080000",
1929                        "20070913T080000",
1930                        "20070916T080000",
1931                        "20070919T080000",
1932                        "20070922T080000",
1933                        "20070925T080000",
1934                        "20070928T080000",
1935                        "20071001T080000",
1936                        "20071004T080000",
1937                        "20071007T080000",
1938                        "20071010T080000",
1939                        "20071013T080000",
1940                        "20071016T080000",
1941                        "20071019T080000",
1942                        "20071022T080000",
1943                        "20071025T080000",
1944                        "20071028T080000",
1945                        "20071031T080000",
1946                        "20071103T080000",
1947                        "20071106T080000",
1948                        "20071109T080000",
1949                        "20071112T080000",
1950                        "20071115T080000",
1951                        "20071118T080000",
1952                        "20071121T080000",
1953                        "20071124T080000",
1954                        "20071127T080000",
1955                        "20071130T080000",
1956                        "20071203T080000",
1957                        "20071206T080000",
1958                        "20071209T080000",
1959                        "20071212T080000",
1960                        "20071215T080000",
1961                        "20071218T080000",
1962                        "20071221T080000",
1963                        "20071224T080000",
1964                        "20071227T080000",
1965                        "20071230T080000",
1966                        "20080102T080000",
1967                        "20080105T080000",
1968                        "20080108T080000",
1969                        "20080111T080000",
1970                        "20080114T080000",
1971                        "20080117T080000",
1972                        "20080120T080000",
1973                        "20080123T080000",
1974                        "20080126T080000",
1975                        "20080129T080000",
1976                        "20080201T080000",
1977                        "20080204T080000",
1978                        "20080207T080000",
1979                        "20080210T080000",
1980                        "20080213T080000",
1981                        "20080216T080000",
1982                        "20080219T080000",
1983                        "20080222T080000",
1984                        "20080225T080000",
1985                        "20080228T080000",
1986                        "20080302T080000",
1987                        "20080305T080000",
1988                        "20080308T080000",
1989                        "20080311T080000",
1990                        "20080314T080000",
1991                        "20080317T080000",
1992                        "20080320T080000",
1993                        "20080323T080000",
1994                        "20080326T080000",
1995                        "20080329T080000",
1996                        "20080401T080000",
1997                        "20080404T080000",
1998                        "20080407T080000",
1999                        "20080410T080000",
2000                        "20080413T080000",
2001                        "20080416T080000",
2002                        "20080419T080000",
2003                        "20080422T080000",
2004                        "20080425T080000",
2005                        "20080428T080000",
2006                        "20080501T080000",
2007                        "20080504T080000",
2008                        "20080507T080000",
2009                        "20080510T080000",
2010                        "20080513T080000",
2011                        "20080516T080000",
2012                        "20080519T080000",
2013                        "20080522T080000",
2014                        "20080525T080000",
2015                        "20080528T080000",
2016                        "20080531T080000",
2017                        "20080603T080000",
2018                        "20080606T080000",
2019                        "20080609T080000",
2020                        "20080612T080000",
2021                        "20080615T080000",
2022                        "20080618T080000",
2023                        "20080621T080000",
2024                        "20080624T080000",
2025                        "20080627T080000",
2026                        "20080630T080000",
2027                        "20080703T080000",
2028                        "20080706T080000",
2029                        "20080709T080000",
2030                        "20080712T080000",
2031                        "20080715T080000",
2032                        "20080718T080000",
2033                        "20080721T080000",
2034                        "20080724T080000",
2035                        "20080727T080000",
2036                        "20080730T080000",
2037                        "20080802T080000",
2038                        "20080805T080000",
2039                        "20080808T080000",
2040                        "20080811T080000",
2041                        "20080814T080000",
2042                        "20080817T080000",
2043                        "20080820T080000",
2044                        "20080823T080000",
2045                        "20080826T080000",
2046                        "20080829T080000",
2047                        "20080901T080000",
2048                        "20080904T080000",
2049                        "20080907T080000",
2050                        "20080910T080000",
2051                        "20080913T080000",
2052                        "20080916T080000",
2053                        "20080919T080000",
2054                        "20080922T080000",
2055                        "20080925T080000",
2056                        "20080928T080000",
2057                        "20081001T080000",
2058                        "20081004T080000",
2059                        "20081007T080000",
2060                        "20081010T080000",
2061                        "20081013T080000",
2062                        "20081016T080000",
2063                        "20081019T080000",
2064                        "20081022T080000",
2065                        "20081025T080000",
2066                        "20081028T080000",
2067                        "20081031T080000",
2068                        "20081103T080000",
2069                        "20081106T080000",
2070                        "20081109T080000",
2071                        "20081112T080000",
2072                        "20081115T080000",
2073                        "20081118T080000",
2074                        "20081121T080000",
2075                        "20081124T080000",
2076                        "20081127T080000",
2077                        "20081130T080000",
2078                        "20081203T080000",
2079                        "20081206T080000",
2080                        "20081209T080000",
2081                        "20081212T080000",
2082                        "20081215T080000",
2083                        "20081218T080000",
2084                        "20081221T080000",
2085                        "20081224T080000",
2086                        "20081227T080000",
2087                        "20081230T080000",
2088                }, "20081230T080000");
2089    }
2090
2091    @SmallTest
2092    public void testFromGoogleCalendar8() throws Exception {
2093        // Annually on October 4
2094        verifyRecurrence("20061004T130000",
2095                "FREQ=YEARLY;INTERVAL=1;WKST=SU",
2096                null /* rdate */, null /* exrule */, null /* exdate */,
2097                "20060101T000000", "20090101T000000",
2098                new String[]{
2099                        "20061004T130000",
2100                        "20071004T130000",
2101                        "20081004T130000",
2102                }, "20081004T130000");
2103    }
2104
2105    @MediumTest
2106    public void testFromGoogleCalendar9() throws Exception {
2107        // Monthly on the last Monday
2108        verifyRecurrence("20061030T170000",
2109                "FREQ=MONTHLY;INTERVAL=1;BYDAY=-1MO;WKST=SU",
2110                null /* rdate */, null /* exrule */, null /* exdate */,
2111                "20060101T000000", "20090101T000000",
2112                new String[]{
2113                        "20061030T170000",
2114                        "20061127T170000",
2115                        "20061225T170000",
2116                        "20070129T170000",
2117                        "20070226T170000",
2118                        "20070326T170000",
2119                        "20070430T170000",
2120                        "20070528T170000",
2121                        "20070625T170000",
2122                        "20070730T170000",
2123                        "20070827T170000",
2124                        "20070924T170000",
2125                        "20071029T170000",
2126                        "20071126T170000",
2127                        "20071231T170000",
2128                        "20080128T170000",
2129                        "20080225T170000",
2130                        "20080331T170000",
2131                        "20080428T170000",
2132                        "20080526T170000",
2133                        "20080630T170000",
2134                        "20080728T170000",
2135                        "20080825T170000",
2136                        "20080929T170000",
2137                        "20081027T170000",
2138                        "20081124T170000",
2139                        "20081229T170000",
2140                }, "20081229T170000");
2141    }
2142
2143    @SmallTest
2144    public void testFromGoogleCalendar10() throws Exception {
2145        // Every 7 weeks on Tuesday, Wednesday
2146        verifyRecurrence("20061004T090000",
2147                "FREQ=WEEKLY;UNTIL=20070223T010000Z;INTERVAL=7;BYDAY=TU,WE;WKST=SU",
2148                null /* rdate */, null /* exrule */, null /* exdate */,
2149                "20060101T000000", "20090101T000000",
2150                new String[]{
2151                        "20061004T090000",
2152                        "20061121T090000",
2153                        "20061122T090000",
2154                        "20070109T090000",
2155                        "20070110T090000",
2156                }, "20070222T170000");
2157    }
2158
2159    @SmallTest
2160    public void testFromGoogleCalendar11() throws Exception {
2161        // Monthly on day 31
2162        verifyRecurrence("20061031T160000",
2163                "FREQ=MONTHLY;INTERVAL=1;WKST=SU",
2164                null /* rdate */, null /* exrule */, null /* exdate */,
2165                "20060101T000000", "20090101T000000",
2166                new String[]{
2167                        "20061031T160000",
2168                        "20061231T160000",
2169                        "20070131T160000",
2170                        "20070331T160000",
2171                        "20070531T160000",
2172                        "20070731T160000",
2173                        "20070831T160000",
2174                        "20071031T160000",
2175                        "20071231T160000",
2176                        "20080131T160000",
2177                        "20080331T160000",
2178                        "20080531T160000",
2179                        "20080731T160000",
2180                        "20080831T160000",
2181                        "20081031T160000",
2182                        "20081231T160000",
2183                },
2184                "20081231T160000");
2185    }
2186
2187    @SmallTest
2188    public void testFromGoogleCalendar12() throws Exception {
2189        // Every 2 months on the first Tuesday
2190        verifyRecurrence("20061004T110000",
2191                "FREQ=MONTHLY;INTERVAL=2;BYDAY=1TU;WKST=SU",
2192                null /* rdate */, null /* exrule */, null /* exdate */,
2193                "20060101T000000", "20090101T000000",
2194                new String[]{
2195                        "20061004T110000",
2196                        "20061205T110000",
2197                        "20070206T110000",
2198                        "20070403T110000",
2199                        "20070605T110000",
2200                        "20070807T110000",
2201                        "20071002T110000",
2202                        "20071204T110000",
2203                        "20080205T110000",
2204                        "20080401T110000",
2205                        "20080603T110000",
2206                        "20080805T110000",
2207                        "20081007T110000",
2208                        "20081202T110000",
2209                },
2210                "20081202T110000");
2211    }
2212
2213    @SmallTest
2214    public void testYearly0() throws Exception {
2215        verifyRecurrence("20080101T100000",
2216                "FREQ=YEARLY;UNTIL=20090131T090000Z;BYMONTH=1;BYDAY=SU,MO",
2217                null /* rdate */, null /* exrule */, null /* exdate */,
2218                "20080101T000000", "20090130T000000",
2219                new String[]{
2220                    "20080101T100000",
2221                    "20080106T100000",
2222                    "20080107T100000",
2223                    "20080113T100000",
2224                    "20080114T100000",
2225                    "20080120T100000",
2226                    "20080121T100000",
2227                    "20080127T100000",
2228                    "20080128T100000",
2229                    "20090104T100000",
2230                    "20090105T100000",
2231                    "20090111T100000",
2232                    "20090112T100000",
2233                    "20090118T100000",
2234                    "20090119T100000",
2235                    "20090125T100000",
2236                    "20090126T100000",
2237                }, "20090131T010000");
2238    }
2239
2240    /**
2241     * This test fails because of a bug in RecurrenceProcessor.expand(). We
2242     * don't have time to fix the bug yet but we don't want to lose track of
2243     * this test either. The "failing" prefix on the method name prevents this
2244     * test from being run. Remove the "failing" prefix when the bug is fixed.
2245     *
2246     * @throws Exception
2247     */
2248    @SmallTest
2249    public void failingTestYearly1() throws Exception {
2250        verifyRecurrence("20060101T100000",
2251                "FREQ=YEARLY;COUNT=10;BYYEARDAY=1,100,200",
2252                null /* rdate */, null /* exrule */, null /* exdate */,
2253                "20060101T000000", "20090131T000000",
2254                new String[]{
2255                "20060101T100000",
2256                "20060409T100000",
2257                "20060718T100000",
2258                "20070101T100000",
2259                "20070409T100000",
2260                "20070718T100000",
2261                "20080101T100000",
2262                "20080410T100000",
2263                "20080719T100000",
2264                "20090101T100000",
2265                });
2266    }
2267
2268    /**
2269     * This test fails because of a bug in RecurrenceProcessor.expand(). We
2270     * don't have time to fix the bug yet but we don't want to lose track of
2271     * this test either. The "failing" prefix on the method name prevents this
2272     * test from being run. Remove the "failing" prefix when the bug is fixed.
2273     *
2274     * @throws Exception
2275     */
2276    @SmallTest
2277    public void failingTestYearly2() throws Exception {
2278        verifyRecurrence("20060101T100000",
2279                "FREQ=YEARLY;COUNT=5;BYWEEKNO=6;BYDAY=MO;WKST=MO",
2280                null /* rdate */, null /* exrule */, null /* exdate */,
2281                "20060101T000000", "20090131T000000",
2282                new String[]{
2283                "20060101T100000",
2284                "20060206T100000",
2285                "20070205T100000",
2286                "20080204T100000",
2287                "20090209T100000",
2288                });
2289    }
2290
2291    /**
2292     * This test fails because of a bug in RecurrenceProcessor.expand(). We
2293     * don't have time to fix the bug yet but we don't want to lose track of
2294     * this test either. The "failing" prefix on the method name prevents this
2295     * test from being run. Remove the "failing" prefix when the bug is fixed.
2296     *
2297     * @throws Exception
2298     */
2299    @SmallTest
2300    public void failingTestYearly3() throws Exception {
2301        verifyRecurrence("20060101T100000",
2302                "FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
2303                null /* rdate */, null /* exrule */, null /* exdate */,
2304                "20060101T000000", "20090131T000000",
2305                new String[]{
2306                "20060101T100000",
2307                "20060302T100000",
2308                "20060309T100000",
2309                "20060316T100000",
2310                "20060323T100000",
2311                "20060330T100000",
2312                "20070301T100000",
2313                "20070308T100000",
2314                "20070315T100000",
2315                "20070322T100000",
2316                "20070329T100000",
2317                "20080306T100000",
2318                "20080313T100000",
2319                "20080320T100000",
2320                "20080327T100000",
2321                });
2322    }
2323
2324    /**
2325     * This test fails because of a bug in RecurrenceProcessor.expand(). We
2326     * don't have time to fix the bug yet but we don't want to lose track of
2327     * this test either. The "failing" prefix on the method name prevents this
2328     * test from being run. Remove the "failing" prefix when the bug is fixed.
2329     *
2330     * @throws Exception
2331     */
2332    @SmallTest
2333    public void failingTestYearly4() throws Exception {
2334        verifyRecurrence("19920101T100000",
2335                "FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8",
2336                null /* rdate */, null /* exrule */, null /* exdate */,
2337                "19920101T000000", "20121231T000000",
2338                new String[]{
2339                "19920101T100000",
2340                "19921103T100000",
2341                "19961105T100000",
2342                "20001107T100000",
2343                "20041102T100000",
2344                "20081104T100000",
2345                "20121106T100000",
2346                });
2347    }
2348
2349    /**
2350     * Test repeating event from Exchange with count field.
2351     * Time range covers the whole repetition.
2352     *
2353     * @throws Exception
2354     */
2355    public void testCount1() throws Exception {
2356        verifyRecurrence("20100324T153000",
2357                "FREQ=WEEKLY;INTERVAL=1;COUNT=10;BYDAY=WE",
2358                null /* rdate */, null /* exrule */, null /* exdate */,
2359                "20100301T000000", "20100630T000000",
2360                new String[]{
2361                        "20100324T153000",
2362                        "20100331T153000",
2363                        "20100407T153000",
2364                        "20100414T153000",
2365                        "20100421T153000",
2366                        "20100428T153000",
2367                        "20100505T153000",
2368                        "20100512T153000",
2369                        "20100519T153000",
2370                        "20100526T153000",
2371                });
2372    }
2373
2374    /**
2375     * Test repeating event from Exchange with count field.
2376     * Time range covers the first part of the repetition.
2377     * @throws Exception
2378     */
2379    public void testCount2() throws Exception {
2380        verifyRecurrence("20100324T153000",
2381                "FREQ=WEEKLY;INTERVAL=1;COUNT=10;BYDAY=WE",
2382                null /* rdate */, null /* exrule */, null /* exdate */,
2383                "20100501T000000", "20100630T000000",
2384                new String[]{
2385                        "20100505T153000",
2386                        "20100512T153000",
2387                        "20100519T153000",
2388                        "20100526T153000",
2389                });
2390    }
2391
2392    /**
2393     * Test repeating event from Exchange with count field.
2394     * Time range is beyond the repetition.
2395     * @throws Exception
2396     */
2397    public void testCount3() throws Exception {
2398        verifyRecurrence("20100324T153000",
2399                "FREQ=WEEKLY;INTERVAL=1;COUNT=10;BYDAY=WE",
2400                null /* rdate */, null /* exrule */, null /* exdate */,
2401                "20100601T000000", "20100630T000000",
2402                new String[]{},
2403                "20100526T153000" /* last */);
2404    }
2405
2406    /**
2407     * Test repeating event from Exchange with count field.
2408     * Time range is before the repetition
2409     * @throws Exception
2410     */
2411    public void testCount4() throws Exception {
2412        verifyRecurrence("20100324T153000",
2413                "FREQ=WEEKLY;INTERVAL=1;COUNT=10;BYDAY=WE",
2414                null /* rdate */, null /* exrule */, null /* exdate */,
2415                "20100101T000000", "20100301T000000",
2416                new String[]{},
2417                null /* last */);
2418    }
2419
2420
2421    // These recurrence rules are used in the loop that measures the performance
2422    // of recurrence expansion.
2423    private static final String[] performanceRrules = new String[] {
2424        "FREQ=DAILY;COUNT=100",
2425        "FREQ=DAILY;INTERVAL=2;UNTIL=20080101T000000Z",
2426        "FREQ=YEARLY;UNTIL=20090131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA",
2427        "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
2428        "FREQ=WEEKLY;COUNT=100;WKST=SU;BYDAY=MO,TU,WE,TH,FR",
2429        "FREQ=MONTHLY;COUNT=100;BYDAY=1FR",
2430        "FREQ=MONTHLY;INTERVAL=2;COUNT=100;BYDAY=1SU,-1SU",
2431        "FREQ=MONTHLY;BYMONTHDAY=1,15",
2432        "FREQ=MONTHLY;INTERVAL=3;COUNT=100;BYMONTHDAY=10,11,12,13,14",
2433        "FREQ=YEARLY;COUNT=100;BYMONTH=6,7,8",
2434        "FREQ=YEARLY;INTERVAL=2;BYMONTH=1,2,3,6,7,8",
2435        "FREQ=YEARLY;COUNT=100;BYYEARDAY=1,100,200",
2436        "FREQ=YEARLY;BYDAY=2MO",
2437        "FREQ=YEARLY;BYWEEKNO=2,3,4;BYDAY=MO",
2438        "FREQ=YEARLY;BYMONTH=3,4,5;BYDAY=TH",
2439        "FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13",
2440        "FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13",
2441        "FREQ=YEARLY;INTERVAL=2;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8",
2442        "FREQ=WEEKLY;INTERVAL=2;COUNT=100;BYDAY=TU,SU;WKST=MO",
2443        "FREQ=WEEKLY;INTERVAL=2;COUNT=100;BYDAY=TU,SU;WKST=SU",
2444    };
2445
2446    /**
2447     * This test never fails.  It just runs for a while (about 10 seconds)
2448     * in order to measure the performance of recurrence expansion.
2449     *
2450     * @throws Exception
2451     */
2452    @LargeTest
2453    public void performanceTextExpand() throws Exception {
2454        String tz = "America/Los_Angeles";
2455        Time dtstart = new Time(tz);
2456        Time rangeStart = new Time(tz);
2457        Time rangeEnd = new Time(tz);
2458        TreeSet<Long> out = new TreeSet<Long>();
2459
2460        dtstart.parse("20010101T000000");
2461        rangeStart.parse("20010101T000000");
2462        rangeEnd.parse("20090101T000000");
2463        long rangeStartMillis = rangeStart.toMillis(false /* use isDst */);
2464        long rangeEndMillis = rangeEnd.toMillis(false /* use isDst */);
2465
2466        long startTime = System.currentTimeMillis();
2467        for (int iterations = 0; iterations < 5; iterations++) {
2468            RecurrenceProcessor rp = new RecurrenceProcessor();
2469
2470            int len = performanceRrules.length;
2471            for (int i = 0; i < len; i++) {
2472                String rrule = performanceRrules[i];
2473                //Log.i(TAG, "expanding rule: " + rrule);
2474                RecurrenceSet recur = new RecurrenceSet(rrule, null, null, null);
2475
2476                long [] dates = rp.expand(dtstart, recur, rangeStartMillis, rangeEndMillis);
2477                //Log.i(TAG, "num instances: " + out.size());
2478
2479                // Also include the time to iterate through the expanded values
2480                for (long date : dates) {
2481                    // Use the date so that this loop is not optimized away.
2482                    if (date == -1) {
2483                        Log.e(TAG, "unexpected date");
2484                        break;
2485                    }
2486                }
2487                out.clear();
2488            }
2489        }
2490
2491        long endTime = System.currentTimeMillis();
2492        long elapsed = endTime - startTime;
2493        Log.i(TAG, "testPerformanceExpand() expand() elapsed millis: " + elapsed);
2494    }
2495
2496    @LargeTest
2497    public void performanceTestNormalize() throws Exception {
2498        final int ITERATIONS = 50000;
2499
2500        String tz = "America/Los_Angeles";
2501        Time date = new Time(tz);
2502        date.parse("20090404T100000");
2503
2504        long startTime = System.currentTimeMillis();
2505
2506        for (int i = 0; i < ITERATIONS; i++) {
2507            date.month += 1;
2508            date.monthDay += 100;
2509            date.normalize(true);
2510            date.month -= 1;
2511            date.monthDay -= 100;
2512            date.normalize(true);
2513        }
2514
2515        long endTime = System.currentTimeMillis();
2516        long elapsed = endTime - startTime;
2517        Log.i(TAG, "date: " + date.format2445());
2518        Log.i(TAG, "testPerformanceNormalize() normalize() elapsed millis: " + elapsed);
2519
2520        // Time the unsafe version
2521        date.parse("20090404T100000");
2522        startTime = System.currentTimeMillis();
2523        for (int i = 0; i < ITERATIONS; i++) {
2524            date.month += 1;
2525            date.monthDay += 100;
2526            RecurrenceProcessor.unsafeNormalize(date);
2527            date.month -= 1;
2528            date.monthDay -= 100;
2529            RecurrenceProcessor.unsafeNormalize(date);
2530        }
2531
2532        endTime = System.currentTimeMillis();
2533        elapsed = endTime - startTime;
2534        Log.i(TAG, "date: " + date.format2445());
2535        Log.i(TAG, "testPerformanceNormalize() unsafeNormalize() elapsed millis: " + elapsed);
2536    }
2537 }
2538