| 1 42 43 package org.jfree.chart.axis.junit; 44 45 import java.io.ByteArrayInputStream ; 46 import java.io.ByteArrayOutputStream ; 47 import java.io.ObjectInput ; 48 import java.io.ObjectInputStream ; 49 import java.io.ObjectOutput ; 50 import java.io.ObjectOutputStream ; 51 import java.text.Format ; 52 import java.text.NumberFormat ; 53 import java.text.ParseException ; 54 import java.text.SimpleDateFormat ; 55 import java.util.ArrayList ; 56 import java.util.Calendar ; 57 import java.util.GregorianCalendar ; 58 import java.util.Iterator ; 59 60 import junit.framework.Test; 61 import junit.framework.TestCase; 62 import junit.framework.TestSuite; 63 64 import org.jfree.chart.axis.SegmentedTimeline; 65 66 71 public class SegmentedTimelineTests extends TestCase { 72 73 74 private static final int TEST_CYCLE_START = 0; 75 76 77 private static final int TEST_CYCLE_END = 1000; 78 79 80 private static final int TEST_CYCLE_INC = 55; 81 82 83 private static final long FIVE_YEARS 84 = 5 * 365 * SegmentedTimeline.DAY_SEGMENT_SIZE; 85 86 87 private static final NumberFormat NUMBER_FORMAT 88 = NumberFormat.getNumberInstance(); 89 90 91 private static final SimpleDateFormat DATE_FORMAT; 92 93 94 private static final SimpleDateFormat DATE_TIME_FORMAT; 95 96 97 private static final String [] MS_EXCEPTIONS = 98 {"0", "2", "4", "10", "15", "16", "17", "18", "19", "20", "21", "22", 99 "23", "24", "47", "58", "100", "101"}; 100 101 102 private static final String [] MS2_BASE_TIMELINE_EXCEPTIONS = 103 {"0", "8", "16", "24", "32", "40", "48", "56", "64", "72", "80", "88", 104 "96", "104", "112", "120", "128", "136"}; 105 106 107 private static final String [] US_HOLIDAYS = 108 {"2000-01-17", "2000-02-21", "2000-04-21", "2000-05-29", "2000-07-04", 109 "2000-09-04", "2000-11-23", "2000-12-25", "2001-01-01", "2001-01-15", 110 "2001-02-19", "2001-04-13", "2001-05-28", "2001-07-04", "2001-09-03", 111 "2001-09-11", "2001-09-12", "2001-09-13", "2001-09-14", "2001-11-22", 112 "2001-12-25", "2002-01-01", "2002-01-21", "2002-02-18", "2002-03-29", 113 "2002-05-27", "2002-07-04", "2002-09-02", "2002-11-28", "2002-12-25"}; 114 115 116 private static final String [] FIFTEEN_MIN_EXCEPTIONS = 117 {"2000-01-10 09:00:00", "2000-01-10 09:15:00", "2000-01-10 09:30:00", 118 "2000-01-10 09:45:00", "2000-01-10 10:00:00", "2000-01-10 10:15:00", 119 "2000-02-15 09:00:00", "2000-02-15 09:15:00", "2000-02-15 09:30:00", 120 "2000-02-15 09:45:00", "2000-02-15 10:00:00", "2000-02-15 10:15:00", 121 "2000-02-16 11:00:00", "2000-02-16 11:15:00", "2000-02-16 11:30:00", 122 "2000-02-16 11:45:00", "2000-02-16 12:00:00", "2000-02-16 12:15:00", 123 "2000-02-16 12:30:00", "2000-02-16 12:45:00", "2000-02-16 01:00:00", 124 "2000-02-16 01:15:00", "2000-02-16 01:30:00", "2000-02-16 01:45:00", 125 "2000-05-17 11:45:00", "2000-05-17 12:00:00", "2000-05-17 12:15:00", 126 "2000-05-17 12:30:00", "2000-05-17 12:45:00", "2000-05-17 01:00:00", 127 "2000-05-17 01:15:00", "2000-05-17 01:30:00", "2000-05-17 01:45:00", 128 "2000-05-17 02:00:00", "2000-05-17 02:15:00", "2000-05-17 02:30:00", 129 "2000-05-17 02:45:00", "2000-05-17 03:00:00", "2000-05-17 03:15:00", 130 "2000-05-17 03:30:00", "2000-05-17 03:45:00", "2000-05-17 04:00:00"}; 131 132 133 private SegmentedTimeline msTimeline; 134 135 139 private SegmentedTimeline ms2Timeline; 140 141 145 private SegmentedTimeline ms2BaseTimeline; 146 147 148 private SegmentedTimeline mondayFridayTimeline; 149 150 151 private SegmentedTimeline fifteenMinTimeline; 152 153 154 private Calendar monday; 155 156 157 private Calendar monday9am; 158 159 160 static { 161 DATE_FORMAT = new SimpleDateFormat ("yyyy-MM-dd"); 162 DATE_FORMAT.setTimeZone(SegmentedTimeline.NO_DST_TIME_ZONE); 163 164 DATE_TIME_FORMAT = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); 165 DATE_TIME_FORMAT.setTimeZone(SegmentedTimeline.NO_DST_TIME_ZONE); 166 } 167 168 173 public static Test suite() { 174 return new TestSuite(SegmentedTimelineTests.class); 175 } 176 177 182 public SegmentedTimelineTests(String name) { 183 super(name); 184 } 185 186 192 protected void setUp() throws Exception { 193 200 this.msTimeline = new SegmentedTimeline(1, 5, 2); 214 this.msTimeline.setStartTime(0); 215 216 this.ms2BaseTimeline = new SegmentedTimeline(4, 1, 1); 231 this.ms2BaseTimeline.setStartTime(0); 232 233 this.ms2Timeline = new SegmentedTimeline(1, 2, 2); 260 this.ms2Timeline.setStartTime(1); 261 this.ms2Timeline.setBaseTimeline(this.ms2BaseTimeline); 262 263 this.mondayFridayTimeline 265 = SegmentedTimeline.newMondayThroughFridayTimeline(); 266 267 this.fifteenMinTimeline 269 = SegmentedTimeline.newFifteenMinuteTimeline(); 270 271 Calendar cal = new GregorianCalendar ( 273 SegmentedTimeline.NO_DST_TIME_ZONE 274 ); 275 cal.set(2001, 0, 1, 0, 0, 0); 276 cal.set(Calendar.MILLISECOND, 0); 277 while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { 278 cal.add(Calendar.DATE, 1); 279 } 280 this.monday = (Calendar ) cal.clone(); 281 282 cal.add(Calendar.HOUR, 9); 284 this.monday9am = (Calendar ) cal.clone(); 285 } 286 287 293 protected void tearDown() throws Exception { 294 } 296 297 301 305 public void testMsSegmentedTimeline() { 306 assertEquals(1, this.msTimeline.getSegmentSize()); 308 assertEquals(0, this.msTimeline.getStartTime()); 309 assertEquals(5, this.msTimeline.getSegmentsIncluded()); 310 assertEquals(2, this.msTimeline.getSegmentsExcluded()); 311 } 312 313 317 public void testMs2SegmentedTimeline() { 318 assertEquals(1, this.ms2Timeline.getSegmentSize()); 320 assertEquals(1, this.ms2Timeline.getStartTime()); 321 assertEquals(2, this.ms2Timeline.getSegmentsIncluded()); 322 assertEquals(2, this.ms2Timeline.getSegmentsExcluded()); 323 assertEquals(this.ms2BaseTimeline, this.ms2Timeline.getBaseTimeline()); 324 } 325 326 330 public void testMondayThroughFridaySegmentedTimeline() { 331 assertEquals( 333 SegmentedTimeline.DAY_SEGMENT_SIZE, 334 this.mondayFridayTimeline.getSegmentSize() 335 ); 336 assertEquals( 337 SegmentedTimeline.FIRST_MONDAY_AFTER_1900, 338 this.mondayFridayTimeline.getStartTime() 339 ); 340 assertEquals(5, this.mondayFridayTimeline.getSegmentsIncluded()); 341 assertEquals(2, this.mondayFridayTimeline.getSegmentsExcluded()); 342 } 343 344 348 public void testFifteenMinSegmentedTimeline() { 349 assertEquals(SegmentedTimeline.FIFTEEN_MINUTE_SEGMENT_SIZE, 350 this.fifteenMinTimeline.getSegmentSize()); 351 assertEquals(SegmentedTimeline.FIRST_MONDAY_AFTER_1900 + 36 352 * this.fifteenMinTimeline.getSegmentSize(), 353 this.fifteenMinTimeline.getStartTime()); 354 assertEquals(28, this.fifteenMinTimeline.getSegmentsIncluded()); 355 assertEquals(68, this.fifteenMinTimeline.getSegmentsExcluded()); 356 } 357 358 362 366 public void testMsSegment() { 367 verifyOneSegment(this.msTimeline); 368 } 369 370 374 public void testMs2Segment() { 375 verifyOneSegment(this.ms2Timeline); 376 } 377 378 382 public void testMondayThroughFridaySegment() { 383 verifyOneSegment(this.mondayFridayTimeline); 384 } 385 386 390 public void testFifteenMinSegment() { 391 verifyOneSegment(this.fifteenMinTimeline); 392 } 393 394 399 public void verifyOneSegment(SegmentedTimeline timeline) { 400 401 for (long testCycle = TEST_CYCLE_START; testCycle < TEST_CYCLE_END; 402 testCycle += TEST_CYCLE_INC) { 403 404 SegmentedTimeline.Segment segment1 = timeline.getSegment( 406 this.monday.getTime().getTime() + testCycle 407 ); 408 SegmentedTimeline.Segment segment2 = 409 timeline.getSegment(segment1.getSegmentEnd() + 1); 410 411 assertEquals( 413 segment1.getSegmentNumber() + 1, segment2.getSegmentNumber() 414 ); 415 assertEquals( 416 segment1.getSegmentEnd() + 1, segment2.getSegmentStart() 417 ); 418 assertEquals( 419 segment1.getSegmentStart() + timeline.getSegmentSize() - 1, 420 segment1.getSegmentEnd() 421 ); 422 assertEquals( 423 segment1.getSegmentStart() + timeline.getSegmentSize(), 424 segment2.getSegmentStart() 425 ); 426 assertEquals( 427 segment1.getSegmentEnd() + timeline.getSegmentSize(), 428 segment2.getSegmentEnd() 429 ); 430 431 long delta; 433 if (timeline.getSegmentSize() > 1000000) { 434 delta = timeline.getSegmentSize() / 10000; 435 } 436 else if (timeline.getSegmentSize() > 100000) { 437 delta = timeline.getSegmentSize() / 1000; 438 } 439 else if (timeline.getSegmentSize() > 10000) { 440 delta = timeline.getSegmentSize() / 100; 441 } 442 else if (timeline.getSegmentSize() > 1000) { 443 delta = timeline.getSegmentSize() / 10; 444 } 445 else if (timeline.getSegmentSize() > 100) { 446 delta = timeline.getSegmentSize() / 5; 447 } 448 else { 449 delta = 1; 450 } 451 452 long start = segment1.getSegmentStart() + delta; 453 long end = segment1.getSegmentStart() 454 + timeline.getSegmentSize() - 1; 455 SegmentedTimeline.Segment lastSeg = timeline.getSegment( 456 segment1.getSegmentStart() 457 ); 458 SegmentedTimeline.Segment seg; 459 for (long i = start; i < end; i += delta) { 460 seg = timeline.getSegment(i); 461 assertEquals( 462 lastSeg.getSegmentNumber(), seg.getSegmentNumber() 463 ); 464 assertEquals(lastSeg.getSegmentStart(), seg.getSegmentStart()); 465 assertEquals(lastSeg.getSegmentEnd(), seg.getSegmentEnd()); 466 assertTrue(lastSeg.getMillisecond() < seg.getMillisecond()); 467 lastSeg = seg; 468 } 469 470 seg = timeline.getSegment(end + 1); 472 assertEquals(segment2.getSegmentNumber(), seg.getSegmentNumber()); 473 assertEquals(segment2.getSegmentStart(), seg.getSegmentStart()); 474 assertEquals(segment2.getSegmentEnd(), seg.getSegmentEnd()); 475 } 476 } 477 478 482 485 public void testMsInc() { 486 verifyInc(this.msTimeline); 487 } 488 489 492 public void testMs2Inc() { 493 verifyInc(this.ms2Timeline); 494 } 495 496 499 public void testMondayThroughFridayInc() { 500 verifyInc(this.mondayFridayTimeline); 501 } 502 503 506 public void testFifteenMinInc() { 507 verifyInc(this.fifteenMinTimeline); 508 } 509 510 514 public void verifyInc(SegmentedTimeline timeline) { 515 for (long testCycle = TEST_CYCLE_START; testCycle < TEST_CYCLE_END; 516 testCycle += TEST_CYCLE_INC) { 517 518 long m = timeline.getSegmentSize(); 519 SegmentedTimeline.Segment segment = timeline.getSegment(testCycle); 520 SegmentedTimeline.Segment seg1 = segment.copy(); 521 for (int i = 0; i < 1000; i++) { 522 523 SegmentedTimeline.Segment seg2 = seg1.copy(); 525 seg2.inc(); 526 527 if ((seg1.getSegmentEnd() + 1) != seg2.getSegmentStart()) { 528 assertTrue( 531 !timeline.containsDomainRange( 532 seg1.getSegmentEnd() + 1, seg2.getSegmentStart() - 1 533 ) 534 ); 535 assertEquals( 536 0, (seg2.getSegmentStart() - seg1.getSegmentStart()) % m 537 ); 538 assertEquals( 539 0, (seg2.getSegmentEnd() - seg1.getSegmentEnd()) % m 540 ); 541 assertEquals( 542 0, (seg2.getMillisecond() - seg1.getMillisecond()) % m 543 ); 544 } 545 else { 546 assertEquals( 548 seg1.getSegmentStart() + m, seg2.getSegmentStart() 549 ); 550 assertEquals( 551 seg1.getSegmentEnd() + m, seg2.getSegmentEnd() 552 ); 553 assertEquals( 554 seg1.getMillisecond() + m, seg2.getMillisecond() 555 ); 556 } 557 558 SegmentedTimeline.Segment seg3 = seg1.copy(); 560 SegmentedTimeline.Segment seg4 = seg1.copy(); 561 562 for (int j = 0; j < i; j++) { 563 seg3.inc(); 564 } 565 seg4.inc(i); 566 567 assertEquals(seg3.getSegmentStart(), seg4.getSegmentStart()); 568 assertEquals(seg3.getSegmentEnd(), seg4.getSegmentEnd()); 569 assertEquals(seg3.getMillisecond(), seg4.getMillisecond()); 570 571 seg1.inc(); 573 } 574 } 575 } 576 577 581 585 public void testMsIncludedAndExcludedSegments() { 586 verifyIncludedAndExcludedSegments(this.msTimeline, 0); 587 } 588 589 593 public void testMs2IncludedAndExcludedSegments() { 594 verifyIncludedAndExcludedSegments(this.ms2Timeline, 1); 595 } 596 597 602 public void testMondayThroughFridayIncludedAndExcludedSegments() { 603 verifyIncludedAndExcludedSegments( 604 this.mondayFridayTimeline, this.monday.getTime().getTime() 605 ); 606 } 607 608 613 public void testFifteenMinIncludedAndExcludedSegments() { 614 verifyIncludedAndExcludedSegments( 615 this.fifteenMinTimeline, this.monday9am.getTime().getTime() 616 ); 617 } 618 619 626 public void verifyIncludedAndExcludedSegments(SegmentedTimeline timeline, 627 long n) { 628 timeline.setExceptionSegments(new java.util.ArrayList ()); 630 631 SegmentedTimeline.Segment segment = timeline.getSegment(n); 633 for (int i = 0; i < 1000; i++) { 634 int d = (i % timeline.getGroupSegmentCount()); 635 if (d < timeline.getSegmentsIncluded()) { 636 assertTrue(segment.inIncludeSegments()); 638 assertTrue(!segment.inExcludeSegments()); 639 assertTrue(!segment.inExceptionSegments()); 640 } 641 else { 642 assertTrue(!segment.inIncludeSegments()); 644 assertTrue(segment.inExcludeSegments()); 645 assertTrue(!segment.inExceptionSegments()); 646 } 647 segment.inc(); 648 } 649 } 650 651 655 660 public void testMsExceptionSegments() throws ParseException { 661 verifyExceptionSegments(this.msTimeline, MS_EXCEPTIONS, NUMBER_FORMAT); 662 } 663 664 669 public void testMs2BaseTimelineExceptionSegments() throws ParseException { 670 verifyExceptionSegments( 671 this.ms2BaseTimeline, MS2_BASE_TIMELINE_EXCEPTIONS, NUMBER_FORMAT 672 ); 673 } 674 675 680 public void testMondayThoughFridayExceptionSegments() 681 throws ParseException { 682 verifyExceptionSegments( 683 this.mondayFridayTimeline, US_HOLIDAYS, DATE_FORMAT 684 ); 685 } 686 687 692 public void testFifteenMinExceptionSegments() throws ParseException { 693 verifyExceptionSegments( 694 this.fifteenMinTimeline, FIFTEEN_MIN_EXCEPTIONS, DATE_TIME_FORMAT 695 ); 696 } 697 698 707 public void verifyExceptionSegments(SegmentedTimeline timeline, 708 String [] exceptionString, 709 Format fmt) 710 throws ParseException { 711 712 long[] exception = verifyFillInExceptions( 714 timeline, exceptionString, fmt 715 ); 716 717 int m = exception.length; 718 719 assertEquals(exception.length, timeline.getExceptionSegments().size()); 721 SegmentedTimeline.Segment lastSegment 722 = timeline.getSegment(exception[m - 1]); 723 for (int i = 0; i < m; i++) { 724 SegmentedTimeline.Segment segment 725 = timeline.getSegment(exception[i]); 726 assertTrue(segment.inExceptionSegments()); 727 assertEquals(m - i, timeline.getExceptionSegmentCount( 729 segment.getSegmentStart(), lastSegment.getSegmentEnd())); 730 assertEquals( 732 Math.max(0, m - i - 2), timeline.getExceptionSegmentCount( 733 exception[i] + 1, exception[m - 1] - 1) 734 ); 735 } 736 737 } 738 739 743 748 public void testMsTranslations() throws ParseException { 749 verifyFillInExceptions(this.msTimeline, MS_EXCEPTIONS, NUMBER_FORMAT); 750 verifyTranslations(this.msTimeline, 0); 751 } 752 753 758 public void testMs2BaseTimelineTranslations() throws ParseException { 759 verifyFillInExceptions( 760 this.ms2BaseTimeline, MS2_BASE_TIMELINE_EXCEPTIONS, NUMBER_FORMAT 761 ); 762 verifyTranslations(this.ms2BaseTimeline, 0); 763 } 764 765 770 public void testMs2Translations() throws ParseException { 771 fillInBaseTimelineExceptions( 772 this.ms2Timeline, MS2_BASE_TIMELINE_EXCEPTIONS, NUMBER_FORMAT 773 ); 774 fillInBaseTimelineExclusionsAsExceptions(this.ms2Timeline, 0, 5000); 775 verifyTranslations(this.ms2Timeline, 1); 776 } 777 778 783 public void testMondayThroughFridayTranslations() throws ParseException { 784 verifyFillInExceptions( 785 this.mondayFridayTimeline, US_HOLIDAYS, DATE_FORMAT 786 ); 787 verifyTranslations( 788 this.mondayFridayTimeline, this.monday.getTime().getTime() 789 ); 790 } 791 792 797 public void testFifteenMinTranslations() throws ParseException { 798 verifyFillInExceptions( 799 this.fifteenMinTimeline, FIFTEEN_MIN_EXCEPTIONS, DATE_TIME_FORMAT 800 ); 801 fillInBaseTimelineExceptions( 802 this.fifteenMinTimeline, US_HOLIDAYS, DATE_FORMAT 803 ); 804 fillInBaseTimelineExclusionsAsExceptions( 805 this.fifteenMinTimeline, 806 this.monday9am.getTime().getTime(), 807 this.monday9am.getTime().getTime() + FIVE_YEARS 808 ); 809 verifyTranslations( 810 this.fifteenMinTimeline, this.monday9am.getTime().getTime() 811 ); 812 } 813 814 820 public void verifyTranslations(SegmentedTimeline timeline, long startTest) { 821 for (long testCycle = TEST_CYCLE_START; testCycle < TEST_CYCLE_END; 822 testCycle += TEST_CYCLE_INC) { 823 824 long millisecond = startTest + testCycle 825 * timeline.getSegmentSize(); 826 SegmentedTimeline.Segment segment 827 = timeline.getSegment(millisecond); 828 829 for (int i = 0; i < 1000; i++) { 830 long translatedValue 831 = timeline.toTimelineValue(segment.getMillisecond()); 832 long newValue = timeline.toMillisecond(translatedValue); 833 834 if (segment.inExcludeSegments() 835 || segment.inExceptionSegments()) { 836 SegmentedTimeline.Segment tempSegment = segment.copy(); 839 tempSegment.moveIndexToStart(); 840 do { 841 tempSegment.inc(); 842 } 843 while (!tempSegment.inIncludeSegments()); 844 assertEquals(tempSegment.getMillisecond(), newValue); 845 } 846 847 else { 848 assertEquals(segment.getMillisecond(), newValue); 849 } |