1 /* 2 ** 3 ** Copyright 2009, 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 18 /* Based on http://code.google.com/p/google-rfc-2445/source/browse/trunk/test/com/google/ical/iter/RRuleIteratorImplTest.java */ 19 20 package com.android.providers.calendar; 21 22 import android.os.Debug; 23 import android.pim.RecurrenceSet; 24 import android.test.suitebuilder.annotation.MediumTest; 25 import android.test.suitebuilder.annotation.Suppress; 26 import android.text.format.Time; 27 import junit.framework.TestCase; 28 29 public class RRuleTest extends TestCase { 30 private static final String TAG = "RRuleTest"; 31 private static final boolean METHOD_TRACE = false; 32 getFormattedDates(long[] dates, Time time, boolean truncate)33 private static String[] getFormattedDates(long[] dates, Time time, boolean truncate) { 34 String[] out = new String[dates.length]; 35 int i = 0; 36 for (long date : dates) { 37 time.set(date); 38 if (truncate) { 39 out[i] = time.format2445().substring(0, 8); // Just YYMMDD 40 } else { 41 out[i] = time.format2445().substring(0, 15); // YYMMDDThhmmss 42 } 43 ++i; 44 } 45 return out; 46 } 47 48 static final String PST = "America/Los_Angeles"; 49 static final String UTC = "UTC"; 50 // Use this date as end of recurrence unlessotherwise specified. 51 static final String DEFAULT_END = "20091212"; 52 runRecurrenceIteratorTest(String rruleText, String dtStart, int limit, String golden)53 private void runRecurrenceIteratorTest(String rruleText, String dtStart, int limit, 54 String golden) throws Exception { 55 runRecurrenceIteratorTest(rruleText, dtStart, limit, golden, null, null, UTC); 56 } 57 runRecurrenceIteratorTest(String rrule, String dtstartStr, int limit, String golden, String advanceTo, String tz)58 private void runRecurrenceIteratorTest(String rrule, String dtstartStr, int limit, 59 String golden, String advanceTo, String tz) throws Exception { 60 runRecurrenceIteratorTest(rrule, dtstartStr, limit, golden, advanceTo, null, tz); 61 } 62 63 /** 64 * Tests a recurrence rule 65 * @param rrule The rule to expand 66 * @param dtstartStr The dtstart to use 67 * @param limit Maximum number of entries to expand. if there are more, "..." is appended to 68 * the result. Note that Android's recurrence expansion doesn't support expanding n results, 69 * so this is faked by expanding until the endAt date, and then taking limit results. 70 * @param golden The desired results 71 * @param advanceTo The starting date for expansion. dtstartStr is used if null is passed in. 72 * @param endAt The ending date. DEFAULT_END is used if null is passed in. 73 * @param tz The time zone. UTC is used if null is passed in. 74 * @throws Exception if anything goes wrong. 75 */ runRecurrenceIteratorTest(String rrule, String dtstartStr, int limit, String golden, String advanceTo, String endAt, String tz)76 private void runRecurrenceIteratorTest(String rrule, String dtstartStr, int limit, 77 String golden, String advanceTo, String endAt, String tz) throws Exception { 78 79 String rdate = ""; 80 String exrule = ""; 81 String exdate = ""; 82 rrule = rrule.replace("RRULE:", ""); 83 // RecurrenceSet does not support folding of lines, so fold here 84 rrule = rrule.replace("\n ", ""); 85 86 Time dtstart = new Time(tz); 87 Time rangeStart = new Time(tz); 88 Time rangeEnd = new Time(tz); 89 Time outCal = new Time(tz); 90 91 dtstart.parse(dtstartStr); 92 if (advanceTo == null) { 93 advanceTo = dtstartStr; 94 } 95 if (endAt == null) { 96 endAt = DEFAULT_END; 97 } 98 99 rangeStart.parse(advanceTo); 100 rangeEnd.parse(endAt); 101 102 103 RecurrenceProcessor rp = new RecurrenceProcessor(); 104 RecurrenceSet recur = new RecurrenceSet(rrule, rdate, exrule, exdate); 105 106 long[] out = rp.expand(dtstart, recur, rangeStart.toMillis(false /* use isDst */), 107 rangeEnd.toMillis(false /* use isDst */)); 108 109 if (METHOD_TRACE) { 110 Debug.stopMethodTracing(); 111 } 112 113 boolean truncate = dtstartStr.length() <= 8; // Just date, not date-time 114 String[] actual = getFormattedDates(out, outCal, truncate); 115 116 StringBuilder sb = new StringBuilder(); 117 int k = 0; 118 while (k < actual.length && --limit >= 0) { 119 if (k != 0) { 120 sb.append(','); 121 } 122 sb.append(actual[k]); 123 k++; 124 } 125 if (limit < 0) { 126 sb.append(",..."); 127 } 128 assertEquals(golden, sb.toString()); 129 } 130 131 // Infinite loop, bug 1662110 132 @MediumTest testFrequencyLimits()133 public void testFrequencyLimits() throws Exception { 134 try { 135 runRecurrenceIteratorTest("RRULE:FREQ=SECONDLY;BYSECOND=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14," + "15,16,17,18,19,20,21,22,23,24,25,26,27,28,29," + "30,31,32,33,34,35,36,37,38,39,40,41,42,43,44," + "45,46,47,48,49,50,51,52,53,54,55,56,57,58,59", "20000101", 1, ""); 136 fail("Don't do that"); 137 } catch (DateException ex) { 138 // pass 139 } 140 } 141 142 @MediumTest testSimpleDaily()143 public void testSimpleDaily() throws Exception { 144 runRecurrenceIteratorTest("RRULE:FREQ=DAILY", "20060120", 5, "20060120,20060121,20060122,20060123,20060124,..."); 145 } 146 147 @MediumTest testSimpleWeekly()148 public void testSimpleWeekly() throws Exception { 149 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY", "20060120", 5, "20060120,20060127,20060203,20060210,20060217,..."); 150 } 151 152 @MediumTest testSimpleMonthly()153 public void testSimpleMonthly() throws Exception { 154 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY", "20060120", 5, "20060120,20060220,20060320,20060420,20060520,..."); 155 } 156 157 @MediumTest testSimpleYearly()158 public void testSimpleYearly() throws Exception { 159 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY", "20060120", 5, "20060120,20070120,20080120,20090120,20100120,...", null, "20120101", UTC); 160 } 161 162 // from section 4.3.10 163 @MediumTest testMultipleByParts()164 public void testMultipleByParts() throws Exception { 165 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU", "19970105", 8, "19970105,19970112,19970119,19970126," + "19990103,19990110,19990117,19990124,..."); 166 } 167 168 @MediumTest testCountWithInterval()169 public void testCountWithInterval() throws Exception { 170 runRecurrenceIteratorTest("RRULE:FREQ=DAILY;COUNT=10;INTERVAL=2", "19970105", 11, "19970105,19970107,19970109,19970111,19970113," + "19970115,19970117,19970119,19970121,19970123"); 171 } 172 173 // from section 4.6.5 174 // Fails: wrong dates 175 @MediumTest 176 @Suppress testNegativeOffsetsA()177 public void testNegativeOffsetsA() throws Exception { 178 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10", "19970105", 5, "19971026,19981025,19991031,20001029,20011028,..."); 179 } 180 181 // Fails: wrong dates 182 @MediumTest 183 @Suppress testNegativeOffsetsB()184 public void testNegativeOffsetsB() throws Exception { 185 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4", "19970105", 5, "19970406,19980405,19990404,20000402,20010401,..."); 186 } 187 188 // Fails: wrong dates 189 @MediumTest 190 @Suppress testNegativeOffsetsC()191 public void testNegativeOffsetsC() throws Exception { 192 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T150000Z", "19970105", 5, "19970406"); 193 } 194 195 // feom section 4.8.5.4 196 @MediumTest testDailyFor10Occ()197 public void testDailyFor10Occ() throws Exception { 198 runRecurrenceIteratorTest("RRULE:FREQ=DAILY;COUNT=10", "19970902T090000", 11, "19970902T090000,19970903T090000,19970904T090000,19970905T090000," + "19970906T090000,19970907T090000,19970908T090000,19970909T090000," + "19970910T090000,19970911T090000"); 199 200 } 201 202 @MediumTest testDailyUntilDec4()203 public void testDailyUntilDec4() throws Exception { 204 runRecurrenceIteratorTest("RRULE:FREQ=DAILY;UNTIL=19971204", "19971128", 11, "19971128,19971129,19971130,19971201,19971202,19971203,19971204"); 205 } 206 207 // Fails: infinite loop 208 @MediumTest 209 @Suppress testEveryOtherDayForever()210 public void testEveryOtherDayForever() throws Exception { 211 runRecurrenceIteratorTest("RRULE:FREQ=DAILY;INTERVAL=2", "19971128", 5, "19971128,19971130,19971202,19971204,19971206,..."); 212 } 213 214 @MediumTest testEvery10Days5Occ()215 public void testEvery10Days5Occ() throws Exception { 216 runRecurrenceIteratorTest("RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5", "19970902", 5, "19970902,19970912,19970922,19971002,19971012"); 217 } 218 219 @MediumTest testWeeklyFor10Occ()220 public void testWeeklyFor10Occ() throws Exception { 221 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;COUNT=10", "19970902", 10, "19970902,19970909,19970916,19970923,19970930," + "19971007,19971014,19971021,19971028,19971104"); 222 } 223 224 @MediumTest testWeeklyUntilDec24()225 public void testWeeklyUntilDec24() throws Exception { 226 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;UNTIL=19971224", "19970902", 25, "19970902,19970909,19970916,19970923,19970930," + "19971007,19971014,19971021,19971028,19971104," + "19971111,19971118,19971125,19971202,19971209," + "19971216,19971223"); 227 } 228 229 @MediumTest testEveryOtherWeekForever()230 public void testEveryOtherWeekForever() throws Exception { 231 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU", "19970902", 11, "19970902,19970916,19970930,19971014,19971028," + "19971111,19971125,19971209,19971223,19980106," + "19980120,..."); 232 } 233 234 @MediumTest testWeeklyOnTuesdayAndThursdayFor5Weeks()235 public void testWeeklyOnTuesdayAndThursdayFor5Weeks() throws Exception { 236 // if UNTIL date does not match start date, then until date treated as 237 // occurring on midnight. 238 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;UNTIL=19971007;WKST=SU;BYDAY=TU,TH", "19970902T090000", 11, "19970902T090000,19970904T090000,19970909T090000,19970911T090000," + "19970916T090000,19970918T090000,19970923T090000,19970925T090000," + "19970930T090000,19971002T090000"); 239 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH", "19970902T090000", 11, "19970902T090000,19970904T090000,19970909T090000,19970911T090000," + "19970916T090000,19970918T090000,19970923T090000,19970925T090000," + "19970930T090000,19971002T090000"); 240 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH", "19970902", 11, "19970902,19970904,19970909,19970911,19970916," + "19970918,19970923,19970925,19970930,19971002"); 241 } 242 243 @MediumTest testEveryOtherWeekOnMWFUntilDec24()244 public void testEveryOtherWeekOnMWFUntilDec24() throws Exception { 245 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;\n" + " BYDAY=MO,WE,FR", "19970903T090000", 25, "19970903T090000,19970905T090000,19970915T090000,19970917T090000," + "19970919T090000,19970929T090000,19971001T090000,19971003T090000," + "19971013T090000,19971015T090000,19971017T090000,19971027T090000," + "19971029T090000,19971031T090000,19971110T090000,19971112T090000," + "19971114T090000,19971124T090000,19971126T090000,19971128T090000," + "19971208T090000,19971210T090000,19971212T090000,19971222T090000"); 246 } 247 248 @MediumTest testEveryOtherWeekOnMWFUntilDec24a()249 public void testEveryOtherWeekOnMWFUntilDec24a() throws Exception { 250 // if the UNTIL date is timed, when the start is not, the time should be 251 // ignored, so we get one more instance 252 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;\n" + " BYDAY=MO,WE,FR", "19970903", 25, "19970903,19970905,19970915,19970917," + "19970919,19970929,19971001,19971003," + "19971013,19971015,19971017,19971027," + "19971029,19971031,19971110,19971112," + "19971114,19971124,19971126,19971128," + "19971208,19971210,19971212,19971222," + "19971224"); 253 } 254 255 // Fails with wrong times 256 @MediumTest 257 @Suppress testEveryOtherWeekOnMWFUntilDec24b()258 public void testEveryOtherWeekOnMWFUntilDec24b() throws Exception { 259 // test with an alternate timezone 260 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T090000Z;WKST=SU;\n" + " BYDAY=MO,WE,FR", "19970903T090000", 25, "19970903T160000,19970905T160000,19970915T160000,19970917T160000," + "19970919T160000,19970929T160000,19971001T160000,19971003T160000," + "19971013T160000,19971015T160000,19971017T160000,19971027T170000," + "19971029T170000,19971031T170000,19971110T170000,19971112T170000," + "19971114T170000,19971124T170000,19971126T170000,19971128T170000," + "19971208T170000,19971210T170000,19971212T170000,19971222T170000", null, PST); 261 } 262 263 @MediumTest testEveryOtherWeekOnTuThFor8Occ()264 public void testEveryOtherWeekOnTuThFor8Occ() throws Exception { 265 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH", "19970902", 8, "19970902,19970904,19970916,19970918,19970930," + "19971002,19971014,19971016"); 266 } 267 268 @MediumTest testMonthlyOnThe1stFridayFor10Occ()269 public void testMonthlyOnThe1stFridayFor10Occ() throws Exception { 270 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR", "19970905", 10, "19970905,19971003,19971107,19971205,19980102," + "19980206,19980306,19980403,19980501,19980605"); 271 } 272 273 @MediumTest testMonthlyOnThe1stFridayUntilDec24()274 public void testMonthlyOnThe1stFridayUntilDec24() throws Exception { 275 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR", "19970905", 4, "19970905,19971003,19971107,19971205"); 276 } 277 278 @MediumTest testEveryOtherMonthOnThe1stAndLastSundayFor10Occ()279 public void testEveryOtherMonthOnThe1stAndLastSundayFor10Occ() throws Exception { 280 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU", "19970907", 10, "19970907,19970928,19971102,19971130,19980104," + "19980125,19980301,19980329,19980503,19980531"); 281 } 282 283 @MediumTest testMonthlyOnTheSecondToLastMondayOfTheMonthFor6Months()284 public void testMonthlyOnTheSecondToLastMondayOfTheMonthFor6Months() throws Exception { 285 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO", "19970922", 6, "19970922,19971020,19971117,19971222,19980119," + "19980216"); 286 } 287 288 @MediumTest testMonthlyOnTheThirdToLastDay()289 public void testMonthlyOnTheThirdToLastDay() throws Exception { 290 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYMONTHDAY=-3", "19970928", 6, "19970928,19971029,19971128,19971229,19980129,19980226,..."); 291 } 292 293 @MediumTest testMonthlyOnThe2ndAnd15thFor10Occ()294 public void testMonthlyOnThe2ndAnd15thFor10Occ() throws Exception { 295 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15", "19970902", 10, "19970902,19970915,19971002,19971015,19971102," + "19971115,19971202,19971215,19980102,19980115"); 296 } 297 298 @MediumTest testMonthlyOnTheFirstAndLastFor10Occ()299 public void testMonthlyOnTheFirstAndLastFor10Occ() throws Exception { 300 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1", "19970930", 10, "19970930,19971001,19971031,19971101,19971130," + "19971201,19971231,19980101,19980131,19980201"); 301 } 302 303 @MediumTest testEvery18MonthsOnThe10thThru15thFor10Occ()304 public void testEvery18MonthsOnThe10thThru15thFor10Occ() throws Exception { 305 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,\n" + " 15", "19970910", 10, "19970910,19970911,19970912,19970913,19970914," + "19970915,19990310,19990311,19990312,19990313"); 306 } 307 308 @MediumTest testEveryTuesdayEveryOtherMonth()309 public void testEveryTuesdayEveryOtherMonth() throws Exception { 310 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU", "19970902", 18, "19970902,19970909,19970916,19970923,19970930," + "19971104,19971111,19971118,19971125,19980106," + "19980113,19980120,19980127,19980303,19980310," + "19980317,19980324,19980331,..."); 311 } 312 313 @MediumTest testYearlyInJuneAndJulyFor10Occurrences()314 public void testYearlyInJuneAndJulyFor10Occurrences() throws Exception { 315 // Note: Since none of the BYDAY, BYMONTHDAY or BYYEARDAY components 316 // are specified, the day is gotten from DTSTART 317 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7", "19970610", 10, "19970610,19970710,19980610,19980710,19990610," + "19990710,20000610,20000710,20010610,20010710"); 318 } 319 320 @MediumTest testEveryOtherYearOnJanuaryFebruaryAndMarchFor10Occurrences()321 public void testEveryOtherYearOnJanuaryFebruaryAndMarchFor10Occurrences() throws Exception { 322 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3", "19970310", 10, "19970310,19990110,19990210,19990310,20010110," + "20010210,20010310,20030110,20030210,20030310"); 323 } 324 325 //Fails: wrong dates 326 @MediumTest 327 @Suppress testEvery3rdYearOnThe1st100thAnd200thDayFor10Occurrences()328 public void testEvery3rdYearOnThe1st100thAnd200thDayFor10Occurrences() throws Exception { 329 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200", "19970101", 10, "19970101,19970410,19970719,20000101,20000409," + "20000718,20030101,20030410,20030719,20060101"); 330 } 331 332 // Fails: infinite loop 333 @MediumTest 334 @Suppress testEvery20thMondayOfTheYearForever()335 public void testEvery20thMondayOfTheYearForever() throws Exception { 336 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=20MO", "19970519", 3, "19970519,19980518,19990517,..."); 337 } 338 339 // Fails: generates wrong dates 340 @MediumTest 341 @Suppress testMondayOfWeekNumber20WhereTheDefaultStartOfTheWeekIsMonday()342 public void testMondayOfWeekNumber20WhereTheDefaultStartOfTheWeekIsMonday() throws Exception { 343 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO", "19970512", 3, "19970512,19980511,19990517,..."); 344 } 345 346 @MediumTest testEveryThursdayInMarchForever()347 public void testEveryThursdayInMarchForever() throws Exception { 348 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH", "19970313", 11, "19970313,19970320,19970327,19980305,19980312," + "19980319,19980326,19990304,19990311,19990318," + "19990325,..."); 349 } 350 351 //Fails: wrong dates 352 @MediumTest 353 @Suppress testEveryThursdayButOnlyDuringJuneJulyAndAugustForever()354 public void testEveryThursdayButOnlyDuringJuneJulyAndAugustForever() throws Exception { 355 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8", "19970605", 39, "19970605,19970612,19970619,19970626,19970703," + "19970710,19970717,19970724,19970731,19970807," + "19970814,19970821,19970828,19980604,19980611," + "19980618,19980625,19980702,19980709,19980716," + "19980723,19980730,19980806,19980813,19980820," + "19980827,19990603,19990610,19990617,19990624," + "19990701,19990708,19990715,19990722,19990729," + "19990805,19990812,19990819,19990826,..."); 356 } 357 358 //Fails: infinite loop 359 @MediumTest 360 @Suppress testEveryFridayThe13thForever()361 public void testEveryFridayThe13thForever() throws Exception { 362 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13", "19970902", 5, "19980213,19980313,19981113,19990813,20001013," + "..."); 363 } 364 365 @MediumTest testTheFirstSaturdayThatFollowsTheFirstSundayOfTheMonthForever()366 public void testTheFirstSaturdayThatFollowsTheFirstSundayOfTheMonthForever() throws Exception { 367 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13", "19970913", 10, "19970913,19971011,19971108,19971213,19980110," + "19980207,19980307,19980411,19980509,19980613," + "..."); 368 } 369 370 @MediumTest testEvery4YearsThe1stTuesAfterAMonInNovForever()371 public void testEvery4YearsThe1stTuesAfterAMonInNovForever() throws Exception { 372 // US Presidential Election Day 373 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,\n" + " 5,6,7,8", "19961105", 3, "19961105,20001107,20041102,..."); 374 } 375 376 // Fails: wrong dates 377 @MediumTest 378 @Suppress testThe3rdInstanceIntoTheMonthOfOneOfTuesWedThursForNext3Months()379 public void testThe3rdInstanceIntoTheMonthOfOneOfTuesWedThursForNext3Months() throws Exception { 380 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3", "19970904", 3, "19970904,19971007,19971106"); 381 } 382 383 // Fails: wrong dates 384 @MediumTest 385 @Suppress testThe2ndToLastWeekdayOfTheMonth()386 public void testThe2ndToLastWeekdayOfTheMonth() throws Exception { 387 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2", "19970929", 7, "19970929,19971030,19971127,19971230,19980129," + "19980226,19980330,..."); 388 } 389 390 // Fails: infinite loop 391 @MediumTest 392 @Suppress testEvery3HoursFrom900AmTo500PmOnASpecificDay()393 public void testEvery3HoursFrom900AmTo500PmOnASpecificDay() throws Exception { 394 runRecurrenceIteratorTest("RRULE:FREQ=HOURLY;INTERVAL=3;UNTIL=19970903T010000Z", "19970902", 7, "00000902,19970909,19970900,19970912,19970900," + "19970915,19970900"); 395 } 396 397 // Fails: infinite loop 398 @MediumTest 399 @Suppress testEvery15MinutesFor6Occurrences()400 public void testEvery15MinutesFor6Occurrences() throws Exception { 401 runRecurrenceIteratorTest("RRULE:FREQ=MINUTELY;INTERVAL=15;COUNT=6", "19970902", 13, "00000902,19970909,19970900,19970909,19970915," + "19970909,19970930,19970909,19970945,19970910," + "19970900,19970910,19970915"); 402 } 403 404 @MediumTest 405 @Suppress testEveryHourAndAHalfFor4Occurrences()406 public void testEveryHourAndAHalfFor4Occurrences() throws Exception { 407 runRecurrenceIteratorTest("RRULE:FREQ=MINUTELY;INTERVAL=90;COUNT=4", "19970902", 9, "00000902,19970909,19970900,19970910,19970930," + "19970912,19970900,19970913,19970930"); 408 } 409 410 // Fails: wrong dates 411 @MediumTest 412 @Suppress testAnExampleWhereTheDaysGeneratedMakesADifferenceBecauseOfWkst()413 public void testAnExampleWhereTheDaysGeneratedMakesADifferenceBecauseOfWkst() throws Exception { 414 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO", "19970805", 4, "19970805,19970810,19970819,19970824"); 415 } 416 417 // Fails: wrong dates 418 @MediumTest 419 @Suppress testAnExampleWhereTheDaysGeneratedMakesADifferenceBecauseOfWkst2()420 public void testAnExampleWhereTheDaysGeneratedMakesADifferenceBecauseOfWkst2() throws Exception { 421 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU", "19970805", 8, "19970805,19970817,19970819,19970831"); 422 } 423 424 // Fails: wrong dates 425 @MediumTest 426 @Suppress testWithByDayAndByMonthDayFilter()427 public void testWithByDayAndByMonthDayFilter() throws Exception { 428 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;COUNT=4;BYDAY=TU,SU;" + "BYMONTHDAY=13,14,15,16,17,18,19,20", "19970805", 8, "19970817,19970819,19970914,19970916"); 429 } 430 431 // Failed: wrong dates 432 @MediumTest 433 @Suppress testAnnuallyInAugustOnTuesAndSunBetween13thAnd20th()434 public void testAnnuallyInAugustOnTuesAndSunBetween13thAnd20th() throws Exception { 435 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;COUNT=4;BYDAY=TU,SU;" + "BYMONTHDAY=13,14,15,16,17,18,19,20;BYMONTH=8", "19970605", 8, "19970817,19970819,19980816,19980818"); 436 } 437 438 // Failed: wrong dates 439 @MediumTest 440 @Suppress testLastDayOfTheYearIsASundayOrTuesday()441 public void testLastDayOfTheYearIsASundayOrTuesday() throws Exception { 442 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;COUNT=4;BYDAY=TU,SU;BYYEARDAY=-1", "19940605", 8, "19951231,19961231,20001231,20021231"); 443 } 444 445 // Fails: wrong dates 446 @MediumTest 447 @Suppress testLastWeekdayOfMonth()448 public void testLastWeekdayOfMonth() throws Exception { 449 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYSETPOS=-1;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR", "19940605", 8, "19940630,19940729,19940831,19940930," + "19941031,19941130,19941230,19950131,..."); 450 } 451 452 // Fails: generates wrong dates 453 @MediumTest 454 @Suppress testMonthsThatStartOrEndOnFriday()455 public void testMonthsThatStartOrEndOnFriday() throws Exception { 456 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYMONTHDAY=1,-1;BYDAY=FR;COUNT=6", "19940605", 8, "19940701,19940930,19950331,19950630,19950901,19951201"); 457 } 458 459 // Fails: can't go that far into future 460 @MediumTest 461 @Suppress testCenturiesThatAreNotLeapYears()462 public void testCenturiesThatAreNotLeapYears() throws Exception { 463 // I can't think of a good reason anyone would want to specify both a 464 // month day and a year day, so here's a really contrived example 465 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=100;BYYEARDAY=60;BYMONTHDAY=1", "19000101", 4, "19000301,21000301,22000301,23000301,...", null, "25000101", UTC); 466 } 467 468 // Fails: generates instances when it shouldn't 469 @MediumTest 470 @Suppress testNoInstancesGenerated()471 public void testNoInstancesGenerated() throws Exception { 472 runRecurrenceIteratorTest("RRULE:FREQ=DAILY;UNTIL=19990101", "20000101", 4, ""); 473 } 474 475 // Fails: generates instances when it shouldn't 476 @MediumTest 477 @Suppress testNoInstancesGenerated2()478 public void testNoInstancesGenerated2() throws Exception { 479 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=30", "20000101", 4, ""); 480 } 481 482 // Fails: generates instances when it shouldn't 483 @MediumTest 484 @Suppress testNoInstancesGenerated3()485 public void testNoInstancesGenerated3() throws Exception { 486 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=4;BYYEARDAY=366", "20000101", 4, ""); 487 } 488 489 //Fails: wrong dates 490 @MediumTest 491 @Suppress testLastWeekdayOfMarch()492 public void testLastWeekdayOfMarch() throws Exception { 493 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYMONTH=3;BYDAY=SA,SU;BYSETPOS=-1", "20000101", 4, "20000326,20010331,20020331,20030330,..."); 494 } 495 496 // Fails: wrong dates 497 @MediumTest 498 @Suppress testFirstWeekdayOfMarch()499 public void testFirstWeekdayOfMarch() throws Exception { 500 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYMONTH=3;BYDAY=SA,SU;BYSETPOS=1", "20000101", 4, "20000304,20010303,20020302,20030301,..."); 501 } 502 503 // January 1999 504 // Mo Tu We Th Fr Sa Su 505 // 1 2 3 // < 4 days, so not a week 506 // 4 5 6 7 8 9 10 507 508 // January 2000 509 // Mo Tu We Th Fr Sa Su 510 // 1 2 // < 4 days, so not a week 511 // 3 4 5 6 7 8 9 512 513 // January 2001 514 // Mo Tu We Th Fr Sa Su 515 // 1 2 3 4 5 6 7 516 // 8 9 10 11 12 13 14 517 518 // January 2002 519 // Mo Tu We Th Fr Sa Su 520 // 1 2 3 4 5 6 521 // 7 8 9 10 11 12 13 522 523 /** 524 * Find the first weekday of the first week of the year. 525 * The first week of the year may be partial, and the first week is considered 526 * to be the first one with at least four days. 527 */ 528 // Fails: wrong dates 529 @MediumTest 530 @Suppress testFirstWeekdayOfFirstWeekOfYear()531 public void testFirstWeekdayOfFirstWeekOfYear() throws Exception { 532 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYWEEKNO=1;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1", "19990101", 4, "19990104,20000103,20010101,20020101,..."); 533 } 534 535 // Fails: wrong dates 536 @MediumTest 537 @Suppress testFirstSundayOfTheYear1()538 public void testFirstSundayOfTheYear1() throws Exception { 539 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYWEEKNO=1;BYDAY=SU", "19990101", 4, "19990110,20000109,20010107,20020106,..."); 540 } 541 542 // Fails: wrong dates 543 @MediumTest 544 @Suppress testFirstSundayOfTheYear2()545 public void testFirstSundayOfTheYear2() throws Exception { 546 // TODO(msamuel): is this right? 547 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=1SU", "19990101", 4, "19990103,20000102,20010107,20020106,..."); 548 } 549 550 // Fails: wrong dates 551 @MediumTest 552 @Suppress testFirstSundayOfTheYear3()553 public void testFirstSundayOfTheYear3() throws Exception { 554 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=SU;BYYEARDAY=1,2,3,4,5,6,7,8,9,10,11,12,13" + ";BYSETPOS=1", "19990101", 4, "19990103,20000102,20010107,20020106,..."); 555 } 556 557 // Fails: wrong dates 558 @MediumTest 559 @Suppress testFirstWeekdayOfYear()560 public void testFirstWeekdayOfYear() throws Exception { 561 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1", "19990101", 4, "19990101,20000103,20010101,20020101,..."); 562 } 563 564 // Fails: wrong dates 565 @MediumTest 566 @Suppress testLastWeekdayOfFirstWeekOfYear()567 public void testLastWeekdayOfFirstWeekOfYear() throws Exception { 568 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYWEEKNO=1;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1", "19990101", 4, "19990108,20000107,20010105,20020104,..."); 569 } 570 571 // January 1999 572 // Mo Tu We Th Fr Sa Su 573 // 1 2 3 574 // 4 5 6 7 8 9 10 575 // 11 12 13 14 15 16 17 576 // 18 19 20 21 22 23 24 577 // 25 26 27 28 29 30 31 578 579 // Fails: wrong dates 580 @MediumTest 581 @Suppress testSecondWeekday1()582 public void testSecondWeekday1() throws Exception { 583 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=2", "19990101", 4, "19990105,19990112,19990119,19990126,..."); 584 } 585 586 // January 1997 587 // Mo Tu We Th Fr Sa Su 588 // 1 2 3 4 5 589 // 6 7 8 9 10 11 12 590 // 13 14 15 16 17 18 19 591 // 20 21 22 23 24 25 26 592 // 27 28 29 30 31 593 594 // Fails: wrong dates 595 @MediumTest 596 @Suppress testSecondWeekday2()597 public void testSecondWeekday2() throws Exception { 598 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=2", "19970101", 4, "19970102,19970107,19970114,19970121,..."); 599 } 600 601 // Fails: wrong dates 602 @MediumTest 603 @Suppress testByYearDayAndByDayFilterInteraction()604 public void testByYearDayAndByDayFilterInteraction() throws Exception { 605 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYYEARDAY=15;BYDAY=3MO", "19990101", 4, "20010115,20070115,20180115,20240115,..."); 606 } 607 608 // Fails: wrong dates 609 @MediumTest 610 @Suppress testByDayWithNegWeekNoAsFilter()611 public void testByDayWithNegWeekNoAsFilter() throws Exception { 612 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;BYMONTHDAY=26;BYDAY=-1FR", "19990101", 4, "19990226,19990326,19991126,20000526,..."); 613 } 614 615 // Fails: wrong dates 616 @MediumTest 617 @Suppress testLastWeekOfTheYear()618 public void testLastWeekOfTheYear() throws Exception { 619 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYWEEKNO=-1", "19990101", 6, "19991227,19991228,19991229,19991230,19991231,20001225,..."); 620 } 621 622 // Fails: not enough dates generated 623 @MediumTest 624 @Suppress testUserSubmittedTest1()625 public void testUserSubmittedTest1() throws Exception { 626 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=WE;BYDAY=SU,TU,TH,SA" + ";UNTIL=20000215T113000Z", "20000127T033000", 20, "20000127T033000,20000129T033000,20000130T033000,20000201T033000," + "20000210T033000,20000212T033000,20000213T033000,20000215T033000"); 627 } 628 629 @MediumTest testAdvanceTo1()630 public void testAdvanceTo1() throws Exception { 631 // a bunch of tests grabbed from above with an advance-to date tacked on 632 633 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH", "19970313", 11, 634 /*"19970313,19970320,19970327,"*/"19980305,19980312," + "19980319,19980326,19990304,19990311,19990318," + "19990325,20000302,20000309,20000316,...", "19970601", UTC); 635 } 636 637 // Fails: infinite loop 638 @MediumTest 639 @Suppress testAdvanceTo2()640 public void testAdvanceTo2() throws Exception { 641 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYDAY=20MO", "19970519", 3, 642 /*"19970519,"*/"19980518,19990517,20000515,...", "19980515", UTC); 643 } 644 645 // Fails: wrong dates 646 @MediumTest 647 @Suppress testAdvanceTo3()648 public void testAdvanceTo3() throws Exception { 649 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=3;UNTIL=20090101;BYYEARDAY=1,100,200", "19970101", 10, 650 /*"19970101,19970410,19970719,20000101,"*/"20000409," + "20000718,20030101,20030410,20030719,20060101,20060410,20060719," + "20090101", "20000228", UTC); 651 } 652 653 //Fails: wrong dates 654 @MediumTest 655 @Suppress testAdvanceTo4()656 public void testAdvanceTo4() throws Exception { 657 // make sure that count preserved 658 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200", "19970101", 10, 659 /*"19970101,19970410,19970719,20000101,"*/"20000409," + "20000718,20030101,20030410,20030719,20060101", "20000228", UTC); 660 } 661 662 // Fails: too many dates 663 @MediumTest 664 @Suppress testAdvanceTo5()665 public void testAdvanceTo5() throws Exception { 666 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3", "19970310", 10, 667 /*"19970310,"*/"19990110,19990210,19990310,20010110," + "20010210,20010310,20030110,20030210,20030310", "19980401", UTC); 668 } 669 670 @MediumTest testAdvanceTo6()671 public void testAdvanceTo6() throws Exception { 672 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;UNTIL=19971224", "19970902", 25, 673 /*"19970902,19970909,19970916,19970923,"*/"19970930," + "19971007,19971014,19971021,19971028,19971104," + "19971111,19971118,19971125,19971202,19971209," + "19971216,19971223", "19970930", UTC); 674 } 675 676 @MediumTest testAdvanceTo7()677 public void testAdvanceTo7() throws Exception { 678 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;INTERVAL=18;BYMONTHDAY=10,11,12,13,14,\n" + " 15", "19970910", 5, 679 /*"19970910,19970911,19970912,19970913,19970914," + 680 "19970915,"*/"19990310,19990311,19990312,19990313,19990314,...", "19990101", UTC); 681 } 682 683 @MediumTest testAdvanceTo8()684 public void testAdvanceTo8() throws Exception { 685 // advancing into the past 686 runRecurrenceIteratorTest("RRULE:FREQ=MONTHLY;INTERVAL=18;BYMONTHDAY=10,11,12,13,14,\n" + " 15", "19970910", 11, "19970910,19970911,19970912,19970913,19970914," + "19970915,19990310,19990311,19990312,19990313,19990314,...", "19970901", UTC); 687 } 688 689 // Fails: wrong dates 690 @MediumTest 691 @Suppress testAdvanceTo9()692 public void testAdvanceTo9() throws Exception { 693 // skips first instance 694 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=100;BYMONTH=2;BYMONTHDAY=29", "19000101", 5, 695 // would return 2000 696 "24000229,28000229,32000229,36000229,40000229,...", "20040101", UTC); 697 } 698 699 // Infinite loop in native code (bug 1686327) 700 @MediumTest 701 @Suppress testAdvanceTo10()702 public void testAdvanceTo10() throws Exception { 703 // filter hits until date before first instnace 704 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;INTERVAL=100;BYMONTH=2;BYMONTHDAY=29;UNTIL=21000101", "19000101", 5, "", "20040101", UTC); 705 } 706 707 // Fails: generates wrong dates 708 @MediumTest 709 @Suppress testAdvanceTo11()710 public void testAdvanceTo11() throws Exception { 711 // advancing something that returns no instances 712 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=30", "20000101", 10, "", "19970901", UTC); 713 } 714 715 // Fails: generates wrong dates 716 @MediumTest 717 @Suppress testAdvanceTo12()718 public void testAdvanceTo12() throws Exception { 719 // advancing something that returns no instances and has a BYSETPOS rule 720 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=30,31;BYSETPOS=1", "20000101", 10, "", "19970901", UTC); 721 } 722 723 // Fails: generates wrong dates 724 @MediumTest 725 @Suppress testAdvanceTo13()726 public void testAdvanceTo13() throws Exception { 727 // advancing way past year generator timeout 728 runRecurrenceIteratorTest("RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=28", "20000101", 10, "", "25000101", UTC); 729 } 730 731 /** 732 * a testcase that yielded dupes due to bysetPos evilness 733 */ 734 @MediumTest 735 @Suppress testCaseThatYieldedDupes()736 public void testCaseThatYieldedDupes() throws Exception { 737 runRecurrenceIteratorTest("RRULE:FREQ=WEEKLY;WKST=SU;INTERVAL=1;BYMONTH=9,1,12,8" + ";BYMONTHDAY=-9,-29,24;BYSETPOS=-1,-4,10,-6,-1,-10,-10,-9,-8", "20060528", 200, "20060924,20061203,20061224,20070902,20071223,20080803,20080824," + "20090823,20100103,20100124,20110123,20120902,20121223,20130922," + "20140803,20140824,20150823,20160103,20160124,20170924,20171203," + "20171224,20180902,20181223,20190922,20200823,20210103,20210124," + "20220123,20230924,20231203,20231224,20240922,20250803,20250824," + "20260823,20270103,20270124,20280123,20280924,20281203,20281224," + "20290902,20291223,20300922,20310803,20310824,20330123,20340924," + "20341203,20341224,20350902,20351223,20360803,20360824,20370823," + "20380103,20380124,20390123,20400902,20401223,20410922,20420803," + "20420824,20430823,20440103,20440124,20450924,20451203,20451224," + "20460902,20461223,20470922,20480823,20490103,20490124,20500123," + "20510924,20511203,20511224,20520922,20530803,20530824,20540823," + "20550103,20550124,20560123,20560924,20561203,20561224,20570902," + "20571223,20580922,20590803,20590824,20610123,20620924,20621203," + "20621224,20630902,20631223,20640803,20640824,20650823,20660103," + "20660124,20670123,20680902,20681223,20690922,20700803,20700824," + "20710823,20720103,20720124,20730924,20731203,20731224,20740902," + "20741223,20750922,20760823,20770103,20770124,20780123,20790924," + "20791203,20791224,20800922,20810803,20810824,20820823,20830103," + "20830124,20840123,20840924,20841203,20841224,20850902,20851223," + "20860922,20870803,20870824,20890123,20900924,20901203,20901224," + "20910902,20911223,20920803,20920824,20930823,20940103,20940124," + "20950123,20960902,20961223,20970922,20980803,20980824,20990823," + "21000103,21000124,21010123,21020924,21021203,21021224,21030902," + "21031223,21040803,21040824,21050823,21060103,21060124,21070123," + "21080902,21081223,21090922,21100803,21100824,21110823,21120103," + "21120124,21130924,21131203,21131224,21140902,21141223,21150922," + "21160823,21170103,21170124,21180123,21190924,21191203,21191224," + "21200922,21210803,21210824,21220823,..."); 738 } 739 } 740