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) 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 java.time.temporal.ChronoField.YEAR_OF_ERA;
63 import static org.testng.Assert.assertEquals;
64 
65 import java.text.ParsePosition;
66 import java.time.LocalDate;
67 import java.time.format.DateTimeFormatter;
68 import java.time.format.DateTimeFormatterBuilder;
69 import java.time.format.DateTimeParseException;
70 import java.time.temporal.TemporalAccessor;
71 import java.time.temporal.TemporalField;
72 import java.time.temporal.WeekFields;
73 import java.util.Locale;
74 
75 import org.testng.annotations.DataProvider;
76 import org.testng.annotations.Test;
77 import test.java.time.format.AbstractTestPrinterParser;
78 
79 /**
80  * Test TCKLocalizedFieldParser.
81  */
82 @Test
83 public class TCKLocalizedFieldParser extends AbstractTestPrinterParser {
84     public static final WeekFields WEEKDEF = WeekFields.of(Locale.US);
85     public static final TemporalField WEEK_BASED_YEAR = WEEKDEF.weekBasedYear();
86     public static final TemporalField WEEK_OF_WEEK_BASED_YEAR = WEEKDEF.weekOfWeekBasedYear();
87     public static final TemporalField DAY_OF_WEEK = WEEKDEF.dayOfWeek();
88     //-----------------------------------------------------------------------
89     @DataProvider(name="FieldPatterns")
provider_fieldPatterns()90     Object[][] provider_fieldPatterns() {
91         return new Object[][] {
92             {"e", "6", 0, 1, 6},
93             {"ee", "06", 0, 2, 6},
94             {"c",  "6", 0, 1 , 6},
95             {"W",  "3", 0, 1, 3},
96             {"w",  "29", 0, 2, 29},
97             {"ww", "29", 0, 2, 29},
98             {"Y", "2013", 0, 4, 2013},
99             {"YY", "13", 0, 2, 2013},
100             {"YYYY", "2013", 0, 4, 2013},
101         };
102     }
103 
104     @Test(dataProvider="FieldPatterns")
test_parse_textField(String pattern, String text, int pos, int expectedPos, long expectedValue)105     public void test_parse_textField(String pattern, String text, int pos, int expectedPos, long expectedValue) {
106         WeekFields weekDef = WeekFields.of(locale);
107         TemporalField field = null;
108         switch(pattern.charAt(0)) {
109             case 'c' :
110             case 'e' :
111                 field = weekDef.dayOfWeek();
112                 break;
113             case 'w':
114                 field = weekDef.weekOfWeekBasedYear();
115                 break;
116             case 'W':
117                 field = weekDef.weekOfMonth();
118                 break;
119             case 'Y':
120                 field = weekDef.weekBasedYear();
121                 break;
122             default:
123                 throw new IllegalStateException("bad format letter from pattern");
124         }
125         ParsePosition ppos = new ParsePosition(pos);
126         DateTimeFormatterBuilder b
127                 = new DateTimeFormatterBuilder().appendPattern(pattern);
128         DateTimeFormatter dtf = b.toFormatter(locale);
129         TemporalAccessor parsed = dtf.parseUnresolved(text, ppos);
130         if (ppos.getErrorIndex() != -1) {
131             assertEquals(ppos.getErrorIndex(), expectedPos);
132         } else {
133             assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position");
134             long value = parsed.getLong(field);
135             assertEquals(value, expectedValue, "Value incorrect for " + field);
136         }
137     }
138 
139     //-----------------------------------------------------------------------
140     @DataProvider(name="LocalWeekMonthYearPatterns")
provider_patternLocalDate()141     Object[][] provider_patternLocalDate() {
142         return new Object[][] {
143             {"e W M y",  "1 1 1 2012", 0, 10, LocalDate.of(2012, 1, 1)},
144             {"e W M y",  "1 2 1 2012", 0, 10, LocalDate.of(2012, 1, 8)},
145             {"e W M y",  "2 2 1 2012", 0, 10, LocalDate.of(2012, 1, 9)},
146             {"e W M y",  "3 2 1 2012", 0, 10, LocalDate.of(2012, 1, 10)},
147             {"e W M y",  "1 3 1 2012", 0, 10, LocalDate.of(2012, 1, 15)},
148             {"e W M y",  "2 3 1 2012", 0, 10, LocalDate.of(2012, 1, 16)},
149             {"e W M y",  "6 2 1 2012", 0, 10, LocalDate.of(2012, 1, 13)},
150             {"e W M y",  "6 2 7 2012", 0, 10, LocalDate.of(2012, 7, 13)},
151             {"'Date: 'y-MM', day-of-week: 'e', week-of-month: 'W",
152                 "Date: 2012-07, day-of-week: 6, week-of-month: 3", 0, 47, LocalDate.of(2012, 7, 20)},
153         };
154     }
155 
156    @Test(dataProvider="LocalWeekMonthYearPatterns")
test_parse_textLocalDate(String pattern, String text, int pos, int expectedPos, LocalDate expectedValue)157     public void test_parse_textLocalDate(String pattern, String text, int pos, int expectedPos, LocalDate expectedValue) {
158         ParsePosition ppos = new ParsePosition(pos);
159         DateTimeFormatterBuilder b = new DateTimeFormatterBuilder().appendPattern(pattern);
160         DateTimeFormatter dtf = b.toFormatter(locale);
161         TemporalAccessor parsed = dtf.parseUnresolved(text, ppos);
162         if (ppos.getErrorIndex() != -1) {
163             assertEquals(ppos.getErrorIndex(), expectedPos);
164         } else {
165             assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position");
166             assertEquals(parsed.isSupported(YEAR_OF_ERA), true);
167             assertEquals(parsed.isSupported(WeekFields.of(locale).dayOfWeek()), true);
168             assertEquals(parsed.isSupported(WeekFields.of(locale).weekOfMonth()) ||
169                     parsed.isSupported(WeekFields.of(locale).weekOfYear()), true);
170             // ensure combination resolves into a date
171             LocalDate result = LocalDate.parse(text, dtf);
172             assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern);
173         }
174     }
175 
176     //-----------------------------------------------------------------------
177     @DataProvider(name="LocalWeekBasedYearPatterns")
provider_patternLocalWeekBasedYearDate()178     Object[][] provider_patternLocalWeekBasedYearDate() {
179         return new Object[][] {
180             //{"w Y",  "29 2012", 0, 7, LocalDate.of(2012, 7, 20)},  // Default lenient dayOfWeek not supported
181             {"e w Y",  "6 29 2012", 0, 9, LocalDate.of(2012, 7, 20)},
182             {"'Date: 'Y', day-of-week: 'e', week-of-year: 'w",
183                 "Date: 2012, day-of-week: 6, week-of-year: 29", 0, 44, LocalDate.of(2012, 7, 20)},
184             {"Y-w-e",  "2008-01-1", 0, 9, LocalDate.of(2007, 12, 30)},
185             {"Y-w-e",  "2008-52-1", 0, 9, LocalDate.of(2008, 12, 21)},
186             {"Y-w-e",  "2008-52-7", 0, 9, LocalDate.of(2008, 12, 27)},
187             {"Y-w-e",  "2009-01-1", 0, 9, LocalDate.of(2008, 12, 28)},
188             {"Y-w-e",  "2009-01-4", 0, 9, LocalDate.of(2008, 12, 31)},
189             {"Y-w-e",  "2009-01-5", 0, 9, LocalDate.of(2009, 1, 1)},
190        };
191     }
192 
193    @Test(dataProvider="LocalWeekBasedYearPatterns")
test_parse_WeekBasedYear(String pattern, String text, int pos, int expectedPos, LocalDate expectedValue)194     public void test_parse_WeekBasedYear(String pattern, String text, int pos, int expectedPos, LocalDate expectedValue) {
195         ParsePosition ppos = new ParsePosition(pos);
196         DateTimeFormatterBuilder b = new DateTimeFormatterBuilder().appendPattern(pattern);
197         DateTimeFormatter dtf = b.toFormatter(locale);
198         TemporalAccessor parsed = dtf.parseUnresolved(text, ppos);
199         if (ppos.getErrorIndex() != -1) {
200             assertEquals(ppos.getErrorIndex(), expectedPos);
201         } else {
202             WeekFields weekDef = WeekFields.of(locale);
203             assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position");
204             assertEquals(parsed.isSupported(weekDef.dayOfWeek()), pattern.indexOf('e') >= 0);
205             assertEquals(parsed.isSupported(weekDef.weekOfWeekBasedYear()), pattern.indexOf('w') >= 0);
206             assertEquals(parsed.isSupported(weekDef.weekBasedYear()), pattern.indexOf('Y') >= 0);
207             // ensure combination resolves into a date
208             LocalDate result = LocalDate.parse(text, dtf);
209             assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern + ", weekDef: " + weekDef);
210         }
211     }
212 
213     //-----------------------------------------------------------------------
214     @DataProvider(name = "adjacentValuePatterns1")
provider_adjacentValuePatterns1()215     Object[][] provider_adjacentValuePatterns1() {
216         return new Object[][] {
217                 {"YYww", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, "1612", 2016, 12},
218                 {"YYYYww", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, "201612", 2016, 12},
219         };
220     }
221 
222     @Test(dataProvider = "adjacentValuePatterns1")
test_adjacentValuePatterns1(String pattern, TemporalField field1, TemporalField field2, String text, int expected1, int expected2)223     public void test_adjacentValuePatterns1(String pattern, TemporalField field1, TemporalField field2,
224             String text, int expected1, int expected2) {
225         DateTimeFormatter df = new DateTimeFormatterBuilder()
226                 .appendPattern(pattern).toFormatter(Locale.US);
227         ParsePosition ppos = new ParsePosition(0);
228         TemporalAccessor parsed = df.parseUnresolved(text, ppos);
229         assertEquals(parsed.get(field1), expected1);
230         assertEquals(parsed.get(field2), expected2);
231     }
232 
233     @DataProvider(name = "adjacentValuePatterns2")
provider_adjacentValuePatterns2()234     Object[][] provider_adjacentValuePatterns2() {
235         return new Object[][] {
236                 {"YYYYwwc", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK,
237                         "2016121", 2016, 12, 1},
238                 {"YYYYwwee", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK,
239                         "20161201", 2016, 12, 1},
240                 {"YYYYwwe", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK,
241                         "2016121", 2016, 12, 1},
242         };
243     }
244 
245     @Test(dataProvider = "adjacentValuePatterns2")
test_adjacentValuePatterns2(String pattern, TemporalField field1, TemporalField field2, TemporalField field3, String text, int expected1, int expected2, int expected3)246     public void test_adjacentValuePatterns2(String pattern, TemporalField field1, TemporalField field2,
247             TemporalField field3, String text, int expected1, int expected2, int expected3) {
248         DateTimeFormatter df = new DateTimeFormatterBuilder()
249                 .appendPattern(pattern).toFormatter(Locale.US);
250         ParsePosition ppos = new ParsePosition(0);
251         TemporalAccessor parsed = df.parseUnresolved(text, ppos);
252         assertEquals(parsed.get(field1), expected1);
253         assertEquals(parsed.get(field2), expected2);
254         assertEquals(parsed.get(field3), expected3);
255     }
256 
257     @Test
test_adjacentValuePatterns3()258     public void test_adjacentValuePatterns3() {
259         String pattern = "yyyyMMddwwc";
260         String text =  "20120720296";
261         DateTimeFormatter df = new DateTimeFormatterBuilder()
262                 .appendPattern(pattern).toFormatter(Locale.US);
263         ParsePosition ppos = new ParsePosition(0);
264         TemporalAccessor parsed = df.parseUnresolved(text, ppos);
265         assertEquals(parsed.get(DAY_OF_WEEK), 6);
266         assertEquals(parsed.get(WEEK_OF_WEEK_BASED_YEAR), 29);
267         LocalDate result = LocalDate.parse(text, df);
268         LocalDate expectedValue = LocalDate.of(2012, 07, 20);
269         assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern);
270     }
271 
272     @DataProvider(name = "invalidPatterns")
provider_invalidPatterns()273     Object[][] provider_invalidPatterns() {
274         return new Object[][] {
275             {"W", "01"},
276             {"c", "01"},
277             {"e", "01"},
278             {"yyyyMMddwwc", "201207202906"}, //  1 extra digit in the input
279         };
280     }
281 
282     @Test(dataProvider = "invalidPatterns", expectedExceptions = DateTimeParseException.class)
test_invalidPatterns(String pattern, String value)283     public void test_invalidPatterns(String pattern, String value) {
284         DateTimeFormatter.ofPattern(pattern).parse(value);
285     }
286 }
287