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) 2008-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_WEEK;
64 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
65 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
66 import static org.testng.Assert.assertEquals;
67 import static org.testng.Assert.assertTrue;
68 import static org.testng.Assert.fail;
69 
70 import java.text.ParsePosition;
71 import java.time.format.DateTimeFormatter;
72 import java.time.format.SignStyle;
73 import java.time.temporal.TemporalAccessor;
74 import java.time.temporal.TemporalField;
75 import java.time.temporal.TemporalQueries;
76 
77 import org.testng.annotations.DataProvider;
78 import org.testng.annotations.Test;
79 
80 /**
81  * Test NumberPrinterParser.
82  */
83 @Test
84 public class TestNumberParser extends AbstractTestPrinterParser {
85 
86     //-----------------------------------------------------------------------
87     @DataProvider(name="error")
data_error()88     Object[][] data_error() {
89         return new Object[][] {
90             {DAY_OF_MONTH, 1, 2, SignStyle.NEVER, "12", -1, IndexOutOfBoundsException.class},
91             {DAY_OF_MONTH, 1, 2, SignStyle.NEVER, "12", 3, IndexOutOfBoundsException.class},
92         };
93     }
94 
95     @Test(dataProvider="error")
test_parse_error(TemporalField field, int min, int max, SignStyle style, String text, int pos, Class<?> expected)96     public void test_parse_error(TemporalField field, int min, int max, SignStyle style, String text, int pos, Class<?> expected) {
97         try {
98             getFormatter(field, min, max, style).parseUnresolved(text, new ParsePosition(pos));
99             fail();
100         } catch (RuntimeException ex) {
101             assertTrue(expected.isInstance(ex));
102         }
103     }
104 
105     //-----------------------------------------------------------------------
106     @DataProvider(name="parseData")
provider_parseData()107     Object[][] provider_parseData() {
108         return new Object[][] {
109             // normal
110             {1, 2, SignStyle.NEVER, 0, "12", 0, 2, 12L},       // normal
111             {1, 2, SignStyle.NEVER, 0, "Xxx12Xxx", 3, 5, 12L}, // parse in middle
112             {1, 2, SignStyle.NEVER, 0, "99912999", 3, 5, 12L}, // parse in middle
113             {2, 4, SignStyle.NEVER, 0, "12345", 0, 4, 1234L},  // stops at max width
114             {2, 4, SignStyle.NEVER, 0, "12-45", 0, 2, 12L},    // stops at dash
115             {2, 4, SignStyle.NEVER, 0, "123-5", 0, 3, 123L},   // stops at dash
116             {1, 10, SignStyle.NORMAL, 0, "2147483647", 0, 10, Integer.MAX_VALUE},
117             {1, 10, SignStyle.NORMAL, 0, "-2147483648", 0, 11, Integer.MIN_VALUE},
118             {1, 10, SignStyle.NORMAL, 0, "2147483648", 0, 10, 2147483648L},
119             {1, 10, SignStyle.NORMAL, 0, "-2147483649", 0, 11, -2147483649L},
120             {1, 10, SignStyle.NORMAL, 0, "987659876598765", 0, 10, 9876598765L},
121             {1, 19, SignStyle.NORMAL, 0, "999999999999999999", 0, 18, 999999999999999999L},
122             {1, 19, SignStyle.NORMAL, 0, "-999999999999999999", 0, 19, -999999999999999999L},
123             {1, 19, SignStyle.NORMAL, 0, "1000000000000000000", 0, 19, 1000000000000000000L},
124             {1, 19, SignStyle.NORMAL, 0, "-1000000000000000000", 0, 20, -1000000000000000000L},
125             {1, 19, SignStyle.NORMAL, 0, "000000000000000000", 0, 18, 0L},
126             {1, 19, SignStyle.NORMAL, 0, "0000000000000000000", 0, 19, 0L},
127             {1, 19, SignStyle.NORMAL, 0, "9223372036854775807", 0, 19, Long.MAX_VALUE},
128             {1, 19, SignStyle.NORMAL, 0, "-9223372036854775808", 0, 20, Long.MIN_VALUE},
129             {1, 19, SignStyle.NORMAL, 0, "9223372036854775808", 0, 18, 922337203685477580L},  // last digit not parsed
130             {1, 19, SignStyle.NORMAL, 0, "-9223372036854775809", 0, 19, -922337203685477580L}, // last digit not parsed
131             // no match
132             {1, 2, SignStyle.NEVER, 1, "A1", 0, 0, 0},
133             {1, 2, SignStyle.NEVER, 1, " 1", 0, 0, 0},
134             {1, 2, SignStyle.NEVER, 1, "  1", 1, 1, 0},
135             {2, 2, SignStyle.NEVER, 1, "1", 0, 0, 0},
136             {2, 2, SignStyle.NEVER, 1, "Xxx1", 0, 0, 0},
137             {2, 2, SignStyle.NEVER, 1, "1", 1, 1, 0},
138             {2, 2, SignStyle.NEVER, 1, "Xxx1", 4, 4, 0},
139             {2, 2, SignStyle.NEVER, 1, "1-2", 0, 0, 0},
140             {1, 19, SignStyle.NORMAL, 0, "-000000000000000000", 0, 0, 0},
141             {1, 19, SignStyle.NORMAL, 0, "-0000000000000000000", 0, 0, 0},
142             // parse reserving space 1 (adjacent-parsing)
143             {1, 1, SignStyle.NEVER, 1, "12", 0, 1, 1L},
144             {1, 19, SignStyle.NEVER, 1, "12", 0, 1, 1L},
145             {1, 19, SignStyle.NEVER, 1, "12345", 0, 4, 1234L},
146             {1, 19, SignStyle.NEVER, 1, "12345678901", 0, 10, 1234567890L},
147             {1, 19, SignStyle.NEVER, 1, "123456789012345678901234567890", 0, 19, 1234567890123456789L},
148             {1, 19, SignStyle.NEVER, 1, "1", 0, 1, 1L},  // error from next field
149             {2, 2, SignStyle.NEVER, 1, "12", 0, 2, 12L},  // error from next field
150             {2, 19, SignStyle.NEVER, 1, "1", 0, 0, 0},
151             // parse reserving space 2 (adjacent-parsing)
152             {1, 1, SignStyle.NEVER, 2, "123", 0, 1, 1L},
153             {1, 19, SignStyle.NEVER, 2, "123", 0, 1, 1L},
154             {1, 19, SignStyle.NEVER, 2, "12345", 0, 3, 123L},
155             {1, 19, SignStyle.NEVER, 2, "12345678901", 0, 9, 123456789L},
156             {1, 19, SignStyle.NEVER, 2, "123456789012345678901234567890", 0, 19, 1234567890123456789L},
157             {1, 19, SignStyle.NEVER, 2, "1", 0, 1, 1L},  // error from next field
158             {1, 19, SignStyle.NEVER, 2, "12", 0, 1, 1L},  // error from next field
159             {2, 2, SignStyle.NEVER, 2, "12", 0, 2, 12L},  // error from next field
160             {2, 19, SignStyle.NEVER, 2, "1", 0, 0, 0},
161             {2, 19, SignStyle.NEVER, 2, "1AAAAABBBBBCCCCC", 0, 0, 0},
162         };
163     }
164 
165     //-----------------------------------------------------------------------
166     @Test(dataProvider="parseData")
test_parse_fresh(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue)167     public void test_parse_fresh(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue) {
168         ParsePosition ppos = new ParsePosition(pos);
169         DateTimeFormatter dtf = getFormatter(DAY_OF_MONTH, minWidth, maxWidth, signStyle);
170         if (subsequentWidth > 0) {
171             // hacky, to reserve space
172             dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withDecimalStyle(decimalStyle);
173         }
174         TemporalAccessor parsed = dtf.parseUnresolved(text, ppos);
175         if (ppos.getErrorIndex() != -1) {
176             assertEquals(ppos.getErrorIndex(), expectedPos);
177         } else {
178             assertTrue(subsequentWidth >= 0);
179             assertEquals(ppos.getIndex(), expectedPos + subsequentWidth);
180             assertEquals(parsed.getLong(DAY_OF_MONTH), expectedValue);
181             assertEquals(parsed.query(TemporalQueries.chronology()), null);
182             assertEquals(parsed.query(TemporalQueries.zoneId()), null);
183         }
184     }
185 
186     @Test(dataProvider="parseData")
test_parse_textField(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue)187     public void test_parse_textField(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue) {
188         ParsePosition ppos = new ParsePosition(pos);
189         DateTimeFormatter dtf = getFormatter(DAY_OF_WEEK, minWidth, maxWidth, signStyle);
190         if (subsequentWidth > 0) {
191             // hacky, to reserve space
192             dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withDecimalStyle(decimalStyle);
193         }
194         TemporalAccessor parsed = dtf.parseUnresolved(text, ppos);
195         if (ppos.getErrorIndex() != -1) {
196             assertEquals(ppos.getErrorIndex(), expectedPos);
197         } else {
198             assertTrue(subsequentWidth >= 0);
199             assertEquals(ppos.getIndex(), expectedPos + subsequentWidth);
200             assertEquals(parsed.getLong(DAY_OF_WEEK), expectedValue);
201             assertEquals(parsed.query(TemporalQueries.chronology()), null);
202             assertEquals(parsed.query(TemporalQueries.zoneId()), null);
203         }
204     }
205 
206     //-----------------------------------------------------------------------
207     @DataProvider(name="parseSignsStrict")
provider_parseSignsStrict()208     Object[][] provider_parseSignsStrict() {
209         return new Object[][] {
210             // basics
211             {"0", 1, 2, SignStyle.NEVER, 1, 0},
212             {"1", 1, 2, SignStyle.NEVER, 1, 1},
213             {"2", 1, 2, SignStyle.NEVER, 1, 2},
214             {"3", 1, 2, SignStyle.NEVER, 1, 3},
215             {"4", 1, 2, SignStyle.NEVER, 1, 4},
216             {"5", 1, 2, SignStyle.NEVER, 1, 5},
217             {"6", 1, 2, SignStyle.NEVER, 1, 6},
218             {"7", 1, 2, SignStyle.NEVER, 1, 7},
219             {"8", 1, 2, SignStyle.NEVER, 1, 8},
220             {"9", 1, 2, SignStyle.NEVER, 1, 9},
221             {"10", 1, 2, SignStyle.NEVER, 2, 10},
222             {"100", 1, 2, SignStyle.NEVER, 2, 10},
223             {"100", 1, 3, SignStyle.NEVER, 3, 100},
224 
225             // never
226             {"0", 1, 2, SignStyle.NEVER, 1, 0},
227             {"5", 1, 2, SignStyle.NEVER, 1, 5},
228             {"50", 1, 2, SignStyle.NEVER, 2, 50},
229             {"500", 1, 2, SignStyle.NEVER, 2, 50},
230             {"-0", 1, 2, SignStyle.NEVER, 0, null},
231             {"-5", 1, 2, SignStyle.NEVER, 0, null},
232             {"-50", 1, 2, SignStyle.NEVER, 0, null},
233             {"-500", 1, 2, SignStyle.NEVER, 0, null},
234             {"-AAA", 1, 2, SignStyle.NEVER, 0, null},
235             {"+0", 1, 2, SignStyle.NEVER, 0, null},
236             {"+5", 1, 2, SignStyle.NEVER, 0, null},
237             {"+50", 1, 2, SignStyle.NEVER, 0, null},
238             {"+500", 1, 2, SignStyle.NEVER, 0, null},
239             {"+AAA", 1, 2, SignStyle.NEVER, 0, null},
240 
241             // not negative
242             {"0", 1, 2, SignStyle.NOT_NEGATIVE, 1, 0},
243             {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5},
244             {"50", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
245             {"500", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
246             {"-0", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
247             {"-5", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
248             {"-50", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
249             {"-500", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
250             {"-AAA", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
251             {"+0", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
252             {"+5", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
253             {"+50", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
254             {"+500", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
255             {"+AAA", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
256 
257             // normal
258             {"0", 1, 2, SignStyle.NORMAL, 1, 0},
259             {"5", 1, 2, SignStyle.NORMAL, 1, 5},
260             {"50", 1, 2, SignStyle.NORMAL, 2, 50},
261             {"500", 1, 2, SignStyle.NORMAL, 2, 50},
262             {"-0", 1, 2, SignStyle.NORMAL, 0, null},
263             {"-5", 1, 2, SignStyle.NORMAL, 2, -5},
264             {"-50", 1, 2, SignStyle.NORMAL, 3, -50},
265             {"-500", 1, 2, SignStyle.NORMAL, 3, -50},
266             {"-AAA", 1, 2, SignStyle.NORMAL, 1, null},
267             {"+0", 1, 2, SignStyle.NORMAL, 0, null},
268             {"+5", 1, 2, SignStyle.NORMAL, 0, null},
269             {"+50", 1, 2, SignStyle.NORMAL, 0, null},
270             {"+500", 1, 2, SignStyle.NORMAL, 0, null},
271             {"+AAA", 1, 2, SignStyle.NORMAL, 0, null},
272 
273             // always
274             {"0", 1, 2, SignStyle.ALWAYS, 0, null},
275             {"5", 1, 2, SignStyle.ALWAYS, 0, null},
276             {"50", 1, 2, SignStyle.ALWAYS, 0, null},
277             {"500", 1, 2, SignStyle.ALWAYS, 0, null},
278             {"-0", 1, 2, SignStyle.ALWAYS, 0, null},
279             {"-5", 1, 2, SignStyle.ALWAYS, 2, -5},
280             {"-50", 1, 2, SignStyle.ALWAYS, 3, -50},
281             {"-500", 1, 2, SignStyle.ALWAYS, 3, -50},
282             {"-AAA", 1, 2, SignStyle.ALWAYS, 1, null},
283             {"+0", 1, 2, SignStyle.ALWAYS, 2, 0},
284             {"+5", 1, 2, SignStyle.ALWAYS, 2, 5},
285             {"+50", 1, 2, SignStyle.ALWAYS, 3, 50},
286             {"+500", 1, 2, SignStyle.ALWAYS, 3, 50},
287             {"+AAA", 1, 2, SignStyle.ALWAYS, 1, null},
288 
289             // exceeds pad
290             {"0", 1, 2, SignStyle.EXCEEDS_PAD, 1, 0},
291             {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5},
292             {"50", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
293             {"500", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
294             {"-0", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
295             {"-5", 1, 2, SignStyle.EXCEEDS_PAD, 2, -5},
296             {"-50", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
297             {"-500", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
298             {"-AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
299             {"+0", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
300             {"+5", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
301             {"+50", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
302             {"+500", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
303             {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
304        };
305     }
306 
307     @Test(dataProvider="parseSignsStrict")
test_parseSignsStrict(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal)308     public void test_parseSignsStrict(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception {
309         ParsePosition pos = new ParsePosition(0);
310         TemporalAccessor parsed = getFormatter(DAY_OF_MONTH, min, max, style).parseUnresolved(input, pos);
311         if (pos.getErrorIndex() != -1) {
312             assertEquals(pos.getErrorIndex(), parseLen);
313         } else {
314             assertEquals(pos.getIndex(), parseLen);
315             assertEquals(parsed.getLong(DAY_OF_MONTH), (long)parseVal);
316             assertEquals(parsed.query(TemporalQueries.chronology()), null);
317             assertEquals(parsed.query(TemporalQueries.zoneId()), null);
318         }
319     }
320 
321     //-----------------------------------------------------------------------
322     @DataProvider(name="parseSignsLenient")
provider_parseSignsLenient()323     Object[][] provider_parseSignsLenient() {
324         return new Object[][] {
325             // never
326             {"0", 1, 2, SignStyle.NEVER, 1, 0},
327             {"5", 1, 2, SignStyle.NEVER, 1, 5},
328             {"50", 1, 2, SignStyle.NEVER, 2, 50},
329             {"500", 1, 2, SignStyle.NEVER, 3, 500},
330             {"-0", 1, 2, SignStyle.NEVER, 2, 0},
331             {"-5", 1, 2, SignStyle.NEVER, 2, -5},
332             {"-50", 1, 2, SignStyle.NEVER, 3, -50},
333             {"-500", 1, 2, SignStyle.NEVER, 4, -500},
334             {"-AAA", 1, 2, SignStyle.NEVER, 1, null},
335             {"+0", 1, 2, SignStyle.NEVER, 2, 0},
336             {"+5", 1, 2, SignStyle.NEVER, 2, 5},
337             {"+50", 1, 2, SignStyle.NEVER, 3, 50},
338             {"+500", 1, 2, SignStyle.NEVER, 4, 500},
339             {"+AAA", 1, 2, SignStyle.NEVER, 1, null},
340             {"50", 2, 2, SignStyle.NEVER, 2, 50},
341             {"-50", 2, 2, SignStyle.NEVER, 0, null},
342             {"+50", 2, 2, SignStyle.NEVER, 0, null},
343 
344             // not negative
345             {"0", 1, 2, SignStyle.NOT_NEGATIVE, 1, 0},
346             {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5},
347             {"50", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
348             {"500", 1, 2, SignStyle.NOT_NEGATIVE, 3, 500},
349             {"-0", 1, 2, SignStyle.NOT_NEGATIVE, 2, 0},
350             {"-5", 1, 2, SignStyle.NOT_NEGATIVE, 2, -5},
351             {"-50", 1, 2, SignStyle.NOT_NEGATIVE, 3, -50},
352             {"-500", 1, 2, SignStyle.NOT_NEGATIVE, 4, -500},
353             {"-AAA", 1, 2, SignStyle.NOT_NEGATIVE, 1, null},
354             {"+0", 1, 2, SignStyle.NOT_NEGATIVE, 2, 0},
355             {"+5", 1, 2, SignStyle.NOT_NEGATIVE, 2, 5},
356             {"+50", 1, 2, SignStyle.NOT_NEGATIVE, 3, 50},
357             {"+500", 1, 2, SignStyle.NOT_NEGATIVE, 4, 500},
358             {"+AAA", 1, 2, SignStyle.NOT_NEGATIVE, 1, null},
359             {"50", 2, 2, SignStyle.NOT_NEGATIVE, 2, 50},
360             {"-50", 2, 2, SignStyle.NOT_NEGATIVE, 0, null},
361             {"+50", 2, 2, SignStyle.NOT_NEGATIVE, 0, null},
362 
363             // normal
364             {"0", 1, 2, SignStyle.NORMAL, 1, 0},
365             {"5", 1, 2, SignStyle.NORMAL, 1, 5},
366             {"50", 1, 2, SignStyle.NORMAL, 2, 50},
367             {"500", 1, 2, SignStyle.NORMAL, 3, 500},
368             {"-0", 1, 2, SignStyle.NORMAL, 2, 0},
369             {"-5", 1, 2, SignStyle.NORMAL, 2, -5},
370             {"-50", 1, 2, SignStyle.NORMAL, 3, -50},
371             {"-500", 1, 2, SignStyle.NORMAL, 4, -500},
372             {"-AAA", 1, 2, SignStyle.NORMAL, 1, null},
373             {"+0", 1, 2, SignStyle.NORMAL, 2, 0},
374             {"+5", 1, 2, SignStyle.NORMAL, 2, 5},
375             {"+50", 1, 2, SignStyle.NORMAL, 3, 50},
376             {"+500", 1, 2, SignStyle.NORMAL, 4, 500},
377             {"+AAA", 1, 2, SignStyle.NORMAL, 1, null},
378             {"50", 2, 2, SignStyle.NORMAL, 2, 50},
379             {"-50", 2, 2, SignStyle.NORMAL, 3, -50},
380             {"+50", 2, 2, SignStyle.NORMAL, 3, 50},
381 
382             // always
383             {"0", 1, 2, SignStyle.ALWAYS, 1, 0},
384             {"5", 1, 2, SignStyle.ALWAYS, 1, 5},
385             {"50", 1, 2, SignStyle.ALWAYS, 2, 50},
386             {"500", 1, 2, SignStyle.ALWAYS, 3, 500},
387             {"-0", 1, 2, SignStyle.ALWAYS, 2, 0},
388             {"-5", 1, 2, SignStyle.ALWAYS, 2, -5},
389             {"-50", 1, 2, SignStyle.ALWAYS, 3, -50},
390             {"-500", 1, 2, SignStyle.ALWAYS, 4, -500},
391             {"-AAA", 1, 2, SignStyle.ALWAYS, 1, null},
392             {"+0", 1, 2, SignStyle.ALWAYS, 2, 0},
393             {"+5", 1, 2, SignStyle.ALWAYS, 2, 5},
394             {"+50", 1, 2, SignStyle.ALWAYS, 3, 50},
395             {"+500", 1, 2, SignStyle.ALWAYS, 4, 500},
396             {"+AAA", 1, 2, SignStyle.ALWAYS, 1, null},
397 
398             // exceeds pad
399             {"0", 1, 2, SignStyle.EXCEEDS_PAD, 1, 0},
400             {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5},
401             {"50", 1, 2, SignStyle.EXCEEDS_PAD, 2, 50},
402             {"500", 1, 2, SignStyle.EXCEEDS_PAD, 3, 500},
403             {"-0", 1, 2, SignStyle.EXCEEDS_PAD, 2, 0},
404             {"-5", 1, 2, SignStyle.EXCEEDS_PAD, 2, -5},
405             {"-50", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
406             {"-500", 1, 2, SignStyle.EXCEEDS_PAD, 4, -500},
407             {"-AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
408             {"+0", 1, 2, SignStyle.EXCEEDS_PAD, 2, 0},
409             {"+5", 1, 2, SignStyle.EXCEEDS_PAD, 2, 5},
410             {"+50", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
411             {"+500", 1, 2, SignStyle.EXCEEDS_PAD, 4, 500},
412             {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
413        };
414     }
415 
416     @Test(dataProvider="parseSignsLenient")
test_parseSignsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal)417     public void test_parseSignsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception {
418         setStrict(false);
419         ParsePosition pos = new ParsePosition(0);
420         TemporalAccessor parsed = getFormatter(DAY_OF_MONTH, min, max, style).parseUnresolved(input, pos);
421         if (pos.getErrorIndex() != -1) {
422             assertEquals(pos.getErrorIndex(), parseLen);
423         } else {
424             assertEquals(pos.getIndex(), parseLen);
425             assertEquals(parsed.getLong(DAY_OF_MONTH), (long)parseVal);
426             assertEquals(parsed.query(TemporalQueries.chronology()), null);
427             assertEquals(parsed.query(TemporalQueries.zoneId()), null);
428         }
429     }
430 
431     //-----------------------------------------------------------------------
432     @DataProvider(name="parseDigitsLenient")
provider_parseDigitsLenient()433     Object[][] provider_parseDigitsLenient() {
434         return new Object[][] {
435                 // never
436                 {"5", 1, 2, SignStyle.NEVER, 1, 5},
437                 {"5", 2, 2, SignStyle.NEVER, 1, 5},
438                 {"54", 1, 3, SignStyle.NEVER, 2, 54},
439                 {"54", 2, 3, SignStyle.NEVER, 2, 54},
440                 {"54", 3, 3, SignStyle.NEVER, 2, 54},
441                 {"543", 1, 3, SignStyle.NEVER, 3, 543},
442                 {"543", 2, 3, SignStyle.NEVER, 3, 543},
443                 {"543", 3, 3, SignStyle.NEVER, 3, 543},
444                 {"5432", 1, 3, SignStyle.NEVER, 4, 5432},
445                 {"5432", 2, 3, SignStyle.NEVER, 4, 5432},
446                 {"5432", 3, 3, SignStyle.NEVER, 4, 5432},
447                 {"5AAA", 2, 3, SignStyle.NEVER, 1, 5},
448 
449                 // not negative
450                 {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5},
451                 {"5", 2, 2, SignStyle.NOT_NEGATIVE, 1, 5},
452                 {"54", 1, 3, SignStyle.NOT_NEGATIVE, 2, 54},
453                 {"54", 2, 3, SignStyle.NOT_NEGATIVE, 2, 54},
454                 {"54", 3, 3, SignStyle.NOT_NEGATIVE, 2, 54},
455                 {"543", 1, 3, SignStyle.NOT_NEGATIVE, 3, 543},
456                 {"543", 2, 3, SignStyle.NOT_NEGATIVE, 3, 543},
457                 {"543", 3, 3, SignStyle.NOT_NEGATIVE, 3, 543},
458                 {"5432", 1, 3, SignStyle.NOT_NEGATIVE, 4, 5432},
459                 {"5432", 2, 3, SignStyle.NOT_NEGATIVE, 4, 5432},
460                 {"5432", 3, 3, SignStyle.NOT_NEGATIVE, 4, 5432},
461                 {"5AAA", 2, 3, SignStyle.NOT_NEGATIVE, 1, 5},
462 
463                 // normal
464                 {"5", 1, 2, SignStyle.NORMAL, 1, 5},
465                 {"5", 2, 2, SignStyle.NORMAL, 1, 5},
466                 {"54", 1, 3, SignStyle.NORMAL, 2, 54},
467                 {"54", 2, 3, SignStyle.NORMAL, 2, 54},
468                 {"54", 3, 3, SignStyle.NORMAL, 2, 54},
469                 {"543", 1, 3, SignStyle.NORMAL, 3, 543},
470                 {"543", 2, 3, SignStyle.NORMAL, 3, 543},
471                 {"543", 3, 3, SignStyle.NORMAL, 3, 543},
472                 {"5432", 1, 3, SignStyle.NORMAL, 4, 5432},
473                 {"5432", 2, 3, SignStyle.NORMAL, 4, 5432},
474                 {"5432", 3, 3, SignStyle.NORMAL, 4, 5432},
475                 {"5AAA", 2, 3, SignStyle.NORMAL, 1, 5},
476 
477                 // always
478                 {"5", 1, 2, SignStyle.ALWAYS, 1, 5},
479                 {"5", 2, 2, SignStyle.ALWAYS, 1, 5},
480                 {"54", 1, 3, SignStyle.ALWAYS, 2, 54},
481                 {"54", 2, 3, SignStyle.ALWAYS, 2, 54},
482                 {"54", 3, 3, SignStyle.ALWAYS, 2, 54},
483                 {"543", 1, 3, SignStyle.ALWAYS, 3, 543},
484                 {"543", 2, 3, SignStyle.ALWAYS, 3, 543},
485                 {"543", 3, 3, SignStyle.ALWAYS, 3, 543},
486                 {"5432", 1, 3, SignStyle.ALWAYS, 4, 5432},
487                 {"5432", 2, 3, SignStyle.ALWAYS, 4, 5432},
488                 {"5432", 3, 3, SignStyle.ALWAYS, 4, 5432},
489                 {"5AAA", 2, 3, SignStyle.ALWAYS, 1, 5},
490 
491                 // exceeds pad
492                 {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5},
493                 {"5", 2, 2, SignStyle.EXCEEDS_PAD, 1, 5},
494                 {"54", 1, 3, SignStyle.EXCEEDS_PAD, 2, 54},
495                 {"54", 2, 3, SignStyle.EXCEEDS_PAD, 2, 54},
496                 {"54", 3, 3, SignStyle.EXCEEDS_PAD, 2, 54},
497                 {"543", 1, 3, SignStyle.EXCEEDS_PAD, 3, 543},
498                 {"543", 2, 3, SignStyle.EXCEEDS_PAD, 3, 543},
499                 {"543", 3, 3, SignStyle.EXCEEDS_PAD, 3, 543},
500                 {"5432", 1, 3, SignStyle.EXCEEDS_PAD, 4, 5432},
501                 {"5432", 2, 3, SignStyle.EXCEEDS_PAD, 4, 5432},
502                 {"5432", 3, 3, SignStyle.EXCEEDS_PAD, 4, 5432},
503                 {"5AAA", 2, 3, SignStyle.EXCEEDS_PAD, 1, 5},
504         };
505     }
506 
507     @Test(dataProvider="parseDigitsLenient")
test_parseDigitsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal)508     public void test_parseDigitsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception {
509         setStrict(false);
510         ParsePosition pos = new ParsePosition(0);
511         TemporalAccessor parsed = getFormatter(DAY_OF_MONTH, min, max, style).parseUnresolved(input, pos);
512         if (pos.getErrorIndex() != -1) {
513             assertEquals(pos.getErrorIndex(), parseLen);
514         } else {
515             assertEquals(pos.getIndex(), parseLen);
516             assertEquals(parsed.getLong(DAY_OF_MONTH), (long)parseVal);
517             assertEquals(parsed.query(TemporalQueries.chronology()), null);
518             assertEquals(parsed.query(TemporalQueries.zoneId()), null);
519         }
520     }
521 
522     //-----------------------------------------------------------------------
523     @DataProvider(name="parseDigitsAdjacentLenient")
provider_parseDigitsAdjacentLenient()524     Object[][] provider_parseDigitsAdjacentLenient() {
525         return new Object[][] {
526                 // never
527                 {"5", 1, null, null},
528                 {"54", 1, null, null},
529 
530                 {"543", 3, 5, 43},
531                 {"543A", 3, 5, 43},
532 
533                 {"5432", 4, 54, 32},
534                 {"5432A", 4, 54, 32},
535 
536                 {"54321", 5, 543, 21},
537                 {"54321A", 5, 543, 21},
538         };
539     }
540 
541     @Test(dataProvider="parseDigitsAdjacentLenient")
test_parseDigitsAdjacentLenient(String input, int parseLen, Integer parseMonth, Integer parsedDay)542     public void test_parseDigitsAdjacentLenient(String input, int parseLen, Integer parseMonth, Integer parsedDay) throws Exception {
543         setStrict(false);
544         ParsePosition pos = new ParsePosition(0);
545         DateTimeFormatter f = builder
546                 .appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL)
547                 .appendValue(DAY_OF_MONTH, 2).toFormatter(locale).withDecimalStyle(decimalStyle);
548         TemporalAccessor parsed = f.parseUnresolved(input, pos);
549         if (pos.getErrorIndex() != -1) {
550             assertEquals(pos.getErrorIndex(), parseLen);
551         } else {
552             assertEquals(pos.getIndex(), parseLen);
553             assertEquals(parsed.getLong(MONTH_OF_YEAR), (long) parseMonth);
554             assertEquals(parsed.getLong(DAY_OF_MONTH), (long) parsedDay);
555             assertEquals(parsed.query(TemporalQueries.chronology()), null);
556             assertEquals(parsed.query(TemporalQueries.zoneId()), null);
557         }
558     }
559 
560 }
561