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.Queries;
  74 import java.time.temporal.TemporalAccessor;
  75 import java.time.temporal.TemporalField;
  76 
  77 import org.testng.annotations.DataProvider;
  78 import org.testng.annotations.Test;
  79 
  80 /**
  81  * Test NumberPrinterParser.
  82  */
  83 @Test(groups={"implementation"})
  84 public class TestNumberParser extends AbstractTestPrinterParser {
  85 
  86     //-----------------------------------------------------------------------
  87     @DataProvider(name="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")
  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")
 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")
 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).withSymbols(symbols);
 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(Queries.chronology()), null);
 182             assertEquals(parsed.query(Queries.zoneId()), null);
 183         }
 184     }
 185 
 186     @Test(dataProvider="parseData")
 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).withSymbols(symbols);
 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(Queries.chronology()), null);
 202             assertEquals(parsed.query(Queries.zoneId()), null);
 203         }
 204     }
 205 
 206     //-----------------------------------------------------------------------
 207     @DataProvider(name="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")
 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(Queries.chronology()), null);
 317             assertEquals(parsed.query(Queries.zoneId()), null);
 318         }
 319     }
 320 
 321     //-----------------------------------------------------------------------
 322     @DataProvider(name="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, 2, 50},
 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, 3, -50},
 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, 3, 50},
 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, 2, 50},
 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, 3, -50},
 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, 3, 50},
 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, 2, 50},
 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, 3, -50},
 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, 3, 50},
 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, 2, 50},
 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, 3, -50},
 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, 3, 50},
 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, 2, 50},
 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, 3, -50},
 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, 3, 50},
 412             {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
 413        };
 414     }
 415 
 416     @Test(dataProvider="parseSignsLenient")
 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(Queries.chronology()), null);
 427             assertEquals(parsed.query(Queries.zoneId()), null);
 428         }
 429     }
 430 
 431     //-----------------------------------------------------------------------
 432     @DataProvider(name="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, 3, 543},
 445                 {"5432", 2, 3, SignStyle.NEVER, 3, 543},
 446                 {"5432", 3, 3, SignStyle.NEVER, 3, 543},
 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, 3, 543},
 459                 {"5432", 2, 3, SignStyle.NOT_NEGATIVE, 3, 543},
 460                 {"5432", 3, 3, SignStyle.NOT_NEGATIVE, 3, 543},
 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, 3, 543},
 473                 {"5432", 2, 3, SignStyle.NORMAL, 3, 543},
 474                 {"5432", 3, 3, SignStyle.NORMAL, 3, 543},
 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, 3, 543},
 487                 {"5432", 2, 3, SignStyle.ALWAYS, 3, 543},
 488                 {"5432", 3, 3, SignStyle.ALWAYS, 3, 543},
 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, 3, 543},
 501                 {"5432", 2, 3, SignStyle.EXCEEDS_PAD, 3, 543},
 502                 {"5432", 3, 3, SignStyle.EXCEEDS_PAD, 3, 543},
 503                 {"5AAA", 2, 3, SignStyle.EXCEEDS_PAD, 1, 5},
 504         };
 505     }
 506 
 507     @Test(dataProvider="parseDigitsLenient")
 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(Queries.chronology()), null);
 518             assertEquals(parsed.query(Queries.zoneId()), null);
 519         }
 520     }
 521 
 522     //-----------------------------------------------------------------------
 523     @DataProvider(name="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", 4, 54, 32},
 537                 {"54321A", 4, 54, 32},
 538         };
 539     }
 540 
 541     @Test(dataProvider="parseDigitsAdjacentLenient")
 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).withSymbols(symbols);
 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(Queries.chronology()), null);
 556             assertEquals(parsed.query(Queries.zoneId()), null);
 557         }
 558     }
 559 
 560 }