1/*
2 * Copyright (c) 2001, 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 * @test
26 * @bug 4322313 4833268 6302990 6304305
27 * @library /java/text/testlib
28 * @summary Make sure that new implementation for
29 * SimpleDateFormat.parse('z' or 'Z') and format('z' or 'Z') work correctly.
30 */
31
32import java.io.*;
33import java.text.*;
34import java.util.*;
35
36public class Bug4322313 extends IntlTest {
37
38    public void Test4322313() {
39        Locale savedLocale = Locale.getDefault();
40        TimeZone savedTimeZone = TimeZone.getDefault();
41        boolean err = false;
42        long mpm = 60 * 1000;   /* Milliseconds per a minute */
43
44        Locale[] locs = {Locale.US, Locale.JAPAN, Locale.UK, new Locale("ar")};
45
46        String[] formats = {
47            "z",
48            "Z",
49        };
50
51        Object[][] valids = {
52          /* given ID      offset                format('z'), ('Z')    index */
53            {"GMT+03:04",  -184L * mpm, "GMT+03:04", "+0304", 9},
54            {"GMT+13:42",  -822L * mpm, "GMT+13:42", "+1342", 9},
55            {"GMT+00:00",   0L,         "GMT+00:00", "+0000", 9},
56            {"GMT+1:11",   -71L * mpm,  "GMT+01:11", "+0111", 8},
57            {"GMT +13:42",  0L,         "GMT",       "+0000", 3},
58            {" GMT",        0L,         "GMT",       "+0000", 4},
59            {"+0304",      -184L * mpm, "GMT+03:04", "+0304", 5},
60            {"+1342",      -822L * mpm, "GMT+13:42", "+1342", 5},
61            {"+0000",       0L,         "GMT+00:00", "+0000", 5},
62            {" +1342",     -822L * mpm, "GMT+13:42", "+1342", 6},
63            /* ISO-LATIN-1 digits */
64            {"GMT+\u0030\u0031:\u0032\u0033", -83L * mpm, "GMT+01:23", "+0123", 9},
65
66           /* In fact, this test case is skipped because TimeZone class can't
67            * recognize TimeZone IDs like "+00234" or "-00234".
68            */
69            {"+00234",     -23L * mpm, "GMT+00:23", "+0023", 5},
70
71            {"GMT-03:04",  184L * mpm, "GMT-03:04", "-0304", 9},
72            {"GMT-13:42",  822L * mpm, "GMT-13:42", "-1342", 9},
73            {"GMT-00:00",  0L,         "GMT+00:00", "+0000", 9},
74            {"GMT-1:11",   71L * mpm,  "GMT-01:11", "-0111", 8},
75            {"GMT -13:42", 0L,         "GMT",       "+0000", 3},
76            {"-0304",      184L * mpm, "GMT-03:04", "-0304", 5},
77            {"-1342",      822L * mpm, "GMT-13:42", "-1342", 5},
78            {" -1342",     822L * mpm, "GMT-13:42", "-1342", 6},
79            /* ISO-LATIN-1 digits */
80            {"GMT-\u0030\u0031:\u0032\u0033", 83L * mpm, "GMT-01:23", "-0123", 9},
81           /* In fact, this test case is skipped because TimeZone class can't
82            * recognize TimeZone IDs like "+00234" or "-00234".
83            */
84            {"-00234",     23L * mpm,  "GMT+00:23", "-0023", 5},
85        };
86
87        Object[][] invalids = {
88          /* given ID       error index   */
89            {"GMT+8",       5},
90            {"GMT+18",      6},
91            {"GMT+208",     6},
92            {"GMT+0304",    6},
93            {"GMT+42195",   5},
94            {"GMT+5:8",     7},
95            {"GMT+23:60",   8},
96            {"GMT+11:1",    8},
97            {"GMT+24:13",   5},
98            {"GMT+421:950", 5},
99            {"GMT+0a:0A",   5},
100            {"GMT+ 13:42",  4},
101            {"GMT+13 :42",  6},
102            {"GMT+13: 42",  7},
103            {"GMT+-13:42",  4},
104            {"G M T",       0},
105            {"+8",          2},
106            {"+18",         3},
107            {"+208",        4},
108            {"+2360",       4},
109            {"+2413",       2},
110            {"+42195",      2},
111            {"+0AbC",       2},
112            {"+ 1342",      1},
113            {"+-1342",      1},
114            {"1342",        0},
115          /* Arabic-Indic digits */
116            {"GMT+\u0660\u0661:\u0662\u0663", 4},
117          /* Extended Arabic-Indic digits */
118            {"GMT+\u06f0\u06f1:\u06f2\u06f3", 4},
119          /* Devanagari digits */
120            {"GMT+\u0966\u0967:\u0968\u0969", 4},
121          /* Fullwidth digits */
122            {"GMT+\uFF10\uFF11:\uFF12\uFF13", 4},
123
124            {"GMT-8",       5},
125            {"GMT-18",      6},
126            {"GMT-208",     6},
127            {"GMT-0304",    6},
128            {"GMT-42195",   5},
129            {"GMT-5:8",     7},
130            {"GMT-23:60",   8},
131            {"GMT-11:1",    8},
132            {"GMT-24:13",   5},
133            {"GMT-421:950", 5},
134            {"GMT-0a:0A",   5},
135            {"GMT- 13:42",  4},
136            {"GMT-13 :42",  6},
137            {"GMT-13: 42",  7},
138            {"GMT-+13:42",  4},
139            {"-8",          2},
140            {"-18",         3},
141            {"-208",        4},
142            {"-2360",       4},
143            {"-2413",       2},
144            {"-42195",      2},
145            {"-0AbC",       2},
146            {"- 1342",      1},
147            {"--1342",      1},
148            {"-802",        2},
149          /* Arabic-Indic digits */
150            {"GMT-\u0660\u0661:\u0662\u0663", 4},
151          /* Extended Arabic-Indic digits */
152            {"GMT-\u06f0\u06f1:\u06f2\u06f3", 4},
153          /* Devanagari digits */
154            {"GMT-\u0966\u0967:\u0968\u0969", 4},
155          /* Fullwidth digits */
156            {"GMT-\uFF10\uFF11:\uFF12\uFF13", 4},
157        };
158
159        try {
160            for (int i=0; i < locs.length; i++) {
161                Locale locale = locs[i];
162                Locale.setDefault(locale);
163
164                for (int j=0; j < formats.length; j++) {
165                    TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
166                    SimpleDateFormat sdf = new SimpleDateFormat(formats[j]);
167                    Date date;
168
169                    /* Okay case */
170                    for (int k=0; k < valids.length; k++) {
171                        ParsePosition pos = new ParsePosition(0);
172                        try {
173                            date = sdf.parse((String)valids[k][0], pos);
174                        }
175                        catch (Exception e) {
176                            err = true;
177                            System.err.println("\tParse  Error [Locale=" +
178                                locale + ", " + formats[j] +
179                                "/\"" + valids[k][0] +
180                                "\"] Unexpected Exception occurred: " + e);
181                            continue;
182                        }
183
184                        int offset = pos.getIndex();
185                        if (offset != ((Integer)valids[k][4]).intValue()) {
186                            err = true;
187                            System.err.println("\tParse  Error [Locale=" +
188                                locale + ", " + formats[j] +
189                                "/\"" + valids[k][0] +
190                                "\"] invalid index: expected:" + valids[k][4] +
191                                ", got:" + offset);
192                        }
193
194                        if (date.getTime() != ((Long)valids[k][1]).longValue()) {
195                            err = true;
196                            System.err.println("\tParse  Error [Locale=" +
197                                locale + ", " + formats[j] +
198                                "/\"" + valids[k][0] +
199                                "\"] expected:" + valids[k][1] +
200                                ", got:" + date.getTime() + ", " + date);
201                        } else {
202/*
203                            logln("\tParse  Okay  [Locale=" +
204                                locale) + ", " + formats[j] +
205                                "/\"" + valids[k][0] +
206                                "\"] expected:" + valids[k][1] +
207                                ", got:" + date.getTime() + ", " + date);
208*/
209
210                            try {
211                                date = sdf.parse((String)valids[k][0]);
212                            }
213                            catch (Exception e) {
214                                err = true;
215                                System.err.println("\tParse  Error [Locale=" +
216                                    locale + ", " + formats[j] +
217                                    "/\"" + valids[k][0] +
218                                    "\"] Unexpected Exception occurred: " + e);
219                                continue;
220                            }
221
222                            /* Since TimeZone.getTimeZone() don't treat
223                             * "+00234" or "-00234" as a valid ID, skips.
224                             */
225                            if (((String)valids[k][0]).length() == 6) {
226                                continue;
227                            }
228
229                            /* Since TimeZone.getTimeZone() don't recognize
230                             * +hhmm/-hhmm format, add "GMT" as prefix.
231                             */
232                            sdf.setTimeZone(TimeZone.getTimeZone(
233                                (((((String)valids[k][0]).charAt(0) != 'G') ?
234                                "GMT" : "") + valids[k][0])));
235                            StringBuffer s = new StringBuffer();
236                            sdf.format(date, s, new FieldPosition(0));
237                            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
238
239                            String got = s.toString();
240                            String expected = (String)valids[k][2+j];
241                            if (!got.equals(expected) &&
242                                // special case to allow the difference between
243                                // DateFormatSymbols.getZoneStrings() and
244                                // TimeZone.getDisplayName() for "GMT+-00:00"
245                                !(got.equals("GMT-00:00") &&
246                                  expected.equals("GMT+00:00"))) {
247                                err = true;
248                                System.err.println("\tFormat Error [Locale=" +
249                                    locale + ", " +
250                                    formats[j] + "/\"" + valids[k][0] +
251                                    "\"] expected:" + valids[k][2+j] +
252                                    ", got:" + s + ", " + date);
253                            } else {
254/*
255                                logln("\tFormat Okay  [Locale=" +
256                                    locale + ", " +
257                                    formats[j] + "/\"" + valids[k][0] +
258                                    "\"] expected:" + valids[k][2+j] +
259                                    ", got:" + s + ", " + date);
260*/
261                            }
262                        }
263                    }
264
265                    /* Error case 1
266                     *   using SimpleDateFormat.parse(String, ParsePosition)
267                     */
268                    for (int k=0; k < invalids.length; k++) {
269                        ParsePosition pos = new ParsePosition(0);
270                        try {
271                            date = sdf.parse((String)invalids[k][0], pos);
272                            if (date != null) {
273                                err = true;
274                                System.err.println("\tParse  Error [Locale=" +
275                                    locale + ", " + formats[j] +
276                                    "/\"" + invalids[k][0] +
277                                    "\"] expected:null , got:" + date);
278                            }
279                            int offset = pos.getErrorIndex();
280                            if (offset != ((Integer)invalids[k][1]).intValue()) {
281                                err = true;
282                                System.err.println("\tParse  Error [Locale=" +
283                                    locale + ", " + formats[j] +
284                                    "/\"" + invalids[k][0] +
285                                    "\"] incorrect offset. expected:" +
286                                    invalids[k][1] + ", got: " + offset);
287                            } else {
288/*
289                                logln("\tParse  Okay  [Locale=" +
290                                    locale + ", " + formats[j] +
291                                    "/\"" + invalids[k][0] +
292                                    "\"] correct offset: " + offset);
293*/
294                            }
295                        }
296                        catch (Exception e) {
297                            err = true;
298                            System.err.println("\tParse  Error [Locale=" +
299                                locale + ", " + formats[j] +
300                                "/\"" + invalids[k][0] +
301                                "\"] Unexpected Exception occurred: " + e);
302                        }
303                    }
304
305                    /* Error case 2
306                     *   using DateFormat.parse(String)
307                     */
308                    boolean correctParseException = false;
309                    for (int k=0; k < invalids.length; k++) {
310                        try {
311                            date = sdf.parse((String)invalids[k][0]);
312                        }
313                        catch (ParseException e) {
314                            correctParseException = true;
315                            int offset = e.getErrorOffset();
316                            if (offset != ((Integer)invalids[k][1]).intValue()) {
317                                err = true;
318                                System.err.println("\tParse  Error [Locale=" +
319                                    locale + ", " + formats[j] +
320                                    "/\"" + invalids[k][0] +
321                                    "\"] Expected exception occurred with an incorrect offset. expected:" +
322                                    invalids[k][1] + ", got: " + offset);
323                            } else {
324/*
325                                logln("\tParse  Okay  [Locale=" +
326                                    locale + ", " + formats[j] +
327                                    "/\"" + invalids[k][0] +
328                                    "\"] Expected exception occurred with an correct offset: "
329                                    + offset);
330*/
331                            }
332                        }
333                        catch (Exception e) {
334                            err = true;
335                            System.err.println("\tParse  Error [Locale=" +
336                                locale + ", " + formats[j] +
337                                "/\"" + invalids[k][0] +
338                                "\"] Invalid exception occurred: " + e);
339                        }
340                        finally {
341                            if (!correctParseException) {
342                                err = true;
343                                System.err.println("\tParse  Error: [Locale=" +
344                                    locale + ", " + formats[j] +
345                                    "/\"" + invalids[k][0] +
346                                    "\"] Expected exception didn't occur.");
347                            }
348                        }
349                    }
350                }
351            }
352        }
353        finally {
354            Locale.setDefault(savedLocale);
355            TimeZone.setDefault(savedTimeZone);
356            if (err) {
357                errln("SimpleDateFormat.parse()/format() test failed");
358            }
359        }
360    }
361
362    public static void main(String[] args) throws Exception {
363        new Bug4322313().run(args);
364    }
365}
366