117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey/*
217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * Copyright (C) 2017 The Android Open Source Project
317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey *
417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * you may not use this file except in compliance with the License.
617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * You may obtain a copy of the License at
717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey *
817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey *
1017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * Unless required by applicable law or agreed to in writing, software
1117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
1217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * See the License for the specific language governing permissions and
1417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey * limitations under the License.
1517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey */
1617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
1717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeypackage android.util;
1817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
1917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport android.support.test.filters.SmallTest;
2017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
2117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport junit.framework.TestCase;
2217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
2317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport java.time.Clock;
2417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport java.time.Instant;
2517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport java.time.Period;
2617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport java.time.ZoneId;
2717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport java.time.ZonedDateTime;
2817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeyimport java.util.Iterator;
2917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
3017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey@SmallTest
3117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkeypublic class RecurrenceRuleTest extends TestCase {
3217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
3317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    static Clock sOriginalClock;
3417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
3517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    @Override
3617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    protected void setUp() throws Exception {
3717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        super.setUp();
3817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        sOriginalClock = RecurrenceRule.sClock;
3917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
4017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
4117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    @Override
4217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    protected void tearDown() throws Exception {
4317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        super.tearDown();
4417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        RecurrenceRule.sClock = sOriginalClock;
4517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
4617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
4717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    private void setClock(Instant instant) {
4817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
4917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
5017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
5117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    public void testSimpleMonth() throws Exception {
5217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        setClock(Instant.parse("2015-11-20T10:15:30.00Z"));
5317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        final RecurrenceRule r = new RecurrenceRule(
5417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-14T00:00:00.000Z"),
5517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                null,
5617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                Period.ofMonths(1));
5717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
5817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertTrue(r.isMonthly());
5917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
600fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        final Iterator<Range<ZonedDateTime>> it = r.cycleIterator();
6117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertTrue(it.hasNext());
620fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        assertEquals(new Range<>(
6317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2015-11-14T00:00:00.00Z"),
6417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2015-12-14T00:00:00.00Z")), it.next());
6517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertTrue(it.hasNext());
660fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        assertEquals(new Range<>(
6717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2015-10-14T00:00:00.00Z"),
6817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2015-11-14T00:00:00.00Z")), it.next());
6917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
7017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
7117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    public void testSimpleDays() throws Exception {
7217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
7317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        final RecurrenceRule r = new RecurrenceRule(
7417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-14T00:11:00.000Z"),
7517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-20T00:11:00.000Z"),
7617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                Period.ofDays(3));
7717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
7817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertFalse(r.isMonthly());
7917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
800fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        final Iterator<Range<ZonedDateTime>> it = r.cycleIterator();
8117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertTrue(it.hasNext());
820fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        assertEquals(new Range<>(
8317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-17T00:11:00.00Z"),
8417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-20T00:11:00.00Z")), it.next());
8517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertTrue(it.hasNext());
860fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        assertEquals(new Range<>(
8717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-14T00:11:00.00Z"),
8817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-17T00:11:00.00Z")), it.next());
8917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertFalse(it.hasNext());
9017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
9117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
9217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    public void testNotRecurring() throws Exception {
9317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
9417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        final RecurrenceRule r = new RecurrenceRule(
9517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-14T00:11:00.000Z"),
9617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-20T00:11:00.000Z"),
9717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                null);
9817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
9917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertFalse(r.isMonthly());
10017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
1010fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        final Iterator<Range<ZonedDateTime>> it = r.cycleIterator();
10217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertTrue(it.hasNext());
1030fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        assertEquals(new Range<>(
10417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-14T00:11:00.000Z"),
10517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2010-11-20T00:11:00.000Z")), it.next());
10617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertFalse(it.hasNext());
10717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
10817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
10917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    public void testNever() throws Exception {
11017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
11117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        final RecurrenceRule r = RecurrenceRule.buildNever();
11217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
11317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertFalse(r.isMonthly());
11417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
1150fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        final Iterator<Range<ZonedDateTime>> it = r.cycleIterator();
11617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertFalse(it.hasNext());
11717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
11817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
11917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    public void testSane() throws Exception {
12017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        final RecurrenceRule r = new RecurrenceRule(
12117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("1980-01-31T00:00:00.000Z"),
12217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                ZonedDateTime.parse("2030-01-31T00:00:00.000Z"),
12317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey                Period.ofMonths(1));
12417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
1250fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey        final Iterator<Range<ZonedDateTime>> it = r.cycleIterator();
12617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        ZonedDateTime lastStart = null;
12717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        int months = 0;
12817bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        while (it.hasNext()) {
1290fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey            final Range<ZonedDateTime> cycle = it.next();
13017bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
13117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            // Make sure cycle has reasonable length
1320fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey            final long length = cycle.getUpper().toEpochSecond() - cycle.getLower().toEpochSecond();
13317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            assertTrue(cycle + " must be more than 4 weeks", length >= 2419200);
13417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            assertTrue(cycle + " must be less than 5 weeks", length <= 3024000);
13517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
13617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            // Make sure we have no gaps
13717bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            if (lastStart != null) {
1380fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey                assertEquals(lastStart, cycle.getUpper());
13917bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            }
1400fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey            lastStart = cycle.getLower();
14117bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey            months++;
14217bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        }
14317bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey
14417bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey        assertEquals(600, months);
14517bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey    }
14617bebd2fd7d3af0bc648172da6ae36f8b55ad7afJeff Sharkey}
147