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