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) 2010-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 */ 60 package test.java.time.format; 61 62 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 63 import static java.time.temporal.ChronoField.DAY_OF_YEAR; 64 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 65 import static java.time.temporal.ChronoField.YEAR; 66 import static java.time.temporal.ChronoField.YEAR_OF_ERA; 67 import static java.time.temporal.ChronoUnit.YEARS; 68 import static org.testng.Assert.assertEquals; 69 import static org.testng.Assert.assertTrue; 70 import static org.testng.Assert.assertNotNull; 71 72 import java.text.ParsePosition; 73 import java.time.LocalDate; 74 import java.time.chrono.Chronology; 75 import java.time.chrono.ChronoLocalDate; 76 import java.time.chrono.HijrahChronology; 77 import java.time.chrono.IsoChronology; 78 import java.time.chrono.JapaneseChronology; 79 import java.time.chrono.MinguoChronology; 80 import java.time.chrono.ThaiBuddhistChronology; 81 import java.time.chrono.ThaiBuddhistDate; 82 import java.time.format.DateTimeFormatter; 83 import java.time.format.DateTimeFormatterBuilder; 84 import java.time.temporal.TemporalAccessor; 85 import java.time.temporal.TemporalField; 86 import java.time.temporal.TemporalQueries; 87 88 import org.testng.annotations.DataProvider; 89 import org.testng.annotations.Test; 90 91 /** 92 * Test ReducedPrinterParser. 93 */ 94 @Test 95 public class TestReducedParser extends AbstractTestPrinterParser { 96 private static final boolean STRICT = true; 97 private static final boolean LENIENT = false; 98 getFormatter0(TemporalField field, int width, int baseValue)99 private DateTimeFormatter getFormatter0(TemporalField field, int width, int baseValue) { 100 return builder.appendValueReduced(field, width, width, baseValue).toFormatter(locale).withDecimalStyle(decimalStyle); 101 } 102 getFormatter0(TemporalField field, int minWidth, int maxWidth, int baseValue)103 private DateTimeFormatter getFormatter0(TemporalField field, int minWidth, int maxWidth, int baseValue) { 104 return builder.appendValueReduced(field, minWidth, maxWidth, baseValue).toFormatter(locale).withDecimalStyle(decimalStyle); 105 } 106 getFormatterBaseDate(TemporalField field, int minWidth, int maxWidth, int baseValue)107 private DateTimeFormatter getFormatterBaseDate(TemporalField field, int minWidth, int maxWidth, int baseValue) { 108 return builder.appendValueReduced(field, minWidth, maxWidth, LocalDate.of(baseValue, 1, 1)).toFormatter(locale).withDecimalStyle(decimalStyle); 109 } 110 111 //----------------------------------------------------------------------- 112 @DataProvider(name="error") data_error()113 Object[][] data_error() { 114 return new Object[][] { 115 {YEAR, 2, 2010, "12", -1, IndexOutOfBoundsException.class}, 116 {YEAR, 2, 2010, "12", 3, IndexOutOfBoundsException.class}, 117 }; 118 } 119 120 @Test(dataProvider="error") test_parse_error(TemporalField field, int width, int baseValue, String text, int pos, Class<?> expected)121 public void test_parse_error(TemporalField field, int width, int baseValue, String text, int pos, Class<?> expected) { 122 try { 123 getFormatter0(field, width, baseValue).parseUnresolved(text, new ParsePosition(pos)); 124 } catch (RuntimeException ex) { 125 assertTrue(expected.isInstance(ex)); 126 } 127 } 128 129 //----------------------------------------------------------------------- test_parse_fieldRangeIgnored()130 public void test_parse_fieldRangeIgnored() throws Exception { 131 ParsePosition pos = new ParsePosition(0); 132 TemporalAccessor parsed = getFormatter0(DAY_OF_YEAR, 3, 10).parseUnresolved("456", pos); 133 assertEquals(pos.getIndex(), 3); 134 assertParsed(parsed, DAY_OF_YEAR, 456L); // parsed dayOfYear=456 135 } 136 137 //----------------------------------------------------------------------- 138 // Parse data and values that are consistent whether strict or lenient 139 // The data is the ChronoField, width, baseValue, text, startPos, endPos, value 140 //----------------------------------------------------------------------- 141 @DataProvider(name="ParseAll") provider_parseAll()142 Object[][] provider_parseAll() { 143 return new Object[][] { 144 // negative zero 145 {YEAR, 1, 2010, "-0", 0, 0, null}, 146 147 // general 148 {YEAR, 2, 2010, "Xxx12Xxx", 3, 5, 2012}, 149 {YEAR, 2, 2010, "12-45", 0, 2, 2012}, 150 151 // other junk 152 {YEAR, 2, 2010, "A0", 0, 0, null}, 153 {YEAR, 2, 2010, " 1", 0, 0, null}, 154 {YEAR, 2, 2010, "-1", 0, 0, null}, 155 {YEAR, 2, 2010, "-10", 0, 0, null}, 156 {YEAR, 2, 2000, " 1", 0, 0, null}, 157 158 // parse OK 1 159 {YEAR, 1, 2010, "1", 0, 1, 2011}, 160 {YEAR, 1, 2010, "3", 1, 1, null}, 161 {YEAR, 1, 2010, "9", 0, 1, 2019}, 162 163 {YEAR, 1, 2005, "0", 0, 1, 2010}, 164 {YEAR, 1, 2005, "4", 0, 1, 2014}, 165 {YEAR, 1, 2005, "5", 0, 1, 2005}, 166 {YEAR, 1, 2005, "9", 0, 1, 2009}, 167 {YEAR, 1, 2010, "1-2", 0, 1, 2011}, 168 169 // parse OK 2 170 {YEAR, 2, 2010, "00", 0, 2, 2100}, 171 {YEAR, 2, 2010, "09", 0, 2, 2109}, 172 {YEAR, 2, 2010, "10", 0, 2, 2010}, 173 {YEAR, 2, 2010, "99", 0, 2, 2099}, 174 175 // parse OK 2 176 {YEAR, 2, -2005, "05", 0, 2, -2005}, 177 {YEAR, 2, -2005, "00", 0, 2, -2000}, 178 {YEAR, 2, -2005, "99", 0, 2, -1999}, 179 {YEAR, 2, -2005, "06", 0, 2, -1906}, 180 181 {YEAR, 2, -2005, "43", 0, 2, -1943}, 182 }; 183 } 184 185 @Test(dataProvider="ParseAll") test_parseAllStrict(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal)186 public void test_parseAllStrict(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal) { 187 ParsePosition ppos = new ParsePosition(pos); 188 setStrict(true); 189 TemporalAccessor parsed = getFormatter0(field, width, baseValue).parseUnresolved(input, ppos); 190 if (ppos.getErrorIndex() != -1) { 191 assertEquals(ppos.getErrorIndex(), parseLen, "error case parse position"); 192 assertEquals(parsed, parseVal, "unexpected parse result"); 193 } else { 194 assertEquals(ppos.getIndex(), parseLen, "parse position"); 195 assertParsed(parsed, YEAR, parseVal != null ? (long) parseVal : null); 196 } 197 } 198 199 @Test(dataProvider="ParseAll") test_parseAllLenient(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal)200 public void test_parseAllLenient(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal) { 201 ParsePosition ppos = new ParsePosition(pos); 202 setStrict(false); 203 TemporalAccessor parsed = getFormatter0(field, width, baseValue).parseUnresolved(input, ppos); 204 if (ppos.getErrorIndex() != -1) { 205 assertEquals(ppos.getErrorIndex(), parseLen, "error case parse position"); 206 assertEquals(parsed, parseVal, "unexpected parse result"); 207 } else { 208 assertEquals(ppos.getIndex(), parseLen, "parse position"); 209 assertParsed(parsed, YEAR, parseVal != null ? (long) parseVal : null); 210 } 211 } 212 213 //----------------------------------------------------------------------- 214 // Parse data and values in strict and lenient modes. 215 // The data is the ChronoField, minWidth, maxWidth, baseValue, text, startPos, 216 // Strict Pair(endPos, value), Lenient Pair(endPos, value) 217 //----------------------------------------------------------------------- 218 @DataProvider(name="ParseLenientSensitive") provider_parseLenientSensitive()219 Object[][] provider_parseLenientSensitive() { 220 return new Object[][] { 221 // few digits supplied 222 {YEAR, 2, 2, 2010, "3", 0, strict(0, null), lenient(1, 3)}, 223 {YEAR, 2, 2, 2010, "4", 0, strict(0, null), lenient(1, 4)}, 224 {YEAR, 2, 2, 2010, "5", 1, strict(1, null), lenient(1, null)}, 225 {YEAR, 2, 2, 2010, "6-2", 0, strict(0, null), lenient(1, 6)}, 226 {YEAR, 2, 2, 2010, "9", 0, strict(0, null), lenient(1, 9)}, 227 228 // other junk 229 {YEAR, 1, 4, 2000, "7A", 0, strict(1, 2007), lenient(1, 2007)}, 230 {YEAR, 2, 2, 2010, "8A", 0, strict(0, null), lenient(1, 8)}, 231 232 // Negative sign cases 233 {YEAR, 2, 4, 2000, "-1", 0, strict(0, null), lenient(2, -1)}, 234 {YEAR, 2, 4, 2000, "-10", 0, strict(0, null), lenient(3, -10)}, 235 236 // Positive sign cases 237 {YEAR, 2, 4, 2000, "+1", 0, strict(0, null), lenient(2, 1)}, 238 {YEAR, 2, 4, 2000, "+10", 0, strict(0, null), lenient(3, 2010)}, 239 240 // No sign cases 241 {YEAR, 1, 1, 2005, "21", 0, strict(1, 2012), lenient(2, 21)}, 242 {YEAR, 1, 2, 2010, "12", 0, strict(2, 12), lenient(2, 12)}, 243 {YEAR, 1, 4, 2000, "87", 0, strict(2, 87), lenient(2, 87)}, 244 {YEAR, 1, 4, 2000, "9876", 0, strict(4, 9876), lenient(4, 9876)}, 245 {YEAR, 2, 2, 2010, "321", 0, strict(2, 2032), lenient(3, 321)}, 246 {YEAR, 2, 4, 2010, "2", 0, strict(0, null), lenient(1, 2)}, 247 {YEAR, 2, 4, 2010, "21", 0, strict(2, 2021), lenient(2, 2021)}, 248 {YEAR, 2, 4, 2010, "321", 0, strict(3, 321), lenient(3, 321)}, 249 {YEAR, 2, 4, 2010, "4321", 0, strict(4, 4321), lenient(4, 4321)}, 250 {YEAR, 2, 4, 2010, "54321", 0, strict(4, 5432), lenient(5, 54321)}, 251 {YEAR, 2, 8, 2010, "87654321", 3, strict(8, 54321), lenient(8, 54321)}, 252 {YEAR, 2, 9, 2010, "987654321", 0, strict(9, 987654321), lenient(9, 987654321)}, 253 {YEAR, 3, 3, 2010, "765", 0, strict(3, 2765), lenient(3, 2765)}, 254 {YEAR, 3, 4, 2010, "76", 0, strict(0, null), lenient(2, 76)}, 255 {YEAR, 3, 4, 2010, "765", 0, strict(3, 2765), lenient(3, 2765)}, 256 {YEAR, 3, 4, 2010, "7654", 0, strict(4, 7654), lenient(4, 7654)}, 257 {YEAR, 3, 4, 2010, "76543", 0, strict(4, 7654), lenient(5, 76543)}, 258 259 // Negative baseValue 260 {YEAR, 2, 4, -2005, "123", 0, strict(3, 123), lenient(3, 123)}, 261 262 // Basics 263 {YEAR, 2, 4, 2010, "10", 0, strict(2, 2010), lenient(2, 2010)}, 264 {YEAR, 2, 4, 2010, "09", 0, strict(2, 2109), lenient(2, 2109)}, 265 }; 266 } 267 268 //----------------------------------------------------------------------- 269 // Parsing tests for strict mode 270 //----------------------------------------------------------------------- 271 @Test(dataProvider="ParseLenientSensitive") test_parseStrict(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, Pair strict, Pair lenient)272 public void test_parseStrict(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, 273 Pair strict, Pair lenient) { 274 ParsePosition ppos = new ParsePosition(pos); 275 setStrict(true); 276 TemporalAccessor parsed = getFormatter0(field, minWidth, maxWidth, baseValue).parseUnresolved(input, ppos); 277 if (ppos.getErrorIndex() != -1) { 278 assertEquals(ppos.getErrorIndex(), strict.parseLen, "error case parse position"); 279 assertEquals(parsed, strict.parseVal, "unexpected parse result"); 280 } else { 281 assertEquals(ppos.getIndex(), strict.parseLen, "parse position"); 282 assertParsed(parsed, YEAR, strict.parseVal != null ? (long) strict.parseVal : null); 283 } 284 } 285 286 @Test(dataProvider="ParseLenientSensitive") test_parseStrict_baseDate(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, Pair strict, Pair lenient)287 public void test_parseStrict_baseDate(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, 288 Pair strict, Pair lenient) { 289 ParsePosition ppos = new ParsePosition(pos); 290 setStrict(true); 291 TemporalAccessor parsed = getFormatterBaseDate(field, minWidth, maxWidth, baseValue).parseUnresolved(input, ppos); 292 if (ppos.getErrorIndex() != -1) { 293 assertEquals(ppos.getErrorIndex(), strict.parseLen, "error case parse position"); 294 assertEquals(parsed, strict.parseVal, "unexpected parse result"); 295 } else { 296 assertEquals(ppos.getIndex(), strict.parseLen, "parse position"); 297 assertParsed(parsed, YEAR, strict.parseVal != null ? (long) strict.parseVal : null); 298 } 299 } 300 301 //----------------------------------------------------------------------- 302 // Parsing tests for lenient mode 303 //----------------------------------------------------------------------- 304 @Test(dataProvider="ParseLenientSensitive") test_parseLenient(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, Pair strict, Pair lenient)305 public void test_parseLenient(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, 306 Pair strict, Pair lenient) { 307 ParsePosition ppos = new ParsePosition(pos); 308 setStrict(false); 309 TemporalAccessor parsed = getFormatter0(field, minWidth, maxWidth, baseValue).parseUnresolved(input, ppos); 310 if (ppos.getErrorIndex() != -1) { 311 assertEquals(ppos.getErrorIndex(), lenient.parseLen, "error case parse position"); 312 assertEquals(parsed, lenient.parseVal, "unexpected parse result"); 313 } else { 314 assertEquals(ppos.getIndex(), lenient.parseLen, "parse position"); 315 assertParsed(parsed, YEAR, lenient.parseVal != null ? (long) lenient.parseVal : null); 316 } 317 } 318 319 @Test(dataProvider="ParseLenientSensitive") test_parseLenient_baseDate(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, Pair strict, Pair lenient)320 public void test_parseLenient_baseDate(TemporalField field, int minWidth, int maxWidth, int baseValue, String input, int pos, 321 Pair strict, Pair lenient) { 322 ParsePosition ppos = new ParsePosition(pos); 323 setStrict(false); 324 TemporalAccessor parsed = getFormatterBaseDate(field, minWidth, maxWidth, baseValue).parseUnresolved(input, ppos); 325 if (ppos.getErrorIndex() != -1) { 326 assertEquals(ppos.getErrorIndex(), lenient.parseLen, "error case parse position"); 327 assertEquals(parsed, lenient.parseVal, "unexpected parse result"); 328 } else { 329 assertEquals(ppos.getIndex(), lenient.parseLen, "parse position"); 330 assertParsed(parsed, YEAR, lenient.parseVal != null ? (long) lenient.parseVal : null); 331 } 332 } 333 assertParsed(TemporalAccessor parsed, TemporalField field, Long value)334 private void assertParsed(TemporalAccessor parsed, TemporalField field, Long value) { 335 if (value == null) { 336 assertEquals(parsed, null, "Parsed Value"); 337 } else { 338 assertEquals(parsed.isSupported(field), true, "isSupported: " + field); 339 assertEquals(parsed.getLong(field), (long) value, "Temporal.getLong: " + field); 340 } 341 } 342 343 344 //----------------------------------------------------------------------- 345 // Cases and values in adjacent parsing mode 346 //----------------------------------------------------------------------- 347 @DataProvider(name="ParseAdjacent") provider_parseAdjacent()348 Object[][] provider_parseAdjacent() { 349 return new Object[][] { 350 // general 351 {"yyMMdd", "19990703", LENIENT, 0, 8, 1999, 7, 3}, 352 {"yyMMdd", "19990703", STRICT, 0, 6, 2019, 99, 7}, 353 {"yyMMdd", "990703", LENIENT, 0, 6, 2099, 7, 3}, 354 {"yyMMdd", "990703", STRICT, 0, 6, 2099, 7, 3}, 355 {"yyMMdd", "200703", LENIENT, 0, 6, 2020, 7, 3}, 356 {"yyMMdd", "200703", STRICT, 0, 6, 2020, 7, 3}, 357 {"ddMMyy", "230714", LENIENT, 0, 6, 2014, 7, 23}, 358 {"ddMMyy", "230714", STRICT, 0, 6, 2014, 7, 23}, 359 {"ddMMyy", "25062001", LENIENT, 0, 8, 2001, 6, 25}, 360 {"ddMMyy", "25062001", STRICT, 0, 6, 2020, 6, 25}, 361 {"ddMMy", "27052002", LENIENT, 0, 8, 2002, 5, 27}, 362 {"ddMMy", "27052002", STRICT, 0, 8, 2002, 5, 27}, 363 }; 364 } 365 366 @Test(dataProvider="ParseAdjacent") test_parseAdjacent(String pattern, String input, boolean strict, int pos, int parseLen, int year, int month, int day)367 public void test_parseAdjacent(String pattern, String input, boolean strict, int pos, int parseLen, int year, int month, int day) { 368 ParsePosition ppos = new ParsePosition(0); 369 builder = new DateTimeFormatterBuilder(); 370 setStrict(strict); 371 builder.appendPattern(pattern); 372 DateTimeFormatter dtf = builder.toFormatter(); 373 374 TemporalAccessor parsed = dtf.parseUnresolved(input, ppos); 375 assertNotNull(parsed, String.format("parse failed: ppos: %s, formatter: %s%n", ppos.toString(), dtf)); 376 if (ppos.getErrorIndex() != -1) { 377 assertEquals(ppos.getErrorIndex(), parseLen, "error case parse position"); 378 } else { 379 assertEquals(ppos.getIndex(), parseLen, "parse position"); 380 assertParsed(parsed, YEAR_OF_ERA, Long.valueOf(year)); 381 assertParsed(parsed, MONTH_OF_YEAR, Long.valueOf(month)); 382 assertParsed(parsed, DAY_OF_MONTH, Long.valueOf(day)); 383 } 384 } 385 386 //----------------------------------------------------------------------- 387 // Cases and values in reduced value parsing mode 388 //----------------------------------------------------------------------- 389 @DataProvider(name="ReducedWithChrono") provider_reducedWithChrono()390 Object[][] provider_reducedWithChrono() { 391 LocalDate baseYear = LocalDate.of(2000, 1, 1); 392 return new Object[][] { 393 {IsoChronology.INSTANCE.date(baseYear)}, 394 {IsoChronology.INSTANCE.date(baseYear).plus(1, YEARS)}, 395 {IsoChronology.INSTANCE.date(baseYear).plus(99, YEARS)}, 396 {HijrahChronology.INSTANCE.date(baseYear)}, 397 {HijrahChronology.INSTANCE.date(baseYear).plus(1, YEARS)}, 398 {HijrahChronology.INSTANCE.date(baseYear).plus(99, YEARS)}, 399 {JapaneseChronology.INSTANCE.date(baseYear)}, 400 {JapaneseChronology.INSTANCE.date(baseYear).plus(1, YEARS)}, 401 {JapaneseChronology.INSTANCE.date(baseYear).plus(99, YEARS)}, 402 {MinguoChronology.INSTANCE.date(baseYear)}, 403 {MinguoChronology.INSTANCE.date(baseYear).plus(1, YEARS)}, 404 {MinguoChronology.INSTANCE.date(baseYear).plus(99, YEARS)}, 405 {ThaiBuddhistChronology.INSTANCE.date(baseYear)}, 406 {ThaiBuddhistChronology.INSTANCE.date(baseYear).plus(1, YEARS)}, 407 {ThaiBuddhistChronology.INSTANCE.date(baseYear).plus(99, YEARS)}, 408 }; 409 } 410 411 @Test(dataProvider="ReducedWithChrono") test_reducedWithChronoYear(ChronoLocalDate date)412 public void test_reducedWithChronoYear(ChronoLocalDate date) { 413 Chronology chrono = date.getChronology(); 414 DateTimeFormatter df 415 = new DateTimeFormatterBuilder().appendValueReduced(YEAR, 2, 2, LocalDate.of(2000, 1, 1)) 416 .toFormatter() 417 .withChronology(chrono); 418 int expected = date.get(YEAR); 419 String input = df.format(date); 420 421 ParsePosition pos = new ParsePosition(0); 422 TemporalAccessor parsed = df.parseUnresolved(input, pos); 423 int actual = parsed.get(YEAR); 424 assertEquals(actual, expected, 425 String.format("Wrong date parsed, chrono: %s, input: %s", 426 chrono, input)); 427 428 } 429 @Test(dataProvider="ReducedWithChrono") test_reducedWithChronoYearOfEra(ChronoLocalDate date)430 public void test_reducedWithChronoYearOfEra(ChronoLocalDate date) { 431 Chronology chrono = date.getChronology(); 432 DateTimeFormatter df 433 = new DateTimeFormatterBuilder().appendValueReduced(YEAR_OF_ERA, 2, 2, LocalDate.of(2000, 1, 1)) 434 .toFormatter() 435 .withChronology(chrono); 436 int expected = date.get(YEAR_OF_ERA); 437 String input = df.format(date); 438 439 ParsePosition pos = new ParsePosition(0); 440 TemporalAccessor parsed = df.parseUnresolved(input, pos); 441 int actual = parsed.get(YEAR_OF_ERA); 442 assertEquals(actual, expected, 443 String.format("Wrong date parsed, chrono: %s, input: %s", 444 chrono, input)); 445 446 } 447 448 @Test test_reducedWithLateChronoChange()449 public void test_reducedWithLateChronoChange() { 450 ThaiBuddhistDate date = ThaiBuddhistDate.of(2543, 1, 1); 451 DateTimeFormatter df 452 = new DateTimeFormatterBuilder() 453 .appendValueReduced(YEAR, 2, 2, LocalDate.of(2000, 1, 1)) 454 .appendLiteral(" ") 455 .appendChronologyId() 456 .toFormatter(); 457 int expected = date.get(YEAR); 458 String input = df.format(date); 459 460 ParsePosition pos = new ParsePosition(0); 461 TemporalAccessor parsed = df.parseUnresolved(input, pos); 462 assertEquals(pos.getIndex(), input.length(), "Input not parsed completely"); 463 assertEquals(pos.getErrorIndex(), -1, "Error index should be -1 (no-error)"); 464 int actual = parsed.get(YEAR); 465 assertEquals(actual, expected, 466 String.format("Wrong date parsed, chrono: %s, input: %s", 467 parsed.query(TemporalQueries.chronology()), input)); 468 469 } 470 471 @Test test_reducedWithLateChronoChangeTwice()472 public void test_reducedWithLateChronoChangeTwice() { 473 DateTimeFormatter df 474 = new DateTimeFormatterBuilder() 475 .appendValueReduced(YEAR, 2, 2, LocalDate.of(2000, 1, 1)) 476 .appendLiteral(" ") 477 .appendChronologyId() 478 .appendLiteral(" ") 479 .appendChronologyId() 480 .toFormatter(); 481 int expected = 2044; 482 String input = "44 ThaiBuddhist ISO"; 483 ParsePosition pos = new ParsePosition(0); 484 TemporalAccessor parsed = df.parseUnresolved(input, pos); 485 assertEquals(pos.getIndex(), input.length(), "Input not parsed completely: " + pos); 486 assertEquals(pos.getErrorIndex(), -1, "Error index should be -1 (no-error)"); 487 int actual = parsed.get(YEAR); 488 assertEquals(actual, expected, 489 String.format("Wrong date parsed, chrono: %s, input: %s", 490 parsed.query(TemporalQueries.chronology()), input)); 491 492 } 493 494 //----------------------------------------------------------------------- 495 // Class to structure the test data 496 //----------------------------------------------------------------------- 497 strict(int parseLen, Integer parseVal)498 private static Pair strict(int parseLen, Integer parseVal) { 499 return new Pair(parseLen, parseVal, STRICT); 500 } lenient(int parseLen, Integer parseVal)501 private static Pair lenient(int parseLen, Integer parseVal) { 502 return new Pair(parseLen, parseVal, LENIENT); 503 } 504 505 private static class Pair { 506 public final int parseLen; 507 public final Integer parseVal; 508 private final boolean strict; Pair(int parseLen, Integer parseVal, boolean strict)509 public Pair(int parseLen, Integer parseVal, boolean strict) { 510 this.parseLen = parseLen; 511 this.parseVal = parseVal; 512 this.strict = strict; 513 } toString()514 public String toString() { 515 return (strict ? "strict" : "lenient") + "(" + parseLen + "," + parseVal + ")"; 516 } 517 } 518 519 } 520