/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * ---------------------------- * SegmentedTimelineTests.java * ---------------------------- * (C) Copyright 2003-2008, by Bill Kelemen and Contributors. * * Original Author: Bill Kelemen; * Contributor(s): David Gilbert (for Object Refinery Limited); * * Changes * ------- * 24-May-2003 : Version 1 (BK); * 07-Jan-2005 : Added test for hashCode() method (DG); * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG); * */ package org.jfree.chart.axis.junit; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.text.Format; import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jfree.chart.axis.SegmentedTimeline; /** * JUnit Tests for the {@link SegmentedTimeline} class. */ public class SegmentedTimelineTests extends TestCase { /** These constants control test cycles in the validateXXXX methods. */ private static final int TEST_CYCLE_START = 0; /** These constants control test cycles in the validateXXXX methods. */ private static final int TEST_CYCLE_END = 1000; /** These constants control test cycles in the validateXXXX methods. */ private static final int TEST_CYCLE_INC = 55; /** Number of ms in five years */ private static final long FIVE_YEARS = 5 * 365 * SegmentedTimeline.DAY_SEGMENT_SIZE; /** Number format object for ms tests. */ private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(); /** Date format object for Monday through Friday tests. */ private static final SimpleDateFormat DATE_FORMAT; /** Date format object 9:00 AM to 4:00 PM tests. */ private static final SimpleDateFormat DATE_TIME_FORMAT; /** Some ms exceptions for ms testing. */ private static final String[] MS_EXCEPTIONS = {"0", "2", "4", "10", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "47", "58", "100", "101"}; /** Some ms4 exceptions for ms testing. */ private static final String[] MS2_BASE_TIMELINE_EXCEPTIONS = {"0", "8", "16", "24", "32", "40", "48", "56", "64", "72", "80", "88", "96", "104", "112", "120", "128", "136"}; /** US non-trading dates in 2000 through 2002 to test exceptions. */ private static final String[] US_HOLIDAYS = {"2000-01-17", "2000-02-21", "2000-04-21", "2000-05-29", "2000-07-04", "2000-09-04", "2000-11-23", "2000-12-25", "2001-01-01", "2001-01-15", "2001-02-19", "2001-04-13", "2001-05-28", "2001-07-04", "2001-09-03", "2001-09-11", "2001-09-12", "2001-09-13", "2001-09-14", "2001-11-22", "2001-12-25", "2002-01-01", "2002-01-21", "2002-02-18", "2002-03-29", "2002-05-27", "2002-07-04", "2002-09-02", "2002-11-28", "2002-12-25"}; /** Some test exceptions for the fifteen min timeline. */ private static final String[] FIFTEEN_MIN_EXCEPTIONS = { "2000-01-10 09:00:00", "2000-01-10 09:15:00", "2000-01-10 09:30:00", "2000-01-10 09:45:00", "2000-01-10 10:00:00", "2000-01-10 10:15:00", "2000-02-15 09:00:00", "2000-02-15 09:15:00", "2000-02-15 09:30:00", "2000-02-15 09:45:00", "2000-02-15 10:00:00", "2000-02-15 10:15:00", "2000-02-16 11:00:00", "2000-02-16 11:15:00", "2000-02-16 11:30:00", "2000-02-16 11:45:00", "2000-02-16 12:00:00", "2000-02-16 12:15:00", "2000-02-16 12:30:00", "2000-02-16 12:45:00", "2000-02-16 01:00:00", "2000-02-16 01:15:00", "2000-02-16 01:30:00", "2000-02-16 01:45:00", "2000-05-17 11:45:00", "2000-05-17 12:00:00", "2000-05-17 12:15:00", "2000-05-17 12:30:00", "2000-05-17 12:45:00", "2000-05-17 01:00:00", "2000-05-17 01:15:00", "2000-05-17 01:30:00", "2000-05-17 01:45:00", "2000-05-17 02:00:00", "2000-05-17 02:15:00", "2000-05-17 02:30:00", "2000-05-17 02:45:00", "2000-05-17 03:00:00", "2000-05-17 03:15:00", "2000-05-17 03:30:00", "2000-05-17 03:45:00", "2000-05-17 04:00:00"}; /** Our 1-ms test timeline using 5 included and 2 excluded segments. */ private SegmentedTimeline msTimeline; /** * Our 1-ms test timeline (with baseTimeline) using 2 included and 2 * excluded segments. */ private SegmentedTimeline ms2Timeline; /** * Our 4-ms test base timeline for ms2Timeline using 1 included and 1 * excluded segments */ private SegmentedTimeline ms2BaseTimeline; /** Our test Monday through Friday test timeline. */ private SegmentedTimeline mondayFridayTimeline; /** Our 9:00 AM to 4:00 PM fifteen minute timeline. */ private SegmentedTimeline fifteenMinTimeline; /** ms from 1970-01-01 to first monday after 2001-01-01. */ private Calendar monday; /** ms from 1970-01-01 to 9 am first monday after 2001-01-01. */ private Calendar monday9am; /** Static initialization block. */ static { DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); DATE_FORMAT.setTimeZone(SegmentedTimeline.NO_DST_TIME_ZONE); DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); DATE_TIME_FORMAT.setTimeZone(SegmentedTimeline.NO_DST_TIME_ZONE); } /** * Returns the tests as a test suite. * * @return The test suite. */ public static Test suite() { return new TestSuite(SegmentedTimelineTests.class); } /** * Constructs a new set of tests. * * @param name the name of the tests. */ public SegmentedTimelineTests(String name) { super(name); } /** * Sets up the fixture, for example, open a network connection. * This method is called before a test is executed. * * @throws Exception if there is a problem. */ protected void setUp() throws Exception { // setup our test timelines // // Legend for comments below: // <spaces> = Segments included in the final timeline // EE = Excluded segments via timeline rules // xx = Exception segments inherited from base timeline exclusions // 1-ms test timeline using 5 included and 2 excluded segments. // // timeline start time = 0 // | // v // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+.. // | | | | | |EE|EE| | | | | |EE|EE| | | | | | |EE|EE| <-- msTimeline // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+.. // \_________ ________/ \_/ // \/ | // segment group segment size = 1 ms // this.msTimeline = new SegmentedTimeline(1, 5, 2); this.msTimeline.setStartTime(0); // 4-ms test base timeline for ms2Timeline using 1 included and 1 // excluded segments // // timeline start time = 0 // | // v // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // | | | | |EE|EE|EE|EE| | | | |EE|EE|EE|EE| | | | | <-- ms2BaseTimeline // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // \__________ _________/ \____ _____/ // \/ \/ // segment group segment size = 4 ms // this.ms2BaseTimeline = new SegmentedTimeline(4, 1, 1); this.ms2BaseTimeline.setStartTime(0); // 1-ms test timeline (with a baseTimeline) using 2 included and 2 // excluded segments centered inside each base segment // // The ms2Timeline without a base would look like this: // // timeline start time = 1 // | // v // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // |EE| | |EE|EE| | |EE|EE| | |EE|EE| | |EE|EE| | |EE| <-- ms2Timeline // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // \____ _____/ \_/ // \/ | // segment group segment size = 1 ms // // With the base timeline some originally included segments are now // removed (see "xx" below): // // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // |EE| | |EE|EE|xx|xx|EE|EE| | |EE|EE|xx|xx|EE|EE| | |EE| <-- ms2Timeline // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // | | | | |EE|EE|EE|EE| | | | |EE|EE|EE|EE| | | | | <-- ms2BaseTimeline // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+... // this.ms2Timeline = new SegmentedTimeline(1, 2, 2); this.ms2Timeline.setStartTime(1); this.ms2Timeline.setBaseTimeline(this.ms2BaseTimeline); // test monday though friday timeline this.mondayFridayTimeline = SegmentedTimeline.newMondayThroughFridayTimeline(); // test 9am-4pm Monday through Friday timeline this.fifteenMinTimeline = SegmentedTimeline.newFifteenMinuteTimeline(); // find first Monday after 2001-01-01 Calendar cal = new GregorianCalendar( SegmentedTimeline.NO_DST_TIME_ZONE); cal.set(2001, 0, 1, 0, 0, 0); cal.set(Calendar.MILLISECOND, 0); while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { cal.add(Calendar.DATE, 1); } this.monday = (Calendar) cal.clone(); // calculate 9am on the first Monday after 2001-01-01 cal.add(Calendar.HOUR, 9); this.monday9am = (Calendar) cal.clone(); } /** * Tears down the fixture, for example, close a network connection. * This method is called after a test is executed. * * @throws Exception if there is a problem. */ protected void tearDown() throws Exception { // does nothing } ////////////////////////////////////////////////////////////////////////// // test construction process ////////////////////////////////////////////////////////////////////////// /** * Tests that the new method that created the msTimeline segmented * timeline did so correctly. */ public void testMsSegmentedTimeline() { // verify attributes set during object construction assertEquals(1, this.msTimeline.getSegmentSize()); assertEquals(0, this.msTimeline.getStartTime()); assertEquals(5, this.msTimeline.getSegmentsIncluded()); assertEquals(2, this.msTimeline.getSegmentsExcluded()); } /** * Tests that the new method that created the ms2Timeline segmented * timeline did so correctly. */ public void testMs2SegmentedTimeline() { // verify attributes set during object construction assertEquals(1, this.ms2Timeline.getSegmentSize()); assertEquals(1, this.ms2Timeline.getStartTime()); assertEquals(2, this.ms2Timeline.getSegmentsIncluded()); assertEquals(2, this.ms2Timeline.getSegmentsExcluded()); assertEquals(this.ms2BaseTimeline, this.ms2Timeline.getBaseTimeline()); } /** * Tests that the factory method that creates Monday through Friday * segmented timeline does so correctly. */ public void testMondayThroughFridaySegmentedTimeline() { // verify attributes set during object construction assertEquals(SegmentedTimeline.DAY_SEGMENT_SIZE, this.mondayFridayTimeline.getSegmentSize()); assertEquals(SegmentedTimeline.FIRST_MONDAY_AFTER_1900, this.mondayFridayTimeline.getStartTime()); assertEquals(5, this.mondayFridayTimeline.getSegmentsIncluded()); assertEquals(2, this.mondayFridayTimeline.getSegmentsExcluded()); } /** * Tests that the factory method that creates a 15-min 9:00 AM 4:00 PM * segmented axis does so correctly. */ public void testFifteenMinSegmentedTimeline() { assertEquals(SegmentedTimeline.FIFTEEN_MINUTE_SEGMENT_SIZE, this.fifteenMinTimeline.getSegmentSize()); assertEquals(SegmentedTimeline.FIRST_MONDAY_AFTER_1900 + 36 * this.fifteenMinTimeline.getSegmentSize(), this.fifteenMinTimeline.getStartTime()); assertEquals(28, this.fifteenMinTimeline.getSegmentsIncluded()); assertEquals(68, this.fifteenMinTimeline.getSegmentsExcluded()); } ////////////////////////////////////////////////////////////////////////// // test one-segment and adjacent segments ////////////////////////////////////////////////////////////////////////// /** * Tests one segment of the ms timeline. Internal indices * inside one segment as well as adjacent segments are verified. */ public void testMsSegment() { verifyOneSegment(this.msTimeline); } /** * Tests one segment of the ms timeline. Internal indices * inside one segment as well as adjacent segments are verified. */ public void testMs2Segment() { verifyOneSegment(this.ms2Timeline); } /** * Tests one segment of the Monday through Friday timeline. Internal indices * inside one segment as well as adjacent segments are verified. */ public void testMondayThroughFridaySegment() { verifyOneSegment(this.mondayFridayTimeline); } /** * Tests one segment of the Fifteen timeline. Internal indices * inside one segment as well as adjacent segments are verified. */ public void testFifteenMinSegment() { verifyOneSegment(this.fifteenMinTimeline); } /** * Tests one segment of the Monday through Friday timeline. Internal indices * inside one segment as well as adjacent segments are verified. * @param timeline the timeline to use for verifications. */ public void verifyOneSegment(SegmentedTimeline timeline) { for (long testCycle = TEST_CYCLE_START; testCycle < TEST_CYCLE_END; testCycle += TEST_CYCLE_INC) { // get two consecutive segments for various tests SegmentedTimeline.Segment segment1 = timeline.getSegment( this.monday.getTime().getTime() + testCycle); SegmentedTimeline.Segment segment2 = timeline.getSegment( segment1.getSegmentEnd() + 1); // verify segments are consecutive and correct assertEquals(segment1.getSegmentNumber() + 1, segment2.getSegmentNumber()); assertEquals(segment1.getSegmentEnd() + 1, segment2.getSegmentStart()); assertEquals(segment1.getSegmentStart() + timeline.getSegmentSize() - 1, segment1.getSegmentEnd()); assertEquals(segment1.getSegmentStart() + timeline.getSegmentSize(), segment2.getSegmentStart()); assertEquals(segment1.getSegmentEnd() + timeline.getSegmentSize(), segment2.getSegmentEnd()); // verify various indices inside a segment are the same segment long delta; if (timeline.getSegmentSize() > 1000000) { delta = timeline.getSegmentSize() / 10000; } else if (timeline.getSegmentSize() > 100000) { delta = timeline.getSegmentSize() / 1000; } else if (timeline.getSegmentSize() > 10000) { delta = timeline.getSegmentSize() / 100; } else if (timeline.getSegmentSize() > 1000) { delta = timeline.getSegmentSize() / 10; } else if (timeline.getSegmentSize() > 100) { delta = timeline.getSegmentSize() / 5; } else { delta = 1; } long start = segment1.getSegmentStart() + delta; long end = segment1.getSegmentStart() + timeline.getSegmentSize() - 1; SegmentedTimeline.Segment lastSeg = timeline.getSegment( segment1.getSegmentStart()); SegmentedTimeline.Segment seg; for (long i = start; i < end; i += delta) { seg = timeline.getSegment(i); assertEquals(lastSeg.getSegmentNumber(), seg.getSegmentNumber()); assertEquals(lastSeg.getSegmentStart(), seg.getSegmentStart()); assertEquals(lastSeg.getSegmentEnd(), seg.getSegmentEnd()); assertTrue(lastSeg.getMillisecond() < seg.getMillisecond()); lastSeg = seg; } // try next segment seg = timeline.getSegment(end + 1); assertEquals(segment2.getSegmentNumber(), seg.getSegmentNumber()); assertEquals(segment2.getSegmentStart(), seg.getSegmentStart()); assertEquals(segment2.getSegmentEnd(), seg.getSegmentEnd()); } } ////////////////////////////////////////////////////////////////////////// // test inc methods ////////////////////////////////////////////////////////////////////////// /** * Tests the inc methods on the msTimeline. */ public void testMsInc() { verifyInc(this.msTimeline); } /** * Tests the inc methods on the msTimeline. */ public void testMs2Inc() { verifyInc(this.ms2Timeline); } /** * Tests the inc methods on the Monday through Friday timeline. */ public void testMondayThroughFridayInc() { verifyInc(this.mondayFridayTimeline); } /** * Tests the inc methods on the Fifteen minute timeline. */ public void testFifteenMinInc() { verifyInc(this.fifteenMinTimeline); } /** * Tests the inc methods. * @param timeline the timeline to use for verifications. */ public void verifyInc(SegmentedTimeline timeline) { for (long testCycle = TEST_CYCLE_START; testCycle < TEST_CYCLE_END; testCycle += TEST_CYCLE_INC) { long m = timeline.getSegmentSize(); SegmentedTimeline.Segment segment = timeline.getSegment(testCycle); SegmentedTimeline.Segment seg1 = segment.copy(); for (int i = 0; i < 1000; i++) { // test inc() method SegmentedTimeline.Segment seg2 = seg1.copy(); seg2.inc(); if ((seg1.getSegmentEnd() + 1) != seg2.getSegmentStart()) { // logically consecutive segments non-physically consecutive // (with non-contained time in between) assertTrue(!timeline.containsDomainRange( seg1.getSegmentEnd() + 1, seg2.getSegmentStart() - 1)); assertEquals(0, (seg2.getSegmentStart() - seg1.getSegmentStart()) % m); assertEquals(0, (seg2.getSegmentEnd() - seg1.getSegmentEnd()) % m); assertEquals(0, (seg2.getMillisecond() - seg1.getMillisecond()) % m); } else { // physically consecutive assertEquals(seg1.getSegmentStart() + m, seg2.getSegmentStart()); assertEquals(seg1.getSegmentEnd() + m, seg2.getSegmentEnd()); assertEquals(seg1.getMillisecond() + m, seg2.getMillisecond()); } // test inc(n) method SegmentedTimeline.Segment seg3 = seg1.copy(); SegmentedTimeline.Segment seg4 = seg1.copy(); for (int j = 0; j < i; j++) { seg3.inc(); } seg4.inc(i); assertEquals(seg3.getSegmentStart(), seg4.getSegmentStart()); assertEquals(seg3.getSegmentEnd(), seg4.getSegmentEnd()); assertEquals(seg3.getMillisecond(), seg4.getMillisecond()); // go to another segment to continue test seg1.inc(); } } } ////////////////////////////////////////////////////////////////////////// // main include and excluded segments ////////////////////////////////////////////////////////////////////////// /** * Tests that the msTimeline's included and excluded * segments are being calculated correctly. */ public void testMsIncludedAndExcludedSegments() { verifyIncludedAndExcludedSegments(this.msTimeline, 0); } /** * Tests that the ms2Timeline's included and excluded * segments are being calculated correctly. */ public void testMs2IncludedAndExcludedSegments() { verifyIncludedAndExcludedSegments(this.ms2Timeline, 1); } /** * Tests that the Monday through Friday timeline's included and excluded * segments are being calculated correctly. The test is performed starting * on the first monday after 1/1/2000 and for five years. */ public void testMondayThroughFridayIncludedAndExcludedSegments() { verifyIncludedAndExcludedSegments(this.mondayFridayTimeline, this.monday.getTime().getTime()); } /** * Tests that the Fifteen-Min timeline's included and excluded * segments are being calculated correctly. The test is performed starting * on the first monday after 1/1/2000 and for five years. */ public void testFifteenMinIncludedAndExcludedSegments() { verifyIncludedAndExcludedSegments(this.fifteenMinTimeline, this.monday9am.getTime().getTime()); } /** * Tests that a timeline's included and excluded segments are being * calculated correctly. * * @param timeline the timeline to verify * @param n the first segment number to start verifying */ public void verifyIncludedAndExcludedSegments(SegmentedTimeline timeline, long n) { // clear any exceptions in this timeline timeline.setExceptionSegments(new java.util.ArrayList()); // test some included and excluded segments SegmentedTimeline.Segment segment = timeline.getSegment(n); for (int i = 0; i < 1000; i++) { int d = (i % timeline.getGroupSegmentCount()); if (d < timeline.getSegmentsIncluded()) { // should be an included segment assertTrue(segment.inIncludeSegments()); assertTrue(!segment.inExcludeSegments()); assertTrue(!segment.inExceptionSegments()); } else { // should be an excluded segment assertTrue(!segment.inIncludeSegments()); assertTrue(segment.inExcludeSegments()); assertTrue(!segment.inExceptionSegments()); } segment.inc(); } } ////////////////////////////////////////////////////////////////////////// // test exception segments ////////////////////////////////////////////////////////////////////////// /** * Tests methods related to exceptions methods in the msTimeline. * * @throws ParseException if there is a parsing error. */ public void testMsExceptionSegments() throws ParseException { verifyExceptionSegments(this.msTimeline, MS_EXCEPTIONS, NUMBER_FORMAT); } /** * Tests methods related to exceptions methods in the ms2BaseTimeline. * * @throws ParseException if there is a parsing error. */ public void testMs2BaseTimelineExceptionSegments() throws ParseException { verifyExceptionSegments(this.ms2BaseTimeline, MS2_BASE_TIMELINE_EXCEPTIONS, NUMBER_FORMAT); } /** * Tests methods related to exceptions methods in the mondayFridayTimeline. * * @throws ParseException if there is a parsing error. */ public void testMondayThoughFridayExceptionSegments() throws ParseException { verifyExceptionSegments(this.mondayFridayTimeline, US_HOLIDAYS, DATE_FORMAT); } /** * Tests methods related to exceptions methods in the fifteenMinTimeline. * * @throws ParseException if there is a parsing error. */ public void testFifteenMinExceptionSegments() throws ParseException { verifyExceptionSegments(this.fifteenMinTimeline, FIFTEEN_MIN_EXCEPTIONS, DATE_TIME_FORMAT); } /** * Tests methods related to adding exceptions. * * @param timeline the timeline to verify * @param exceptionString array of Strings that represent the exceptions * @param fmt Format object that can parse the exceptionString strings * * @throws ParseException if there is a parsing error. */ public void verifyExceptionSegments(SegmentedTimeline timeline, String[] exceptionString, Format fmt) throws ParseException { // fill in the exceptions long[] exception = verifyFillInExceptions(timeline, exceptionString, fmt); int m = exception.length; // verify list of exceptions assertEquals(exception.length, timeline.getExceptionSegments().size()); SegmentedTimeline.Segment lastSegment = timeline.getSegment( exception[m - 1]); for (int i = 0; i < m; i++) { SegmentedTimeline.Segment segment = timeline.getSegment( exception[i]); assertTrue(segment.inExceptionSegments()); // include current exception and last one assertEquals(m - i, timeline.getExceptionSegmentCount( segment.getSegmentStart(), lastSegment.getSegmentEnd())); // exclude current exception and last one assertEquals(Math.max(0, m - i - 2), timeline.getExceptionSegmentCount(exception[i] + 1, exception[m - 1] - 1)); } } ////////////////////////////////////////////////////////////////////////// // test timeline translations ////////////////////////////////////////////////////////////////////////// /** * Tests translations for 1-ms timeline * * @throws ParseException if there is a parsing error. */ public void testMsTranslations() throws ParseException { verifyFillInExceptions(this.msTimeline, MS_EXCEPTIONS, NUMBER_FORMAT); verifyTranslations(this.msTimeline, 0); } /** * Tests translations for the base timeline used for the ms2Timeline * * @throws ParseException if there is a parsing error. */ public void testMs2BaseTimelineTranslations() throws ParseException { verifyFillInExceptions(this.ms2BaseTimeline, MS2_BASE_TIMELINE_EXCEPTIONS, NUMBER_FORMAT); verifyTranslations(this.ms2BaseTimeline, 0); } /** * Tests translations for the Monday through Friday timeline * * @throws ParseException if there is a parsing error. */ public void testMs2Translations() throws ParseException { fillInBaseTimelineExceptions(this.ms2Timeline, MS2_BASE_TIMELINE_EXCEPTIONS, NUMBER_FORMAT); fillInBaseTimelineExclusionsAsExceptions(this.ms2Timeline, 0, 5000); verifyTranslations(this.ms2Timeline, 1); } /** * Tests translations for the Monday through Friday timeline * * @throws ParseException if there is a parsing error. */ public void textMondayThroughFridayTranslations() throws ParseException { verifyFillInExceptions(this.mondayFridayTimeline, US_HOLIDAYS, DATE_FORMAT); verifyTranslations(this.mondayFridayTimeline, this.monday.getTime().getTime()); } /** * Tests translations for the Fifteen Min timeline * * @throws ParseException if there is a parsing error. */ public void testFifteenMinTranslations() throws ParseException { verifyFillInExceptions(this.fifteenMinTimeline, FIFTEEN_MIN_EXCEPTIONS, DATE_TIME_FORMAT); fillInBaseTimelineExceptions(this.fifteenMinTimeline, US_HOLIDAYS, DATE_FORMAT); fillInBaseTimelineExclusionsAsExceptions(this.fifteenMinTimeline, this.monday9am.getTime().getTime(), this.monday9am.getTime().getTime() + FIVE_YEARS); verifyTranslations(this.fifteenMinTimeline, this.monday9am.getTime().getTime()); } /** * Tests translations between timelines. * * @param timeline the timeline to use for verifications. * @param startTest ??. */ public void verifyTranslations(SegmentedTimeline timeline, long startTest) { for (long testCycle = TEST_CYCLE_START; testCycle < TEST_CYCLE_END; testCycle += TEST_CYCLE_INC) { long millisecond = startTest + testCycle * timeline.getSegmentSize(); SegmentedTimeline.Segment segment = timeline.getSegment( millisecond); for (int i = 0; i < 1000; i++) { long translatedValue = timeline.toTimelineValue( segment.getMillisecond()); long newValue = timeline.toMillisecond(translatedValue); if (segment.inExcludeSegments() || segment.inExceptionSegments()) { // the reverse transformed value will be in the start of the // next non-excluded and non-exception segment SegmentedTimeline.Segment tempSegment = segment.copy(); tempSegment.moveIndexToStart(); do { tempSegment.inc(); } while (!tempSegment.inIncludeSegments()); assertEquals(tempSegment.getMillisecond(), newValue); } else { assertEquals(segment.getMillisecond(), newValue); } segment.inc(); } } } ////////////////////////////////////////////////////////////////////////// // test serialization ////////////////////////////////////////////////////////////////////////// /** * Serialize an instance, restore it, and check for equality. */ public void testSerialization() { verifySerialization(this.msTimeline); verifySerialization(this.ms2Timeline); verifySerialization(this.ms2BaseTimeline); verifySerialization(SegmentedTimeline.newMondayThroughFridayTimeline()); verifySerialization(SegmentedTimeline.newFifteenMinuteTimeline()); } /** * Tests serialization of an instance. * @param a1 The timeline to verify the serialization */ private void verifySerialization(SegmentedTimeline a1) { SegmentedTimeline a2 = null; try { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(buffer); out.writeObject(a1); out.close(); ObjectInput in = new ObjectInputStream( new ByteArrayInputStream(buffer.toByteArray())); a2 = (SegmentedTimeline) in.readObject(); in.close(); } catch (Exception e) { e.printStackTrace(); } assertEquals(a1, a2); } /** * Adds an array of exceptions to the timeline. The timeline exception list * is first cleared. * @param timeline The timeline where the exceptions will be stored * @param exceptionString The exceptions to load * @param fmt The date formatter to use to parse each exceptions[i] value * @throws ParseException If there is any exception parsing each * exceptions[i] value. * @return An array of Dates[] containing each exception date. */ private long[] verifyFillInExceptions(SegmentedTimeline timeline, String[] exceptionString, Format fmt) throws ParseException { // make sure there are no exceptions timeline.setExceptionSegments(new java.util.ArrayList()); assertEquals(0, timeline.getExceptionSegments().size()); // add our exceptions and store locally in ArrayList of Longs ArrayList exceptionList = new ArrayList(); for (int i = 0; i < exceptionString.length; i++) { long e; if (fmt instanceof NumberFormat) { e = ((NumberFormat) fmt).parse(exceptionString[i]).longValue(); } else { e = timeline.getTime(((SimpleDateFormat) fmt) .parse(exceptionString[i])); } // only add an exception if it is currently an included segment SegmentedTimeline.Segment segment = timeline.getSegment(e); if (segment.inIncludeSegments()) { timeline.addException(e); exceptionList.add(new Long(e)); assertEquals(exceptionList.size(), timeline.getExceptionSegments().size()); assertTrue(segment.inExceptionSegments()); } } // make array of exceptions long[] exception = new long[exceptionList.size()]; int i = 0; for (Iterator iter = exceptionList.iterator(); iter.hasNext();) { Long l = (Long) iter.next(); exception[i++] = l.longValue(); } return (exception); } /** * Adds an array of exceptions relative to the base timeline. * * @param timeline The timeline where the exceptions will be stored * @param exceptionString The exceptions to load * @param fmt The date formatter to use to parse each exceptions[i] value * @throws ParseException If there is any exception parsing each * exceptions[i] value. */ private void fillInBaseTimelineExceptions(SegmentedTimeline timeline, String[] exceptionString, Format fmt) throws ParseException { SegmentedTimeline baseTimeline = timeline.getBaseTimeline(); for (int i = 0; i < exceptionString.length; i++) { long e; if (fmt instanceof NumberFormat) { e = ((NumberFormat) fmt).parse(exceptionString[i]).longValue(); } else { e = timeline.getTime(((SimpleDateFormat) fmt) .parse(exceptionString[i])); } timeline.addBaseTimelineException(e); // verify all timeline segments included in the // baseTimeline.segment are now exceptions SegmentedTimeline.Segment segment1 = baseTimeline.getSegment(e); for (SegmentedTimeline.Segment segment2 = timeline.getSegment(segment1.getSegmentStart()); segment2.getSegmentStart() <= segment1.getSegmentEnd(); segment2.inc()) { if (!segment2.inExcludeSegments()) { assertTrue(segment2.inExceptionSegments()); } } } } /** * Adds new exceptions to a timeline. The exceptions are the excluded * segments from its base timeline. * * @param timeline the timeline. * @param from the start. * @param to the end. */ private void fillInBaseTimelineExclusionsAsExceptions( SegmentedTimeline timeline, long from, long to) { // add the base timeline exclusions as timeline's esceptions timeline.addBaseTimelineExclusions(from, to); // validate base timeline exclusions added as timeline's esceptions for (SegmentedTimeline.Segment segment1 = timeline.getBaseTimeline() .getSegment(from); segment1.getSegmentStart() <= to; segment1.inc()) { if (segment1.inExcludeSegments()) { // verify all timeline segments included in the // baseTimeline.segment are now exceptions for (SegmentedTimeline.Segment segment2 = timeline.getSegment( segment1.getSegmentStart()); segment2.getSegmentStart() <= segment1.getSegmentEnd(); segment2.inc()) { if (!segment2.inExcludeSegments()) { assertTrue(segment2.inExceptionSegments()); } } } } } /** * Confirm that cloning works. */ public void testCloning() { SegmentedTimeline l1 = new SegmentedTimeline(1000, 5, 2); SegmentedTimeline l2 = null; try { l2 = (SegmentedTimeline) l1.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } assertTrue(l1 != l2); assertTrue(l1.getClass() == l2.getClass()); assertTrue(l1.equals(l2)); } /** * Confirm that the equals method can distinguish all the required fields. */ public void testEquals() { SegmentedTimeline l1 = new SegmentedTimeline(1000, 5, 2); SegmentedTimeline l2 = new SegmentedTimeline(1000, 5, 2); assertTrue(l1.equals(l2)); l1 = new SegmentedTimeline(1000, 5, 2); l2 = new SegmentedTimeline(1001, 5, 2); assertFalse(l1.equals(l2)); l1 = new SegmentedTimeline(1000, 5, 2); l2 = new SegmentedTimeline(1000, 4, 2); assertFalse(l1.equals(l2)); l1 = new SegmentedTimeline(1000, 5, 2); l2 = new SegmentedTimeline(1000, 5, 1); assertFalse(l1.equals(l2)); l1 = new SegmentedTimeline(1000, 5, 2); l2 = new SegmentedTimeline(1000, 5, 2); // start time... l1.setStartTime(1234L); assertFalse(l1.equals(l2)); l2.setStartTime(1234L); assertTrue(l1.equals(l2)); } /** * Two objects that are equal are required to return the same hashCode. */ public void testHashCode() { SegmentedTimeline l1 = new SegmentedTimeline(1000, 5, 2); SegmentedTimeline l2 = new SegmentedTimeline(1000, 5, 2); assertTrue(l1.equals(l2)); int h1 = l1.hashCode(); int h2 = l2.hashCode(); assertEquals(h1, h2); } /** * Serialize an instance, restore it, and check for equality. */ public void testSerialization2() { SegmentedTimeline l1 = new SegmentedTimeline(1000, 5, 2); SegmentedTimeline l2 = null; try { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(buffer); out.writeObject(l1); out.close(); ObjectInput in = new ObjectInputStream( new ByteArrayInputStream(buffer.toByteArray())); l2 = (SegmentedTimeline) in.readObject(); in.close(); } catch (Exception e) { e.printStackTrace(); } boolean b = l1.equals(l2); assertTrue(b); } ////////////////////////////////////////////////////////////////////////// // utility methods ////////////////////////////////////////////////////////////////////////// /** * Tests a basic segmented timeline. */ public void testBasicSegmentedTimeline() { SegmentedTimeline stl = new SegmentedTimeline(10, 2, 3); stl.setStartTime(946684800000L); // 1-Jan-2000 assertFalse(stl.containsDomainValue(946684799999L)); assertTrue(stl.containsDomainValue(946684800000L)); assertTrue(stl.containsDomainValue(946684800019L)); assertFalse(stl.containsDomainValue(946684800020L)); assertFalse(stl.containsDomainValue(946684800049L)); assertTrue(stl.containsDomainValue(946684800050L)); assertTrue(stl.containsDomainValue(946684800069L)); assertFalse(stl.containsDomainValue(946684800070L)); assertFalse(stl.containsDomainValue(946684800099L)); assertTrue(stl.containsDomainValue(946684800100L)); assertEquals(0, stl.toTimelineValue(946684800000L)); assertEquals(19, stl.toTimelineValue(946684800019L)); assertEquals(20, stl.toTimelineValue(946684800020L)); assertEquals(20, stl.toTimelineValue(946684800049L)); assertEquals(20, stl.toTimelineValue(946684800050L)); assertEquals(39, stl.toTimelineValue(946684800069L)); assertEquals(40, stl.toTimelineValue(946684800070L)); assertEquals(40, stl.toTimelineValue(946684800099L)); assertEquals(40, stl.toTimelineValue(946684800100L)); assertEquals(946684800000L, stl.toMillisecond(0)); assertEquals(946684800019L, stl.toMillisecond(19)); assertEquals(946684800050L, stl.toMillisecond(20)); assertEquals(946684800069L, stl.toMillisecond(39)); assertEquals(946684800100L, stl.toMillisecond(40)); } /** * Tests a basic time line with one exception. */ public void testSegmentedTimelineWithException1() { SegmentedTimeline stl = new SegmentedTimeline(10, 2, 3); stl.setStartTime(946684800000L); // 1-Jan-2000 stl.addException(946684800050L); assertFalse(stl.containsDomainValue(946684799999L)); assertTrue(stl.containsDomainValue(946684800000L)); assertTrue(stl.containsDomainValue(946684800019L)); assertFalse(stl.containsDomainValue(946684800020L)); assertFalse(stl.containsDomainValue(946684800049L)); assertFalse(stl.containsDomainValue(946684800050L)); assertFalse(stl.containsDomainValue(946684800059L)); assertTrue(stl.containsDomainValue(946684800060L)); assertTrue(stl.containsDomainValue(946684800069L)); assertFalse(stl.containsDomainValue(946684800070L)); assertFalse(stl.containsDomainValue(946684800099L)); assertTrue(stl.containsDomainValue(946684800100L)); //long v = stl.toTimelineValue(946684800020L); assertEquals(0, stl.toTimelineValue(946684800000L)); assertEquals(19, stl.toTimelineValue(946684800019L)); assertEquals(20, stl.toTimelineValue(946684800020L)); assertEquals(20, stl.toTimelineValue(946684800049L)); assertEquals(20, stl.toTimelineValue(946684800050L)); assertEquals(29, stl.toTimelineValue(946684800069L)); assertEquals(30, stl.toTimelineValue(946684800070L)); assertEquals(30, stl.toTimelineValue(946684800099L)); assertEquals(30, stl.toTimelineValue(946684800100L)); assertEquals(946684800000L, stl.toMillisecond(0)); assertEquals(946684800019L, stl.toMillisecond(19)); assertEquals(946684800060L, stl.toMillisecond(20)); assertEquals(946684800069L, stl.toMillisecond(29)); assertEquals(946684800100L, stl.toMillisecond(30)); } ////////////////////////////////////////////////////////////////////////// // main method only for debug ////////////////////////////////////////////////////////////////////////// /** * Only use to debug JUnit suite. * * @param args ignored. * * @throws Exception if there is some problem. */ public static void main(String[] args) throws Exception { SegmentedTimelineTests test = new SegmentedTimelineTests("Test"); test.setUp(); test.testMondayThoughFridayExceptionSegments(); test.tearDown(); } }