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