1 /*
  2  * Copyright (c) 2000, 2023, 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 4372743
 27  * @summary test that checks transitions of ERA and YEAR which are caused by add(MONTH).
 28  * @run junit bug4372743
 29  */
 30 
 31 import java.util.GregorianCalendar;
 32 import java.util.TimeZone;
 33 import java.util.stream.Stream;
 34 
 35 import static java.util.GregorianCalendar.AD;
 36 import static java.util.GregorianCalendar.APRIL;
 37 import static java.util.GregorianCalendar.AUGUST;
 38 import static java.util.GregorianCalendar.BC;
 39 import static java.util.GregorianCalendar.DECEMBER;
 40 import static java.util.GregorianCalendar.ERA;
 41 import static java.util.GregorianCalendar.FEBRUARY;
 42 import static java.util.GregorianCalendar.JANUARY;
 43 import static java.util.GregorianCalendar.JULY;
 44 import static java.util.GregorianCalendar.JUNE;
 45 import static java.util.GregorianCalendar.MARCH;
 46 import static java.util.GregorianCalendar.MAY;
 47 import static java.util.GregorianCalendar.MONTH;
 48 import static java.util.GregorianCalendar.NOVEMBER;
 49 import static java.util.GregorianCalendar.OCTOBER;
 50 import static java.util.GregorianCalendar.SEPTEMBER;
 51 import static java.util.GregorianCalendar.YEAR;
 52 
 53 import org.junit.jupiter.api.AfterAll;
 54 import org.junit.jupiter.api.BeforeAll;
 55 
 56 import org.junit.jupiter.params.ParameterizedTest;
 57 import org.junit.jupiter.params.provider.Arguments;
 58 import org.junit.jupiter.params.provider.MethodSource;
 59 
 60 import static org.junit.jupiter.api.Assertions.assertEquals;
 61 
 62 public class bug4372743 {
 63 
 64     // Save JVM default timezone
 65     private static final TimeZone savedTz = TimeZone.getDefault();
 66 
 67     // Set custom JVM default timezone
 68     @BeforeAll
 69     static void initAll() {
 70         TimeZone.setDefault(TimeZone.getTimeZone("PST"));
 71     }
 72 
 73     // Restore JVM default timezone
 74     @AfterAll
 75     static void tearDownAll() {
 76         TimeZone.setDefault(savedTz);
 77     }
 78 
 79     /*
 80      * Set GregorianCalendar to (March 3, A.D. 2) and test adding
 81      * to the month field. Ensure that the added field is as expected.
 82      */
 83     @ParameterizedTest
 84     @MethodSource("A_D_Values")
 85     public void A_D_Test(GregorianCalendar gc, int monthValue) {
 86         for (int i = 0; i < tableSize; i+=(-monthValue)) {
 87             check(gc, i);
 88             gc.add(MONTH, monthValue);
 89         }
 90     }
 91 
 92     // Given in format: (A.D.) GregorianCalendar, amount to add
 93     private static Stream<Arguments> A_D_Values() {
 94         return Stream.of(
 95                 Arguments.of(new GregorianCalendar(2, MARCH, 3), -1),
 96                 Arguments.of(new GregorianCalendar(2, MARCH, 3), -7));
 97     }
 98 
 99     /*
100      * Set GregorianCalendar to (March 10, 2 B.C.) and test adding
101      * to the month field. Ensure that the added field is as expected.
102      */
103     @ParameterizedTest
104     @MethodSource("B_C_Values")
105     public void B_C_Test(GregorianCalendar gc, int monthValue) {
106             gc.add(YEAR, -3);
107             for (int i = tableSize - 1; i >= 0; i-=monthValue) {
108                 check(gc, i);
109                 gc.add(MONTH, monthValue);
110             }
111     }
112 
113     // Given in format: (B.C.) GregorianCalendar, amount to add
114     private static Stream<Arguments> B_C_Values() {
115         return Stream.of(
116                 Arguments.of(new GregorianCalendar(2, OCTOBER, 10), 1),
117                 Arguments.of(new GregorianCalendar(2, OCTOBER, 10), 8));
118     }
119 
120     // Check golden data array with actual value
121     private void check(GregorianCalendar gc, int index) {
122         assertEquals(data[index][ERA], gc.get(ERA), "Invalid era");
123         assertEquals(data[index][YEAR], gc.get(YEAR), "Invalid year");
124         assertEquals(data[index][MONTH], gc.get(MONTH), "Invalid month");
125     }
126 
127     // Expected ERA, YEAR, and MONTH combinations
128     private final int[][] data = {
129         {AD, 2, MARCH},
130         {AD, 2, FEBRUARY},
131         {AD, 2, JANUARY},
132         {AD, 1, DECEMBER},
133         {AD, 1, NOVEMBER},
134         {AD, 1, OCTOBER},
135         {AD, 1, SEPTEMBER},
136         {AD, 1, AUGUST},
137         {AD, 1, JULY},
138         {AD, 1, JUNE},
139         {AD, 1, MAY},
140         {AD, 1, APRIL},
141         {AD, 1, MARCH},
142         {AD, 1, FEBRUARY},
143         {AD, 1, JANUARY},
144         {BC, 1, DECEMBER},
145         {BC, 1, NOVEMBER},
146         {BC, 1, OCTOBER},
147         {BC, 1, SEPTEMBER},
148         {BC, 1, AUGUST},
149         {BC, 1, JULY},
150         {BC, 1, JUNE},
151         {BC, 1, MAY},
152         {BC, 1, APRIL},
153         {BC, 1, MARCH},
154         {BC, 1, FEBRUARY},
155         {BC, 1, JANUARY},
156         {BC, 2, DECEMBER},
157         {BC, 2, NOVEMBER},
158         {BC, 2, OCTOBER}};
159     private final int tableSize = data.length;
160 }