#!/usr/bin/perl
use warnings;
use strict;
use Test::More tests => 62;
#use Test::More 'no_plan';
use lib 'lib/', '../lib/';
BEGIN {
use_ok 'HOP::Stream', ':all' or die;
}
my @exported = qw(
cutsort
drop
filter
head
insert
is_node
iterator_to_stream
list_to_stream
append
merge
node
promise
show
tail
transform
upto
upfrom
);
foreach my $function (@exported) {
no strict 'refs';
ok defined &$function, "&$function should be exported to our namespace";
}
# node
ok my $stream = node( 3, 4 ), 'Calling node() should succeed';
is_deeply $stream, [ 3, 4 ], '... returning a stream node';
ok my $new_stream = node( 7, $stream ),
'... and a node may be in the node() arguments';
is_deeply $new_stream, [ 7, $stream ], '... and the new node should be correct';
# head
is head($new_stream), 7, 'head() should return the head of a node';
# tail
is tail($new_stream), $stream, 'tail() should return the tail of a node';
# drop
ok my $head = drop($new_stream), 'drop() should succeed';
is $head, 7, '... returning the head of the node';
is_deeply $new_stream, $stream,
'... and setting the tail of the node as the node';
# upto
ok !upto( 5, 4 ),
'upto() should return false if the first number is greater than the second';
ok $stream = upto( 4, 7 ),
'... but it should succeed if the first number is less than the second';
my @numbers;
while ( defined( my $num = drop($stream) ) ) {
push @numbers, $num;
}
is_deeply \@numbers, [ 4, 5, 6, 7 ],
'... and the stream should return all of the numbers';
# upfrom
ok $stream = upfrom(42), 'upfrom() should return a stream';
@numbers = ();
for ( 1 .. 10 ) {
push @numbers, drop($stream);
}
is_deeply \@numbers, [ 42 .. 51 ],
'... which should return the numbers we expect';
# show
show( $stream, 5 );
is show( $stream, 5 ), "52 53 54 55 56 ", 'Show should print the correct values';
# transform
my $evens = transform { $_[0] * 2 } upfrom(1);
ok $evens, 'Calling transform() on a stream should succeed';
@numbers = ();
for ( 1 .. 5 ) {
push @numbers, drop($evens);
}
is_deeply \@numbers, [ 2, 4, 6, 8, 10 ],
'... which should return the numbers we expect';
# filter
# forget the parens in the filter and it's an infinite loop
$evens = filter { !( $_[0] % 2 ) } upfrom(1);
ok $evens, 'Calling filter() on a stream should succeed';
@numbers = ();
for ( 1 .. 5 ) {
push @numbers, drop($evens);
}
is_deeply \@numbers, [ 2, 4, 6, 8, 10 ],
'... which should return the numbers we expect';
# append
my $stream1 = upto(4, 7);
my $stream2 = upto(12, 15);
my $stream3 = upto(25, 28);
ok $stream = append($stream1, $stream2, $stream3),
"append() should return a stream";
@numbers = ();
while ( defined( my $num = drop($stream) ) ) {
push @numbers, $num;
}
is_deeply \@numbers, [ 4..7, 12..15, 25..28 ],
'... and the stream should return all of the numbers';
# merge
sub scale {
my ( $s, $c ) = @_;
transform { $_[0] * $c } $s;
}
my $hamming;
$hamming = node(
1,
promise {
merge(
scale( $hamming, 2 ),
merge( scale( $hamming, 3 ), scale( $hamming, 5 ), )
)
}
);
@numbers = ();
for ( 1 .. 10 ) {
push @numbers, drop($hamming);
}
is_deeply \@numbers, [ 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 ],
'merge() should let us merge sorted streams';
$evens = transform { $_[0] * 2 } upfrom(1);
my $odds = transform { ( $_[0] * 2 ) - 1 } upfrom(1);
my $number = merge( $odds, $evens );
@numbers = ();
for ( 1 .. 10 ) {
push @numbers, drop($number);
}
is_deeply \@numbers, [ 1 .. 10 ], '... and create the numbers one to ten';
# iterator_to_stream
my @iter = qw/2 4 6 8/;
my $iter = sub { shift @iter };
ok $stream = iterator_to_stream($iter),
'iterator_to_stream() should convert an iterator to a stream';
@numbers = ();
while ( defined( my $number = drop($stream) ) ) {
push @numbers, $number;
}
is_deeply \@numbers, [ 2, 4, 6, 8 ],
'... and the stream should return the correct values';
# list_to_stream
ok my $list = list_to_stream( 1 .. 9, node(10) ),
'list_to_stream() should return a stream';
@numbers = ();
while ( defined( my $num = drop($list) ) ) {
push @numbers, $num;
}
is_deeply \@numbers, [ 1 .. 10 ], '... and create the numbers one to ten';
# list_to_stream, final node computed internally
ok $list = list_to_stream( 1 .. 10 ),
'list_to_stream() should return a stream';
@numbers = ();
while ( defined( my $num = drop($list) ) ) {
push @numbers, $num;
}
is_deeply \@numbers, [ 1 .. 10 ], '... and create the numbers one to ten';
# insert
my @list = qw/seventeen three one/; # sorted by descending length
my $compare = sub { length $_[0] < length $_[1] };
insert @list, 'four', $compare;
is_deeply \@list, [qw/seventeen three four one/],
'insert() should be able to insert items according to our sort criteria';
#
# streams of array refs do not work properly, because tail [a,b] is b, even if [a,b] is
# the last stream element, and not a node
# Solution: bless nodes, check is_node in head, tail, list_to_stream
#
$stream = list_to_stream( [A => 1], [B => 2] );
is_deeply $stream,
bless([ [A => 1],
bless([ [B => 2],
undef ],
'HOP::Stream')],
'HOP::Stream'), "stream of array refs";
is_deeply head($stream), [A => 1], "... head is array ref";
is_deeply tail($stream),
bless([ [B => 2],
undef ],
'HOP::Stream'), "... tail is stream";
drop($stream);
is_deeply $stream,
bless([ [B => 2],
undef ],
'HOP::Stream'), "stream of array refs, dropped 1";
is_deeply head($stream), [B => 2], "... head is array ref";
is_deeply tail($stream), undef, "... tail is stream";
drop($stream);
is_deeply $stream, undef, "stream of array refs, dropped 2";
is_deeply head($stream), undef, "... head is undef";
is_deeply tail($stream), undef, "... tail is undef";
drop($stream);
is_deeply $stream, undef, "stream of array refs, dropped 3";
is_deeply head($stream), undef, "... head is undef";
is_deeply tail($stream), undef, "... tail is undef";
#
# use a non-stream as stream
#
$stream = [1, [2, [3]]];
is head($stream), undef, "no head of non-stream";
is tail($stream), undef, "no head of non-stream";