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