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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
  28  *
  29  * All rights reserved.
  30  *
  31  * Redistribution and use in source and binary forms, with or without
  32  * modification, are permitted provided that the following conditions are met:
  33  *
  34  *  * Redistributions of source code must retain the above copyright notice,
  35  *    this list of conditions and the following disclaimer.
  36  *
  37  *  * Redistributions in binary form must reproduce the above copyright notice,
  38  *    this list of conditions and the following disclaimer in the documentation
  39  *    and/or other materials provided with the distribution.
  40  *
  41  *  * Neither the name of JSR-310 nor the names of its contributors
  42  *    may be used to endorse or promote products derived from this software
  43  *    without specific prior written permission.
  44  *
  45  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  46  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  47  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  48  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  49  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  50  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  51  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  52  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  53  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  54  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  55  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  56  */
  57 package tck.java.time.chrono;
  58 
  59 import java.time.Clock;
  60 import static org.testng.Assert.assertEquals;
  61 import static org.testng.Assert.assertFalse;
  62 import static org.testng.Assert.assertTrue;
  63 import static org.testng.Assert.fail;
  64 
  65 import java.time.DateTimeException;
  66 import java.time.ZoneId;
  67 import java.time.ZoneOffset;
  68 import java.time.chrono.ChronoLocalDate;
  69 import java.time.chrono.Chronology;
  70 import java.time.chrono.Era;
  71 import java.time.chrono.HijrahChronology;
  72 import java.time.chrono.HijrahDate;
  73 import java.time.chrono.HijrahEra;
  74 import java.time.chrono.IsoChronology;
  75 import java.time.format.ResolverStyle;
  76 import java.time.temporal.ChronoField;
  77 import java.time.temporal.TemporalField;
  78 import java.util.HashMap;
  79 import java.util.List;
  80 import java.util.Map;
  81 
  82 import org.testng.Assert;
  83 import org.testng.annotations.DataProvider;
  84 import org.testng.annotations.Test;
  85 
  86 /**
  87  * Test.
  88  */
  89 @Test
  90 public class TCKHijrahChronology {
  91 
  92     //-----------------------------------------------------------------------
  93     // Chronology.ofName("Hijrah")  Lookup by name
  94     //-----------------------------------------------------------------------
  95     @Test
  96     public void test_chrono_byName() {
  97         Chronology c = HijrahChronology.INSTANCE;
  98         Chronology test = Chronology.of("Hijrah-umalqura");
  99         Assert.assertNotNull(test, "The Hijrah-umalqura calendar could not be found by name");
 100         Assert.assertEquals(test.getId(), "Hijrah-umalqura", "ID mismatch");
 101         Assert.assertEquals(test.getCalendarType(), "islamic-umalqura", "Type mismatch");
 102         Assert.assertEquals(test, c);
 103     }
 104 
 105     // Tests for dateNow() method
 106     @Test
 107     public void test_dateNow(){
 108         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now()) ;
 109         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now(ZoneId.systemDefault())) ;
 110         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now(Clock.systemDefaultZone())) ;
 111         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now(Clock.systemDefaultZone().getZone())) ;
 112 
 113         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahChronology.INSTANCE.dateNow(ZoneId.systemDefault())) ;
 114         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahChronology.INSTANCE.dateNow(Clock.systemDefaultZone())) ;
 115         assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahChronology.INSTANCE.dateNow(Clock.systemDefaultZone().getZone())) ;
 116 
 117         ZoneId zoneId = ZoneId.of("Europe/Paris");
 118         assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahChronology.INSTANCE.dateNow(Clock.system(zoneId))) ;
 119         assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahChronology.INSTANCE.dateNow(Clock.system(zoneId).getZone())) ;
 120         assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahDate.now(Clock.system(zoneId))) ;
 121         assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahDate.now(Clock.system(zoneId).getZone())) ;
 122 
 123         assertEquals(HijrahChronology.INSTANCE.dateNow(ZoneId.of(ZoneOffset.UTC.getId())), HijrahChronology.INSTANCE.dateNow(Clock.systemUTC())) ;
 124     }
 125 
 126     // Sample invalid dates
 127     @DataProvider(name="badDates")
 128     Object[][] data_badDates() {
 129         return new Object[][] {
 130             {1299, 12, 29},
 131             {1320, 1, 29 + 1},
 132             {1320, 12, 29 + 1},
 133             {1434, -1, 1},
 134             {1605, 1, 29},
 135             {1434, 0, 1},
 136             {1434, 14, 1},
 137             {1434, 15, 1},
 138             {1434, 1, -1},
 139             {1434, 1, 0},
 140             {1434, 1, 32},
 141             {1434, 12, -1},
 142             {1434, 12, 0},
 143             {1434, 12, 32},
 144         };
 145     }
 146 
 147     // This is a negative test to verify if the API throws exception if an invalid date is provided
 148     @Test(dataProvider="badDates", expectedExceptions=DateTimeException.class)
 149     public void test_badDates(int year, int month, int dom) {
 150         HijrahChronology.INSTANCE.date(year, month, dom);
 151     }
 152 
 153     // Negative test or dateYearDay with day too large
 154     @Test(expectedExceptions=java.time.DateTimeException.class)
 155     public void test_ofYearDayTooLarge() {
 156         int year = 1435;
 157         int lengthOfYear = HijrahChronology.INSTANCE.dateYearDay(year, 1).lengthOfYear();
 158         HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(year, lengthOfYear + 1);
 159     }
 160 
 161     //-----------------------------------------------------------------------
 162     // Bad Era for Chronology.date(era,...) and Chronology.prolepticYear(Era,...)
 163     //-----------------------------------------------------------------------
 164     @Test
 165     public void test_InvalidEras() {
 166         // Verify that the eras from every other Chronology are invalid
 167         for (Chronology chrono : Chronology.getAvailableChronologies()) {
 168             if (chrono instanceof HijrahChronology) {
 169                 continue;
 170             }
 171             List<Era> eras = chrono.eras();
 172             for (Era era : eras) {
 173                 try {
 174                     ChronoLocalDate date = HijrahChronology.INSTANCE.date(era, 1, 1, 1);
 175                     fail("HijrahChronology.date did not throw ClassCastException for Era: " + era);
 176                 } catch (ClassCastException cex) {
 177                     ; // ignore expected exception
 178                 }
 179 
 180                 /* TODO: Test for checking HijrahDate.of(Era, y, m, d) method if it is added.
 181                 try {
 182                     @SuppressWarnings("unused")
 183                     HijrahDate jdate = HijrahDate.of(era, 1, 1, 1);
 184                     fail("HijrahDate.of did not throw ClassCastException for Era: " + era);
 185                 } catch (ClassCastException cex) {
 186                     ; // ignore expected exception
 187                 }
 188                 */
 189 
 190                 try {
 191                     @SuppressWarnings("unused")
 192                     int year = HijrahChronology.INSTANCE.prolepticYear(era, 1);
 193                     fail("HijrahChronology.prolepticYear did not throw ClassCastException for Era: " + era);
 194                 } catch (ClassCastException cex) {
 195                     ; // ignore expected exception
 196                 }
 197             }
 198         }
 199     }
 200     //-----------------------------------------------------------------------
 201     // Tests for HijrahChronology resolve
 202     //-----------------------------------------------------------------------
 203     @DataProvider(name = "resolve_styleByEra")
 204     Object[][] data_resolve_styleByEra() {
 205         Object[][] result = new Object[ResolverStyle.values().length * HijrahEra.values().length][];
 206         int i = 0;
 207         for (ResolverStyle style : ResolverStyle.values()) {
 208             for (HijrahEra era : HijrahEra.values()) {
 209                 result[i++] = new Object[] {style, era};
 210             }
 211         }
 212         return result;
 213     }
 214 
 215     @Test(dataProvider = "resolve_styleByEra")
 216     public void test_resolve_yearOfEra_eraOnly_valid(ResolverStyle style, HijrahEra era) {
 217         Map<TemporalField, Long> fieldValues = new HashMap<>();
 218         fieldValues.put(ChronoField.ERA, (long) era.getValue());
 219         HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style);
 220         assertEquals(date, null);
 221         assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue());
 222         assertEquals(fieldValues.size(), 1);
 223     }
 224 
 225     @Test(dataProvider = "resolve_styleByEra")
 226     public void test_resolve_yearOfEra_eraAndYearOfEraOnly_valid(ResolverStyle style, HijrahEra era) {
 227         Map<TemporalField, Long> fieldValues = new HashMap<>();
 228         fieldValues.put(ChronoField.ERA, (long) era.getValue());
 229         fieldValues.put(ChronoField.YEAR_OF_ERA, 1343L);
 230         HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style);
 231         assertEquals(date, null);
 232         assertEquals(fieldValues.get(ChronoField.ERA), null);
 233         assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), null);
 234         assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1343L);
 235         assertEquals(fieldValues.size(), 1);
 236     }
 237 
 238     @Test(dataProvider = "resolve_styleByEra")
 239     public void test_resolve_yearOfEra_eraAndYearOnly_valid(ResolverStyle style, HijrahEra era) {
 240         Map<TemporalField, Long> fieldValues = new HashMap<>();
 241         fieldValues.put(ChronoField.ERA, (long) era.getValue());
 242         fieldValues.put(ChronoField.YEAR, 1343L);
 243         HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style);
 244         assertEquals(date, null);
 245         assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue());
 246         assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1343L);
 247         assertEquals(fieldValues.size(), 2);
 248     }
 249 
 250     @DataProvider(name = "resolve_styles")
 251     Object[][] data_resolve_styles() {
 252         Object[][] result = new Object[ResolverStyle.values().length][];
 253         int i = 0;
 254         for (ResolverStyle style : ResolverStyle.values()) {
 255             result[i++] = new Object[] {style};
 256         }
 257         return result;
 258     }
 259 
 260     @Test(dataProvider = "resolve_styles")
 261     public void test_resolve_yearOfEra_yearOfEraOnly_valid(ResolverStyle style) {
 262         Map<TemporalField, Long> fieldValues = new HashMap<>();
 263         fieldValues.put(ChronoField.YEAR_OF_ERA, 1343L);
 264         HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style);
 265         assertEquals(date, null);
 266         assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), (style != ResolverStyle.STRICT) ? null : (Long) 1343L);
 267         assertEquals(fieldValues.get(ChronoField.YEAR), (style == ResolverStyle.STRICT) ? null : (Long) 1343L);
 268         assertEquals(fieldValues.size(), 1);
 269     }
 270 
 271     @Test(dataProvider = "resolve_styles")
 272     public void test_resolve_yearOfEra_yearOfEraAndYearOnly_valid(ResolverStyle style) {
 273         Map<TemporalField, Long> fieldValues = new HashMap<>();
 274         fieldValues.put(ChronoField.YEAR_OF_ERA, 1343L);
 275         fieldValues.put(ChronoField.YEAR, 1343L);
 276         HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style);
 277         assertEquals(date, null);
 278         assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), null);
 279         assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1343L);
 280         assertEquals(fieldValues.size(), 1);
 281     }
 282 
 283     //-----------------------------------------------------------------------
 284     // Sample Hijrah Calendar data; official data is in lib/hijrah-ummalqura.properties
 285     // 1432=29 30 30 30 29 30 29 30 29 30 29 29  total = 354
 286     // 1433=30 29 30 30 29 30 30 29 30 29 30 29  total = 355
 287     // 1434=29 30 29 30 29 30 30 29 30 30 29 29  total = 354
 288     // 1435=30 29 30 29 30 29 30 29 30 30 29 30  total = 355
 289     //-----------------------------------------------------------------------
 290     @DataProvider(name = "resolve_ymd")
 291     Object[][] data_resolve_ymd() {
 292         // Compute the number of days in various month and years so that test cases
 293         // are not dependent on specific calendar data
 294         // Month numbers are always 1..12 so they can be used literally
 295         final int year = 1434;
 296         final int yearP1 = year + 1;
 297         final int yearP2 = year + 2;
 298         final int yearM1 = year - 1;
 299         final int yearM2 = year - 2;
 300         final int lastDayInYear = dateYearDay(year, 1).lengthOfYear();
 301         final int lastDayInYearP1 = dateYearDay(yearP1, 1).lengthOfYear();
 302         final int lastDayInYearM1 = dateYearDay(yearM1, 1).lengthOfYear();
 303         final int lastDayInYearM2 = dateYearDay(yearM2, 1).lengthOfYear();
 304         final int lastDayInMonthM1 = date(yearM1, 12, 1).lengthOfMonth();
 305         final int lastDayInMonthM2 = date(yearM1, 11, 1).lengthOfMonth();
 306         final int lastDayInMonthM11 = date(yearM1, 2, 1).lengthOfMonth();
 307 
 308         final int lastDayInMonth1 = date(year, 1, 1).lengthOfMonth();
 309         final int lastDayInMonth2 = date(year, 2, 1).lengthOfMonth();
 310         final int lastDayInMonth4 = date(year, 4, 1).lengthOfMonth();
 311         final int lastDayInMonth5 = date(year, 5, 1).lengthOfMonth();
 312         final int lastDayInMonth6 = date(year, 6, 1).lengthOfMonth();
 313         final int lastDayInMonth7 = date(year, 7, 1).lengthOfMonth();
 314 
 315         return new Object[][] {
 316                 {year, 1, -lastDayInYearM1, dateYearDay(yearM2, lastDayInYearM2), false, false},
 317                 {year, 1, -lastDayInYearM1 + 1, date(yearM1, 1, 1), false, false},
 318                 {year, 1, -lastDayInMonthM1, date(yearM1, 11, lastDayInMonthM2), false, false},
 319                 {year, 1, -lastDayInMonthM1 + 1, date(yearM1, 12, 1), false, false},
 320                 {year, 1, -12, date(yearM1, 12, lastDayInMonthM1 - 12), false, false},
 321                 {year, 1, 1, date(year, 1, 1), true, true},
 322                 {year, 1, lastDayInMonth1 + lastDayInMonth2 - 1, date(year, 2, lastDayInMonth2 - 1), false, false},
 323                 {year, 1, lastDayInMonth1 + lastDayInMonth2, date(year, 2, lastDayInMonth2), false, false},
 324                 {year, 1, lastDayInMonth1 + lastDayInMonth2 + 1 , date(year, 3, 1), false, false},
 325                 {year, 1, lastDayInYear, dateYearDay(year, lastDayInYear), false, false},
 326                 {year, 1, lastDayInYear + 1, date(1435, 1, 1), false, false},
 327                 {year, 1, lastDayInYear + lastDayInYearP1, dateYearDay(yearP1, lastDayInYearP1), false, false},
 328                 {year, 1, lastDayInYear + lastDayInYearP1 + 1, date(yearP2, 1, 1), false, false},
 329 
 330                 {year, 2, 1, date(year, 2, 1), true, true},
 331                 {year, 2, lastDayInMonth2 - 2, date(year, 2, lastDayInMonth2 - 2), true, true},
 332                 {year, 2, lastDayInMonth2 - 1, date(year, 2, lastDayInMonth2 - 1), true, true},
 333                 {year, 2, lastDayInMonth2, date(year, 2, lastDayInMonth2), date(year, 2, lastDayInMonth2), true},
 334                 {year, 2, lastDayInMonth2 + 1, date(year, 3, 1), false, false},
 335 
 336                 {year, -12, 1, date(yearM2, 12, 1), false, false},
 337                 {year, -11, 1, date(yearM1, 1, 1), false, false},
 338                 {year, -1, 1, date(yearM1, 11, 1), false, false},
 339                 {year, 0, 1, date(yearM1, 12, 1), false, false},
 340                 {year, 1, 1, date(year, 1, 1), true, true},
 341                 {year, 12, 1, date(year, 12, 1), true, true},
 342                 {year, 13, 1, date(yearP1, 1, 1), false, false},
 343                 {year, 24, 1, date(yearP1, 12, 1), false, false},
 344                 {year, 25, 1, date(yearP2, 1, 1), false, false},
 345 
 346                 {year, 6, -lastDayInMonth5, date(year, 4, lastDayInMonth4), false, false},
 347                 {year, 6, -lastDayInMonth5 + 1, date(year, 5, 1), false, false},
 348                 {year, 6, -1, date(year, 5, lastDayInMonth5 - 1), false, false},
 349                 {year, 6, 0, date(year, 5, lastDayInMonth5), false, false},
 350                 {year, 6, 1, date(year, 6, 1), true, true},
 351                 {year, 6, lastDayInMonth6 - 1 , date(year, 6, lastDayInMonth6 - 1), true, true},
 352                 {year, 6, lastDayInMonth6, date(year, 6, lastDayInMonth6), date(year, 6, lastDayInMonth6), true},
 353                 {year, 6, lastDayInMonth6 + 1, date(year, 7, 1), false, false},
 354                 {year, 6, lastDayInMonth6 + lastDayInMonth7 , date(year, 7, lastDayInMonth7), false, false},
 355                 {year, 6, lastDayInMonth6 + lastDayInMonth7 + 1, date(year, 8, 1), false, false},
 356 
 357                 {yearM1, 2, 1, date(yearM1, 2, 1), true, true},
 358                 {yearM1, 2, lastDayInMonthM11 - 1, date(yearM1, 2, lastDayInMonthM11 - 1), true, true},
 359                 {yearM1, 2, lastDayInMonthM11, date(yearM1, 2, lastDayInMonthM11), true, true},
 360                 {yearM1, 2, lastDayInMonthM11 + 1, date(yearM1, 3, 1), date(yearM1, 2, lastDayInMonthM11), false},
 361                 {yearM1, 2, lastDayInMonthM11 + 2, date(yearM1, 3, 2), false, false},
 362                 // Bad dates
 363                 {1299, 12, 1, null, false, false},
 364                 {1601, 1, 1, null, false, false},
 365 
 366         };
 367     }
 368 
 369     @Test(dataProvider = "resolve_ymd")
 370     public void test_resolve_ymd_lenient(int y, int m, int d, HijrahDate expected, Object smart, boolean strict) {
 371         Map<TemporalField, Long> fieldValues = new HashMap<>();
 372         fieldValues.put(ChronoField.YEAR, (long) y);
 373         fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m);
 374         fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d);
 375 
 376         if (expected != null) {
 377             HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT);
 378             assertEquals(date, expected);
 379             assertEquals(fieldValues.size(), 0);
 380         } else {
 381             try {
 382                 HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT);
 383                 fail("Should have failed, returned: " + date);
 384             } catch (DateTimeException ex) {
 385                 // expected
 386             }
 387         }
 388     }
 389 
 390     @Test(dataProvider = "resolve_ymd")
 391     public void test_resolve_ymd_smart(int y, int m, int d, HijrahDate expected, Object smart, boolean strict) {
 392         Map<TemporalField, Long> fieldValues = new HashMap<>();
 393         fieldValues.put(ChronoField.YEAR, (long) y);
 394         fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m);
 395         fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d);
 396         if (Boolean.TRUE.equals(smart)) {
 397             HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART);
 398             assertEquals(date, expected);
 399             assertEquals(fieldValues.size(), 0);
 400         } else if (smart instanceof HijrahDate) {
 401             HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART);
 402             assertEquals(date, smart);
 403         } else {
 404             try {
 405                 HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART);
 406                 fail("Should have failed, returned: " + date);
 407             } catch (DateTimeException ex) {
 408                 // expected
 409             }
 410         }
 411     }
 412 
 413     @Test(dataProvider = "resolve_ymd")
 414     public void test_resolve_ymd_strict(int y, int m, int d, HijrahDate expected, Object smart, boolean strict) {
 415         Map<TemporalField, Long> fieldValues = new HashMap<>();
 416         fieldValues.put(ChronoField.YEAR, (long) y);
 417         fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m);
 418         fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d);
 419         if (strict) {
 420             HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT);
 421             assertEquals(date, expected, "Resolved to incorrect date");
 422             assertEquals(fieldValues.size(), 0);
 423         } else {
 424             try {
 425                 HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT);
 426                 fail("Should have failed, returned: " + date);
 427             } catch (DateTimeException ex) {
 428                 // expected
 429             }
 430         }
 431     }
 432 
 433     //-----------------------------------------------------------------------
 434     @DataProvider(name = "resolve_yd")
 435     Object[][] data_resolve_yd() {
 436         // Compute the number of days in various month and years so that test cases
 437         // are not dependent on specific calendar data
 438         // Month numbers are always 1..12 so they can be used literally
 439         final int year = 1343;
 440         final int yearP1 = year + 1;
 441         final int yearP2 = year + 2;
 442         final int yearM1 = year - 1;
 443         final int yearM2 = year - 2;
 444         final int lastDayInYear = dateYearDay(year, 1).lengthOfYear();
 445         final int lastDayInYearP1 = dateYearDay(yearP1, 1).lengthOfYear();
 446         final int lastDayInYearM1 = dateYearDay(yearM1, 1).lengthOfYear();
 447         final int lastDayInYearM2 = dateYearDay(yearM2, 1).lengthOfYear();
 448 
 449         final int lastDayInMonthM1 = date(yearM1, 12, 1).lengthOfMonth();
 450         final int lastDayInMonthM2 = date(yearM1, 11, 1).lengthOfMonth();
 451         final int lastDayInMonthM11 = date(yearM1, 2, 1).lengthOfMonth();
 452 
 453         final int lastDayInMonth1 = date(year, 1, 1).lengthOfMonth();
 454         final int lastDayInMonth2 = date(year, 2, 1).lengthOfMonth();
 455         final int lastDayInMonth4 = date(year, 4, 1).lengthOfMonth();
 456         final int lastDayInMonth5 = date(year, 5, 1).lengthOfMonth();
 457         final int lastDayInMonth6 = date(year, 6, 1).lengthOfMonth();
 458         final int lastDayInMonth7 = date(year, 7, 1).lengthOfMonth();
 459 
 460         return new Object[][] {
 461                 {year, -lastDayInYearM1, dateYearDay(yearM2, lastDayInYearM2), false, false},
 462                 {year, -lastDayInYearM1 + 1, date(yearM1, 1, 1), false, false},
 463                 {year, -lastDayInMonthM1, date(yearM1, 11, lastDayInMonthM2), false, false},
 464                 {year, -lastDayInMonthM1 + 1, date(yearM1, 12, 1), false, false},
 465                 {year, -12, date(yearM1, 12, lastDayInMonthM1 - 12), false, false},
 466                 {year, -1, date(yearM1, 12, lastDayInMonthM1 - 1), false, false},
 467                 {year, 0, date(yearM1, 12, lastDayInMonthM1), false, false},
 468                 {year, 1, date(year, 1, 1), true, true},
 469                 {year, 2, date(year, 1, 2), true, true},
 470                 {year, lastDayInMonth1, date(year, 1, lastDayInMonth1), true, true},
 471                 {year, lastDayInMonth1 + 1, date(year, 2, 1), true, true},
 472                 {year, lastDayInMonth1 + lastDayInMonth2 - 1, date(year, 2, lastDayInMonth2 - 1), true, true},
 473                 {year, lastDayInMonth1 + lastDayInMonth2, date(year, 2, lastDayInMonth2), true, true},
 474                 {year, lastDayInMonth1 + lastDayInMonth2 + 1, date(year, 3, 1), true, true},
 475                 {year, lastDayInYear - 1, dateYearDay(year, lastDayInYear - 1), true, true},
 476                 {year, lastDayInYear, dateYearDay(year, lastDayInYear), true, true},
 477                 {year, lastDayInYear + 1, date(yearP1, 1, 1), false, false},
 478                 {year, lastDayInYear + lastDayInYearP1, dateYearDay(yearP1, lastDayInYearP1), false, false},
 479                 {year, lastDayInYear + lastDayInYearP1 + 1, date(yearP2, 1, 1), false, false},
 480         };
 481     }
 482 
 483     @Test(dataProvider = "resolve_yd")
 484     public void test_resolve_yd_lenient(int y, int d, HijrahDate expected, boolean smart, boolean strict) {
 485         Map<TemporalField, Long> fieldValues = new HashMap<>();
 486         fieldValues.put(ChronoField.YEAR, (long) y);
 487         fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d);
 488         HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT);
 489         assertEquals(date, expected);
 490         assertEquals(fieldValues.size(), 0);
 491     }
 492 
 493     @Test(dataProvider = "resolve_yd")
 494     public void test_resolve_yd_smart(int y, int d, HijrahDate expected, boolean smart, boolean strict) {
 495         Map<TemporalField, Long> fieldValues = new HashMap<>();
 496         fieldValues.put(ChronoField.YEAR, (long) y);
 497         fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d);
 498         if (smart) {
 499             HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART);
 500             assertEquals(date, expected);
 501             assertEquals(fieldValues.size(), 0);
 502         } else {
 503             try {
 504                 HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART);
 505                 fail("Should have failed, returned date: " + date);
 506             } catch (DateTimeException ex) {
 507                 // expected
 508             }
 509         }
 510     }
 511 
 512     @Test(dataProvider = "resolve_yd")
 513     public void test_resolve_yd_strict(int y, int d, HijrahDate expected, boolean smart, boolean strict) {
 514         Map<TemporalField, Long> fieldValues = new HashMap<>();
 515         fieldValues.put(ChronoField.YEAR, (long) y);
 516         fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d);
 517         if (strict) {
 518             HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT);
 519             assertEquals(date, expected);
 520             assertEquals(fieldValues.size(), 0);
 521         } else {
 522             try {
 523                 HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT);
 524                 fail("Should have failed, returned date: " + date);
 525             } catch (DateTimeException ex) {
 526                 // expected
 527             }
 528         }
 529     }
 530 
 531     //-----------------------------------------------------------------------
 532     private static HijrahDate date(int y, int m, int d) {
 533         return HijrahDate.of(y, m, d);
 534     }
 535 
 536     private static HijrahDate dateYearDay(int y, int doy) {
 537         return HijrahChronology.INSTANCE.dateYearDay(y, doy);
 538     }
 539 
 540     //-----------------------------------------------------------------------
 541     // equals()
 542     //-----------------------------------------------------------------------
 543     @Test
 544     public void test_equals_true() {
 545         assertTrue(HijrahChronology.INSTANCE.equals(HijrahChronology.INSTANCE));
 546     }
 547 
 548     @Test
 549     public void test_equals_false() {
 550         assertFalse(HijrahChronology.INSTANCE.equals(IsoChronology.INSTANCE));
 551     }
 552 }