The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;
use utf8;

use Test::More;

use Tickit::RenderBuffer qw( LINE_SINGLE CAP_START CAP_END CAP_BOTH );

use Tickit::Pen;

my $rb = Tickit::RenderBuffer->new(
   lines => 30,
   cols  => 30,
);

my @methods;
{
   package TestWindow;

   use Tickit::Utils qw( string_count );
   use Tickit::StringPos;

   sub goto
   {
      shift;
      push @methods, [ goto => @_ ];
   }

   sub print
   {
      shift;
      push @methods, [ print => $_[0], { $_[1]->getattrs } ];
      string_count( $_[0], my $pos = Tickit::StringPos->zero );
      return $pos;
   }

   sub erasech
   {
      shift;
      push @methods, [ erasech => $_[0], $_[1], { $_[2]->getattrs } ];
      return Tickit::StringPos->limit_columns( $_[0] );
   }
}
my $win = bless [], "TestWindow";

# Initially empty
{
   my $warned;
   local $SIG{__WARN__} = sub { $warned++ };

   $rb->flush_to_window( $win );

   is_deeply( \@methods,
              [],
              'Empty RenderBuffer renders nothing to window' );
   ok( $warned, '->flush_to_window caused a warning' );
}

# Absolute spans
{
   # Direct pen
   my $pen = Tickit::Pen->new( fg => 1 );
   $rb->text_at( 0, 1, "text span", $pen );
   $rb->erase_at( 1, 1, 5, $pen );

   # Stored pen
   $rb->setpen( Tickit::Pen->new( bg => 2 ) );
   $rb->text_at( 2, 1, "another span" );
   $rb->erase_at( 3, 1, 10 );

   # Combined pens
   $rb->text_at( 4, 1, "third span", $pen );
   $rb->erase_at( 5, 1, 7, $pen );

   $rb->flush_to_window( $win );

   is_deeply( \@methods,
              [
                 [ goto => 0, 1 ], [ print => "text span", { fg => 1 } ],
                 [ goto => 1, 1 ], [ erasech => 5, undef, { fg => 1 } ],
                 [ goto => 2, 1 ], [ print => "another span", { bg => 2 } ],
                 [ goto => 3, 1 ], [ erasech => 10, undef, { bg => 2 } ],
                 [ goto => 4, 1 ], [ print => "third span", { fg => 1, bg => 2 } ],
                 [ goto => 5, 1 ], [ erasech => 7, undef, { fg => 1, bg => 2 } ],
              ],
              'RenderBuffer renders text to window' );
   undef @methods;

   $rb->flush_to_window( $win );
   is_deeply( \@methods, [], 'RenderBuffer now empty after render to window' );
   undef @methods;
}

# Simple lines explicit pen
{
   my $pen = Tickit::Pen->new;

   # Line printing no longer merges neighbouring cells by pen equivalence
   sub printcells
   {
      my ( $text, $pen ) = @_;
      return map { [ print => $_, $pen ] } split //, $text;
   }

   $rb->hline_at( 10, 10, 20, LINE_SINGLE, $pen );
   $rb->hline_at( 11, 10, 20, LINE_SINGLE, $pen, CAP_START );
   $rb->hline_at( 12, 10, 20, LINE_SINGLE, $pen, CAP_END );
   $rb->hline_at( 13, 10, 20, LINE_SINGLE, $pen, CAP_BOTH );

   $rb->flush_to_window( $win );
   is_deeply( \@methods,
              [ [ goto => 10, 10 ], printcells( "╶" . ( "─" x 9 ) . "╴", {}),
                [ goto => 11, 10 ], printcells( ( "─" x 10 ) . "╴", {} ),
                [ goto => 12, 10 ], printcells( "╶" . ( "─" x 10 ), {} ),
                [ goto => 13, 10 ], printcells( ( "─" x 11 ), {} ) ],
              'RenderBuffer renders hline_ats to window' );
   undef @methods;

   $rb->vline_at( 10, 20, 10, LINE_SINGLE, $pen );
   $rb->vline_at( 10, 20, 11, LINE_SINGLE, $pen, CAP_START );
   $rb->vline_at( 10, 20, 12, LINE_SINGLE, $pen, CAP_END );
   $rb->vline_at( 10, 20, 13, LINE_SINGLE, $pen, CAP_BOTH );

   $rb->flush_to_window( $win );
   is_deeply( \@methods,
              [ [ goto => 10, 10 ], printcells( "╷│╷│", {} ),
                ( map { [ goto => $_, 10 ], printcells( "││││", {} ) } 11 .. 19 ),
                [ goto => 20, 10 ], printcells( "╵╵││", {} ),
              ],
              'RenderBuffer renders vline_ats to window' );
   undef @methods;
}

# Characters
{
   my $pen = Tickit::Pen->new;

   $rb->char_at( 5, 5, 0x41, $pen );
   $rb->char_at( 5, 6, 0x42, $pen );
   $rb->char_at( 5, 7, 0x43, $pen );

   $rb->flush_to_window( $win );
   is_deeply( \@methods,
              [
                 [ goto => 5, 5 ],
                 [ print => "A", {} ],
                 [ print => "B", {} ],
                 [ print => "C", {} ],
              ],
              'RenderBuffer renders char_at to window' );
   undef @methods;
}

done_testing;