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