1/*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * This file is available under and governed by the GNU General Public
26 * License version 2 only, as published by the Free Software Foundation.
27 * However, the following notice accompanied the original version of this
28 * file:
29 *
30 * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
31 *
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions are met:
36 *
37 *  * Redistributions of source code must retain the above copyright notice,
38 *    this list of conditions and the following disclaimer.
39 *
40 *  * Redistributions in binary form must reproduce the above copyright notice,
41 *    this list of conditions and the following disclaimer in the documentation
42 *    and/or other materials provided with the distribution.
43 *
44 *  * Neither the name of JSR-310 nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
51 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
52 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
53 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
54 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
55 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
56 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
57 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 */
60package tck.java.time;
61
62import static java.time.temporal.ChronoUnit.DAYS;
63import static java.time.temporal.ChronoUnit.HOURS;
64import static java.time.temporal.ChronoUnit.YEARS;
65import static org.testng.Assert.assertEquals;
66
67import java.time.DateTimeException;
68import java.time.Duration;
69import java.time.LocalDate;
70import java.time.Period;
71import java.time.chrono.ThaiBuddhistChronology;
72import java.time.format.DateTimeParseException;
73import java.time.temporal.ChronoUnit;
74import java.time.temporal.Temporal;
75import java.time.temporal.TemporalAmount;
76import java.time.temporal.TemporalUnit;
77import java.util.ArrayList;
78import java.util.Collections;
79import java.util.List;
80import java.util.Locale;
81
82import org.testng.annotations.DataProvider;
83import org.testng.annotations.Test;
84
85/**
86 * Test Period.
87 */
88@Test
89public class TCKPeriod extends AbstractTCKTest {
90
91    //-----------------------------------------------------------------------
92    // ofYears(int)
93    //-----------------------------------------------------------------------
94    @Test
95    public void factory_ofYears_int() {
96        assertPeriod(Period.ofYears(0), 0, 0, 0);
97        assertPeriod(Period.ofYears(1), 1, 0, 0);
98        assertPeriod(Period.ofYears(234), 234, 0, 0);
99        assertPeriod(Period.ofYears(-100), -100, 0, 0);
100        assertPeriod(Period.ofYears(Integer.MAX_VALUE), Integer.MAX_VALUE, 0, 0);
101        assertPeriod(Period.ofYears(Integer.MIN_VALUE), Integer.MIN_VALUE, 0, 0);
102    }
103
104    //-----------------------------------------------------------------------
105    // ofMonths(int)
106    //-----------------------------------------------------------------------
107    @Test
108    public void factory_ofMonths_int() {
109        assertPeriod(Period.ofMonths(0), 0, 0, 0);
110        assertPeriod(Period.ofMonths(1), 0, 1, 0);
111        assertPeriod(Period.ofMonths(234), 0, 234, 0);
112        assertPeriod(Period.ofMonths(-100), 0, -100, 0);
113        assertPeriod(Period.ofMonths(Integer.MAX_VALUE), 0, Integer.MAX_VALUE, 0);
114        assertPeriod(Period.ofMonths(Integer.MIN_VALUE), 0, Integer.MIN_VALUE, 0);
115    }
116
117    //-----------------------------------------------------------------------
118    // ofWeeks(int)
119    //-----------------------------------------------------------------------
120    @Test
121    public void factory_ofWeeks_int() {
122        assertPeriod(Period.ofWeeks(0), 0, 0, 0);
123        assertPeriod(Period.ofWeeks(1), 0, 0, 7);
124        assertPeriod(Period.ofWeeks(234), 0, 0, 234 * 7);
125        assertPeriod(Period.ofWeeks(-100), 0, 0, -100 * 7);
126        assertPeriod(Period.ofWeeks(Integer.MAX_VALUE / 7), 0, 0, (Integer.MAX_VALUE / 7) * 7);
127        assertPeriod(Period.ofWeeks(Integer.MIN_VALUE / 7), 0, 0, (Integer.MIN_VALUE / 7) * 7);
128    }
129
130    //-----------------------------------------------------------------------
131    // ofDays(int)
132    //-----------------------------------------------------------------------
133    @Test
134    public void factory_ofDays_int() {
135        assertPeriod(Period.ofDays(0), 0, 0, 0);
136        assertPeriod(Period.ofDays(1), 0, 0, 1);
137        assertPeriod(Period.ofDays(234), 0, 0, 234);
138        assertPeriod(Period.ofDays(-100), 0, 0, -100);
139        assertPeriod(Period.ofDays(Integer.MAX_VALUE), 0, 0, Integer.MAX_VALUE);
140        assertPeriod(Period.ofDays(Integer.MIN_VALUE), 0, 0, Integer.MIN_VALUE);
141    }
142
143    //-----------------------------------------------------------------------
144    // of(int3)
145    //-----------------------------------------------------------------------
146    @Test
147    public void factory_of_ints() {
148        assertPeriod(Period.of(1, 2, 3), 1, 2, 3);
149        assertPeriod(Period.of(0, 2, 3), 0, 2, 3);
150        assertPeriod(Period.of(1, 0, 0), 1, 0, 0);
151        assertPeriod(Period.of(0, 0, 0), 0, 0, 0);
152        assertPeriod(Period.of(-1, -2, -3), -1, -2, -3);
153    }
154
155    //-----------------------------------------------------------------------
156    // from(TemporalAmount)
157    //-----------------------------------------------------------------------
158    @Test
159    public void factory_from_TemporalAmount_Period() {
160        TemporalAmount amount = Period.of(1, 2, 3);
161        assertPeriod(Period.from(amount), 1, 2, 3);
162    }
163
164    @Test
165    public void factory_from_TemporalAmount_YearsDays() {
166        TemporalAmount amount = new TemporalAmount() {
167            @Override
168            public long get(TemporalUnit unit) {
169                if (unit == YEARS) {
170                    return 23;
171                } else {
172                    return 45;
173                }
174            }
175            @Override
176            public List<TemporalUnit> getUnits() {
177                List<TemporalUnit> list = new ArrayList<>();
178                list.add(YEARS);
179                list.add(DAYS);
180                return list;
181            }
182            @Override
183            public Temporal addTo(Temporal temporal) {
184                throw new UnsupportedOperationException();
185            }
186            @Override
187            public Temporal subtractFrom(Temporal temporal) {
188                throw new UnsupportedOperationException();
189            }
190        };
191        assertPeriod(Period.from(amount), 23, 0, 45);
192    }
193
194    @Test(expectedExceptions = ArithmeticException.class)
195    public void factory_from_TemporalAmount_Years_tooBig() {
196        TemporalAmount amount = new TemporalAmount() {
197            @Override
198            public long get(TemporalUnit unit) {
199                return ((long) (Integer.MAX_VALUE)) + 1;
200            }
201            @Override
202            public List<TemporalUnit> getUnits() {
203                return Collections.<TemporalUnit>singletonList(YEARS);
204            }
205            @Override
206            public Temporal addTo(Temporal temporal) {
207                throw new UnsupportedOperationException();
208            }
209            @Override
210            public Temporal subtractFrom(Temporal temporal) {
211                throw new UnsupportedOperationException();
212            }
213        };
214        Period.from(amount);
215    }
216
217    @Test(expectedExceptions = DateTimeException.class)
218    public void factory_from_TemporalAmount_DaysHours() {
219        TemporalAmount amount = new TemporalAmount() {
220            @Override
221            public long get(TemporalUnit unit) {
222                if (unit == DAYS) {
223                    return 1;
224                } else {
225                    return 2;
226                }
227            }
228            @Override
229            public List<TemporalUnit> getUnits() {
230                List<TemporalUnit> list = new ArrayList<>();
231                list.add(DAYS);
232                list.add(HOURS);
233                return list;
234            }
235            @Override
236            public Temporal addTo(Temporal temporal) {
237                throw new UnsupportedOperationException();
238            }
239            @Override
240            public Temporal subtractFrom(Temporal temporal) {
241                throw new UnsupportedOperationException();
242            }
243        };
244        Period.from(amount);
245    }
246
247    @Test(expectedExceptions = DateTimeException.class)
248    public void factory_from_TemporalAmount_NonISO() {
249        Period.from(ThaiBuddhistChronology.INSTANCE.period(1, 1, 1));
250    }
251
252    @Test(expectedExceptions = DateTimeException.class)
253    public void factory_from_TemporalAmount_Duration() {
254        Period.from(Duration.ZERO);
255    }
256
257    @Test(expectedExceptions = NullPointerException.class)
258    public void factory_from_TemporalAmount_null() {
259        Period.from(null);
260    }
261
262    //-----------------------------------------------------------------------
263    // parse(String)
264    //-----------------------------------------------------------------------
265    @DataProvider(name="parseSuccess")
266    Object[][] data_factory_parseSuccess() {
267        return new Object[][] {
268                {"P1Y", Period.ofYears(1)},
269                {"P12Y", Period.ofYears(12)},
270                {"P987654321Y", Period.ofYears(987654321)},
271                {"P+1Y", Period.ofYears(1)},
272                {"P+12Y", Period.ofYears(12)},
273                {"P+987654321Y", Period.ofYears(987654321)},
274                {"P+0Y", Period.ofYears(0)},
275                {"P0Y", Period.ofYears(0)},
276                {"P-0Y", Period.ofYears(0)},
277                {"P-25Y", Period.ofYears(-25)},
278                {"P-987654321Y", Period.ofYears(-987654321)},
279                {"P" + Integer.MAX_VALUE + "Y", Period.ofYears(Integer.MAX_VALUE)},
280                {"P" + Integer.MIN_VALUE + "Y", Period.ofYears(Integer.MIN_VALUE)},
281
282                {"P1M", Period.ofMonths(1)},
283                {"P12M", Period.ofMonths(12)},
284                {"P987654321M", Period.ofMonths(987654321)},
285                {"P+1M", Period.ofMonths(1)},
286                {"P+12M", Period.ofMonths(12)},
287                {"P+987654321M", Period.ofMonths(987654321)},
288                {"P+0M", Period.ofMonths(0)},
289                {"P0M", Period.ofMonths(0)},
290                {"P-0M", Period.ofMonths(0)},
291                {"P-25M", Period.ofMonths(-25)},
292                {"P-987654321M", Period.ofMonths(-987654321)},
293                {"P" + Integer.MAX_VALUE + "M", Period.ofMonths(Integer.MAX_VALUE)},
294                {"P" + Integer.MIN_VALUE + "M", Period.ofMonths(Integer.MIN_VALUE)},
295
296                {"P1W", Period.ofDays(1 * 7)},
297                {"P12W", Period.ofDays(12 * 7)},
298                {"P7654321W", Period.ofDays(7654321 * 7)},
299                {"P+1W", Period.ofDays(1 * 7)},
300                {"P+12W", Period.ofDays(12 * 7)},
301                {"P+7654321W", Period.ofDays(7654321 * 7)},
302                {"P+0W", Period.ofDays(0)},
303                {"P0W", Period.ofDays(0)},
304                {"P-0W", Period.ofDays(0)},
305                {"P-25W", Period.ofDays(-25 * 7)},
306                {"P-7654321W", Period.ofDays(-7654321 * 7)},
307
308                {"P1D", Period.ofDays(1)},
309                {"P12D", Period.ofDays(12)},
310                {"P987654321D", Period.ofDays(987654321)},
311                {"P+1D", Period.ofDays(1)},
312                {"P+12D", Period.ofDays(12)},
313                {"P+987654321D", Period.ofDays(987654321)},
314                {"P+0D", Period.ofDays(0)},
315                {"P0D", Period.ofDays(0)},
316                {"P-0D", Period.ofDays(0)},
317                {"P-25D", Period.ofDays(-25)},
318                {"P-987654321D", Period.ofDays(-987654321)},
319                {"P" + Integer.MAX_VALUE + "D", Period.ofDays(Integer.MAX_VALUE)},
320                {"P" + Integer.MIN_VALUE + "D", Period.ofDays(Integer.MIN_VALUE)},
321
322                {"P0Y0M0D", Period.of(0, 0, 0)},
323                {"P2Y0M0D", Period.of(2, 0, 0)},
324                {"P0Y3M0D", Period.of(0, 3, 0)},
325                {"P0Y0M4D", Period.of(0, 0, 4)},
326                {"P2Y3M25D", Period.of(2, 3, 25)},
327                {"P-2Y3M25D", Period.of(-2, 3, 25)},
328                {"P2Y-3M25D", Period.of(2, -3, 25)},
329                {"P2Y3M-25D", Period.of(2, 3, -25)},
330                {"P-2Y-3M-25D", Period.of(-2, -3, -25)},
331
332                {"P0Y0M0W0D", Period.of(0, 0, 0)},
333                {"P2Y3M4W25D", Period.of(2, 3, 4 * 7 + 25)},
334                {"P-2Y-3M-4W-25D", Period.of(-2, -3, -4 * 7 - 25)},
335        };
336    }
337
338    @Test(dataProvider="parseSuccess")
339    public void factory_parse(String text, Period expected) {
340        Period p = Period.parse(text);
341        assertEquals(p, expected);
342    }
343
344    @Test(dataProvider="parseSuccess")
345    public void factory_parse_plus(String text, Period expected) {
346        Period p = Period.parse("+" + text);
347        assertEquals(p, expected);
348    }
349
350    @Test(dataProvider="parseSuccess")
351    public void factory_parse_minus(String text, Period expected) {
352        Period p = null;
353        try {
354            p = Period.parse("-" + text);
355        } catch (DateTimeParseException ex) {
356            assertEquals(expected.getYears() == Integer.MIN_VALUE ||
357                    expected.getMonths() == Integer.MIN_VALUE ||
358                    expected.getDays() == Integer.MIN_VALUE, true);
359            return;
360        }
361        // not inside try/catch or it breaks test
362        assertEquals(p, expected.negated());
363    }
364
365    @Test(dataProvider="parseSuccess")
366    public void factory_parse_lowerCase(String text, Period expected) {
367        Period p = Period.parse(text.toLowerCase(Locale.ENGLISH));
368        assertEquals(p, expected);
369    }
370
371    @DataProvider(name="parseFailure")
372    Object[][] data_parseFailure() {
373        return new Object[][] {
374                {""},
375                {"PTD"},
376                {"AT0D"},
377                {"PA0D"},
378                {"PT0A"},
379
380                {"PT+D"},
381                {"PT-D"},
382                {"PT.D"},
383                {"PTAD"},
384
385                {"PT+0D"},
386                {"PT-0D"},
387                {"PT+1D"},
388                {"PT-.D"},
389
390                {"P1Y1MT1D"},
391                {"P1YMD"},
392                {"P1Y2Y"},
393                {"PT1M+3S"},
394
395                {"P1M2Y"},
396                {"P1W2Y"},
397                {"P1D2Y"},
398                {"P1W2M"},
399                {"P1D2M"},
400                {"P1D2W"},
401
402                {"PT1S1"},
403                {"PT1S."},
404                {"PT1SA"},
405                {"PT1M1"},
406                {"PT1M."},
407                {"PT1MA"},
408
409                {"P"+ (((long) Integer.MAX_VALUE) + 1) + "Y"},
410                {"P"+ (((long) Integer.MAX_VALUE) + 1) + "M"},
411                {"P"+ (((long) Integer.MAX_VALUE) + 1) + "D"},
412                {"P"+ (((long) Integer.MIN_VALUE) - 1) + "Y"},
413                {"P"+ (((long) Integer.MIN_VALUE) - 1) + "M"},
414                {"P"+ (((long) Integer.MIN_VALUE) - 1) + "D"},
415
416                {"Rubbish"},
417        };
418    }
419
420    @Test(dataProvider="parseFailure", expectedExceptions=DateTimeParseException.class)
421    public void factory_parseFailures(String text) {
422        try {
423            Period.parse(text);
424        } catch (DateTimeParseException ex) {
425            assertEquals(ex.getParsedString(), text);
426            throw ex;
427        }
428    }
429
430    @Test(expectedExceptions=NullPointerException.class)
431    public void factory_parse_null() {
432        Period.parse(null);
433    }
434
435    //-----------------------------------------------------------------------
436    // between(LocalDate,LocalDate)
437    //-----------------------------------------------------------------------
438    @DataProvider(name="between")
439    Object[][] data_between() {
440        return new Object[][] {
441                {2010, 1, 1, 2010, 1, 1, 0, 0, 0},
442                {2010, 1, 1, 2010, 1, 2, 0, 0, 1},
443                {2010, 1, 1, 2010, 1, 31, 0, 0, 30},
444                {2010, 1, 1, 2010, 2, 1, 0, 1, 0},
445                {2010, 1, 1, 2010, 2, 28, 0, 1, 27},
446                {2010, 1, 1, 2010, 3, 1, 0, 2, 0},
447                {2010, 1, 1, 2010, 12, 31, 0, 11, 30},
448                {2010, 1, 1, 2011, 1, 1, 1, 0, 0},
449                {2010, 1, 1, 2011, 12, 31, 1, 11, 30},
450                {2010, 1, 1, 2012, 1, 1, 2, 0, 0},
451
452                {2010, 1, 10, 2010, 1, 1, 0, 0, -9},
453                {2010, 1, 10, 2010, 1, 2, 0, 0, -8},
454                {2010, 1, 10, 2010, 1, 9, 0, 0, -1},
455                {2010, 1, 10, 2010, 1, 10, 0, 0, 0},
456                {2010, 1, 10, 2010, 1, 11, 0, 0, 1},
457                {2010, 1, 10, 2010, 1, 31, 0, 0, 21},
458                {2010, 1, 10, 2010, 2, 1, 0, 0, 22},
459                {2010, 1, 10, 2010, 2, 9, 0, 0, 30},
460                {2010, 1, 10, 2010, 2, 10, 0, 1, 0},
461                {2010, 1, 10, 2010, 2, 28, 0, 1, 18},
462                {2010, 1, 10, 2010, 3, 1, 0, 1, 19},
463                {2010, 1, 10, 2010, 3, 9, 0, 1, 27},
464                {2010, 1, 10, 2010, 3, 10, 0, 2, 0},
465                {2010, 1, 10, 2010, 12, 31, 0, 11, 21},
466                {2010, 1, 10, 2011, 1, 1, 0, 11, 22},
467                {2010, 1, 10, 2011, 1, 9, 0, 11, 30},
468                {2010, 1, 10, 2011, 1, 10, 1, 0, 0},
469
470                {2010, 3, 30, 2011, 5, 1, 1, 1, 1},
471                {2010, 4, 30, 2011, 5, 1, 1, 0, 1},
472
473                {2010, 2, 28, 2012, 2, 27, 1, 11, 30},
474                {2010, 2, 28, 2012, 2, 28, 2, 0, 0},
475                {2010, 2, 28, 2012, 2, 29, 2, 0, 1},
476
477                {2012, 2, 28, 2014, 2, 27, 1, 11, 30},
478                {2012, 2, 28, 2014, 2, 28, 2, 0, 0},
479                {2012, 2, 28, 2014, 3, 1, 2, 0, 1},
480
481                {2012, 2, 29, 2014, 2, 28, 1, 11, 30},
482                {2012, 2, 29, 2014, 3, 1, 2, 0, 1},
483                {2012, 2, 29, 2014, 3, 2, 2, 0, 2},
484
485                {2012, 2, 29, 2016, 2, 28, 3, 11, 30},
486                {2012, 2, 29, 2016, 2, 29, 4, 0, 0},
487                {2012, 2, 29, 2016, 3, 1, 4, 0, 1},
488
489                {2010, 1, 1, 2009, 12, 31, 0, 0, -1},
490                {2010, 1, 1, 2009, 12, 30, 0, 0, -2},
491                {2010, 1, 1, 2009, 12, 2, 0, 0, -30},
492                {2010, 1, 1, 2009, 12, 1, 0, -1, 0},
493                {2010, 1, 1, 2009, 11, 30, 0, -1, -1},
494                {2010, 1, 1, 2009, 11, 2, 0, -1, -29},
495                {2010, 1, 1, 2009, 11, 1, 0, -2, 0},
496                {2010, 1, 1, 2009, 1, 2, 0, -11, -30},
497                {2010, 1, 1, 2009, 1, 1, -1, 0, 0},
498
499                {2010, 1, 15, 2010, 1, 15, 0, 0, 0},
500                {2010, 1, 15, 2010, 1, 14, 0, 0, -1},
501                {2010, 1, 15, 2010, 1, 1, 0, 0, -14},
502                {2010, 1, 15, 2009, 12, 31, 0, 0, -15},
503                {2010, 1, 15, 2009, 12, 16, 0, 0, -30},
504                {2010, 1, 15, 2009, 12, 15, 0, -1, 0},
505                {2010, 1, 15, 2009, 12, 14, 0, -1, -1},
506
507                {2010, 2, 28, 2009, 3, 1, 0, -11, -27},
508                {2010, 2, 28, 2009, 2, 28, -1, 0, 0},
509                {2010, 2, 28, 2009, 2, 27, -1, 0, -1},
510
511                {2010, 2, 28, 2008, 2, 29, -1, -11, -28},
512                {2010, 2, 28, 2008, 2, 28, -2, 0, 0},
513                {2010, 2, 28, 2008, 2, 27, -2, 0, -1},
514
515                {2012, 2, 29, 2009, 3, 1, -2, -11, -28},
516                {2012, 2, 29, 2009, 2, 28, -3, 0, -1},
517                {2012, 2, 29, 2009, 2, 27, -3, 0, -2},
518
519                {2012, 2, 29, 2008, 3, 1, -3, -11, -28},
520                {2012, 2, 29, 2008, 2, 29, -4, 0, 0},
521                {2012, 2, 29, 2008, 2, 28, -4, 0, -1},
522        };
523    }
524
525    @Test(dataProvider="between")
526    public void factory_between_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) {
527        LocalDate start = LocalDate.of(y1, m1, d1);
528        LocalDate end = LocalDate.of(y2, m2, d2);
529        Period test = Period.between(start, end);
530        assertPeriod(test, ye, me, de);
531        //assertEquals(start.plus(test), end);
532    }
533
534    @Test(expectedExceptions=NullPointerException.class)
535    public void factory_between_LocalDate_nullFirst() {
536        Period.between((LocalDate) null, LocalDate.of(2010, 1, 1));
537    }
538
539    @Test(expectedExceptions=NullPointerException.class)
540    public void factory_between_LocalDate_nullSecond() {
541        Period.between(LocalDate.of(2010, 1, 1), (LocalDate) null);
542    }
543
544    //-----------------------------------------------------------------------
545    // isZero()
546    //-----------------------------------------------------------------------
547    @Test
548    public void test_isZero() {
549        assertEquals(Period.of(0, 0, 0).isZero(), true);
550        assertEquals(Period.of(1, 2, 3).isZero(), false);
551        assertEquals(Period.of(1, 0, 0).isZero(), false);
552        assertEquals(Period.of(0, 2, 0).isZero(), false);
553        assertEquals(Period.of(0, 0, 3).isZero(), false);
554    }
555
556    //-----------------------------------------------------------------------
557    // isNegative()
558    //-----------------------------------------------------------------------
559    @Test
560    public void test_isPositive() {
561        assertEquals(Period.of(0, 0, 0).isNegative(), false);
562        assertEquals(Period.of(1, 2, 3).isNegative(), false);
563        assertEquals(Period.of(1, 0, 0).isNegative(), false);
564        assertEquals(Period.of(0, 2, 0).isNegative(), false);
565        assertEquals(Period.of(0, 0, 3).isNegative(), false);
566
567        assertEquals(Period.of(-1, -2, -3).isNegative(), true);
568        assertEquals(Period.of(-1, -2, 3).isNegative(), true);
569        assertEquals(Period.of(1, -2, -3).isNegative(), true);
570        assertEquals(Period.of(-1, 2, -3).isNegative(), true);
571        assertEquals(Period.of(-1, 2, 3).isNegative(), true);
572        assertEquals(Period.of(1, -2, 3).isNegative(), true);
573        assertEquals(Period.of(1, 2, -3).isNegative(), true);
574    }
575
576    //-----------------------------------------------------------------------
577    // withYears()
578    //-----------------------------------------------------------------------
579    @Test
580    public void test_withYears() {
581        assertPeriod(Period.of(1, 2, 3).withYears(1), 1, 2, 3);
582        assertPeriod(Period.of(1, 2, 3).withYears(10), 10, 2, 3);
583        assertPeriod(Period.of(1, 2, 3).withYears(-10), -10, 2, 3);
584        assertPeriod(Period.of(-1, -2, -3).withYears(10), 10, -2, -3);
585        assertPeriod(Period.of(1, 2, 3).withYears(0), 0, 2, 3);
586    }
587
588    //-----------------------------------------------------------------------
589    // withMonths()
590    //-----------------------------------------------------------------------
591    @Test
592    public void test_withMonths() {
593        assertPeriod(Period.of(1, 2, 3).withMonths(2), 1, 2, 3);
594        assertPeriod(Period.of(1, 2, 3).withMonths(10), 1, 10, 3);
595        assertPeriod(Period.of(1, 2, 3).withMonths(-10), 1, -10, 3);
596        assertPeriod(Period.of(-1, -2, -3).withMonths(10), -1, 10, -3);
597        assertPeriod(Period.of(1, 2, 3).withMonths(0), 1, 0, 3);
598    }
599
600    //-----------------------------------------------------------------------
601    // withDays()
602    //-----------------------------------------------------------------------
603    @Test
604    public void test_withDays() {
605        assertPeriod(Period.of(1, 2, 3).withDays(3), 1, 2, 3);
606        assertPeriod(Period.of(1, 2, 3).withDays(10), 1, 2, 10);
607        assertPeriod(Period.of(1, 2, 3).withDays(-10), 1, 2, -10);
608        assertPeriod(Period.of(-1, -2, -3).withDays(10), -1, -2, 10);
609        assertPeriod(Period.of(1, 2, 3).withDays(0), 1, 2, 0);
610    }
611
612    //-----------------------------------------------------------------------
613    // plus(Period)
614    //-----------------------------------------------------------------------
615    @DataProvider(name="plus")
616    Object[][] data_plus() {
617        return new Object[][] {
618                {pymd(0, 0, 0), pymd(0, 0, 0), pymd(0, 0, 0)},
619                {pymd(0, 0, 0), pymd(5, 0, 0), pymd(5, 0, 0)},
620                {pymd(0, 0, 0), pymd(-5, 0, 0), pymd(-5, 0, 0)},
621                {pymd(0, 0, 0), pymd(0, 5, 0), pymd(0, 5, 0)},
622                {pymd(0, 0, 0), pymd(0, -5, 0), pymd(0, -5, 0)},
623                {pymd(0, 0, 0), pymd(0, 0, 5), pymd(0, 0, 5)},
624                {pymd(0, 0, 0), pymd(0, 0, -5), pymd(0, 0, -5)},
625                {pymd(0, 0, 0), pymd(2, 3, 4), pymd(2, 3, 4)},
626                {pymd(0, 0, 0), pymd(-2, -3, -4), pymd(-2, -3, -4)},
627
628                {pymd(4, 5, 6), pymd(2, 3, 4), pymd(6, 8, 10)},
629                {pymd(4, 5, 6), pymd(-2, -3, -4), pymd(2, 2, 2)},
630        };
631    }
632
633    @Test(dataProvider="plus")
634    public void test_plus_TemporalAmount(Period base, Period add, Period expected) {
635        assertEquals(base.plus(add), expected);
636    }
637
638    @Test(expectedExceptions = DateTimeException.class)
639    public void test_plus_TemporalAmount_nonISO() {
640        pymd(4, 5, 6).plus(ThaiBuddhistChronology.INSTANCE.period(1, 0, 0));
641    }
642
643    @Test(expectedExceptions = DateTimeException.class)
644    public void test_plus_TemporalAmount_DaysHours() {
645        TemporalAmount amount = new TemporalAmount() {
646            @Override
647            public long get(TemporalUnit unit) {
648                if (unit == DAYS) {
649                    return 1;
650                } else {
651                    return 2;
652                }
653            }
654            @Override
655            public List<TemporalUnit> getUnits() {
656                List<TemporalUnit> list = new ArrayList<>();
657                list.add(DAYS);
658                list.add(HOURS);
659                return list;
660            }
661            @Override
662            public Temporal addTo(Temporal temporal) {
663                throw new UnsupportedOperationException();
664            }
665            @Override
666            public Temporal subtractFrom(Temporal temporal) {
667                throw new UnsupportedOperationException();
668            }
669        };
670        pymd(4, 5, 6).plus(amount);
671    }
672
673    //-----------------------------------------------------------------------
674    // plusYears()
675    //-----------------------------------------------------------------------
676    @Test
677    public void test_plusYears() {
678        assertPeriod(Period.of(1, 2, 3).plusYears(0), 1, 2, 3);
679        assertPeriod(Period.of(1, 2, 3).plusYears(10), 11, 2, 3);
680        assertPeriod(Period.of(1, 2, 3).plusYears(-10), -9, 2, 3);
681        assertPeriod(Period.of(1, 2, 3).plusYears(-1), 0, 2, 3);
682
683        assertPeriod(Period.of(1, 2, 3).plus(Period.ofYears(0)), 1, 2, 3);
684        assertPeriod(Period.of(1, 2, 3).plus(Period.ofYears(10)), 11, 2, 3);
685        assertPeriod(Period.of(1, 2, 3).plus(Period.ofYears(-10)), -9, 2, 3);
686        assertPeriod(Period.of(1, 2, 3).plus(Period.ofYears(-1)), 0, 2, 3);
687    }
688
689    @Test(expectedExceptions=ArithmeticException.class)
690    public void test_plusYears_overflowTooBig() {
691        Period test = Period.ofYears(Integer.MAX_VALUE);
692        test.plusYears(1);
693    }
694
695    @Test(expectedExceptions=ArithmeticException.class)
696    public void test_plusYears_overflowTooSmall() {
697        Period test = Period.ofYears(Integer.MIN_VALUE);
698        test.plusYears(-1);
699    }
700
701    //-----------------------------------------------------------------------
702    // plusMonths()
703    //-----------------------------------------------------------------------
704    @Test
705    public void test_plusMonths() {
706        assertPeriod(Period.of(1, 2, 3).plusMonths(0), 1, 2, 3);
707        assertPeriod(Period.of(1, 2, 3).plusMonths(10), 1, 12, 3);
708        assertPeriod(Period.of(1, 2, 3).plusMonths(-10), 1, -8, 3);
709        assertPeriod(Period.of(1, 2, 3).plusMonths(-2), 1, 0, 3);
710
711        assertPeriod(Period.of(1, 2, 3).plus(Period.ofMonths(0)), 1, 2, 3);
712        assertPeriod(Period.of(1, 2, 3).plus(Period.ofMonths(10)), 1, 12, 3);
713        assertPeriod(Period.of(1, 2, 3).plus(Period.ofMonths(-10)), 1, -8, 3);
714        assertPeriod(Period.of(1, 2, 3).plus(Period.ofMonths(-2)), 1, 0, 3);
715    }
716
717    @Test(expectedExceptions=ArithmeticException.class)
718    public void test_plusMonths_overflowTooBig() {
719        Period test = Period.ofMonths(Integer.MAX_VALUE);
720        test.plusMonths(1);
721    }
722
723    @Test(expectedExceptions=ArithmeticException.class)
724    public void test_plusMonths_overflowTooSmall() {
725        Period test = Period.ofMonths(Integer.MIN_VALUE);
726        test.plusMonths(-1);
727    }
728
729    //-----------------------------------------------------------------------
730    // plusDays()
731    //-----------------------------------------------------------------------
732    @Test
733    public void test_plusDays() {
734        assertPeriod(Period.of(1, 2, 3).plusDays(0), 1, 2, 3);
735        assertPeriod(Period.of(1, 2, 3).plusDays(10), 1, 2, 13);
736        assertPeriod(Period.of(1, 2, 3).plusDays(-10), 1, 2, -7);
737        assertPeriod(Period.of(1, 2, 3).plusDays(-3), 1, 2, 0);
738
739        assertPeriod(Period.of(1, 2, 3).plus(Period.ofDays(0)), 1, 2, 3);
740        assertPeriod(Period.of(1, 2, 3).plus(Period.ofDays(10)), 1, 2, 13);
741        assertPeriod(Period.of(1, 2, 3).plus(Period.ofDays(-10)), 1, 2, -7);
742        assertPeriod(Period.of(1, 2, 3).plus(Period.ofDays(-3)), 1, 2, 0);
743    }
744
745    @Test(expectedExceptions=ArithmeticException.class)
746    public void test_plusDays_overflowTooBig() {
747        Period test = Period.ofDays(Integer.MAX_VALUE);
748        test.plusDays(1);
749    }
750
751    @Test(expectedExceptions=ArithmeticException.class)
752    public void test_plusDays_overflowTooSmall() {
753        Period test = Period.ofDays(Integer.MIN_VALUE);
754        test.plusDays(-1);
755    }
756
757    //-----------------------------------------------------------------------
758    // minus(Period)
759    //-----------------------------------------------------------------------
760    @DataProvider(name="minus")
761    Object[][] data_minus() {
762        return new Object[][] {
763                {pymd(0, 0, 0), pymd(0, 0, 0), pymd(0, 0, 0)},
764                {pymd(0, 0, 0), pymd(5, 0, 0), pymd(-5, 0, 0)},
765                {pymd(0, 0, 0), pymd(-5, 0, 0), pymd(5, 0, 0)},
766                {pymd(0, 0, 0), pymd(0, 5, 0), pymd(0, -5, 0)},
767                {pymd(0, 0, 0), pymd(0, -5, 0), pymd(0, 5, 0)},
768                {pymd(0, 0, 0), pymd(0, 0, 5), pymd(0, 0, -5)},
769                {pymd(0, 0, 0), pymd(0, 0, -5), pymd(0, 0, 5)},
770                {pymd(0, 0, 0), pymd(2, 3, 4), pymd(-2, -3, -4)},
771                {pymd(0, 0, 0), pymd(-2, -3, -4), pymd(2, 3, 4)},
772
773                {pymd(4, 5, 6), pymd(2, 3, 4), pymd(2, 2, 2)},
774                {pymd(4, 5, 6), pymd(-2, -3, -4), pymd(6, 8, 10)},
775        };
776    }
777
778    @Test(dataProvider="minus")
779    public void test_minus_TemporalAmount(Period base, Period subtract, Period expected) {
780        assertEquals(base.minus(subtract), expected);
781    }
782
783    @Test(expectedExceptions = DateTimeException.class)
784    public void test_minus_TemporalAmount_nonISO() {
785        pymd(4, 5, 6).minus(ThaiBuddhistChronology.INSTANCE.period(1, 0, 0));
786    }
787
788    @Test(expectedExceptions = DateTimeException.class)
789    public void test_minus_TemporalAmount_DaysHours() {
790        TemporalAmount amount = new TemporalAmount() {
791            @Override
792            public long get(TemporalUnit unit) {
793                if (unit == DAYS) {
794                    return 1;
795                } else {
796                    return 2;
797                }
798            }
799            @Override
800            public List<TemporalUnit> getUnits() {
801                List<TemporalUnit> list = new ArrayList<>();
802                list.add(DAYS);
803                list.add(HOURS);
804                return list;
805            }
806            @Override
807            public Temporal addTo(Temporal temporal) {
808                throw new UnsupportedOperationException();
809            }
810            @Override
811            public Temporal subtractFrom(Temporal temporal) {
812                throw new UnsupportedOperationException();
813            }
814        };
815        pymd(4, 5, 6).minus(amount);
816    }
817
818    //-----------------------------------------------------------------------
819    // minusYears()
820    //-----------------------------------------------------------------------
821    @Test
822    public void test_minusYears() {
823        assertPeriod(Period.of(1, 2, 3).minusYears(0), 1, 2, 3);
824        assertPeriod(Period.of(1, 2, 3).minusYears(10), -9, 2, 3);
825        assertPeriod(Period.of(1, 2, 3).minusYears(-10), 11, 2, 3);
826        assertPeriod(Period.of(1, 2, 3).minusYears(-1), 2, 2, 3);
827
828        assertPeriod(Period.of(1, 2, 3).minus(Period.ofYears(0)), 1, 2, 3);
829        assertPeriod(Period.of(1, 2, 3).minus(Period.ofYears(10)), -9, 2, 3);
830        assertPeriod(Period.of(1, 2, 3).minus(Period.ofYears(-10)), 11, 2, 3);
831        assertPeriod(Period.of(1, 2, 3).minus(Period.ofYears(-1)), 2, 2, 3);
832    }
833
834    @Test(expectedExceptions=ArithmeticException.class)
835    public void test_minusYears_overflowTooBig() {
836        Period test = Period.ofYears(Integer.MAX_VALUE);
837        test.minusYears(-1);
838    }
839
840    @Test(expectedExceptions=ArithmeticException.class)
841    public void test_minusYears_overflowTooSmall() {
842        Period test = Period.ofYears(Integer.MIN_VALUE);
843        test.minusYears(1);
844    }
845
846    //-----------------------------------------------------------------------
847    // minusMonths()
848    //-----------------------------------------------------------------------
849    @Test
850    public void test_minusMonths() {
851        assertPeriod(Period.of(1, 2, 3).minusMonths(0), 1, 2, 3);
852        assertPeriod(Period.of(1, 2, 3).minusMonths(10), 1, -8, 3);
853        assertPeriod(Period.of(1, 2, 3).minusMonths(-10), 1, 12, 3);
854        assertPeriod(Period.of(1, 2, 3).minusMonths(-2), 1, 4, 3);
855
856        assertPeriod(Period.of(1, 2, 3).minus(Period.ofMonths(0)), 1, 2, 3);
857        assertPeriod(Period.of(1, 2, 3).minus(Period.ofMonths(10)), 1, -8, 3);
858        assertPeriod(Period.of(1, 2, 3).minus(Period.ofMonths(-10)), 1, 12, 3);
859        assertPeriod(Period.of(1, 2, 3).minus(Period.ofMonths(-2)), 1, 4, 3);
860    }
861
862    @Test(expectedExceptions=ArithmeticException.class)
863    public void test_minusMonths_overflowTooBig() {
864        Period test = Period.ofMonths(Integer.MAX_VALUE);
865        test.minusMonths(-1);
866    }
867
868    @Test(expectedExceptions=ArithmeticException.class)
869    public void test_minusMonths_overflowTooSmall() {
870        Period test = Period.ofMonths(Integer.MIN_VALUE);
871        test.minusMonths(1);
872    }
873
874    //-----------------------------------------------------------------------
875    // minusDays()
876    //-----------------------------------------------------------------------
877    @Test
878    public void test_minusDays() {
879        assertPeriod(Period.of(1, 2, 3).minusDays(0), 1, 2, 3);
880        assertPeriod(Period.of(1, 2, 3).minusDays(10), 1, 2, -7);
881        assertPeriod(Period.of(1, 2, 3).minusDays(-10), 1, 2, 13);
882        assertPeriod(Period.of(1, 2, 3).minusDays(-3), 1, 2, 6);
883
884        assertPeriod(Period.of(1, 2, 3).minus(Period.ofDays(0)), 1, 2, 3);
885        assertPeriod(Period.of(1, 2, 3).minus(Period.ofDays(10)), 1, 2, -7);
886        assertPeriod(Period.of(1, 2, 3).minus(Period.ofDays(-10)), 1, 2, 13);
887        assertPeriod(Period.of(1, 2, 3).minus(Period.ofDays(-3)), 1, 2, 6);
888    }
889
890    @Test(expectedExceptions=ArithmeticException.class)
891    public void test_minusDays_overflowTooBig() {
892        Period test = Period.ofDays(Integer.MAX_VALUE);
893        test.minusDays(-1);
894    }
895
896    @Test(expectedExceptions=ArithmeticException.class)
897    public void test_minusDays_overflowTooSmall() {
898        Period test = Period.ofDays(Integer.MIN_VALUE);
899        test.minusDays(1);
900    }
901
902    //-----------------------------------------------------------------------
903    // multipliedBy()
904    //-----------------------------------------------------------------------
905    @Test
906    public void test_multipliedBy() {
907        Period test = Period.of(1, 2, 3);
908        assertPeriod(test.multipliedBy(0), 0, 0, 0);
909        assertPeriod(test.multipliedBy(1), 1, 2, 3);
910        assertPeriod(test.multipliedBy(2), 2, 4, 6);
911        assertPeriod(test.multipliedBy(-3), -3, -6, -9);
912    }
913
914    @Test
915    public void test_multipliedBy_zeroBase() {
916        assertPeriod(Period.ZERO.multipliedBy(2), 0, 0, 0);
917    }
918
919    @Test(expectedExceptions=ArithmeticException.class)
920    public void test_multipliedBy_overflowTooBig() {
921        Period test = Period.ofYears(Integer.MAX_VALUE / 2 + 1);
922        test.multipliedBy(2);
923    }
924
925    @Test(expectedExceptions=ArithmeticException.class)
926    public void test_multipliedBy_overflowTooSmall() {
927        Period test = Period.ofYears(Integer.MIN_VALUE / 2 - 1);
928        test.multipliedBy(2);
929    }
930
931    //-----------------------------------------------------------------------
932    // negated()
933    //-----------------------------------------------------------------------
934    @Test
935    public void test_negated() {
936        assertPeriod(Period.of(0, 0, 0).negated(), 0 ,0, 0);
937        assertPeriod(Period.of(1, 2, 3).negated(), -1, -2, -3);
938        assertPeriod(Period.of(-1, -2, -3).negated(), 1, 2, 3);
939        assertPeriod(Period.of(-1, 2, -3).negated(), 1, -2, 3);
940        assertPeriod(Period.of(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE).negated(),
941                -Integer.MAX_VALUE, -Integer.MAX_VALUE, -Integer.MAX_VALUE);
942    }
943
944    @Test(expectedExceptions=ArithmeticException.class)
945    public void test_negated_overflow_years() {
946        Period.ofYears(Integer.MIN_VALUE).negated();
947    }
948
949    @Test(expectedExceptions=ArithmeticException.class)
950    public void test_negated_overflow_months() {
951        Period.ofMonths(Integer.MIN_VALUE).negated();
952    }
953
954    @Test(expectedExceptions=ArithmeticException.class)
955    public void test_negated_overflow_days() {
956        Period.ofDays(Integer.MIN_VALUE).negated();
957    }
958
959    //-----------------------------------------------------------------------
960    // normalized()
961    //-----------------------------------------------------------------------
962    @DataProvider(name="normalized")
963    Object[][] data_normalized() {
964        return new Object[][] {
965                {0, 0,  0, 0},
966                {1, 0,  1, 0},
967                {-1, 0,  -1, 0},
968
969                {1, 1,  1, 1},
970                {1, 2,  1, 2},
971                {1, 11,  1, 11},
972                {1, 12,  2, 0},
973                {1, 13,  2, 1},
974                {1, 23,  2, 11},
975                {1, 24,  3, 0},
976                {1, 25,  3, 1},
977
978                {1, -1,  0, 11},
979                {1, -2,  0, 10},
980                {1, -11,  0, 1},
981                {1, -12,  0, 0},
982                {1, -13,  0, -1},
983                {1, -23,  0, -11},
984                {1, -24,  -1, 0},
985                {1, -25,  -1, -1},
986                {1, -35,  -1, -11},
987                {1, -36,  -2, 0},
988                {1, -37,  -2, -1},
989
990                {-1, 1,  0, -11},
991                {-1, 11,  0, -1},
992                {-1, 12,  0, 0},
993                {-1, 13,  0, 1},
994                {-1, 23,  0, 11},
995                {-1, 24,  1, 0},
996                {-1, 25,  1, 1},
997
998                {-1, -1,  -1, -1},
999                {-1, -11,  -1, -11},
1000                {-1, -12,  -2, 0},
1001                {-1, -13,  -2, -1},
1002        };
1003    }
1004
1005    @Test(dataProvider="normalized")
1006    public void test_normalized(int inputYears, int inputMonths, int expectedYears, int expectedMonths) {
1007        assertPeriod(Period.of(inputYears, inputMonths, 0).normalized(), expectedYears, expectedMonths, 0);
1008    }
1009
1010    @Test(dataProvider="normalized")
1011    public void test_normalized_daysUnaffected(int inputYears, int inputMonths, int expectedYears, int expectedMonths) {
1012        assertPeriod(Period.of(inputYears, inputMonths, 5).normalized(), expectedYears, expectedMonths, 5);
1013    }
1014
1015    @Test(expectedExceptions=ArithmeticException.class)
1016    public void test_normalized_min() {
1017        Period base = Period.of(Integer.MIN_VALUE, -12, 0);
1018        base.normalized();
1019    }
1020
1021    @Test(expectedExceptions=ArithmeticException.class)
1022    public void test_normalized_max() {
1023        Period base = Period.of(Integer.MAX_VALUE, 12, 0);
1024        base.normalized();
1025    }
1026
1027    //-----------------------------------------------------------------------
1028    // addTo()
1029    //-----------------------------------------------------------------------
1030    @DataProvider(name="addTo")
1031    Object[][] data_addTo() {
1032        return new Object[][] {
1033                {pymd(0, 0, 0),  date(2012, 6, 30), date(2012, 6, 30)},
1034
1035                {pymd(1, 0, 0),  date(2012, 6, 10), date(2013, 6, 10)},
1036                {pymd(0, 1, 0),  date(2012, 6, 10), date(2012, 7, 10)},
1037                {pymd(0, 0, 1),  date(2012, 6, 10), date(2012, 6, 11)},
1038
1039                {pymd(-1, 0, 0),  date(2012, 6, 10), date(2011, 6, 10)},
1040                {pymd(0, -1, 0),  date(2012, 6, 10), date(2012, 5, 10)},
1041                {pymd(0, 0, -1),  date(2012, 6, 10), date(2012, 6, 9)},
1042
1043                {pymd(1, 2, 3),  date(2012, 6, 27), date(2013, 8, 30)},
1044                {pymd(1, 2, 3),  date(2012, 6, 28), date(2013, 8, 31)},
1045                {pymd(1, 2, 3),  date(2012, 6, 29), date(2013, 9, 1)},
1046                {pymd(1, 2, 3),  date(2012, 6, 30), date(2013, 9, 2)},
1047                {pymd(1, 2, 3),  date(2012, 7, 1), date(2013, 9, 4)},
1048
1049                {pymd(1, 0, 0),  date(2011, 2, 28), date(2012, 2, 28)},
1050                {pymd(4, 0, 0),  date(2011, 2, 28), date(2015, 2, 28)},
1051                {pymd(1, 0, 0),  date(2012, 2, 29), date(2013, 2, 28)},
1052                {pymd(4, 0, 0),  date(2012, 2, 29), date(2016, 2, 29)},
1053
1054                {pymd(1, 1, 0),  date(2011, 1, 29), date(2012, 2, 29)},
1055                {pymd(1, 2, 0),  date(2012, 2, 29), date(2013, 4, 29)},
1056        };
1057    }
1058
1059    @Test(dataProvider="addTo")
1060    public void test_addTo(Period period, LocalDate baseDate, LocalDate expected) {
1061        assertEquals(period.addTo(baseDate), expected);
1062    }
1063
1064    @Test(dataProvider="addTo")
1065    public void test_addTo_usingLocalDatePlus(Period period, LocalDate baseDate, LocalDate expected) {
1066        assertEquals(baseDate.plus(period), expected);
1067    }
1068
1069    @Test(expectedExceptions=NullPointerException.class)
1070    public void test_addTo_nullZero() {
1071        Period.ZERO.addTo(null);
1072    }
1073
1074    @Test(expectedExceptions=NullPointerException.class)
1075    public void test_addTo_nullNonZero() {
1076        Period.ofDays(2).addTo(null);
1077    }
1078
1079    //-----------------------------------------------------------------------
1080    // subtractFrom()
1081    //-----------------------------------------------------------------------
1082    @DataProvider(name="subtractFrom")
1083    Object[][] data_subtractFrom() {
1084        return new Object[][] {
1085                {pymd(0, 0, 0), date(2012, 6, 30), date(2012, 6, 30)},
1086
1087                {pymd(1, 0, 0), date(2012, 6, 10), date(2011, 6, 10)},
1088                {pymd(0, 1, 0), date(2012, 6, 10), date(2012, 5, 10)},
1089                {pymd(0, 0, 1), date(2012, 6, 10), date(2012, 6, 9)},
1090
1091                {pymd(-1, 0, 0), date(2012, 6, 10), date(2013, 6, 10)},
1092                {pymd(0, -1, 0), date(2012, 6, 10), date(2012, 7, 10)},
1093                {pymd(0, 0, -1), date(2012, 6, 10), date(2012, 6, 11)},
1094
1095                {pymd(1, 2, 3), date(2012, 8, 30), date(2011, 6, 27)},
1096                {pymd(1, 2, 3), date(2012, 8, 31), date(2011, 6, 27)},
1097                {pymd(1, 2, 3), date(2012, 9, 1), date(2011, 6, 28)},
1098                {pymd(1, 2, 3), date(2012, 9, 2), date(2011, 6, 29)},
1099                {pymd(1, 2, 3), date(2012, 9, 3), date(2011, 6, 30)},
1100                {pymd(1, 2, 3), date(2012, 9, 4), date(2011, 7, 1)},
1101
1102                {pymd(1, 0, 0), date(2011, 2, 28), date(2010, 2, 28)},
1103                {pymd(4, 0, 0), date(2011, 2, 28), date(2007, 2, 28)},
1104                {pymd(1, 0, 0), date(2012, 2, 29), date(2011, 2, 28)},
1105                {pymd(4, 0, 0), date(2012, 2, 29), date(2008, 2, 29)},
1106
1107                {pymd(1, 1, 0), date(2013, 3, 29), date(2012, 2, 29)},
1108                {pymd(1, 2, 0), date(2012, 2, 29), date(2010, 12, 29)},
1109        };
1110    }
1111
1112    @Test(dataProvider="subtractFrom")
1113    public void test_subtractFrom(Period period, LocalDate baseDate, LocalDate expected) {
1114        assertEquals(period.subtractFrom(baseDate), expected);
1115    }
1116
1117    @Test(dataProvider="subtractFrom")
1118    public void test_subtractFrom_usingLocalDateMinus(Period period, LocalDate baseDate, LocalDate expected) {
1119        assertEquals(baseDate.minus(period), expected);
1120    }
1121
1122    @Test(expectedExceptions=NullPointerException.class)
1123    public void test_subtractFrom_nullZero() {
1124        Period.ZERO.subtractFrom(null);
1125    }
1126
1127    @Test(expectedExceptions=NullPointerException.class)
1128    public void test_subtractFrom_nullNonZero() {
1129        Period.ofDays(2).subtractFrom(null);
1130    }
1131
1132    //-----------------------------------------------------------------------
1133    // get units
1134    //-----------------------------------------------------------------------
1135    @Test
1136    public void test_Period_getUnits() {
1137        Period period = Period.of(2012, 1, 1);
1138        List<TemporalUnit> units = period.getUnits();
1139        assertEquals(units.size(), 3, "Period.getUnits should return 3 units");
1140        assertEquals(units.get(0), ChronoUnit.YEARS, "Period.getUnits contains ChronoUnit.YEARS");
1141        assertEquals(units.get(1), ChronoUnit.MONTHS, "Period.getUnits contains ChronoUnit.MONTHS");
1142        assertEquals(units.get(2), ChronoUnit.DAYS, "Period.getUnits contains ChronoUnit.DAYS");
1143    }
1144
1145
1146    @DataProvider(name="GoodTemporalUnit")
1147    Object[][] data_goodTemporalUnit() {
1148        return new Object[][] {
1149            {2, ChronoUnit.DAYS},
1150            {2, ChronoUnit.MONTHS},
1151            {2, ChronoUnit.YEARS},
1152        };
1153    }
1154
1155    @Test(dataProvider="GoodTemporalUnit")
1156    public void test_good_getUnit(long amount, TemporalUnit unit) {
1157        Period period = Period.of(2, 2, 2);
1158        long actual = period.get(unit);
1159        assertEquals(actual, amount, "Value of unit: " + unit);
1160    }
1161
1162    @DataProvider(name="BadTemporalUnit")
1163    Object[][] data_badTemporalUnit() {
1164        return new Object[][] {
1165            {ChronoUnit.MICROS},
1166            {ChronoUnit.MILLIS},
1167            {ChronoUnit.HALF_DAYS},
1168            {ChronoUnit.DECADES},
1169            {ChronoUnit.CENTURIES},
1170            {ChronoUnit.MILLENNIA},
1171        };
1172    }
1173
1174    @Test(dataProvider="BadTemporalUnit", expectedExceptions=DateTimeException.class)
1175    public void test_bad_getUnit(TemporalUnit unit) {
1176        Period period = Period.of(2, 2, 2);
1177        period.get(unit);
1178    }
1179
1180    //-----------------------------------------------------------------------
1181    // equals() / hashCode()
1182    //-----------------------------------------------------------------------
1183    public void test_equals() {
1184        assertEquals(Period.of(1, 0, 0).equals(Period.ofYears(1)), true);
1185        assertEquals(Period.of(0, 1, 0).equals(Period.ofMonths(1)), true);
1186        assertEquals(Period.of(0, 0, 1).equals(Period.ofDays(1)), true);
1187        assertEquals(Period.of(1, 2, 3).equals(Period.of(1, 2, 3)), true);
1188
1189        assertEquals(Period.ofYears(1).equals(Period.ofYears(1)), true);
1190        assertEquals(Period.ofYears(1).equals(Period.ofYears(2)), false);
1191
1192        assertEquals(Period.ofMonths(1).equals(Period.ofMonths(1)), true);
1193        assertEquals(Period.ofMonths(1).equals(Period.ofMonths(2)), false);
1194
1195        assertEquals(Period.ofDays(1).equals(Period.ofDays(1)), true);
1196        assertEquals(Period.ofDays(1).equals(Period.ofDays(2)), false);
1197
1198        assertEquals(Period.of(1, 2, 3).equals(Period.of(0, 2, 3)), false);
1199        assertEquals(Period.of(1, 2, 3).equals(Period.of(1, 0, 3)), false);
1200        assertEquals(Period.of(1, 2, 3).equals(Period.of(1, 2, 0)), false);
1201    }
1202
1203    public void test_equals_self() {
1204        Period test = Period.of(1, 2, 3);
1205        assertEquals(test.equals(test), true);
1206    }
1207
1208    public void test_equals_null() {
1209        Period test = Period.of(1, 2, 3);
1210        assertEquals(test.equals(null), false);
1211    }
1212
1213    public void test_equals_otherClass() {
1214        Period test = Period.of(1, 2, 3);
1215        assertEquals(test.equals(""), false);
1216    }
1217
1218    //-----------------------------------------------------------------------
1219    public void test_hashCode() {
1220        Period test5 = Period.ofDays(5);
1221        Period test6 = Period.ofDays(6);
1222        Period test5M = Period.ofMonths(5);
1223        Period test5Y = Period.ofYears(5);
1224        assertEquals(test5.hashCode() == test5.hashCode(), true);
1225        assertEquals(test5.hashCode() == test6.hashCode(), false);
1226    }
1227
1228    //-----------------------------------------------------------------------
1229    // toString()
1230    //-----------------------------------------------------------------------
1231    @DataProvider(name="toStringAndParse")
1232    Object[][] data_toString() {
1233        return new Object[][] {
1234                {Period.ZERO, "P0D"},
1235                {Period.ofDays(0), "P0D"},
1236                {Period.ofYears(1), "P1Y"},
1237                {Period.ofMonths(1), "P1M"},
1238                {Period.ofDays(1), "P1D"},
1239                {Period.of(1, 2, 0), "P1Y2M"},
1240                {Period.of(0, 2, 3), "P2M3D"},
1241                {Period.of(1, 2, 3), "P1Y2M3D"},
1242        };
1243    }
1244
1245    @Test(dataProvider="toStringAndParse")
1246    public void test_toString(Period input, String expected) {
1247        assertEquals(input.toString(), expected);
1248    }
1249
1250    @Test(dataProvider="toStringAndParse")
1251    public void test_parse(Period test, String expected) {
1252        assertEquals(Period.parse(expected), test);
1253    }
1254
1255    //-----------------------------------------------------------------------
1256    private void assertPeriod(Period test, int y, int m, int d) {
1257        assertEquals(test.getYears(), y, "years");
1258        assertEquals(test.getMonths(), m, "months");
1259        assertEquals(test.getDays(), d, "days");
1260        assertEquals(test.toTotalMonths(), y * 12L + m, "totalMonths");
1261    }
1262
1263    private static Period pymd(int y, int m, int d) {
1264        return Period.of(y, m, d);
1265    }
1266
1267    private static LocalDate date(int y, int m, int d) {
1268        return LocalDate.of(y, m, d);
1269    }
1270
1271}
1272