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 static org.testng.Assert.assertEquals; 60 import static org.testng.Assert.assertTrue; 61 62 import java.io.ByteArrayInputStream; 63 import java.io.ByteArrayOutputStream; 64 import java.io.ObjectInputStream; 65 import java.io.ObjectOutputStream; 66 import java.time.DateTimeException; 67 import java.time.Duration; 68 import java.time.LocalDate; 69 import java.time.LocalTime; 70 import java.time.ZoneOffset; 71 import java.time.chrono.ChronoLocalDate; 72 import java.time.chrono.Chronology; 73 import java.time.chrono.HijrahChronology; 74 import java.time.chrono.IsoChronology; 75 import java.time.chrono.JapaneseChronology; 76 import java.time.chrono.MinguoChronology; 77 import java.time.chrono.ThaiBuddhistChronology; 78 import java.time.temporal.ChronoUnit; 79 import java.time.temporal.Temporal; 80 import java.time.temporal.TemporalAccessor; 81 import java.time.temporal.TemporalAdjuster; 82 import java.time.temporal.TemporalAmount; 83 import java.time.temporal.TemporalField; 84 import java.time.temporal.TemporalUnit; 85 import java.time.temporal.ValueRange; 86 import java.util.ArrayList; 87 import java.util.Collections; 88 import java.util.List; 89 90 import org.testng.Assert; 91 import org.testng.annotations.DataProvider; 92 import org.testng.annotations.Test; 93 94 /** 95 * Test assertions that must be true for all built-in chronologies. 96 */ 97 @Test 98 public class TCKChronoLocalDate { 99 100 //----------------------------------------------------------------------- 101 // regular data factory for names and descriptions of available calendars 102 //----------------------------------------------------------------------- 103 @DataProvider(name = "calendars") data_of_calendars()104 Chronology[][] data_of_calendars() { 105 return new Chronology[][]{ 106 {HijrahChronology.INSTANCE}, 107 {IsoChronology.INSTANCE}, 108 {JapaneseChronology.INSTANCE}, 109 {MinguoChronology.INSTANCE}, 110 {ThaiBuddhistChronology.INSTANCE}}; 111 } 112 113 @Test(dataProvider="calendars") test_badWithAdjusterChrono(Chronology chrono)114 public void test_badWithAdjusterChrono(Chronology chrono) { 115 LocalDate refDate = LocalDate.of(2013, 1, 1); 116 ChronoLocalDate date = chrono.date(refDate); 117 for (Chronology[] clist : data_of_calendars()) { 118 Chronology chrono2 = clist[0]; 119 ChronoLocalDate date2 = chrono2.date(refDate); 120 TemporalAdjuster adjuster = new FixedAdjuster(date2); 121 if (chrono != chrono2) { 122 try { 123 date.with(adjuster); 124 Assert.fail("WithAdjuster should have thrown a ClassCastException"); 125 } catch (ClassCastException cce) { 126 // Expected exception; not an error 127 } 128 } else { 129 // Same chronology, 130 ChronoLocalDate result = date.with(adjuster); 131 assertEquals(result, date2, "WithAdjuster failed to replace date"); 132 } 133 } 134 } 135 136 @Test(dataProvider="calendars") test_badPlusAdjusterChrono(Chronology chrono)137 public void test_badPlusAdjusterChrono(Chronology chrono) { 138 LocalDate refDate = LocalDate.of(2013, 1, 1); 139 ChronoLocalDate date = chrono.date(refDate); 140 for (Chronology[] clist : data_of_calendars()) { 141 Chronology chrono2 = clist[0]; 142 ChronoLocalDate date2 = chrono2.date(refDate); 143 TemporalAmount adjuster = new FixedAdjuster(date2); 144 if (chrono != chrono2) { 145 try { 146 date.plus(adjuster); 147 Assert.fail("WithAdjuster should have thrown a ClassCastException"); 148 } catch (ClassCastException cce) { 149 // Expected exception; not an error 150 } 151 } else { 152 // Same chronology, 153 ChronoLocalDate result = date.plus(adjuster); 154 assertEquals(result, date2, "WithAdjuster failed to replace date"); 155 } 156 } 157 } 158 159 @Test(dataProvider="calendars") test_badMinusAdjusterChrono(Chronology chrono)160 public void test_badMinusAdjusterChrono(Chronology chrono) { 161 LocalDate refDate = LocalDate.of(2013, 1, 1); 162 ChronoLocalDate date = chrono.date(refDate); 163 for (Chronology[] clist : data_of_calendars()) { 164 Chronology chrono2 = clist[0]; 165 ChronoLocalDate date2 = chrono2.date(refDate); 166 TemporalAmount adjuster = new FixedAdjuster(date2); 167 if (chrono != chrono2) { 168 try { 169 date.minus(adjuster); 170 Assert.fail("WithAdjuster should have thrown a ClassCastException"); 171 } catch (ClassCastException cce) { 172 // Expected exception; not an error 173 } 174 } else { 175 // Same chronology, 176 ChronoLocalDate result = date.minus(adjuster); 177 assertEquals(result, date2, "WithAdjuster failed to replace date"); 178 } 179 } 180 } 181 182 @Test(dataProvider="calendars") test_badPlusTemporalUnitChrono(Chronology chrono)183 public void test_badPlusTemporalUnitChrono(Chronology chrono) { 184 LocalDate refDate = LocalDate.of(2013, 1, 1); 185 ChronoLocalDate date = chrono.date(refDate); 186 for (Chronology[] clist : data_of_calendars()) { 187 Chronology chrono2 = clist[0]; 188 ChronoLocalDate date2 = chrono2.date(refDate); 189 TemporalUnit adjuster = new FixedTemporalUnit(date2); 190 if (chrono != chrono2) { 191 try { 192 date.plus(1, adjuster); 193 Assert.fail("TemporalUnit.doAdd plus should have thrown a ClassCastException" + date.getClass() 194 + ", can not be cast to " + date2.getClass()); 195 } catch (ClassCastException cce) { 196 // Expected exception; not an error 197 } 198 } else { 199 // Same chronology, 200 ChronoLocalDate result = date.plus(1, adjuster); 201 assertEquals(result, date2, "WithAdjuster failed to replace date"); 202 } 203 } 204 } 205 206 @Test(dataProvider="calendars") test_badMinusTemporalUnitChrono(Chronology chrono)207 public void test_badMinusTemporalUnitChrono(Chronology chrono) { 208 LocalDate refDate = LocalDate.of(2013, 1, 1); 209 ChronoLocalDate date = chrono.date(refDate); 210 for (Chronology[] clist : data_of_calendars()) { 211 Chronology chrono2 = clist[0]; 212 ChronoLocalDate date2 = chrono2.date(refDate); 213 TemporalUnit adjuster = new FixedTemporalUnit(date2); 214 if (chrono != chrono2) { 215 try { 216 date.minus(1, adjuster); 217 Assert.fail("TemporalUnit.doAdd minus should have thrown a ClassCastException" + date.getClass() 218 + ", can not be cast to " + date2.getClass()); 219 } catch (ClassCastException cce) { 220 // Expected exception; not an error 221 } 222 } else { 223 // Same chronology, 224 ChronoLocalDate result = date.minus(1, adjuster); 225 assertEquals(result, date2, "WithAdjuster failed to replace date"); 226 } 227 } 228 } 229 230 @Test(dataProvider="calendars") test_badTemporalFieldChrono(Chronology chrono)231 public void test_badTemporalFieldChrono(Chronology chrono) { 232 LocalDate refDate = LocalDate.of(2013, 1, 1); 233 ChronoLocalDate date = chrono.date(refDate); 234 for (Chronology[] clist : data_of_calendars()) { 235 Chronology chrono2 = clist[0]; 236 ChronoLocalDate date2 = chrono2.date(refDate); 237 TemporalField adjuster = new FixedTemporalField(date2); 238 if (chrono != chrono2) { 239 try { 240 date.with(adjuster, 1); 241 Assert.fail("TemporalField doSet should have thrown a ClassCastException" + date.getClass() 242 + ", can not be cast to " + date2.getClass()); 243 } catch (ClassCastException cce) { 244 // Expected exception; not an error 245 } 246 } else { 247 // Same chronology, 248 ChronoLocalDate result = date.with(adjuster, 1); 249 assertEquals(result, date2, "TemporalField doSet failed to replace date"); 250 } 251 } 252 } 253 254 //----------------------------------------------------------------------- 255 // isBefore, isAfter, isEqual, DATE_COMPARATOR 256 //----------------------------------------------------------------------- 257 @Test(dataProvider="calendars") test_date_comparisons(Chronology chrono)258 public void test_date_comparisons(Chronology chrono) { 259 List<ChronoLocalDate> dates = new ArrayList<>(); 260 261 ChronoLocalDate date = chrono.date(LocalDate.of(2013, 1, 1)); 262 263 // Insert dates in order, no duplicates 264 dates.add(date.minus(1, ChronoUnit.YEARS)); 265 dates.add(date.minus(1, ChronoUnit.MONTHS)); 266 dates.add(date.minus(1, ChronoUnit.WEEKS)); 267 dates.add(date.minus(1, ChronoUnit.DAYS)); 268 dates.add(date); 269 dates.add(date.plus(1, ChronoUnit.DAYS)); 270 dates.add(date.plus(1, ChronoUnit.WEEKS)); 271 dates.add(date.plus(1, ChronoUnit.MONTHS)); 272 dates.add(date.plus(1, ChronoUnit.YEARS)); 273 274 // Check these dates against the corresponding dates for every calendar 275 for (Chronology[] clist : data_of_calendars()) { 276 List<ChronoLocalDate> otherDates = new ArrayList<>(); 277 Chronology chrono2 = clist[0]; 278 for (ChronoLocalDate d : dates) { 279 otherDates.add(chrono2.date(d)); 280 } 281 282 // Now compare the sequence of original dates with the sequence of converted dates 283 for (int i = 0; i < dates.size(); i++) { 284 ChronoLocalDate a = dates.get(i); 285 for (int j = 0; j < otherDates.size(); j++) { 286 ChronoLocalDate b = otherDates.get(j); 287 int cmp = ChronoLocalDate.timeLineOrder().compare(a, b); 288 if (i < j) { 289 assertTrue(cmp < 0, a + " compare " + b); 290 assertEquals(a.isBefore(b), true, a + " isBefore " + b); 291 assertEquals(a.isAfter(b), false, a + " isAfter " + b); 292 assertEquals(a.isEqual(b), false, a + " isEqual " + b); 293 } else if (i > j) { 294 assertTrue(cmp > 0, a + " compare " + b); 295 assertEquals(a.isBefore(b), false, a + " isBefore " + b); 296 assertEquals(a.isAfter(b), true, a + " isAfter " + b); 297 assertEquals(a.isEqual(b), false, a + " isEqual " + b); 298 } else { 299 assertTrue(cmp == 0, a + " compare " + b); 300 assertEquals(a.isBefore(b), false, a + " isBefore " + b); 301 assertEquals(a.isAfter(b), false, a + " isAfter " + b); 302 assertEquals(a.isEqual(b), true, a + " isEqual " + b); 303 } 304 } 305 } 306 } 307 } 308 309 310 //----------------------------------------------------------------------- 311 @Test(dataProvider="calendars") test_from_TemporalAccessor(Chronology chrono)312 public void test_from_TemporalAccessor(Chronology chrono) { 313 LocalDate refDate = LocalDate.of(2013, 1, 1); 314 ChronoLocalDate date = chrono.date(refDate); 315 ChronoLocalDate test1 = ChronoLocalDate.from(date); 316 assertEquals(test1, date); 317 ChronoLocalDate test2 = ChronoLocalDate.from(date.atTime(LocalTime.of(12, 30))); 318 assertEquals(test2, date); 319 ChronoLocalDate test3 = ChronoLocalDate.from(date.atTime(LocalTime.of(12, 30)).atZone(ZoneOffset.UTC)); 320 assertEquals(test3, date); 321 } 322 323 @Test(expectedExceptions = DateTimeException.class) test_from_TemporalAccessor_timeOnly()324 public void test_from_TemporalAccessor_timeOnly() { 325 ChronoLocalDate.from(LocalTime.of(12, 30)); 326 } 327 328 @Test(expectedExceptions = NullPointerException.class) test_from_TemporalAccessor_null()329 public void test_from_TemporalAccessor_null() { 330 ChronoLocalDate.from(null); 331 } 332 333 //----------------------------------------------------------------------- 334 /** 335 * FixedAdjusted returns a fixed Temporal in all adjustments. 336 * Construct an adjuster with the Temporal that should be returned from adjust. 337 */ 338 static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { 339 private Temporal datetime; 340 FixedAdjuster(Temporal datetime)341 FixedAdjuster(Temporal datetime) { 342 this.datetime = datetime; 343 } 344 345 @Override adjustInto(Temporal ignore)346 public Temporal adjustInto(Temporal ignore) { 347 return datetime; 348 } 349 350 @Override addTo(Temporal ignore)351 public Temporal addTo(Temporal ignore) { 352 return datetime; 353 } 354 355 @Override subtractFrom(Temporal ignore)356 public Temporal subtractFrom(Temporal ignore) { 357 return datetime; 358 } 359 360 @Override get(TemporalUnit unit)361 public long get(TemporalUnit unit) { 362 throw new UnsupportedOperationException("Not supported yet."); 363 } 364 365 @Override getUnits()366 public List<TemporalUnit> getUnits() { 367 throw new UnsupportedOperationException("Not supported yet."); 368 } 369 } 370 371 /** 372 * FixedTemporalUnit returns a fixed Temporal in all adjustments. 373 * Construct an FixedTemporalUnit with the Temporal that should be returned from doAdd. 374 */ 375 static class FixedTemporalUnit implements TemporalUnit { 376 private Temporal temporal; 377 FixedTemporalUnit(Temporal temporal)378 FixedTemporalUnit(Temporal temporal) { 379 this.temporal = temporal; 380 } 381 382 @Override getDuration()383 public Duration getDuration() { 384 throw new UnsupportedOperationException("Not supported yet."); 385 } 386 387 @Override isDurationEstimated()388 public boolean isDurationEstimated() { 389 throw new UnsupportedOperationException("Not supported yet."); 390 } 391 392 @Override isDateBased()393 public boolean isDateBased() { 394 return false; 395 } 396 397 @Override isTimeBased()398 public boolean isTimeBased() { 399 return false; 400 } 401 402 @Override isSupportedBy(Temporal temporal)403 public boolean isSupportedBy(Temporal temporal) { 404 throw new UnsupportedOperationException("Not supported yet."); 405 } 406 407 @SuppressWarnings("unchecked") 408 @Override addTo(R temporal, long amount)409 public <R extends Temporal> R addTo(R temporal, long amount) { 410 return (R) this.temporal; 411 } 412 413 @Override between(Temporal temporal1, Temporal temporal2)414 public long between(Temporal temporal1, Temporal temporal2) { 415 throw new UnsupportedOperationException("Not supported yet."); 416 } 417 418 @Override toString()419 public String toString() { 420 return "FixedTemporalUnit"; 421 } 422 } 423 424 /** 425 * FixedTemporalField returns a fixed Temporal in all adjustments. 426 * Construct an FixedTemporalField with the Temporal that should be returned from doSet. 427 */ 428 static class FixedTemporalField implements TemporalField { 429 private Temporal temporal; FixedTemporalField(Temporal temporal)430 FixedTemporalField(Temporal temporal) { 431 this.temporal = temporal; 432 } 433 434 @Override getBaseUnit()435 public TemporalUnit getBaseUnit() { 436 throw new UnsupportedOperationException("Not supported yet."); 437 } 438 439 @Override getRangeUnit()440 public TemporalUnit getRangeUnit() { 441 throw new UnsupportedOperationException("Not supported yet."); 442 } 443 444 @Override range()445 public ValueRange range() { 446 throw new UnsupportedOperationException("Not supported yet."); 447 } 448 449 @Override isDateBased()450 public boolean isDateBased() { 451 return false; 452 } 453 454 @Override isTimeBased()455 public boolean isTimeBased() { 456 return false; 457 } 458 459 @Override isSupportedBy(TemporalAccessor temporal)460 public boolean isSupportedBy(TemporalAccessor temporal) { 461 throw new UnsupportedOperationException("Not supported yet."); 462 } 463 464 @Override rangeRefinedBy(TemporalAccessor temporal)465 public ValueRange rangeRefinedBy(TemporalAccessor temporal) { 466 throw new UnsupportedOperationException("Not supported yet."); 467 } 468 469 @Override getFrom(TemporalAccessor temporal)470 public long getFrom(TemporalAccessor temporal) { 471 throw new UnsupportedOperationException("Not supported yet."); 472 } 473 474 @SuppressWarnings("unchecked") 475 @Override adjustInto(R temporal, long newValue)476 public <R extends Temporal> R adjustInto(R temporal, long newValue) { 477 return (R) this.temporal; 478 } 479 480 @Override toString()481 public String toString() { 482 return "FixedTemporalField"; 483 } 484 } 485 } 486