1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendarcommon2;
18
19import com.android.calendarcommon2.EventRecurrence.InvalidFormatException;
20
21import android.test.suitebuilder.annotation.SmallTest;
22import android.test.suitebuilder.annotation.Suppress;
23
24import junit.framework.TestCase;
25
26import java.util.Arrays;
27
28/**
29 * Test android.pim.EventRecurrence.
30 *
31 * adb shell am instrument -w -e class com.android.calendarcommon2.EventRecurrenceTest \
32 *   com.android.calendarcommon2.tests/android.test.InstrumentationTestRunner
33 */
34public class EventRecurrenceTest extends TestCase {
35
36    @SmallTest
37    public void test0() throws Exception {
38        verifyRecurType("FREQ=SECONDLY",
39                /* int freq */         EventRecurrence.SECONDLY,
40                /* String until */     null,
41                /* int count */        0,
42                /* int interval */     0,
43                /* int[] bysecond */   null,
44                /* int[] byminute */   null,
45                /* int[] byhour */     null,
46                /* int[] byday */      null,
47                /* int[] bydayNum */   null,
48                /* int[] bymonthday */ null,
49                /* int[] byyearday */  null,
50                /* int[] byweekno */   null,
51                /* int[] bymonth */    null,
52                /* int[] bysetpos */   null,
53                /* int wkst */         EventRecurrence.MO
54        );
55    }
56
57    @SmallTest
58    public void test1() throws Exception {
59        verifyRecurType("FREQ=MINUTELY",
60                /* int freq */         EventRecurrence.MINUTELY,
61                /* String until */     null,
62                /* int count */        0,
63                /* int interval */     0,
64                /* int[] bysecond */   null,
65                /* int[] byminute */   null,
66                /* int[] byhour */     null,
67                /* int[] byday */      null,
68                /* int[] bydayNum */   null,
69                /* int[] bymonthday */ null,
70                /* int[] byyearday */  null,
71                /* int[] byweekno */   null,
72                /* int[] bymonth */    null,
73                /* int[] bysetpos */   null,
74                /* int wkst */         EventRecurrence.MO
75        );
76    }
77
78    @SmallTest
79    public void test2() throws Exception {
80        verifyRecurType("FREQ=HOURLY",
81                /* int freq */         EventRecurrence.HOURLY,
82                /* String until */     null,
83                /* int count */        0,
84                /* int interval */     0,
85                /* int[] bysecond */   null,
86                /* int[] byminute */   null,
87                /* int[] byhour */     null,
88                /* int[] byday */      null,
89                /* int[] bydayNum */   null,
90                /* int[] bymonthday */ null,
91                /* int[] byyearday */  null,
92                /* int[] byweekno */   null,
93                /* int[] bymonth */    null,
94                /* int[] bysetpos */   null,
95                /* int wkst */         EventRecurrence.MO
96        );
97    }
98
99    @SmallTest
100    public void test3() throws Exception {
101        verifyRecurType("FREQ=DAILY",
102                /* int freq */         EventRecurrence.DAILY,
103                /* String until */     null,
104                /* int count */        0,
105                /* int interval */     0,
106                /* int[] bysecond */   null,
107                /* int[] byminute */   null,
108                /* int[] byhour */     null,
109                /* int[] byday */      null,
110                /* int[] bydayNum */   null,
111                /* int[] bymonthday */ null,
112                /* int[] byyearday */  null,
113                /* int[] byweekno */   null,
114                /* int[] bymonth */    null,
115                /* int[] bysetpos */   null,
116                /* int wkst */         EventRecurrence.MO
117        );
118    }
119
120    @SmallTest
121    public void test4() throws Exception {
122        verifyRecurType("FREQ=WEEKLY",
123                /* int freq */         EventRecurrence.WEEKLY,
124                /* String until */     null,
125                /* int count */        0,
126                /* int interval */     0,
127                /* int[] bysecond */   null,
128                /* int[] byminute */   null,
129                /* int[] byhour */     null,
130                /* int[] byday */      null,
131                /* int[] bydayNum */   null,
132                /* int[] bymonthday */ null,
133                /* int[] byyearday */  null,
134                /* int[] byweekno */   null,
135                /* int[] bymonth */    null,
136                /* int[] bysetpos */   null,
137                /* int wkst */         EventRecurrence.MO
138        );
139    }
140
141    @SmallTest
142    public void test5() throws Exception {
143        verifyRecurType("FREQ=MONTHLY",
144                /* int freq */         EventRecurrence.MONTHLY,
145                /* String until */     null,
146                /* int count */        0,
147                /* int interval */     0,
148                /* int[] bysecond */   null,
149                /* int[] byminute */   null,
150                /* int[] byhour */     null,
151                /* int[] byday */      null,
152                /* int[] bydayNum */   null,
153                /* int[] bymonthday */ null,
154                /* int[] byyearday */  null,
155                /* int[] byweekno */   null,
156                /* int[] bymonth */    null,
157                /* int[] bysetpos */   null,
158                /* int wkst */         EventRecurrence.MO
159        );
160    }
161
162    @SmallTest
163    public void test6() throws Exception {
164        verifyRecurType("FREQ=YEARLY",
165                /* int freq */         EventRecurrence.YEARLY,
166                /* String until */     null,
167                /* int count */        0,
168                /* int interval */     0,
169                /* int[] bysecond */   null,
170                /* int[] byminute */   null,
171                /* int[] byhour */     null,
172                /* int[] byday */      null,
173                /* int[] bydayNum */   null,
174                /* int[] bymonthday */ null,
175                /* int[] byyearday */  null,
176                /* int[] byweekno */   null,
177                /* int[] bymonth */    null,
178                /* int[] bysetpos */   null,
179                /* int wkst */         EventRecurrence.MO
180        );
181    }
182
183    @SmallTest
184    public void test7() throws Exception {
185        // with an until
186        verifyRecurType("FREQ=DAILY;UNTIL=112233T223344Z",
187                /* int freq */         EventRecurrence.DAILY,
188                /* String until */     "112233T223344Z",
189                /* int count */        0,
190                /* int interval */     0,
191                /* int[] bysecond */   null,
192                /* int[] byminute */   null,
193                /* int[] byhour */     null,
194                /* int[] byday */      null,
195                /* int[] bydayNum */   null,
196                /* int[] bymonthday */ null,
197                /* int[] byyearday */  null,
198                /* int[] byweekno */   null,
199                /* int[] bymonth */    null,
200                /* int[] bysetpos */   null,
201                /* int wkst */         EventRecurrence.MO
202        );
203    }
204
205    @SmallTest
206    public void test8() throws Exception {
207        // with a count
208        verifyRecurType("FREQ=DAILY;COUNT=334",
209                /* int freq */         EventRecurrence.DAILY,
210                /* String until */     null,
211                /* int count */        334,
212                /* int interval */     0,
213                /* int[] bysecond */   null,
214                /* int[] byminute */   null,
215                /* int[] byhour */     null,
216                /* int[] byday */      null,
217                /* int[] bydayNum */   null,
218                /* int[] bymonthday */ null,
219                /* int[] byyearday */  null,
220                /* int[] byweekno */   null,
221                /* int[] bymonth */    null,
222                /* int[] bysetpos */   null,
223                /* int wkst */         EventRecurrence.MO
224        );
225    }
226
227    @SmallTest
228    public void test9() throws Exception {
229        // with a count
230        verifyRecurType("FREQ=DAILY;INTERVAL=5000",
231                /* int freq */         EventRecurrence.DAILY,
232                /* String until */     null,
233                /* int count */        0,
234                /* int interval */     5000,
235                /* int[] bysecond */   null,
236                /* int[] byminute */   null,
237                /* int[] byhour */     null,
238                /* int[] byday */      null,
239                /* int[] bydayNum */   null,
240                /* int[] bymonthday */ null,
241                /* int[] byyearday */  null,
242                /* int[] byweekno */   null,
243                /* int[] bymonth */    null,
244                /* int[] bysetpos */   null,
245                /* int wkst */         EventRecurrence.MO
246        );
247    }
248
249    @SmallTest
250    public void test10() throws Exception {
251        // verifyRecurType all of the BY* ones with one element
252        verifyRecurType("FREQ=DAILY"
253                + ";BYSECOND=0"
254                + ";BYMINUTE=1"
255                + ";BYHOUR=2"
256                + ";BYMONTHDAY=30"
257                + ";BYYEARDAY=300"
258                + ";BYWEEKNO=53"
259                + ";BYMONTH=12"
260                + ";BYSETPOS=-15"
261                + ";WKST=SU",
262                /* int freq */         EventRecurrence.DAILY,
263                /* String until */     null,
264                /* int count */        0,
265                /* int interval */     0,
266                /* int[] bysecond */   new int[]{0},
267                /* int[] byminute */   new int[]{1},
268                /* int[] byhour */     new int[]{2},
269                /* int[] byday */      null,
270                /* int[] bydayNum */   null,
271                /* int[] bymonthday */ new int[]{30},
272                /* int[] byyearday */  new int[]{300},
273                /* int[] byweekno */   new int[]{53},
274                /* int[] bymonth */    new int[]{12},
275                /* int[] bysetpos */   new int[]{-15},
276                /* int wkst */         EventRecurrence.SU
277        );
278    }
279
280    @SmallTest
281    public void test11() throws Exception {
282        // verifyRecurType all of the BY* ones with one element
283        verifyRecurType("FREQ=DAILY"
284                + ";BYSECOND=0,30,59"
285                + ";BYMINUTE=0,41,59"
286                + ";BYHOUR=0,4,23"
287                + ";BYMONTHDAY=-31,-1,1,31"
288                + ";BYYEARDAY=-366,-1,1,366"
289                + ";BYWEEKNO=-53,-1,1,53"
290                + ";BYMONTH=1,12"
291                + ";BYSETPOS=1,2,3,4,500,10000"
292                + ";WKST=SU",
293                /* int freq */         EventRecurrence.DAILY,
294                /* String until */     null,
295                /* int count */        0,
296                /* int interval */     0,
297                /* int[] bysecond */   new int[]{0, 30, 59},
298                /* int[] byminute */   new int[]{0, 41, 59},
299                /* int[] byhour */     new int[]{0, 4, 23},
300                /* int[] byday */      null,
301                /* int[] bydayNum */   null,
302                /* int[] bymonthday */ new int[]{-31, -1, 1, 31},
303                /* int[] byyearday */  new int[]{-366, -1, 1, 366},
304                /* int[] byweekno */   new int[]{-53, -1, 1, 53},
305                /* int[] bymonth */    new int[]{1, 12},
306                /* int[] bysetpos */   new int[]{1, 2, 3, 4, 500, 10000},
307                /* int wkst */         EventRecurrence.SU
308        );
309    }
310
311    private static class Check {
312        Check(String k, int... v) {
313            key = k;
314            values = v;
315        }
316
317        String key;
318        int[] values;
319    }
320
321    // this is a negative verifyRecurType case to verifyRecurType the range of the numbers accepted
322    @SmallTest
323    public void test12() throws Exception {
324        Check[] checks = new Check[]{
325                new Check("BYSECOND", -100, -1, 60, 100),
326                new Check("BYMINUTE", -100, -1, 60, 100),
327                new Check("BYHOUR", -100, -1, 24, 100),
328                new Check("BYMONTHDAY", -100, -32, 0, 32, 100),
329                new Check("BYYEARDAY", -400, -367, 0, 367, 400),
330                new Check("BYWEEKNO", -100, -54, 0, 54, 100),
331                new Check("BYMONTH", -100, -5, 0, 13, 100)
332        };
333
334        for (Check ck : checks) {
335            for (int n : ck.values) {
336                String recur = "FREQ=DAILY;" + ck.key + "=" + n;
337                try {
338                    EventRecurrence er = new EventRecurrence();
339                    er.parse(recur);
340                    fail("Negative verifyRecurType failed. "
341                            + " parse failed to throw an exception for '"
342                            + recur + "'");
343                } catch (EventRecurrence.InvalidFormatException e) {
344                    // expected
345                }
346            }
347        }
348    }
349
350    // verifyRecurType BYDAY
351    @SmallTest
352    public void test13() throws Exception {
353        verifyRecurType("FREQ=DAILY;BYDAY=1SU,-2MO,+33TU,WE,TH,FR,SA",
354                /* int freq */         EventRecurrence.DAILY,
355                /* String until */     null,
356                /* int count */        0,
357                /* int interval */     0,
358                /* int[] bysecond */   null,
359                /* int[] byminute */   null,
360                /* int[] byhour */     null,
361                /* int[] byday */      new int[] {
362                        EventRecurrence.SU,
363                        EventRecurrence.MO,
364                        EventRecurrence.TU,
365                        EventRecurrence.WE,
366                        EventRecurrence.TH,
367                        EventRecurrence.FR,
368                        EventRecurrence.SA
369                },
370                /* int[] bydayNum */   new int[]{1, -2, 33, 0, 0, 0, 0},
371                /* int[] bymonthday */ null,
372                /* int[] byyearday */  null,
373                /* int[] byweekno */   null,
374                /* int[] bymonth */    null,
375                /* int[] bysetpos */   null,
376                /* int wkst */         EventRecurrence.MO
377        );
378    }
379
380    @Suppress
381    // Repro bug #2331761 - this should fail because of the last comma into BYDAY
382    public void test14() throws Exception {
383        verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;BYDAY=MO,TU,WE,",
384                /* int freq */         EventRecurrence.WEEKLY,
385                /* String until */     "20100129T130000Z",
386                /* int count */        0,
387                /* int interval */     1,
388                /* int[] bysecond */   null,
389                /* int[] byminute */   null,
390                /* int[] byhour */     null,
391                /* int[] byday */      new int[] {
392                        EventRecurrence.MO,
393                        EventRecurrence.TU,
394                        EventRecurrence.WE,
395                },
396                /* int[] bydayNum */   new int[]{0, 0, 0},
397                /* int[] bymonthday */ null,
398                /* int[] byyearday */  null,
399                /* int[] byweekno */   null,
400                /* int[] bymonth */    null,
401                /* int[] bysetpos */   null,
402                /* int wkst */         EventRecurrence.MO
403        );
404    }
405
406    // This test should pass
407    public void test15() throws Exception {
408        verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;"
409                + "BYDAY=MO,TU,WE,TH,FR,SA,SU",
410                /* int freq */         EventRecurrence.WEEKLY,
411                /* String until */     "20100129T130000Z",
412                /* int count */        0,
413                /* int interval */     1,
414                /* int[] bysecond */   null,
415                /* int[] byminute */   null,
416                /* int[] byhour */     null,
417                /* int[] byday */      new int[] {
418                        EventRecurrence.MO,
419                        EventRecurrence.TU,
420                        EventRecurrence.WE,
421                        EventRecurrence.TH,
422                        EventRecurrence.FR,
423                        EventRecurrence.SA,
424                        EventRecurrence.SU
425                },
426                /* int[] bydayNum */   new int[]{0, 0, 0, 0, 0, 0, 0},
427                /* int[] bymonthday */ null,
428                /* int[] byyearday */  null,
429                /* int[] byweekno */   null,
430                /* int[] bymonth */    null,
431                /* int[] bysetpos */   null,
432                /* int wkst */         EventRecurrence.MO
433        );
434    }
435
436    // Sample coming from RFC2445
437    public void test16() throws Exception {
438        verifyRecurType("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1",
439                /* int freq */         EventRecurrence.MONTHLY,
440                /* String until */     null,
441                /* int count */        0,
442                /* int interval */     0,
443                /* int[] bysecond */   null,
444                /* int[] byminute */   null,
445                /* int[] byhour */     null,
446                /* int[] byday */      new int[] {
447                        EventRecurrence.MO,
448                        EventRecurrence.TU,
449                        EventRecurrence.WE,
450                        EventRecurrence.TH,
451                        EventRecurrence.FR
452                },
453                /* int[] bydayNum */   new int[] {0, 0, 0, 0, 0},
454                /* int[] bymonthday */ null,
455                /* int[] byyearday */  null,
456                /* int[] byweekno */   null,
457                /* int[] bymonth */    null,
458                /* int[] bysetpos */   new int[] { -1 },
459                /* int wkst */         EventRecurrence.MO
460        );
461    }
462
463    // Sample coming from RFC2445
464    public void test17() throws Exception {
465        verifyRecurType("FREQ=DAILY;COUNT=10;INTERVAL=2",
466                /* int freq */         EventRecurrence.DAILY,
467                /* String until */     null,
468                /* int count */        10,
469                /* int interval */     2,
470                /* int[] bysecond */   null,
471                /* int[] byminute */   null,
472                /* int[] byhour */     null,
473                /* int[] byday */      null,
474                /* int[] bydayNum */   null,
475                /* int[] bymonthday */ null,
476                /* int[] byyearday */  null,
477                /* int[] byweekno */   null,
478                /* int[] bymonth */    null,
479                /* int[] bysetpos */   null,
480                /* int wkst */         EventRecurrence.MO
481        );
482    }
483
484    // Sample coming from RFC2445
485    public void test18() throws Exception {
486        verifyRecurType("FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10",
487                /* int freq */         EventRecurrence.YEARLY,
488                /* String until */     null,
489                /* int count */        0,
490                /* int interval */     0,
491                /* int[] bysecond */   null,
492                /* int[] byminute */   null,
493                /* int[] byhour */     null,
494                /* int[] byday */      new int[] {
495                        EventRecurrence.SU
496                },
497                /* int[] bydayNum */   new int[] { -1 },
498                /* int[] bymonthday */ null,
499                /* int[] byyearday */  null,
500                /* int[] byweekno */   null,
501                /* int[] bymonth */    new int[] { 10 },
502                /* int[] bysetpos */   null,
503                /* int wkst */         EventRecurrence.MO
504        );
505    }
506
507    // Sample coming from bug #1640517
508    public void test19() throws Exception {
509        verifyRecurType("FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
510                /* int freq */         EventRecurrence.YEARLY,
511                /* String until */     null,
512                /* int count */        0,
513                /* int interval */     0,
514                /* int[] bysecond */   null,
515                /* int[] byminute */   null,
516                /* int[] byhour */     null,
517                /* int[] byday */      new int[] {
518                        EventRecurrence.TH
519                },
520                /* int[] bydayNum */   new int[] { 0 },
521                /* int[] bymonthday */ null,
522                /* int[] byyearday */  null,
523                /* int[] byweekno */   null,
524                /* int[] bymonth */    new int[] { 3 },
525                /* int[] bysetpos */   null,
526                /* int wkst */         EventRecurrence.MO
527        );
528    }
529
530    // INTERVAL = 0 -> Interval = 1 bug #5676414
531    public void test20() throws Exception {
532        verifyRecurType("FREQ=YEARLY;BYMONTHDAY=18;BYMONTH=10;INTERVAL=0;",
533                /* int freq */         EventRecurrence.YEARLY,
534                /* String until */     null,
535                /* int count */        0,
536                /* int interval */     1,
537                /* int[] bysecond */   null,
538                /* int[] byminute */   null,
539                /* int[] byhour */     null,
540                /* int[] byday */      null,
541                /* int[] bydayNum */   null,
542                /* int[] bymonthday */ new int[]{18},
543                /* int[] byyearday */  null,
544                /* int[] byweekno */   null,
545                /* int[] bymonth */    new int[]{10},
546                /* int[] bysetpos */   null,
547                /* int wkst */         EventRecurrence.MO
548        );
549    }
550
551    // Working case: INTERVAL=1 -> Interval = 1 bug #5676414
552    public void test21() throws Exception {
553        verifyRecurType("FREQ=WEEKLY;WKST=SU;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR",
554                /* int freq */         EventRecurrence.WEEKLY,
555                /* String until */     null,
556                /* int count */        0,
557                /* int interval */     1,
558                /* int[] bysecond */   null,
559                /* int[] byminute */   null,
560                /* int[] byhour */     null,
561                /* int[] byday */      new int[] {
562                        EventRecurrence.MO,
563                        EventRecurrence.TU,
564                        EventRecurrence.WE,
565                        EventRecurrence.TH,
566                        EventRecurrence.FR,
567                },
568                /* int[] bydayNum */   new int[]{0, 0, 0, 0, 0},
569                /* int[] bymonthday */ null,
570                /* int[] byyearday */  null,
571                /* int[] byweekno */   null,
572                /* int[] bymonth */    null,
573                /* int[] bysetpos */   null,
574                /* int wkst */         EventRecurrence.SU
575        );
576    }
577
578    // Working case: INTERVAL=2 -> Interval = 2 bug #5676414
579    public void test22() throws Exception {
580        verifyRecurType("FREQ=WEEKLY;WKST=SU;INTERVAL=2;BYDAY=MO,TU,WE,TH,FR",
581                /* int freq */         EventRecurrence.WEEKLY,
582                /* String until */     null,
583                /* int count */        0,
584                /* int interval */     2,
585                /* int[] bysecond */   null,
586                /* int[] byminute */   null,
587                /* int[] byhour */     null,
588                /* int[] byday */      new int[] {
589                        EventRecurrence.MO,
590                        EventRecurrence.TU,
591                        EventRecurrence.WE,
592                        EventRecurrence.TH,
593                        EventRecurrence.FR,
594                },
595                /* int[] bydayNum */   new int[]{0, 0, 0, 0, 0},
596                /* int[] bymonthday */ null,
597                /* int[] byyearday */  null,
598                /* int[] byweekno */   null,
599                /* int[] bymonth */    null,
600                /* int[] bysetpos */   null,
601                /* int wkst */         EventRecurrence.SU
602        );
603    }
604
605    // COUNT < 0 -> Count = 1 bug #5676414
606    public void test23() throws Exception {
607        verifyRecurType("FREQ=WEEKLY;COUNT=-20;BYDAY=MO,TU,WE,TH,FR;",
608                /* int freq */         EventRecurrence.WEEKLY,
609                /* String until */     null,
610                /* int count */        1,
611                /* int interval */     0,
612                /* int[] bysecond */   null,
613                /* int[] byminute */   null,
614                /* int[] byhour */     null,
615                /* int[] byday */      new int[] {
616                        EventRecurrence.MO,
617                        EventRecurrence.TU,
618                        EventRecurrence.WE,
619                        EventRecurrence.TH,
620                        EventRecurrence.FR,
621                },
622                /* int[] bydayNum */   new int[]{0, 0, 0, 0, 0},
623                /* int[] bymonthday */ null,
624                /* int[] byyearday */  null,
625                /* int[] byweekno */   null,
626                /* int[] bymonth */    null,
627                /* int[] bysetpos */   null,
628                /* int wkst */         EventRecurrence.MO
629        );
630    }
631
632    // Working case: COUNT=2 -> Count=2 bug #5676414
633    public void test24() throws Exception {
634        verifyRecurType("FREQ=WEEKLY;COUNT=2;BYDAY=MO,TU,WE,TH,FR;",
635                /* int freq */         EventRecurrence.WEEKLY,
636                /* String until */     null,
637                /* int count */        2,
638                /* int interval */     0,
639                /* int[] bysecond */   null,
640                /* int[] byminute */   null,
641                /* int[] byhour */     null,
642                /* int[] byday */      new int[] {
643                        EventRecurrence.MO,
644                        EventRecurrence.TU,
645                        EventRecurrence.WE,
646                        EventRecurrence.TH,
647                        EventRecurrence.FR,
648                },
649                /* int[] bydayNum */   new int[]{0, 0, 0, 0, 0},
650                /* int[] bymonthday */ null,
651                /* int[] byyearday */  null,
652                /* int[] byweekno */   null,
653                /* int[] bymonth */    null,
654                /* int[] bysetpos */   null,
655                /* int wkst */         EventRecurrence.MO
656        );
657    }
658
659    // for your copying pleasure
660    public void fakeTestXX() throws Exception {
661        verifyRecurType("FREQ=DAILY;",
662                /* int freq */         EventRecurrence.DAILY,
663                /* String until */     null,
664                /* int count */        0,
665                /* int interval */     0,
666                /* int[] bysecond */   null,
667                /* int[] byminute */   null,
668                /* int[] byhour */     null,
669                /* int[] byday */      null,
670                /* int[] bydayNum */   null,
671                /* int[] bymonthday */ null,
672                /* int[] byyearday */  null,
673                /* int[] byweekno */   null,
674                /* int[] bymonth */    null,
675                /* int[] bysetpos */   null,
676                /* int wkst */         EventRecurrence.MO
677        );
678    }
679
680    private static void cmp(int vlen, int[] v, int[] correct, String name) {
681        if ((correct == null && v != null)
682                || (correct != null && v == null)) {
683            throw new RuntimeException("One is null, one isn't for " + name
684                    + ": correct=" + Arrays.toString(correct)
685                    + " actual=" + Arrays.toString(v));
686        }
687        if ((correct == null && vlen != 0)
688                || (vlen != (correct == null ? 0 : correct.length))) {
689            throw new RuntimeException("Reported length mismatch for " + name
690                    + ": correct=" + ((correct == null) ? "null" : correct.length)
691                    + " actual=" + vlen);
692        }
693        if (correct == null) {
694            return;
695        }
696        if (v.length < correct.length) {
697            throw new RuntimeException("Array length mismatch for " + name
698                    + ": correct=" + Arrays.toString(correct)
699                    + " actual=" + Arrays.toString(v));
700        }
701        for (int i = 0; i < correct.length; i++) {
702            if (v[i] != correct[i]) {
703                throw new RuntimeException("Array value mismatch for " + name
704                        + ": correct=" + Arrays.toString(correct)
705                        + " actual=" + Arrays.toString(v));
706            }
707        }
708    }
709
710    private static boolean eq(String a, String b) {
711        if ((a == null && b != null) || (a != null && b == null)) {
712            return false;
713        } else {
714            return a == b || a.equals(b);
715        }
716    }
717
718    private static void verifyRecurType(String recur,
719            int freq, String until, int count, int interval,
720            int[] bysecond, int[] byminute, int[] byhour,
721            int[] byday, int[] bydayNum, int[] bymonthday,
722            int[] byyearday, int[] byweekno, int[] bymonth,
723            int[] bysetpos, int wkst) {
724        EventRecurrence eventRecurrence = new EventRecurrence();
725        eventRecurrence.parse(recur);
726        if (eventRecurrence.freq != freq
727                || !eq(eventRecurrence.until, until)
728                || eventRecurrence.count != count
729                || eventRecurrence.interval != interval
730                || eventRecurrence.wkst != wkst) {
731            System.out.println("Error... got:");
732            print(eventRecurrence);
733            System.out.println("expected:");
734            System.out.println("{");
735            System.out.println("    freq=" + freq);
736            System.out.println("    until=" + until);
737            System.out.println("    count=" + count);
738            System.out.println("    interval=" + interval);
739            System.out.println("    wkst=" + wkst);
740            System.out.println("    bysecond=" + Arrays.toString(bysecond));
741            System.out.println("    byminute=" + Arrays.toString(byminute));
742            System.out.println("    byhour=" + Arrays.toString(byhour));
743            System.out.println("    byday=" + Arrays.toString(byday));
744            System.out.println("    bydayNum=" + Arrays.toString(bydayNum));
745            System.out.println("    bymonthday=" + Arrays.toString(bymonthday));
746            System.out.println("    byyearday=" + Arrays.toString(byyearday));
747            System.out.println("    byweekno=" + Arrays.toString(byweekno));
748            System.out.println("    bymonth=" + Arrays.toString(bymonth));
749            System.out.println("    bysetpos=" + Arrays.toString(bysetpos));
750            System.out.println("}");
751            throw new RuntimeException("Mismatch in fields");
752        }
753        cmp(eventRecurrence.bysecondCount, eventRecurrence.bysecond, bysecond, "bysecond");
754        cmp(eventRecurrence.byminuteCount, eventRecurrence.byminute, byminute, "byminute");
755        cmp(eventRecurrence.byhourCount, eventRecurrence.byhour, byhour, "byhour");
756        cmp(eventRecurrence.bydayCount, eventRecurrence.byday, byday, "byday");
757        cmp(eventRecurrence.bydayCount, eventRecurrence.bydayNum, bydayNum, "bydayNum");
758        cmp(eventRecurrence.bymonthdayCount, eventRecurrence.bymonthday, bymonthday, "bymonthday");
759        cmp(eventRecurrence.byyeardayCount, eventRecurrence.byyearday, byyearday, "byyearday");
760        cmp(eventRecurrence.byweeknoCount, eventRecurrence.byweekno, byweekno, "byweekno");
761        cmp(eventRecurrence.bymonthCount, eventRecurrence.bymonth, bymonth, "bymonth");
762        cmp(eventRecurrence.bysetposCount, eventRecurrence.bysetpos, bysetpos, "bysetpos");
763    }
764
765    private static void print(EventRecurrence er) {
766        System.out.println("{");
767        System.out.println("    freq=" + er.freq);
768        System.out.println("    until=" + er.until);
769        System.out.println("    count=" + er.count);
770        System.out.println("    interval=" + er.interval);
771        System.out.println("    wkst=" + er.wkst);
772        System.out.println("    bysecond=" + Arrays.toString(er.bysecond));
773        System.out.println("    bysecondCount=" + er.bysecondCount);
774        System.out.println("    byminute=" + Arrays.toString(er.byminute));
775        System.out.println("    byminuteCount=" + er.byminuteCount);
776        System.out.println("    byhour=" + Arrays.toString(er.byhour));
777        System.out.println("    byhourCount=" + er.byhourCount);
778        System.out.println("    byday=" + Arrays.toString(er.byday));
779        System.out.println("    bydayNum=" + Arrays.toString(er.bydayNum));
780        System.out.println("    bydayCount=" + er.bydayCount);
781        System.out.println("    bymonthday=" + Arrays.toString(er.bymonthday));
782        System.out.println("    bymonthdayCount=" + er.bymonthdayCount);
783        System.out.println("    byyearday=" + Arrays.toString(er.byyearday));
784        System.out.println("    byyeardayCount=" + er.byyeardayCount);
785        System.out.println("    byweekno=" + Arrays.toString(er.byweekno));
786        System.out.println("    byweeknoCount=" + er.byweeknoCount);
787        System.out.println("    bymonth=" + Arrays.toString(er.bymonth));
788        System.out.println("    bymonthCount=" + er.bymonthCount);
789        System.out.println("    bysetpos=" + Arrays.toString(er.bysetpos));
790        System.out.println("    bysetposCount=" + er.bysetposCount);
791        System.out.println("}");
792    }
793
794
795    /** A list of valid rules.  The parser must accept these. */
796    private static final String[] GOOD_RRULES = {
797        /* extracted wholesale from from RFC 2445 section 4.8.5.4 */
798        "FREQ=DAILY;COUNT=10",
799        "FREQ=DAILY;UNTIL=19971224T000000Z",
800        "FREQ=DAILY;INTERVAL=2",
801        "FREQ=DAILY;INTERVAL=10;COUNT=5",
802        "FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA",
803        "FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1",
804        "FREQ=WEEKLY;COUNT=10",
805        "FREQ=WEEKLY;UNTIL=19971224T000000Z",
806        "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
807        "FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH",
808        "FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH",
809        "FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR",
810        "FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH",
811        "FREQ=MONTHLY;COUNT=10;BYDAY=1FR",
812        "FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR",
813        "FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU",
814        "FREQ=MONTHLY;COUNT=6;BYDAY=-2MO",
815        "FREQ=MONTHLY;BYMONTHDAY=-3",
816        "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15",
817        "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1",
818        "FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15",
819        "FREQ=MONTHLY;INTERVAL=2;BYDAY=TU",
820        "FREQ=YEARLY;COUNT=10;BYMONTH=6,7",
821        "FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3",
822        "FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200",
823        "FREQ=YEARLY;BYDAY=20MO",
824        "FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO",
825        "FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
826        "FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8",
827        "FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13",
828        "FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13",
829        "FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8",
830        "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3",
831        "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2",
832        "FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z",
833        "FREQ=MINUTELY;INTERVAL=15;COUNT=6",
834        "FREQ=MINUTELY;INTERVAL=90;COUNT=4",
835        "FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40",
836        "FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16",
837        "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO",
838        "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU",
839        /* a few more */
840        "FREQ=SECONDLY;BYSECOND=0,15,59",
841        "FREQ=MINUTELY;BYMINUTE=0,15,59",
842        "FREQ=HOURLY;BYHOUR=+0,+15,+23",
843        "INTERVAL=4;FREQ=YEARLY",
844        "FREQ=DAILY;X-WHATEVER=blah",
845        //"freq=daily;wkst=su",                               // mixed case currently not allowed
846        "FREQ=WEEKLY;INTERVAL=2;BYDAY=Mo;;UNTIL=20120327T000000Z", // double simicolon should be allowed
847        "FREQ=MONTHLY;BYDAY=1Mo",
848        "FREQ=MONTHLY;BYDAY=2Mo,2We,4Mo,4We",
849        "FREQ=MONTHLY;WKST=SU;BYMONTHDAY=25;UNTIL=20110524",
850        "FREQ=WEEKLY;BYDAY=MO;WKST=SU;UNTIL=20111218T010000Z"
851    };
852
853    /** The parser must reject these. */
854    private static final String[] BAD_RRULES = {
855        "FREQ=MONTHLY;FREQ=MONTHLY",                        // can't specify twice
856        "FREQ=MONTHLY;COUNT=1;COUNT=1",                     // can't specify twice
857        "FREQ=SECONDLY;BYSECOND=60",                        // range
858        "FREQ=MINUTELY;BYMINUTE=-1",                        // range
859        "FREQ=HOURLY;BYHOUR=24",                            // range
860        "FREQ=YEARLY;BYMONTHDAY=0",                         // zero not valid
861        "BYMONTHDAY=1",                                     // must specify FREQ
862        //"FREQ=YEARLY;COUNT=1;UNTIL=12345",                  // can't have both COUNT and UNTIL
863        //"FREQ=DAILY;UNTIL=19970829T021400e",                // invalid date
864    };
865
866    /**
867     * Simple test of good/bad rules.
868     */
869    @SmallTest
870    public void testBasicParse() {
871        for (String rule : GOOD_RRULES) {
872            EventRecurrence recur = new EventRecurrence();
873            recur.parse(rule);
874        }
875
876        for (String rule : BAD_RRULES) {
877            EventRecurrence recur = new EventRecurrence();
878            boolean didThrow = false;
879
880            try {
881                recur.parse(rule);
882            } catch (InvalidFormatException ife) {
883                didThrow = true;
884            }
885
886            assertTrue("Expected throw on " + rule, didThrow);
887        }
888    }
889}
890