1/*
2 * Copyright (c) 2014, 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
24package datatype;
25
26import java.math.BigDecimal;
27import java.math.BigInteger;
28import java.util.Calendar;
29import java.util.Date;
30import java.util.GregorianCalendar;
31import java.util.TimeZone;
32
33import javax.xml.datatype.DatatypeConfigurationException;
34import javax.xml.datatype.DatatypeConstants;
35import javax.xml.datatype.DatatypeFactory;
36import javax.xml.datatype.Duration;
37import javax.xml.namespace.QName;
38
39import org.testng.Assert;
40import org.testng.AssertJUnit;
41import org.testng.annotations.BeforeMethod;
42import org.testng.annotations.Listeners;
43import org.testng.annotations.Test;
44
45/*
46 * @test
47 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
48 * @run testng/othervm -DrunSecMngr=true datatype.DurationTest
49 * @run testng/othervm datatype.DurationTest
50 * @summary Test Duration.
51 */
52@Listeners({jaxp.library.BasePolicy.class})
53public class DurationTest {
54
55    private final static boolean DEBUG = true;
56
57    protected Duration duration = null;
58
59    @BeforeMethod
60    public void setUp() {
61        try {
62            duration = DatatypeFactory.newInstance().newDuration(100);
63        } catch (DatatypeConfigurationException dce) {
64            dce.printStackTrace();
65            Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage());
66        }
67    }
68
69    @Test
70    public void testDurationSubtract() {
71        try {
72            Duration bigDur = DatatypeFactory.newInstance().newDuration(20000);
73            Duration smallDur = DatatypeFactory.newInstance().newDuration(10000);
74            if (smallDur.subtract(bigDur).getSign() != -1) {
75                Assert.fail("smallDur.subtract(bigDur).getSign() is not -1");
76            }
77            if (bigDur.subtract(smallDur).getSign() != 1) {
78                Assert.fail("bigDur.subtract(smallDur).getSign() is not 1");
79            }
80            if (smallDur.subtract(smallDur).getSign() != 0) {
81                Assert.fail("smallDur.subtract(smallDur).getSign() is not 0");
82            }
83        } catch (DatatypeConfigurationException e) {
84            e.printStackTrace();
85        }
86    }
87
88    @Test
89    public void testDurationMultiply() {
90        int num = 5000; // millisends. 5 seconds
91        int factor = 2;
92        try {
93            Duration dur = DatatypeFactory.newInstance().newDuration(num);
94            if (dur.multiply(factor).getSeconds() != 10) {
95                Assert.fail("duration.multiply() return wrong value");
96            }
97            // factor is 2*10^(-1)
98            if (dur.multiply(new BigDecimal(new BigInteger("2"), 1)).getSeconds() != 1) {
99                Assert.fail("duration.multiply() return wrong value");
100            }
101            if (dur.subtract(DatatypeFactory.newInstance().newDuration(1000)).multiply(new BigDecimal(new BigInteger("2"), 1)).getSeconds() != 0) {
102                Assert.fail("duration.multiply() return wrong value");
103            }
104        } catch (DatatypeConfigurationException e) {
105            e.printStackTrace();
106        }
107    }
108
109    @Test
110    public void testDurationAndCalendar1() {
111        int year = 1;
112        int month = 2;
113        int day = 3;
114        int hour = 4;
115        int min = 5;
116        int sec = 6;
117        String lexicalRepresentation = "P" + year + "Y" + month + "M" + day + "DT" + hour + "H" + min + "M" + sec + "S";
118        try {
119            Duration dur = DatatypeFactory.newInstance().newDuration(lexicalRepresentation);
120            System.out.println(dur.toString());
121            AssertJUnit.assertTrue("year should be 1", dur.getYears() == year);
122            AssertJUnit.assertTrue("month should be 2", dur.getMonths() == month);
123            AssertJUnit.assertTrue("day should be 3", dur.getDays() == day);
124            AssertJUnit.assertTrue("hour should be 4", dur.getHours() == hour);
125            AssertJUnit.assertTrue("minute should be 5", dur.getMinutes() == min);
126            AssertJUnit.assertTrue("second should be 6", dur.getSeconds() == sec);
127        } catch (DatatypeConfigurationException e) {
128            e.printStackTrace();
129        }
130    }
131
132    @Test
133    public void testDurationAndCalendar2() {
134        try {
135            AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("PT10.00099S")
136                    .getTimeInMillis(new Date()) == 10000);
137            AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("-PT10.00099S")
138                    .getTimeInMillis(new Date()) == -10000);
139            AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("PT10.00099S")
140                    .getTimeInMillis(new GregorianCalendar()) == 10000);
141            AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("-PT10.00099S")
142                    .getTimeInMillis(new GregorianCalendar()) == -10000);
143        } catch (DatatypeConfigurationException e) {
144            e.printStackTrace();
145        }
146    }
147
148    @Test
149    public void testDurationAndCalendar3() {
150        try {
151            Calendar cal = new GregorianCalendar();
152            cal.set(Calendar.SECOND, 59);
153            DatatypeFactory.newInstance().newDuration(10000).addTo(cal);
154            AssertJUnit.assertTrue("sec will be 9", cal.get(Calendar.SECOND) == 9);
155
156            Date date = new Date();
157            date.setSeconds(59);
158            DatatypeFactory.newInstance().newDuration(10000).addTo(date);
159            AssertJUnit.assertTrue("sec will be 9", date.getSeconds() == 9);
160        } catch (DatatypeConfigurationException e) {
161            e.printStackTrace();
162        }
163    }
164
165    @Test
166    public void testEqualsWithDifferentObjectParam() {
167
168        AssertJUnit.assertFalse("equals method should return false for any object other than Duration", duration.equals(new Integer(0)));
169    }
170
171    @Test
172    public void testEqualsWithNullObjectParam() {
173
174        AssertJUnit.assertFalse("equals method should return false for null parameter", duration.equals(null));
175    }
176
177    @Test
178    public void testEqualsWithEqualObjectParam() {
179        try {
180            AssertJUnit.assertTrue("equals method is expected to return true", duration.equals(DatatypeFactory.newInstance().newDuration(100)));
181        } catch (DatatypeConfigurationException dce) {
182            dce.printStackTrace();
183            Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage());
184        }
185    }
186
187    /**
188     * Inspired by CR 5077522 Duration.compare makes mistakes for some values.
189     */
190    @Test
191    public void testCompareWithInderterminateRelation() {
192
193        final String[][] partialOrder = { // partialOrder
194        { "P1Y", "<>", "P365D" }, { "P1Y", "<>", "P366D" }, { "P1M", "<>", "P28D" }, { "P1M", "<>", "P29D" }, { "P1M", "<>", "P30D" }, { "P1M", "<>", "P31D" },
195                { "P5M", "<>", "P150D" }, { "P5M", "<>", "P151D" }, { "P5M", "<>", "P152D" }, { "P5M", "<>", "P153D" }, { "PT2419200S", "<>", "P1M" },
196                { "PT2678400S", "<>", "P1M" }, { "PT31536000S", "<>", "P1Y" }, { "PT31622400S", "<>", "P1Y" }, { "PT525600M", "<>", "P1Y" },
197                { "PT527040M", "<>", "P1Y" }, { "PT8760H", "<>", "P1Y" }, { "PT8784H", "<>", "P1Y" }, { "P365D", "<>", "P1Y" }, };
198
199        DatatypeFactory df = null;
200        try {
201            df = DatatypeFactory.newInstance();
202        } catch (DatatypeConfigurationException ex) {
203            ex.printStackTrace();
204            Assert.fail(ex.toString());
205        }
206
207        boolean compareErrors = false;
208
209        for (int valueIndex = 0; valueIndex < partialOrder.length; ++valueIndex) {
210            Duration duration1 = df.newDuration(partialOrder[valueIndex][0]);
211            Duration duration2 = df.newDuration(partialOrder[valueIndex][2]);
212            int cmp = duration1.compare(duration2);
213            int expected = ">".equals(partialOrder[valueIndex][1]) ? DatatypeConstants.GREATER
214                    : "<".equals(partialOrder[valueIndex][1]) ? DatatypeConstants.LESSER : "==".equals(partialOrder[valueIndex][1]) ? DatatypeConstants.EQUAL
215                            : DatatypeConstants.INDETERMINATE;
216
217            // just note any errors, do not fail until all cases have been
218            // tested
219            if (expected != cmp) {
220                compareErrors = true;
221                System.err.println("returned " + cmp2str(cmp) + " for durations \'" + duration1 + "\' and " + duration2 + "\', but expected "
222                        + cmp2str(expected));
223            }
224        }
225
226        if (compareErrors) {
227            // TODO; fix bug, these tests should pass
228            if (false) {
229                Assert.fail("Errors in comparing indeterminate relations, see Stderr");
230            } else {
231                System.err.println("Please fix this bug: " + "Errors in comparing indeterminate relations, see Stderr");
232            }
233        }
234    }
235
236    public static String cmp2str(int cmp) {
237        return cmp == DatatypeConstants.LESSER ? "LESSER" : cmp == DatatypeConstants.GREATER ? "GREATER" : cmp == DatatypeConstants.EQUAL ? "EQUAL"
238                : cmp == DatatypeConstants.INDETERMINATE ? "INDETERMINATE" : "UNDEFINED";
239    }
240
241    /**
242     * Inspired by CR 6238220 javax.xml.datatype.Duration has no clear
243     * description concerning return values range.
244     */
245    @Test
246    public void testNormalizedReturnValues() throws Exception {
247
248        final Object[] TEST_VALUES = {
249                // test 61 seconds -> 1 minute, 1 second
250                true, // isPositive,
251                BigInteger.ZERO, // years,
252                BigInteger.ZERO, // months
253                BigInteger.ZERO, // days
254                BigInteger.ZERO, // hours
255                BigInteger.ZERO, // minutes
256                new BigDecimal(61), // seconds
257                61000L, // durationInMilliSeconds,
258                "P0Y0M0DT0H0M61S", // lexicalRepresentation
259
260                // test - 61 seconds -> - 1 minute, 1 second
261                false, // isPositive,
262                BigInteger.ZERO, // years,
263                BigInteger.ZERO, // months
264                BigInteger.ZERO, // days
265                BigInteger.ZERO, // hours
266                BigInteger.ZERO, // minutes
267                new BigDecimal(61), // seconds
268                61000L, // durationInMilliSeconds,
269                "-P0Y0M0DT0H0M61S", // lexicalRepresentation
270        };
271
272        final Object[] NORM_VALUES = {
273                // test 61 seconds -> 1 minute, 1 second
274                true, // normalized isPositive,
275                BigInteger.ZERO, // normalized years,
276                BigInteger.ZERO, // normalized months
277                BigInteger.ZERO, // normalized days
278                BigInteger.ZERO, // normalized hours
279                BigInteger.ONE, // normalized minutes
280                BigDecimal.ONE, // normalized seconds
281                61000L, // normalized durationInMilliSeconds,
282                "P0Y0M0DT0H1M1.000S", // normalized lexicalRepresentation
283
284                // test - 61 seconds -> - 1 minute, 1 second
285                false, // normalized isPositive,
286                BigInteger.ZERO, // normalized years,
287                BigInteger.ZERO, // normalized months
288                BigInteger.ZERO, // normalized days
289                BigInteger.ZERO, // normalized hours
290                BigInteger.ONE, // normalized minutes
291                BigDecimal.ONE, // normalized seconds
292                61000L, // normalized durationInMilliSeconds,
293                "-P0Y0M0DT0H1M1.000S" // normalized lexicalRepresentation
294        };
295
296        for (int onValue = 0; onValue < TEST_VALUES.length; onValue += 9) {
297            newDurationTester(((Boolean) TEST_VALUES[onValue]).booleanValue(), // isPositive,
298                    ((Boolean) NORM_VALUES[onValue]).booleanValue(), // normalized
299                                                                     // isPositive,
300                    (BigInteger) TEST_VALUES[onValue + 1], // years,
301                    (BigInteger) NORM_VALUES[onValue + 1], // normalized years,
302                    (BigInteger) TEST_VALUES[onValue + 2], // months
303                    (BigInteger) NORM_VALUES[onValue + 2], // normalized months
304                    (BigInteger) TEST_VALUES[onValue + 3], // days
305                    (BigInteger) NORM_VALUES[onValue + 3], // normalized days
306                    (BigInteger) TEST_VALUES[onValue + 4], // hours
307                    (BigInteger) NORM_VALUES[onValue + 4], // normalized hours
308                    (BigInteger) TEST_VALUES[onValue + 5], // minutes
309                    (BigInteger) NORM_VALUES[onValue + 5], // normalized minutes
310                    (BigDecimal) TEST_VALUES[onValue + 6], // seconds
311                    (BigDecimal) NORM_VALUES[onValue + 6], // normalized seconds
312                    ((Long) TEST_VALUES[onValue + 7]).longValue(), // durationInMilliSeconds,
313                    ((Long) NORM_VALUES[onValue + 7]).longValue(), // normalized
314                                                                   // durationInMilliSeconds,
315                    (String) TEST_VALUES[onValue + 8], // lexicalRepresentation
316                    (String) NORM_VALUES[onValue + 8]); // normalized
317                                                        // lexicalRepresentation
318
319            newDurationDayTimeTester(((Boolean) TEST_VALUES[onValue]).booleanValue(), // isPositive,
320                    ((Boolean) NORM_VALUES[onValue]).booleanValue(), // normalized
321                                                                     // isPositive,
322                    BigInteger.ZERO, // years,
323                    BigInteger.ZERO, // normalized years,
324                    BigInteger.ZERO, // months
325                    BigInteger.ZERO, // normalized months
326                    (BigInteger) TEST_VALUES[onValue + 3], // days
327                    (BigInteger) NORM_VALUES[onValue + 3], // normalized days
328                    (BigInteger) TEST_VALUES[onValue + 4], // hours
329                    (BigInteger) NORM_VALUES[onValue + 4], // normalized hours
330                    (BigInteger) TEST_VALUES[onValue + 5], // minutes
331                    (BigInteger) NORM_VALUES[onValue + 5], // normalized minutes
332                    (BigDecimal) TEST_VALUES[onValue + 6], // seconds
333                    (BigDecimal) NORM_VALUES[onValue + 6], // normalized seconds
334                    ((Long) TEST_VALUES[onValue + 7]).longValue(), // durationInMilliSeconds,
335                    ((Long) NORM_VALUES[onValue + 7]).longValue(), // normalized
336                                                                   // durationInMilliSeconds,
337                    (String) TEST_VALUES[onValue + 8], // lexicalRepresentation
338                    (String) NORM_VALUES[onValue + 8]); // normalized
339                                                        // lexicalRepresentation
340        }
341    }
342
343    private void newDurationTester(boolean isPositive, boolean normalizedIsPositive, BigInteger years, BigInteger normalizedYears, BigInteger months,
344            BigInteger normalizedMonths, BigInteger days, BigInteger normalizedDays, BigInteger hours, BigInteger normalizedHours, BigInteger minutes,
345            BigInteger normalizedMinutes, BigDecimal seconds, BigDecimal normalizedSeconds, long durationInMilliSeconds, long normalizedDurationInMilliSeconds,
346            String lexicalRepresentation, String normalizedLexicalRepresentation) {
347
348        DatatypeFactory datatypeFactory = null;
349        try {
350            datatypeFactory = DatatypeFactory.newInstance();
351        } catch (DatatypeConfigurationException ex) {
352            ex.printStackTrace();
353            Assert.fail(ex.toString());
354        }
355
356        // create 4 Durations using the 4 different constructors
357
358        Duration durationBigInteger = datatypeFactory.newDuration(isPositive, years, months, days, hours, minutes, seconds);
359        durationAssertEquals(durationBigInteger, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(),
360                normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(),
361                normalizedDurationInMilliSeconds, normalizedLexicalRepresentation);
362
363        Duration durationInt = datatypeFactory.newDuration(isPositive, years.intValue(), months.intValue(), days.intValue(), hours.intValue(),
364                minutes.intValue(), seconds.intValue());
365        durationAssertEquals(durationInt, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(),
366                normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(),
367                normalizedDurationInMilliSeconds, normalizedLexicalRepresentation);
368
369        Duration durationMilliseconds = datatypeFactory.newDuration(durationInMilliSeconds);
370        durationAssertEquals(durationMilliseconds, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(),
371                normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(),
372                normalizedDurationInMilliSeconds, normalizedLexicalRepresentation);
373
374        Duration durationLexical = datatypeFactory.newDuration(lexicalRepresentation);
375        durationAssertEquals(durationLexical, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(),
376                normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(),
377                normalizedDurationInMilliSeconds, normalizedLexicalRepresentation);
378    }
379
380    private void newDurationDayTimeTester(boolean isPositive, boolean normalizedIsPositive, BigInteger years, BigInteger normalizedYears, BigInteger months,
381            BigInteger normalizedMonths, BigInteger days, BigInteger normalizedDays, BigInteger hours, BigInteger normalizedHours, BigInteger minutes,
382            BigInteger normalizedMinutes, BigDecimal seconds, BigDecimal normalizedSeconds, long durationInMilliSeconds, long normalizedDurationInMilliSeconds,
383            String lexicalRepresentation, String normalizedLexicalRepresentation) {
384
385        DatatypeFactory datatypeFactory = null;
386        try {
387            datatypeFactory = DatatypeFactory.newInstance();
388        } catch (DatatypeConfigurationException ex) {
389            ex.printStackTrace();
390            Assert.fail(ex.toString());
391        }
392
393        // create 4 dayTime Durations using the 4 different constructors
394
395        Duration durationDayTimeBigInteger = datatypeFactory.newDurationDayTime(isPositive, days, hours, minutes, seconds.toBigInteger());
396        durationAssertEquals(durationDayTimeBigInteger, DatatypeConstants.DURATION_DAYTIME, normalizedIsPositive, normalizedYears.intValue(),
397                normalizedMonths.intValue(), normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(),
398                normalizedDurationInMilliSeconds, normalizedLexicalRepresentation);
399
400        /*
401         * Duration durationDayTimeInt = datatypeFactory.newDurationDayTime(
402         * isPositive, days.intValue(), hours.intValue(), minutes.intValue(),
403         * seconds.intValue()); Duration durationDayTimeMilliseconds =
404         * datatypeFactory.newDurationDayTime( durationInMilliSeconds); Duration
405         * durationDayTimeLexical = datatypeFactory.newDurationDayTime(
406         * lexicalRepresentation);
407         * Duration durationYearMonthBigInteger =
408         * datatypeFactory.newDurationYearMonth( isPositive, years, months);
409         * Duration durationYearMonthInt = datatypeFactory.newDurationYearMonth(
410         * isPositive, years.intValue(), months.intValue()); Duration
411         * durationYearMonthMilliseconds = datatypeFactory.newDurationYearMonth(
412         * durationInMilliSeconds); Duration durationYearMonthLexical =
413         * datatypeFactory.newDurationYearMonth( lexicalRepresentation) ;
414         */
415
416    }
417
418    private void durationAssertEquals(Duration duration, QName xmlSchemaType, boolean isPositive, int years, int months, int days, int hours, int minutes,
419            int seconds, long milliseconds, String lexical) {
420
421        final TimeZone GMT = TimeZone.getTimeZone("GMT");
422        final GregorianCalendar EPOCH = new GregorianCalendar(GMT);
423        EPOCH.clear();
424
425        if (DEBUG) {
426            System.out.println("Testing Duration: " + duration.toString());
427        }
428
429        // sign
430        if (DEBUG) {
431            boolean actual = (duration.getSign() == 1) ? true : false;
432            System.out.println("sign:");
433            System.out.println("    expected: \"" + isPositive + "\"");
434            System.out.println("    actual:   \"" + actual + "\"");
435        }
436
437        if (DEBUG) {
438            System.out.println("years:");
439            System.out.println("    expected: \"" + years + "\"");
440            System.out.println("    actual:   \"" + duration.getYears() + "\"");
441        }
442
443        if (DEBUG) {
444            System.out.println("months:");
445            System.out.println("    expected: \"" + months + "\"");
446            System.out.println("    actual:   \"" + duration.getMonths() + "\"");
447        }
448
449        if (DEBUG) {
450            System.out.println("days:");
451            System.out.println("    expected: \"" + days + "\"");
452            System.out.println("    actual:   \"" + duration.getDays() + "\"");
453        }
454
455        if (DEBUG) {
456            System.out.println("hours:");
457            System.out.println("    expected: \"" + hours + "\"");
458            System.out.println("    actual:   \"" + duration.getHours() + "\"");
459        }
460
461        if (DEBUG) {
462            System.out.println("minutes:");
463            System.out.println("    expected: \"" + minutes + "\"");
464            System.out.println("    actual:   \"" + duration.getMinutes() + "\"");
465        }
466
467        if (DEBUG) {
468            System.out.println("seconds:");
469            System.out.println("    expected: \"" + seconds + "\"");
470            System.out.println("    actual:   \"" + duration.getSeconds() + "\"");
471        }
472
473        if (DEBUG) {
474            System.out.println("milliseconds:");
475            System.out.println("    expected: \"" + milliseconds + "\"");
476            System.out.println("    actual:   \"" + duration.getTimeInMillis(EPOCH) + "\"");
477        }
478
479        if (DEBUG) {
480            System.out.println("lexical:");
481            System.out.println("    expected: \"" + lexical + "\"");
482            System.out.println("    actual:   \"" + duration.toString() + "\"");
483        }
484
485    }
486}
487