1 /* 2 * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * * Neither the name of JSR-310 nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.threeten.bp.chrono; 33 34 import static org.testng.Assert.assertEquals; 35 import static org.testng.Assert.assertTrue; 36 37 import java.io.ByteArrayInputStream; 38 import java.io.ByteArrayOutputStream; 39 import java.io.ObjectInputStream; 40 import java.io.ObjectOutputStream; 41 import java.util.ArrayList; 42 import java.util.List; 43 import java.util.Locale; 44 import java.util.Map; 45 46 import org.testng.Assert; 47 import org.testng.annotations.DataProvider; 48 import org.testng.annotations.Test; 49 import org.threeten.bp.Duration; 50 import org.threeten.bp.LocalDate; 51 import org.threeten.bp.format.ResolverStyle; 52 import org.threeten.bp.temporal.ChronoUnit; 53 import org.threeten.bp.temporal.Temporal; 54 import org.threeten.bp.temporal.TemporalAccessor; 55 import org.threeten.bp.temporal.TemporalAdjuster; 56 import org.threeten.bp.temporal.TemporalAmount; 57 import org.threeten.bp.temporal.TemporalField; 58 import org.threeten.bp.temporal.TemporalUnit; 59 import org.threeten.bp.temporal.ValueRange; 60 61 /** 62 * Test assertions that must be true for all built-in chronologies. 63 */ 64 @Test 65 public class TestChronoLocalDate { 66 //----------------------------------------------------------------------- 67 // regular data factory for names and descriptions of available calendars 68 //----------------------------------------------------------------------- 69 @DataProvider(name = "calendars") data_of_calendars()70 Chronology[][] data_of_calendars() { 71 return new Chronology[][]{ 72 {HijrahChronology.INSTANCE}, 73 {IsoChronology.INSTANCE}, 74 {JapaneseChronology.INSTANCE}, 75 {MinguoChronology.INSTANCE}, 76 {ThaiBuddhistChronology.INSTANCE}}; 77 } 78 79 @Test(dataProvider="calendars") test_badWithAdjusterChrono(Chronology chrono)80 public void test_badWithAdjusterChrono(Chronology chrono) { 81 LocalDate refDate = LocalDate.of(1900, 1, 1); 82 ChronoLocalDate date = chrono.date(refDate); 83 for (Chronology[] clist : data_of_calendars()) { 84 Chronology chrono2 = clist[0]; 85 ChronoLocalDate date2 = chrono2.date(refDate); 86 TemporalAdjuster adjuster = new FixedAdjuster(date2); 87 if (chrono != chrono2) { 88 try { 89 date.with(adjuster); 90 Assert.fail("WithAdjuster should have thrown a ClassCastException"); 91 } catch (ClassCastException cce) { 92 // Expected exception; not an error 93 } 94 } else { 95 // Same chronology, 96 ChronoLocalDate result = date.with(adjuster); 97 assertEquals(result, date2, "WithAdjuster failed to replace date"); 98 } 99 } 100 } 101 102 @Test(dataProvider="calendars") test_badPlusAdjusterChrono(Chronology chrono)103 public void test_badPlusAdjusterChrono(Chronology chrono) { 104 LocalDate refDate = LocalDate.of(1900, 1, 1); 105 ChronoLocalDate date = chrono.date(refDate); 106 for (Chronology[] clist : data_of_calendars()) { 107 Chronology chrono2 = clist[0]; 108 ChronoLocalDate date2 = chrono2.date(refDate); 109 TemporalAmount adjuster = new FixedAdjuster(date2); 110 if (chrono != chrono2) { 111 try { 112 date.plus(adjuster); 113 Assert.fail("WithAdjuster should have thrown a ClassCastException"); 114 } catch (ClassCastException cce) { 115 // Expected exception; not an error 116 } 117 } else { 118 // Same chronology, 119 ChronoLocalDate result = date.plus(adjuster); 120 assertEquals(result, date2, "WithAdjuster failed to replace date"); 121 } 122 } 123 } 124 125 @Test(dataProvider="calendars") test_badMinusAdjusterChrono(Chronology chrono)126 public void test_badMinusAdjusterChrono(Chronology chrono) { 127 LocalDate refDate = LocalDate.of(1900, 1, 1); 128 ChronoLocalDate date = chrono.date(refDate); 129 for (Chronology[] clist : data_of_calendars()) { 130 Chronology chrono2 = clist[0]; 131 ChronoLocalDate date2 = chrono2.date(refDate); 132 TemporalAmount adjuster = new FixedAdjuster(date2); 133 if (chrono != chrono2) { 134 try { 135 date.minus(adjuster); 136 Assert.fail("WithAdjuster should have thrown a ClassCastException"); 137 } catch (ClassCastException cce) { 138 // Expected exception; not an error 139 } 140 } else { 141 // Same chronology, 142 ChronoLocalDate result = date.minus(adjuster); 143 assertEquals(result, date2, "WithAdjuster failed to replace date"); 144 } 145 } 146 } 147 148 @Test(dataProvider="calendars") test_badPlusPeriodUnitChrono(Chronology chrono)149 public void test_badPlusPeriodUnitChrono(Chronology chrono) { 150 LocalDate refDate = LocalDate.of(1900, 1, 1); 151 ChronoLocalDate date = chrono.date(refDate); 152 for (Chronology[] clist : data_of_calendars()) { 153 Chronology chrono2 = clist[0]; 154 ChronoLocalDate date2 = chrono2.date(refDate); 155 TemporalUnit adjuster = new FixedPeriodUnit(date2); 156 if (chrono != chrono2) { 157 try { 158 date.plus(1, adjuster); 159 Assert.fail("PeriodUnit.doAdd plus should have thrown a ClassCastException" + date.getClass() 160 + ", can not be cast to " + date2.getClass()); 161 } catch (ClassCastException cce) { 162 // Expected exception; not an error 163 } 164 } else { 165 // Same chronology, 166 ChronoLocalDate result = date.plus(1, adjuster); 167 assertEquals(result, date2, "WithAdjuster failed to replace date"); 168 } 169 } 170 } 171 172 @Test(dataProvider="calendars") test_badMinusPeriodUnitChrono(Chronology chrono)173 public void test_badMinusPeriodUnitChrono(Chronology chrono) { 174 LocalDate refDate = LocalDate.of(1900, 1, 1); 175 ChronoLocalDate date = chrono.date(refDate); 176 for (Chronology[] clist : data_of_calendars()) { 177 Chronology chrono2 = clist[0]; 178 ChronoLocalDate date2 = chrono2.date(refDate); 179 TemporalUnit adjuster = new FixedPeriodUnit(date2); 180 if (chrono != chrono2) { 181 try { 182 date.minus(1, adjuster); 183 Assert.fail("PeriodUnit.doAdd minus should have thrown a ClassCastException" + date.getClass() 184 + ", can not be cast to " + date2.getClass()); 185 } catch (ClassCastException cce) { 186 // Expected exception; not an error 187 } 188 } else { 189 // Same chronology, 190 ChronoLocalDate result = date.minus(1, adjuster); 191 assertEquals(result, date2, "WithAdjuster failed to replace date"); 192 } 193 } 194 } 195 196 @Test(dataProvider="calendars") test_badDateTimeFieldChrono(Chronology chrono)197 public void test_badDateTimeFieldChrono(Chronology chrono) { 198 LocalDate refDate = LocalDate.of(1900, 1, 1); 199 ChronoLocalDate date = chrono.date(refDate); 200 for (Chronology[] clist : data_of_calendars()) { 201 Chronology chrono2 = clist[0]; 202 ChronoLocalDate date2 = chrono2.date(refDate); 203 TemporalField adjuster = new FixedDateTimeField(date2); 204 if (chrono != chrono2) { 205 try { 206 date.with(adjuster, 1); 207 Assert.fail("DateTimeField doSet should have thrown a ClassCastException" + date.getClass() 208 + ", can not be cast to " + date2.getClass()); 209 } catch (ClassCastException cce) { 210 // Expected exception; not an error 211 } 212 } else { 213 // Same chronology, 214 ChronoLocalDate result = date.with(adjuster, 1); 215 assertEquals(result, date2, "DateTimeField doSet failed to replace date"); 216 } 217 } 218 } 219 220 //----------------------------------------------------------------------- 221 // isBefore, isAfter, isEqual, DATE_COMPARATOR 222 //----------------------------------------------------------------------- 223 @Test(dataProvider="calendars") test_date_comparisons(Chronology chrono)224 public void test_date_comparisons(Chronology chrono) { 225 List<ChronoLocalDate> dates = new ArrayList<ChronoLocalDate>(); 226 227 ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); 228 229 // Insert dates in order, no duplicates 230 if (chrono != JapaneseChronology.INSTANCE) { 231 dates.add(date.minus(1000, ChronoUnit.YEARS)); 232 dates.add(date.minus(100, ChronoUnit.YEARS)); 233 } 234 dates.add(date.minus(10, ChronoUnit.YEARS)); 235 dates.add(date.minus(1, ChronoUnit.YEARS)); 236 dates.add(date.minus(1, ChronoUnit.MONTHS)); 237 dates.add(date.minus(1, ChronoUnit.WEEKS)); 238 dates.add(date.minus(1, ChronoUnit.DAYS)); 239 dates.add(date); 240 dates.add(date.plus(1, ChronoUnit.DAYS)); 241 dates.add(date.plus(1, ChronoUnit.WEEKS)); 242 dates.add(date.plus(1, ChronoUnit.MONTHS)); 243 dates.add(date.plus(1, ChronoUnit.YEARS)); 244 dates.add(date.plus(10, ChronoUnit.YEARS)); 245 dates.add(date.plus(100, ChronoUnit.YEARS)); 246 dates.add(date.plus(1000, ChronoUnit.YEARS)); 247 248 // Check these dates against the corresponding dates for every calendar 249 for (Chronology[] clist : data_of_calendars()) { 250 List<ChronoLocalDate> otherDates = new ArrayList<ChronoLocalDate>(); 251 Chronology chrono2 = clist[0]; 252 if (chrono2 == JapaneseChronology.INSTANCE) { 253 continue; 254 } 255 for (ChronoLocalDate d : dates) { 256 otherDates.add(chrono2.date(d)); 257 } 258 259 // Now compare the sequence of original dates with the sequence of converted dates 260 for (int i = 0; i < dates.size(); i++) { 261 ChronoLocalDate a = dates.get(i); 262 for (int j = 0; j < otherDates.size(); j++) { 263 ChronoLocalDate b = otherDates.get(j); 264 int cmp = ChronoLocalDate.timeLineOrder().compare(a, b); 265 if (i < j) { 266 assertTrue(cmp < 0, a + " compare " + b); 267 assertEquals(a.isBefore(b), true, a + " isBefore " + b); 268 assertEquals(a.isAfter(b), false, a + " isAfter " + b); 269 assertEquals(a.isEqual(b), false, a + " isEqual " + b); 270 } else if (i > j) { 271 assertTrue(cmp > 0, a + " compare " + b); 272 assertEquals(a.isBefore(b), false, a + " isBefore " + b); 273 assertEquals(a.isAfter(b), true, a + " isAfter " + b); 274 assertEquals(a.isEqual(b), false, a + " isEqual " + b); 275 } else { 276 assertTrue(cmp == 0, a + " compare " + b); 277 assertEquals(a.isBefore(b), false, a + " isBefore " + b); 278 assertEquals(a.isAfter(b), false, a + " isAfter " + b); 279 assertEquals(a.isEqual(b), true, a + " isEqual " + b); 280 } 281 } 282 } 283 } 284 } 285 286 //----------------------------------------------------------------------- 287 // Test Serialization of Calendars 288 //----------------------------------------------------------------------- 289 @Test( dataProvider="calendars") test_ChronoSerialization(Chronology chrono)290 public void test_ChronoSerialization(Chronology chrono) throws Exception { 291 LocalDate ref = LocalDate.of(1900, 1, 5); 292 ChronoLocalDate orginal = chrono.date(ref); 293 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 294 ObjectOutputStream out = new ObjectOutputStream(baos); 295 out.writeObject(orginal); 296 out.close(); 297 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 298 ObjectInputStream in = new ObjectInputStream(bais); 299 ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); 300 assertEquals(ser, orginal, "deserialized date is wrong"); 301 } 302 303 /** 304 * FixedAdjusted returns a fixed DateTime in all adjustments. 305 * Construct an adjuster with the DateTime that should be returned. 306 */ 307 static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { 308 private Temporal datetime; 309 FixedAdjuster(Temporal datetime)310 FixedAdjuster(Temporal datetime) { 311 this.datetime = datetime; 312 } 313 314 @Override adjustInto(Temporal ignore)315 public Temporal adjustInto(Temporal ignore) { 316 return datetime; 317 } 318 319 @Override addTo(Temporal ignore)320 public Temporal addTo(Temporal ignore) { 321 return datetime; 322 } 323 324 @Override subtractFrom(Temporal ignore)325 public Temporal subtractFrom(Temporal ignore) { 326 return datetime; 327 } 328 329 @Override getUnits()330 public List<TemporalUnit> getUnits() { 331 throw new UnsupportedOperationException("Not supported yet."); 332 } 333 334 @Override get(TemporalUnit unit)335 public long get(TemporalUnit unit) { 336 throw new UnsupportedOperationException("Not supported yet."); 337 } 338 } 339 340 /** 341 * FixedPeriodUnit returns a fixed DateTime in all adjustments. 342 * Construct an FixedPeriodUnit with the DateTime that should be returned. 343 */ 344 static class FixedPeriodUnit implements TemporalUnit { 345 private Temporal dateTime; 346 FixedPeriodUnit(Temporal dateTime)347 FixedPeriodUnit(Temporal dateTime) { 348 this.dateTime = dateTime; 349 } 350 351 @Override toString()352 public String toString() { 353 return "FixedPeriodUnit"; 354 } 355 356 @Override getDuration()357 public Duration getDuration() { 358 throw new UnsupportedOperationException("Not supported yet."); 359 } 360 361 @Override isDurationEstimated()362 public boolean isDurationEstimated() { 363 throw new UnsupportedOperationException("Not supported yet."); 364 } 365 366 @Override isDateBased()367 public boolean isDateBased() { 368 throw new UnsupportedOperationException("Not supported yet."); 369 } 370 371 @Override isTimeBased()372 public boolean isTimeBased() { 373 throw new UnsupportedOperationException("Not supported yet."); 374 } 375 376 @Override isSupportedBy(Temporal dateTime)377 public boolean isSupportedBy(Temporal dateTime) { 378 throw new UnsupportedOperationException("Not supported yet."); 379 } 380 381 @SuppressWarnings("unchecked") 382 @Override addTo(R dateTime, long periodToAdd)383 public <R extends Temporal> R addTo(R dateTime, long periodToAdd) { 384 return (R) this.dateTime; 385 } 386 387 @Override between(Temporal temporal1, Temporal temporal2)388 public long between(Temporal temporal1, Temporal temporal2) { 389 throw new UnsupportedOperationException("Not supported yet."); 390 } 391 } 392 393 /** 394 * FixedDateTimeField returns a fixed DateTime in all adjustments. 395 * Construct an FixedDateTimeField with the DateTime that should be returned from doSet. 396 */ 397 static class FixedDateTimeField implements TemporalField { 398 private Temporal dateTime; FixedDateTimeField(Temporal dateTime)399 FixedDateTimeField(Temporal dateTime) { 400 this.dateTime = dateTime; 401 } 402 403 @Override toString()404 public String toString() { 405 return "FixedDateTimeField"; 406 } 407 408 @Override getBaseUnit()409 public TemporalUnit getBaseUnit() { 410 throw new UnsupportedOperationException("Not supported yet."); 411 } 412 413 @Override getRangeUnit()414 public TemporalUnit getRangeUnit() { 415 throw new UnsupportedOperationException("Not supported yet."); 416 } 417 418 @Override range()419 public ValueRange range() { 420 throw new UnsupportedOperationException("Not supported yet."); 421 } 422 423 @Override isDateBased()424 public boolean isDateBased() { 425 throw new UnsupportedOperationException("Not supported yet."); 426 } 427 428 @Override isTimeBased()429 public boolean isTimeBased() { 430 throw new UnsupportedOperationException("Not supported yet."); 431 } 432 433 @Override isSupportedBy(TemporalAccessor dateTime)434 public boolean isSupportedBy(TemporalAccessor dateTime) { 435 throw new UnsupportedOperationException("Not supported yet."); 436 } 437 438 @Override rangeRefinedBy(TemporalAccessor dateTime)439 public ValueRange rangeRefinedBy(TemporalAccessor dateTime) { 440 throw new UnsupportedOperationException("Not supported yet."); 441 } 442 443 @Override getFrom(TemporalAccessor dateTime)444 public long getFrom(TemporalAccessor dateTime) { 445 throw new UnsupportedOperationException("Not supported yet."); 446 } 447 448 @SuppressWarnings("unchecked") 449 @Override adjustInto(R dateTime, long newValue)450 public <R extends Temporal> R adjustInto(R dateTime, long newValue) { 451 return (R) this.dateTime; 452 } 453 454 @Override getDisplayName(Locale locale)455 public String getDisplayName(Locale locale) { 456 throw new UnsupportedOperationException("Not supported yet."); 457 } 458 459 @Override resolve(Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle)460 public TemporalAccessor resolve(Map<TemporalField, Long> fieldValues, 461 TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { 462 return null; 463 } 464 } 465 } 466