#!/usr/bin/perl # ########################################################################## # # Title: Build time tests of DS::Transformer::Buffer.pm # Creation date: 2007-04-16 # Author: Michael Zedeler # Description: Tests DS::Transformer::Buffer # File: $Source: /data/cvs/lib/DSlib/t/39_buffer.t,v $ # Repository: kronhjorten # State: $State: Exp $ # Documentation: inline # Recepient: - # ########################################################################## # use strict; use warnings; use Test::More tests => 35; BEGIN { $| = 1; $^W = 1; } use DS::TypeSpec::Any; use DS::Transformer::Sub; use DS::Target::Sink; use_ok('DS::Transformer::Buffer'); my $transformer; sub rowmap { my( $row ) = @_; my $result; if( $row ) { for( sort keys %$row ) { $result .= "$_ = \"$row->{$_}\" "; } chop( $result ); } else { $result = ''; } return $result; } for( $transformer ) { $_ = new DS::Transformer::Buffer; ok( $_ ); isa_ok( $_ => 'DS::Transformer::Buffer' ); eval { $_->fetch; }; isnt( $@, '', 'Should not allow fetching from empty buffer' ); my $importer = new ImporterTest( 9 ); $_->attach_source( $importer ); my $last = 'nothing yet'; my $debugger = new DS::Transformer::Sub( sub { my( $self, $row ) = @_; $last = rowmap( $row ) || 'nothing more'; return $row; }, $DS::TypeSpec::Any, $DS::TypeSpec::Any ); $_->attach_target( $debugger ); $debugger->attach_target( new DS::Target::Sink ); eval { $_->fetch; }; isnt( $@, '', 'Should not allow fetching from empty buffer' ); is( $last, 'nothing yet' ); $importer->execute( 1 ); is( $last, 'count = "1" modulo_3 = "1"' ); $importer->execute( 1 ); is( $last, 'count = "2" modulo_3 = "2"' ); $_->unfetch; $importer->execute( 1 ); is( $last, 'count = "2" modulo_3 = "2"' ); $importer->execute( 1 ); is( $last, 'count = "3" modulo_3 = "0"' ); is( rowmap( $_->fetch ), 'count = "4" modulo_3 = "1"' ); eval { $_->fetch; }; isnt( $@, '', 'Should not allow fetching past last available row in buffer' ); for( my $i = 1; $i <= 4; $i++ ) { eval { $_->unfetch; }; is( $@, '', 'Should be able to rewind through buffer.' ); } eval { $_->unfetch; }; isnt( $@, '', 'Should not allow unfetching beyond first row in buffer' ); is( rowmap( $_->fetch ), 'count = "1" modulo_3 = "1"', 'Re-fetch first row in buffer'); $_->flush; eval { $_->unfetch; }; isnt( $@, '', 'Should not allow unfetching beyond first available row in buffer' ); is( rowmap( $_->fetch ), 'count = "2" modulo_3 = "2"', 'Re-fetch second row in buffer'); eval { $_->unfetch; }; is( $@, '', 'Should allow unfetching second row in buffer' ); # The buffer is 0-indexed, meaning that flush(2) will ensure that the first # *three* elements are flushed. eval { $_->flush( 2 ); }; is( $@, '', 'Should allow flushing up to (and including) position 2' ); eval { $_->unfetch; }; isnt( $@, '', 'Should not allow unfetching beyond first available row in buffer' ); is( rowmap( $_->fetch ), 'count = "4" modulo_3 = "1"' ); $last = ''; $importer->execute( 6 ); is( $last, 'count = "10" modulo_3 = "1"' ); $last = ''; $importer->execute( 1 ); is( $last, 'nothing more', 'Buffer should return end of stream (undef)' ); $last = ''; $importer->execute( 1 ); is( $last, 'nothing more', 'Buffer should return end of stream (undef)' ); $last = ''; $importer->execute( 1 ); is( $last, 'nothing more', 'Buffer should return end of stream (undef)' ); # Check that after EOS it is still possible to unfetch and fetch last value eval { $_->unfetch; $_->unfetch; }; is( $@, '' ); is( rowmap( $_->fetch ), 'count = "10" modulo_3 = "1"' ); is( rowmap( $_->fetch ), '' ); eval { $_->fetch; }; isnt( $@, '' ); # Check that sending another EOS after unfetch will bring up # last element followed by EOS eval { $_->unfetch; $_->unfetch; }; is( $@, '' ); $last = ''; $importer->execute( 1 ); is( $last, 'count = "10" modulo_3 = "1"', 'Bring back last element after EOS should be possible with unfetch' ); $last = ''; $importer->execute( 1 ); is( $last, 'nothing more', 'The buffer should be past last element now, returning EOS.' ); } package ImporterTest; use base qw{ DS::Importer }; sub new { my( $class, $max ) = @_; my $typespec = new DS::TypeSpec('mytype', [ new DS::TypeSpec::Field( 'count' ), new DS::TypeSpec::Field( 'modulo_3' )] ); my $self = $class->SUPER::new( $typespec ); $self->{counter} = 0; $self->{max} = $max; return $self; } sub _fetch { my( $self ) = @_; if( $self->{counter} > $self->{max} ) { return undef; } else { $self->{counter}++; return {count => $self->{counter}, modulo_3 => $self->{counter} % 3}; } } 1;