• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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