1 /*
   2  * Copyright (c) 2012, 2016, 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.OFFSET_SECONDS;
  63 import static org.testng.Assert.assertEquals;
  64 import static org.testng.Assert.assertTrue;
  65 
  66 import java.text.ParsePosition;
  67 import java.time.ZoneOffset;
  68 import java.time.temporal.TemporalAccessor;
  69 
  70 import org.testng.annotations.DataProvider;
  71 import org.testng.annotations.Test;
  72 
  73 /**
  74  * Test ZoneOffsetPrinterParser.
  75  */
  76 @Test
  77 public class TestZoneOffsetParser extends AbstractTestPrinterParser {
  78 
  79     //-----------------------------------------------------------------------
  80     @DataProvider(name="error")
  81     Object[][] data_error() {
  82         return new Object[][] {
  83             {"+HH:MM:ss", "Z", "hello", -1, IndexOutOfBoundsException.class},
  84             {"+HH:MM:ss", "Z", "hello", 6, IndexOutOfBoundsException.class},
  85         };
  86     }
  87 
  88     @Test(dataProvider="error")
  89     public void test_parse_error(String pattern, String noOffsetText, String text, int pos, Class<?> expected) {
  90         try {
  91             getFormatter(pattern, noOffsetText).parseUnresolved(text, new ParsePosition(pos));
  92         } catch (RuntimeException ex) {
  93             assertTrue(expected.isInstance(ex));
  94         }
  95     }
  96 
  97     //-----------------------------------------------------------------------
  98     public void test_parse_exactMatch_UTC() throws Exception {
  99         ParsePosition pos = new ParsePosition(0);
 100         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("Z", pos);
 101         assertEquals(pos.getIndex(), 1);
 102         assertParsed(parsed, ZoneOffset.UTC);
 103     }
 104 
 105     public void test_parse_startStringMatch_UTC() throws Exception {
 106         ParsePosition pos = new ParsePosition(0);
 107         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("ZOTHER", pos);
 108         assertEquals(pos.getIndex(), 1);
 109         assertParsed(parsed, ZoneOffset.UTC);
 110     }
 111 
 112     public void test_parse_midStringMatch_UTC() throws Exception {
 113         ParsePosition pos = new ParsePosition(5);
 114         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("OTHERZOTHER", pos);
 115         assertEquals(pos.getIndex(), 6);
 116         assertParsed(parsed, ZoneOffset.UTC);
 117     }
 118 
 119     public void test_parse_endStringMatch_UTC() throws Exception {
 120         ParsePosition pos = new ParsePosition(5);
 121         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("OTHERZ", pos);
 122         assertEquals(pos.getIndex(), 6);
 123         assertParsed(parsed, ZoneOffset.UTC);
 124     }
 125 
 126     //-----------------------------------------------------------------------
 127     public void test_parse_exactMatch_UTC_EmptyUTC() throws Exception {
 128         ParsePosition pos = new ParsePosition(0);
 129         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("", pos);
 130         assertEquals(pos.getIndex(), 0);
 131         assertParsed(parsed, ZoneOffset.UTC);
 132     }
 133 
 134     public void test_parse_startStringMatch_UTC_EmptyUTC() throws Exception {
 135         ParsePosition pos = new ParsePosition(0);
 136         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("OTHER", pos);
 137         assertEquals(pos.getIndex(), 0);
 138         assertParsed(parsed, ZoneOffset.UTC);
 139     }
 140 
 141     public void test_parse_midStringMatch_UTC_EmptyUTC() throws Exception {
 142         ParsePosition pos = new ParsePosition(5);
 143         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("OTHEROTHER", pos);
 144         assertEquals(pos.getIndex(), 5);
 145         assertParsed(parsed, ZoneOffset.UTC);
 146     }
 147 
 148     public void test_parse_endStringMatch_UTC_EmptyUTC() throws Exception {
 149         ParsePosition pos = new ParsePosition(5);
 150         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("OTHER", pos);
 151         assertEquals(pos.getIndex(), 5);
 152         assertParsed(parsed, ZoneOffset.UTC);
 153     }
 154 
 155     //-----------------------------------------------------------------------
 156     @DataProvider(name="offsets")
 157     Object[][] provider_offsets() {
 158         return new Object[][] {
 159             {"+HH", "+00", ZoneOffset.UTC},
 160             {"+HH", "-00", ZoneOffset.UTC},
 161             {"+HH", "+01", ZoneOffset.ofHours(1)},
 162             {"+HH", "-01", ZoneOffset.ofHours(-1)},
 163 
 164             {"+HHMM", "+0000", ZoneOffset.UTC},
 165             {"+HHMM", "-0000", ZoneOffset.UTC},
 166             {"+HHMM", "+0102", ZoneOffset.ofHoursMinutes(1, 2)},
 167             {"+HHMM", "-0102", ZoneOffset.ofHoursMinutes(-1, -2)},
 168 
 169             {"+HH:MM", "+00:00", ZoneOffset.UTC},
 170             {"+HH:MM", "-00:00", ZoneOffset.UTC},
 171             {"+HH:MM", "+01:02", ZoneOffset.ofHoursMinutes(1, 2)},
 172             {"+HH:MM", "-01:02", ZoneOffset.ofHoursMinutes(-1, -2)},
 173 
 174             {"+HHMMss", "+0000", ZoneOffset.UTC},
 175             {"+HHMMss", "-0000", ZoneOffset.UTC},
 176             {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
 177             {"+HHMMss", "+0159", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)},
 178             {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
 179             {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
 180             {"+HHMMss", "+010215", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)},
 181             {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
 182             {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
 183             {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
 184 
 185             {"+HHMMss", "+000000", ZoneOffset.UTC},
 186             {"+HHMMss", "-000000", ZoneOffset.UTC},
 187             {"+HHMMss", "+010000", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
 188             {"+HHMMss", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
 189             {"+HHMMss", "+015959", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)},
 190             {"+HHMMss", "+020000", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
 191             {"+HHMMss", "+180000", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
 192             {"+HHMMss", "-010000", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
 193             {"+HHMMss", "-020000", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
 194             {"+HHMMss", "-180000", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
 195 
 196             {"+HH:MM:ss", "+00:00", ZoneOffset.UTC},
 197             {"+HH:MM:ss", "-00:00", ZoneOffset.UTC},
 198             {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
 199             {"+HH:MM:ss", "+01:02", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)},
 200             {"+HH:MM:ss", "+01:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)},
 201             {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
 202             {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
 203             {"+HH:MM:ss", "+01:02:15", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)},
 204             {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
 205             {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
 206             {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
 207 
 208             {"+HH:MM:ss", "+00:00:00", ZoneOffset.UTC},
 209             {"+HH:MM:ss", "-00:00:00", ZoneOffset.UTC},
 210             {"+HH:MM:ss", "+01:00:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
 211             {"+HH:MM:ss", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
 212             {"+HH:MM:ss", "+01:59:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)},
 213             {"+HH:MM:ss", "+02:00:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
 214             {"+HH:MM:ss", "+18:00:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
 215             {"+HH:MM:ss", "-01:00:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
 216             {"+HH:MM:ss", "-02:00:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
 217             {"+HH:MM:ss", "-18:00:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
 218 
 219             {"+HHMMSS", "+000000", ZoneOffset.UTC},
 220             {"+HHMMSS", "-000000", ZoneOffset.UTC},
 221             {"+HHMMSS", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
 222             {"+HHMMSS", "-010203", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)},
 223 
 224             {"+HH:MM:SS", "+00:00:00", ZoneOffset.UTC},
 225             {"+HH:MM:SS", "-00:00:00", ZoneOffset.UTC},
 226             {"+HH:MM:SS", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
 227             {"+HH:MM:SS", "-01:02:03", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)},
 228         };
 229     }
 230 
 231     @Test(dataProvider="offsets")
 232     public void test_parse_exactMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
 233         ParsePosition pos = new ParsePosition(0);
 234         TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved(parse, pos);
 235         assertEquals(pos.getIndex(), parse.length());
 236         assertParsed(parsed, expected);
 237     }
 238 
 239     @Test(dataProvider="offsets")
 240     public void test_parse_startStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
 241         ParsePosition pos = new ParsePosition(0);
 242         TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved(parse + ":OTHER", pos);
 243         assertEquals(pos.getIndex(), parse.length());
 244         assertParsed(parsed, expected);
 245     }
 246 
 247     @Test(dataProvider="offsets")
 248     public void test_parse_midStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
 249         ParsePosition pos = new ParsePosition(5);
 250         TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved("OTHER" + parse + ":OTHER", pos);
 251         assertEquals(pos.getIndex(), parse.length() + 5);
 252         assertParsed(parsed, expected);
 253     }
 254 
 255     @Test(dataProvider="offsets")
 256     public void test_parse_endStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
 257         ParsePosition pos = new ParsePosition(5);
 258         TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved("OTHER" + parse, pos);
 259         assertEquals(pos.getIndex(), parse.length() + 5);
 260         assertParsed(parsed, expected);
 261     }
 262 
 263     @Test(dataProvider="offsets")
 264     public void test_parse_exactMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
 265         ParsePosition pos = new ParsePosition(0);
 266         TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved(parse, pos);
 267         assertEquals(pos.getIndex(), parse.length());
 268         assertParsed(parsed, expected);
 269     }
 270 
 271     @Test(dataProvider="offsets")
 272     public void test_parse_startStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
 273         ParsePosition pos = new ParsePosition(0);
 274         TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved(parse + ":OTHER", pos);
 275         assertEquals(pos.getIndex(), parse.length());
 276         assertParsed(parsed, expected);
 277     }
 278 
 279     @Test(dataProvider="offsets")
 280     public void test_parse_midStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
 281         ParsePosition pos = new ParsePosition(5);
 282         TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved("OTHER" + parse + ":OTHER", pos);
 283         assertEquals(pos.getIndex(), parse.length() + 5);
 284         assertParsed(parsed, expected);
 285     }
 286 
 287     @Test(dataProvider="offsets")
 288     public void test_parse_endStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
 289         ParsePosition pos = new ParsePosition(5);
 290         TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved("OTHER" + parse, pos);
 291         assertEquals(pos.getIndex(), parse.length() + 5);
 292         assertParsed(parsed, expected);
 293     }
 294 
 295     //-----------------------------------------------------------------------
 296     @DataProvider(name="bigOffsets")
 297     Object[][] provider_bigOffsets() {
 298         return new Object[][] {
 299             {"+HH", "+19", 19 * 3600},
 300             {"+HH", "-19", -(19 * 3600)},
 301 
 302             {"+HHMM", "+1801", 18 * 3600 + 1 * 60},
 303             {"+HHMM", "-1801", -(18 * 3600 + 1 * 60)},
 304 
 305             {"+HH:MM", "+18:01", 18 * 3600 + 1 * 60},
 306             {"+HH:MM", "-18:01", -(18 * 3600 + 1 * 60)},
 307 
 308             {"+HHMMss", "+180103", 18 * 3600 + 1 * 60 + 3},
 309             {"+HHMMss", "-180103", -(18 * 3600 + 1 * 60 + 3)},
 310 
 311             {"+HH:MM:ss", "+18:01:03", 18 * 3600 + 1 * 60 + 3},
 312             {"+HH:MM:ss", "-18:01:03", -(18 * 3600 + 1 * 60 + 3)},
 313 
 314             {"+HHMMSS", "+180103", 18 * 3600 + 1 * 60 + 3},
 315             {"+HHMMSS", "-180103", -(18 * 3600 + 1 * 60 + 3)},
 316 
 317             {"+HH:MM:SS", "+18:01:03", 18 * 3600 + 1 * 60 + 3},
 318             {"+HH:MM:SS", "-18:01:03", -(18 * 3600 + 1 * 60 + 3)},
 319         };
 320     }
 321 
 322     @Test(dataProvider="bigOffsets")
 323     public void test_parse_bigOffsets(String pattern, String parse, long offsetSecs) throws Exception {
 324         ParsePosition pos = new ParsePosition(0);
 325         TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved(parse, pos);
 326         assertEquals(pos.getIndex(), parse.length());
 327         assertEquals(parsed.getLong(OFFSET_SECONDS), offsetSecs);
 328     }
 329 
 330     //-----------------------------------------------------------------------
 331     @DataProvider(name="badOffsets")
 332     Object[][] provider_badOffsets() {
 333         return new Object[][] {
 334             {"+HH", "+1", 0},
 335             {"+HH", "-1", 0},
 336             {"+HH", "01", 0},
 337             {"+HH", "01", 0},
 338             {"+HH", "+AA", 0},
 339 
 340             {"+HHMM", "+1", 0},
 341             {"+HHMM", "+01", 0},
 342             {"+HHMM", "+001", 0},
 343             {"+HHMM", "0102", 0},
 344             {"+HHMM", "+01:02", 0},
 345             {"+HHMM", "+AAAA", 0},
 346 
 347             {"+HH:MM", "+1", 0},
 348             {"+HH:MM", "+01", 0},
 349             {"+HH:MM", "+0:01", 0},
 350             {"+HH:MM", "+00:1", 0},
 351             {"+HH:MM", "+0:1", 0},
 352             {"+HH:MM", "+:", 0},
 353             {"+HH:MM", "01:02", 0},
 354             {"+HH:MM", "+0102", 0},
 355             {"+HH:MM", "+AA:AA", 0},
 356 
 357             {"+HHMMss", "+1", 0},
 358             {"+HHMMss", "+01", 0},
 359             {"+HHMMss", "+001", 0},
 360             {"+HHMMss", "0102", 0},
 361             {"+HHMMss", "+01:02", 0},
 362             {"+HHMMss", "+AAAA", 0},
 363 
 364             {"+HH:MM:ss", "+1", 0},
 365             {"+HH:MM:ss", "+01", 0},
 366             {"+HH:MM:ss", "+0:01", 0},
 367             {"+HH:MM:ss", "+00:1", 0},
 368             {"+HH:MM:ss", "+0:1", 0},
 369             {"+HH:MM:ss", "+:", 0},
 370             {"+HH:MM:ss", "01:02", 0},
 371             {"+HH:MM:ss", "+0102", 0},
 372             {"+HH:MM:ss", "+AA:AA", 0},
 373 
 374             {"+HHMMSS", "+1", 0},
 375             {"+HHMMSS", "+01", 0},
 376             {"+HHMMSS", "+001", 0},
 377             {"+HHMMSS", "0102", 0},
 378             {"+HHMMSS", "+01:02", 0},
 379             {"+HHMMSS", "+AAAA", 0},
 380 
 381             {"+HH:MM:SS", "+1", 0},
 382             {"+HH:MM:SS", "+01", 0},
 383             {"+HH:MM:SS", "+0:01", 0},
 384             {"+HH:MM:SS", "+00:1", 0},
 385             {"+HH:MM:SS", "+0:1", 0},
 386             {"+HH:MM:SS", "+:", 0},
 387             {"+HH:MM:SS", "01:02", 0},
 388             {"+HH:MM:SS", "+0102", 0},
 389             {"+HH:MM:SS", "+AA:AA", 0},
 390         };
 391     }
 392 
 393     @Test(dataProvider="badOffsets")
 394     public void test_parse_invalid(String pattern, String parse, int expectedPosition) throws Exception {
 395         ParsePosition pos = new ParsePosition(0);
 396         TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved(parse, pos);
 397         assertEquals(pos.getErrorIndex(), expectedPosition);
 398         assertEquals(parsed, null);
 399     }
 400 
 401     //-----------------------------------------------------------------------
 402     //-----------------------------------------------------------------------
 403     //-----------------------------------------------------------------------
 404     public void test_parse_caseSensitiveUTC_matchedCase() throws Exception {
 405         setCaseSensitive(true);
 406         ParsePosition pos = new ParsePosition(0);
 407         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("Z", pos);
 408         assertEquals(pos.getIndex(), 1);
 409         assertParsed(parsed, ZoneOffset.UTC);
 410     }
 411 
 412     public void test_parse_caseSensitiveUTC_unmatchedCase() throws Exception {
 413         setCaseSensitive(true);
 414         ParsePosition pos = new ParsePosition(0);
 415         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("z", pos);
 416         assertEquals(pos.getErrorIndex(), 0);
 417         assertEquals(parsed, null);
 418     }
 419 
 420     public void test_parse_caseInsensitiveUTC_matchedCase() throws Exception {
 421         setCaseSensitive(false);
 422         ParsePosition pos = new ParsePosition(0);
 423         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("Z", pos);
 424         assertEquals(pos.getIndex(), 1);
 425         assertParsed(parsed, ZoneOffset.UTC);
 426     }
 427 
 428     public void test_parse_caseInsensitiveUTC_unmatchedCase() throws Exception {
 429         setCaseSensitive(false);
 430         ParsePosition pos = new ParsePosition(0);
 431         TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("z", pos);
 432         assertEquals(pos.getIndex(), 1);
 433         assertParsed(parsed, ZoneOffset.UTC);
 434     }
 435 
 436     private void assertParsed(TemporalAccessor parsed, ZoneOffset expectedOffset) {
 437         if (expectedOffset == null) {
 438             assertEquals(parsed, null);
 439         } else {
 440             assertEquals(parsed.isSupported(OFFSET_SECONDS), true);
 441             assertEquals(parsed.getLong(OFFSET_SECONDS), (long) expectedOffset.getTotalSeconds());
 442         }
 443     }
 444 
 445 }