#!/usr/bin/perl -w use strict; use Test::More; plan tests => 53; use DateTime; use DateTime::Duration; use DateTime::Set; use DateTime::SpanSet; # use warnings; use constant INFINITY => DateTime::INFINITY; use constant NEG_INFINITY => DateTime::NEG_INFINITY; sub str { if ( ref($_[0]) ) { return $_[0]->datetime if $_[0]->is_finite; return INFINITY if $_[0]->isa( "DateTime::Infinite::Future" ); return NEG_INFINITY; } return $_[0]; } sub span_str { eval { str($_[0]->min) . '..' . str($_[0]->max) } } #====================================================================== # SPANSET TESTS #====================================================================== { my $start1 = new DateTime( year => '1810', month => '9', day => '20' ); my $end1 = new DateTime( year => '1811', month => '10', day => '21' ); my $start2 = new DateTime( year => '1812', month => '11', day => '22' ); my $end2 = new DateTime( year => '1813', month => '12', day => '23' ); my $start_set = DateTime::Set->from_datetimes( dates => [ $start1, $start2 ] ); my $end_set = DateTime::Set->from_datetimes( dates => [ $end1, $end2 ] ); my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $end_set ); my $iter = $s1->iterator; my $res = span_str( $iter->next ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1812-11-22T00:00:00..1813-12-23T00:00:00', "got $res" ); # reverse with start/end dates $s1 = DateTime::SpanSet->from_sets( start_set => $end_set, end_set => $start_set ); $iter = $s1->iterator; $res = span_str( $iter->next ); is( $res, NEG_INFINITY.'..1810-09-20T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1811-10-21T00:00:00..1812-11-22T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1813-12-23T00:00:00..'.INFINITY, "got $res" ); # as_list my @spans = $s1->as_list; isa_ok ( $spans[0], 'DateTime::Span' ); $res = span_str( $spans[0] ); is( $res, NEG_INFINITY.'..1810-09-20T00:00:00', "as_list got $res" ); # intersected_spans my $intersected = $s1->intersected_spans( $end1 ); $res = span_str( $intersected ); # diag "intersected with ". span_str( $s1 ); is( $res, $end1->datetime .'..'.$start2->datetime, "intersected got $res" ); { # next( $dt ) my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $end_set ); my $dt = new DateTime( year => '1809', month => '8', day => '19' ); my $next = $s1->next( $dt ); $res = span_str( $next ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "next dt got $res" ); is( $next->end_is_open, 1, 'end is open' ); is( $next->start_is_open, 0, 'start is closed' ); # next( $span ) $next = $s1->next( $next ); $res = span_str( $next ); is( $res, '1812-11-22T00:00:00..1813-12-23T00:00:00', "next span got $res" ); is( $next->end_is_open, 1, 'end is open' ); is( $next->start_is_open, 0, 'start is closed' ); } { # previous( $dt ) my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $end_set ); my $dt = new DateTime( year => '1812', month => '11', day => '25' ); my $previous = $s1->previous( $dt ); $res = span_str( $previous ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "previous dt got $res" ); my $current = $s1->current( $dt ); $res = span_str( $current ); is( $res, '1812-11-22T00:00:00..1813-12-23T00:00:00', "current dt got $res" ); my $closest = $s1->closest( $dt ); $res = span_str( $closest ); is( $res, '1812-11-22T00:00:00..1813-12-23T00:00:00', "closest dt got $res" ); $dt = new DateTime( year => '1812', month => '11', day => '20' ); $closest = $s1->closest( $dt ); $res = span_str( $closest ); is( $res, '1812-11-22T00:00:00..1813-12-23T00:00:00', "closest dt got $res" ); $dt = new DateTime( year => '1811', month => '10', day => '25' ); $closest = $s1->closest( $dt ); $res = span_str( $closest ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "closest dt got $res" ); $dt = new DateTime( year => '1812', month => '8', day => '19' ); $previous = $s1->previous( $dt ); $res = span_str( $previous ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "previous dt got $res" ); is( $previous->end_is_open, 1, 'end is open' ); is( $previous->start_is_open, 0, 'start is closed' ); # previous( $span ) $previous = $s1->previous( $previous ); is( $previous, undef , 'no previous' ); #$res = span_str( $previous ); #is( $res, NEG_INFINITY.'..1810-09-20T00:00:00', # "previous span got $res" ); #is( eval{ $previous->end_is_open }, 1, 'end is open' ); #is( eval{ $previous->start_is_open }, 1, 'start is open' ); #is( eval{ $previous->duration->delta_seconds }, INFINITY, 'span size is infinite' ); } # TODO: { # local $TODO = 'spanset duration should be an object'; # eval { is ( $s1->duration->delta_seconds, INFINITY, 'spanset size is infinite' ); # } or # ok( 0, 'not a duration object' ); # } } # special case: end == start { my $start1 = new DateTime( year => '1810', month => '9', day => '20' ); my $end1 = new DateTime( year => '1811', month => '10', day => '21' ); my $start2 = new DateTime( year => '1811', month => '10', day => '21' ); my $end2 = new DateTime( year => '1812', month => '11', day => '22' ); my $start_set = DateTime::Set->from_datetimes( dates => [ $start1, $start2 ] ); my $end_set = DateTime::Set->from_datetimes( dates => [ $end1, $end2 ] ); my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $end_set ); my $iter = $s1->iterator; my $res = span_str( $iter->next ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1811-10-21T00:00:00..1812-11-22T00:00:00', "got $res" ); } # special case: start_set == end_set { my $start1 = new DateTime( year => '1810', month => '9', day => '20' ); my $start2 = new DateTime( year => '1811', month => '10', day => '21' ); my $start3 = new DateTime( year => '1812', month => '11', day => '22' ); my $start4 = new DateTime( year => '1813', month => '12', day => '23' ); my $start_set = DateTime::Set->from_datetimes( dates => [ $start1, $start2, $start3, $start4 ] ); my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $start_set ); my $iter = $s1->iterator; my $res = span_str( $iter->next ); is( $res, NEG_INFINITY.'..1810-09-20T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1810-09-20T00:00:00..1811-10-21T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1811-10-21T00:00:00..1812-11-22T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1812-11-22T00:00:00..1813-12-23T00:00:00', "got $res" ); $res = span_str( $iter->next ); is( $res, '1813-12-23T00:00:00..'.INFINITY, "got $res" ); } # special case: start_set == end_set == recurrence { my $start_set = DateTime::Set->from_recurrence( next => sub { $_[0]->truncate( to => 'day' ) ->add( days => 1 ) }, span => DateTime::Span->from_datetimes( start => new DateTime( year => '1810', month => '9', day => '20' ) ), ); # test if the recurrence works properly my $set_iter = $start_set->iterator; my $res = str( $set_iter->next ); is( $res, '1810-09-20T00:00:00', "recurrence works properly - got $res" ); $res = str( $set_iter->next ); is( $res, '1810-09-21T00:00:00', "recurrence works properly - got $res" ); # create spanset my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $start_set ); my $iter = $s1->iterator; $res = span_str( $iter->next ); is( $res, NEG_INFINITY.'..1810-09-20T00:00:00', "start_set == end_set recurrence works properly - got $res" ); $res = span_str( $iter->next ); is( $res, '1810-09-20T00:00:00..1810-09-21T00:00:00', "start_set == end_set recurrence works properly - got $res" ); $res = span_str( $iter->next ); is( $res, '1810-09-21T00:00:00..1810-09-22T00:00:00', "start_set == end_set recurrence works properly - got $res" ); } # set_and_duration { my $start_set = DateTime::Set->from_recurrence( next => sub { $_[0]->truncate( to => 'day' ) ->add( days => 1 ) }, span => DateTime::Span->from_datetimes( start => new DateTime( year => '1810', month => '9', day => '20' ) ), ); my $span_set = DateTime::SpanSet->from_set_and_duration( set => $start_set, hours => 1 ); my $iter = $span_set->iterator; my $res = span_str( $iter->next ); is( $res, '1810-09-20T00:00:00..1810-09-20T01:00:00', "start_set == end_set recurrence works properly - got $res" ); $res = span_str( $iter->next ); is( $res, '1810-09-21T00:00:00..1810-09-21T01:00:00', "start_set == end_set recurrence works properly - got $res" ); } # test the iterator limits. Ben Bennett. { my $start1 = new DateTime( year => '1810', month => '9', day => '20' ); my $end1 = new DateTime( year => '1811', month => '10', day => '21' ); my $start2 = new DateTime( year => '1812', month => '11', day => '22' ); my $end2 = new DateTime( year => '1813', month => '12', day => '23' ); my $end3 = new DateTime( year => '1813', month => '12', day => '1' ); my $start_set = DateTime::Set->from_datetimes( dates => [ $start1, $start2 ] ); my $end_set = DateTime::Set->from_datetimes( dates => [ $end1, $end2 ] ); my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $end_set ); my $iter_all = $s1->iterator; my $iter_limit = $s1->iterator(start => $start1, end => $end3); my $iter_limit2 = $s1->iterator( span => DateTime::Span->from_datetimes( start => $start1, end => $end3) ); my $res_a = span_str( $iter_all->next ); my $res_l = span_str( $iter_limit->next ); my $res_2 = span_str( $iter_limit2->next ); is( $res_a, $res_l, "limited iterator got $res_a" ); is( $res_a, $res_2, "other limited iterator got $res_a" ); $res_a = span_str( $iter_all->next ); $res_l = span_str( $iter_limit->next ); is( $res_l, '1812-11-22T00:00:00..1813-12-01T00:00:00', "limited iterator works properly" ); is( $res_a, '1812-11-22T00:00:00..1813-12-23T00:00:00', "limited iterator doesn't break regular iterator" ); } { # start_set / end_set my $start1 = new DateTime( year => '1810', month => '9', day => '20' ); my $end1 = new DateTime( year => '1811', month => '10', day => '21' ); my $start2 = new DateTime( year => '1812', month => '11', day => '22' ); my $end2 = new DateTime( year => '1813', month => '12', day => '23' ); my $end3 = new DateTime( year => '1813', month => '12', day => '1' ); my $start_set = DateTime::Set->from_datetimes( dates => [ $start1, $start2 ] ); my $end_set = DateTime::Set->from_datetimes( dates => [ $end1, $end2 ] ); my $s1 = DateTime::SpanSet->from_sets( start_set => $start_set, end_set => $end_set ); isa_ok( $s1->start_set , "DateTime::Set" , "start_set" ); isa_ok( $s1->end_set , "DateTime::Set" , "end_set" ); is( "".$s1->start_set->{set}, "".$start_set->{set} , "start_set" ); is( "".$s1->end_set->{set}, "".$end_set->{set} , "end_set" ); } { # start_set / end_set using recurrences my $start_set = DateTime::Set->from_recurrence( next => sub { $_[0]->truncate( to => 'day' ) ->add( days => 1 ) }, ); my $span_set = DateTime::SpanSet->from_set_and_duration( set => $start_set, hours => 1 ); my $dt = new DateTime( year => '1810', month => '9', day => '20', hour => 12 ); my $res; $res = span_str( $span_set->next( $dt ) ); is( $res, '1810-09-21T00:00:00..1810-09-21T01:00:00', "next span_set occurrence - got $res" ); my $set1 = $span_set->start_set; $res = $set1->next( $dt ); is( $res->datetime, '1810-09-21T00:00:00', "next span_set-start occurrence - got $res" ); my $set2 = $span_set->end_set; $res = $set2->next( $dt ); is( $res->datetime, '1810-09-21T01:00:00', "next span_set-end occurrence - got $res" ); ok( ! $span_set->contains( $dt ), "span_set recurrence does not contain" ); ok( $span_set->contains( DateTime->new( year => '1810', month => '9', day => '20', hour => 0 ) ), "span_set recurrence contains, dt == start" ); ok( ! $span_set->contains( DateTime->new( year => '1810', month => '9', day => '20', hour => 1 ) ), "span_set recurrence does not contain, dt == end" ); ok( ! $span_set->intersects( DateTime->new( year => '1810', month => '9', day => '20', hour => 1 ) ), "span_set recurrence does not intersect, dt == end" ); }