• 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 tck.java.time.format;
61 
62 import static org.testng.Assert.assertEquals;
63 import static org.testng.Assert.assertNotNull;
64 
65 import java.text.ParsePosition;
66 import java.time.DateTimeException;
67 import java.time.LocalDateTime;
68 import java.time.ZoneId;
69 import java.time.ZoneOffset;
70 import java.time.ZonedDateTime;
71 import java.time.format.DateTimeFormatter;
72 import java.time.format.DateTimeFormatterBuilder;
73 import java.time.temporal.TemporalAccessor;
74 import java.time.temporal.TemporalQueries;
75 import java.util.Locale;
76 import java.util.Objects;
77 
78 import org.testng.annotations.BeforeMethod;
79 import org.testng.annotations.DataProvider;
80 import org.testng.annotations.Test;
81 
82 /**
83  * Test DateTimeFormatterBuilder.appendZoneId().
84  */
85 @Test
86 public class TCKZoneIdPrinterParser {
87 
88     private static final ZoneOffset OFFSET_UTC = ZoneOffset.UTC;
89     private static final ZoneOffset OFFSET_P0123 = ZoneOffset.ofHoursMinutes(1, 23);
90     private static final ZoneId EUROPE_PARIS = ZoneId.of("Europe/Paris");
91     private static final ZoneId AMERICA_NEW_YORK = ZoneId.of("America/New_York");
92     private static final LocalDateTime DT_2012_06_30_12_30_40 = LocalDateTime.of(2012, 6, 30, 12, 30, 40);
93 
94     private DateTimeFormatterBuilder builder;
95     private ParsePosition pos;
96 
97     @BeforeMethod
setUp()98     public void setUp() {
99         builder = new DateTimeFormatterBuilder();
100         pos = new ParsePosition(0);
101     }
102 
103     //-----------------------------------------------------------------------
104     @DataProvider(name="print")
data_print()105     Object[][] data_print() {
106         return new Object[][] {
107                 {DT_2012_06_30_12_30_40, EUROPE_PARIS, "Europe/Paris"},
108                 {DT_2012_06_30_12_30_40, AMERICA_NEW_YORK, "America/New_York"},
109                 {DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
110                 {DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"},
111         };
112     }
113 
114     @Test(dataProvider="print")
test_print(LocalDateTime ldt, ZoneId zone, String expected)115     public void test_print(LocalDateTime ldt, ZoneId zone, String expected) {
116         ZonedDateTime zdt = ldt.atZone(zone);
117         builder.appendZoneId();
118         String output = builder.toFormatter().format(zdt);
119         assertEquals(output, expected);
120     }
121 
122     @Test(dataProvider="print")
test_print_pattern_VV(LocalDateTime ldt, ZoneId zone, String expected)123     public void test_print_pattern_VV(LocalDateTime ldt, ZoneId zone, String expected) {
124         ZonedDateTime zdt = ldt.atZone(zone);
125         builder.appendPattern("VV");
126         String output = builder.toFormatter().format(zdt);
127         assertEquals(output, expected);
128     }
129 
130     //-----------------------------------------------------------------------
131     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_V1rejected()132     public void test_print_pattern_V1rejected() {
133         builder.appendPattern("V");
134     }
135 
136     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_V3rejected()137     public void test_print_pattern_V3rejected() {
138         builder.appendPattern("VVV");
139     }
140 
141     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_V4rejected()142     public void test_print_pattern_V4rejected() {
143         builder.appendPattern("VVVV");
144     }
145 
146     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_V5rejected()147     public void test_print_pattern_V5rejected() {
148         builder.appendPattern("VVVVV");
149     }
150 
151     //-----------------------------------------------------------------------
152     @DataProvider(name="parseSuccess")
data_parseSuccess()153     Object[][] data_parseSuccess() {
154         return new Object[][] {
155                 {"Z", 1, -1, ZoneId.of("Z"), true},
156                 {"UTC", 3, -1, ZoneId.of("UTC"), false},
157                 {"UT", 2, -1, ZoneId.of("UT"), false},
158                 {"GMT", 3, -1, ZoneId.of("GMT"), false},
159                 {"GMT0", 4, -1, ZoneId.of("GMT0"), false},
160 
161                 {"+00:00", 6, -1, ZoneOffset.UTC, true},
162                 {"UTC+00:00", 9, -1, ZoneId.of("UTC"), false},
163                 {"UT+00:00", 8, -1, ZoneId.of("UT"), false},
164                 {"GMT+00:00", 9, -1, ZoneId.of("GMT"), false},
165                 {"-00:00", 6, -1, ZoneOffset.UTC, true},
166                 {"UTC-00:00", 9, -1, ZoneId.of("UTC"), false},
167                 {"UT-00:00", 8, -1, ZoneId.of("UT"), false},
168                 {"GMT-00:00", 9, -1, ZoneId.of("GMT"), false},
169 
170                 {"+01:30", 6, -1, ZoneOffset.ofHoursMinutes(1, 30), true},
171                 {"UTC+01:30", 9, -1, ZoneId.of("UTC+01:30"), false},
172                 {"UT+02:30", 8, -1, ZoneId.of("UT+02:30"), false},
173                 {"GMT+03:30", 9, -1, ZoneId.of("GMT+03:30"), false},
174                 {"-01:30", 6, -1, ZoneOffset.ofHoursMinutes(-1, -30), true},
175                 {"UTC-01:30", 9, -1, ZoneId.of("UTC-01:30"), false},
176                 {"UT-02:30", 8, -1, ZoneId.of("UT-02:30"), false},
177                 {"GMT-03:30", 9, -1, ZoneId.of("GMT-03:30"), false},
178 
179                 // fallback to UTC
180                 {"UTC-01:WW", 3, -1, ZoneId.of("UTC"), false},
181                 {"UT-02:WW", 2, -1, ZoneId.of("UT"), false},
182                 {"GMT-03:WW", 3, -1, ZoneId.of("GMT"), false},
183                 {"Z0", 1, -1, ZoneOffset.UTC, true},
184                 {"UTC1", 3, -1, ZoneId.of("UTC"), false},
185 
186                 // Z not parsed as zero
187                 {"UTCZ", 3, -1, ZoneId.of("UTC"), false},
188                 {"UTZ", 2, -1, ZoneId.of("UT"), false},
189                 {"GMTZ", 3, -1, ZoneId.of("GMT"), false},
190 
191                 // 0 not parsed
192                 {"UTC0", 3, -1, ZoneId.of("UTC"), false},
193                 {"UT0", 2, -1, ZoneId.of("UT"), false},
194 
195                 // fail to parse
196                 {"", 0, 0, null, false},
197                 {"A", 0, 0, null, false},
198                 {"UZ", 0, 0, null, false},
199                 {"GMA", 0, 0, null, false},
200                 {"0", 0, 0, null, false},
201                 {"+", 0, 0, null, false},
202                 {"-", 0, 0, null, false},
203 
204                 // zone IDs
205                 {"Europe/London", 13, -1, ZoneId.of("Europe/London"), false},
206                 {"America/New_York", 16, -1, ZoneId.of("America/New_York"), false},
207                 {"America/Bogusville", 0, 0, null, false},
208         };
209     }
210 
211     @Test(dataProvider="parseSuccess")
test_ZoneId_parseSuccess_plain( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)212     public void test_ZoneId_parseSuccess_plain(
213         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
214     {
215         builder.appendZoneId();
216         test(text, expectedIndex, expectedErrorIndex, expected, isZoneOffset);
217     }
218 
219     @Test(dataProvider="parseSuccess")
test_ZoneId_parseSuccess_prefix( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)220     public void test_ZoneId_parseSuccess_prefix(
221         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
222     {
223         builder.appendZoneId();
224         pos.setIndex(3);
225         test("XXX" + text,
226              expectedIndex + 3,
227              expectedErrorIndex >= 0 ? expectedErrorIndex + 3 : expectedErrorIndex,
228              expected, isZoneOffset);
229     }
230 
231     @Test(dataProvider="parseSuccess")
test_ZoneId_parseSuccess_suffix( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)232     public void test_ZoneId_parseSuccess_suffix(
233         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
234     {
235         builder.appendZoneId();
236         test(text + "XXX", expectedIndex, expectedErrorIndex, expected, isZoneOffset);
237     }
238 
239     @Test(dataProvider="parseSuccess")
test_ZoneId_parseSuccess_caseSensitive( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)240     public void test_ZoneId_parseSuccess_caseSensitive(
241         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
242     {
243         builder.parseCaseSensitive().appendZoneId();
244 
245         if (text.matches("[^A-Z]*[A-Z].*")) {  // if input has letters
246             String lcText = text.toLowerCase(Locale.ENGLISH);
247             TemporalAccessor parsed = builder.toFormatter().parseUnresolved(lcText, pos);
248             assertEquals(pos.getErrorIndex() >= 0, true);
249             assertEquals(pos.getIndex(), 0);
250             assertEquals(parsed, null);
251         } else {
252             test(text.toLowerCase(Locale.ENGLISH), expectedIndex, expectedErrorIndex, expected, isZoneOffset);
253         }
254     }
255 
256     @Test(dataProvider="parseSuccess")
test_ZoneId_parseSuccess_caseInsensitive( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)257     public void test_ZoneId_parseSuccess_caseInsensitive(
258         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
259     {
260         builder.parseCaseInsensitive().appendZoneId();
261         test(text.toLowerCase(Locale.ENGLISH), expectedIndex, expectedErrorIndex, expected, isZoneOffset);
262     }
263 
264     @Test(dataProvider="parseSuccess")
test_ZoneOrOffsetId_parseSuccess_plain( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)265     public void test_ZoneOrOffsetId_parseSuccess_plain(
266         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
267     {
268         builder.appendZoneOrOffsetId();
269         test(text, expectedIndex, expectedErrorIndex, expected, isZoneOffset);
270     }
271 
272     @Test(dataProvider="parseSuccess")
test_ZoneOrOffsetId_parseSuccess_prefix( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)273     public void test_ZoneOrOffsetId_parseSuccess_prefix(
274         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
275     {
276         builder.appendZoneOrOffsetId();
277         pos.setIndex(3);
278         test("XXX" + text,
279              expectedIndex + 3,
280              expectedErrorIndex >= 0 ? expectedErrorIndex + 3 : expectedErrorIndex,
281              expected, isZoneOffset);
282     }
283 
284     @Test(dataProvider="parseSuccess")
test_ZoneOrOffsetId_parseSuccess_suffix( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)285     public void test_ZoneOrOffsetId_parseSuccess_suffix(
286         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
287     {
288         builder.appendZoneOrOffsetId();
289         test(text + "XXX", expectedIndex, expectedErrorIndex, expected, isZoneOffset);
290     }
291 
292     @Test(dataProvider="parseSuccess")
test_ZoneOrOffsetId_parseSuccess_caseSensitive( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)293     public void test_ZoneOrOffsetId_parseSuccess_caseSensitive(
294         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
295     {
296         builder.parseCaseSensitive().appendZoneOrOffsetId();
297         if (text.matches("[^A-Z]*[A-Z].*")) {  // if input has letters
298             String lcText = text.toLowerCase(Locale.ENGLISH);
299             TemporalAccessor parsed = builder.toFormatter().parseUnresolved(lcText, pos);
300             assertEquals(pos.getErrorIndex() >= 0, true);
301             assertEquals(pos.getIndex(), 0);
302             assertEquals(parsed, null);
303         } else {
304             test(text.toLowerCase(Locale.ENGLISH), expectedIndex, expectedErrorIndex, expected, isZoneOffset);
305         }
306     }
307 
308     @Test(dataProvider="parseSuccess")
test_ZoneOrOffsetIdparseSuccess_caseInsensitive( String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)309     public void test_ZoneOrOffsetIdparseSuccess_caseInsensitive(
310         String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)
311     {
312         builder.parseCaseInsensitive().appendZoneOrOffsetId();
313         test(text.toLowerCase(Locale.ENGLISH), expectedIndex, expectedErrorIndex, expected, isZoneOffset);
314     }
315 
test(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected, boolean isZoneOffset)316     private void test(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected,
317                       boolean isZoneOffset) {
318         TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos);
319         assertEquals(pos.getErrorIndex(), expectedErrorIndex, "Incorrect error index parsing: " + text);
320         assertEquals(pos.getIndex(), expectedIndex, "Incorrect index parsing: " + text);
321         if (expected != null) {
322             assertEquals(parsed.query(TemporalQueries.zoneId()),
323                          expected,
324                          "Incorrect zoneId parsing: " + text);
325             assertEquals(parsed.query(TemporalQueries.offset()),
326                          isZoneOffset ? expected : null,
327                          "Incorrect offset parsing: " + text);
328             assertEquals(parsed.query(TemporalQueries.zone()),
329                          expected,
330                          "Incorrect zone parsing: " + text);
331         } else {
332             assertEquals(parsed, null);
333         }
334     }
335 
336 }
337