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 Test::More;
use File::Monitor;
use File::Monitor::Object;
use File::Monitor::Delta;

plan tests => 384;

my @tests = (
  {
    name     => 'No files',
    old_info => {
      mode      => 0x000081a4,
      atime     => 1170281355,
      ctime     => 1170281355,
      mtime     => 1170281355,
      blk_size  => 4096,
      blocks    => 0,
      dev       => 234881026,
      gid       => 0,
      uid       => 501,
      inode     => 2828759,
      num_links => 1,
      rdev      => 0,
      size      => 0,
      error     => '',
    },
    new_info => {
      mode      => 0x000040c9,
      atime     => 1170281385,
      ctime     => 1170281365,
      mtime     => 1170281315,
      blk_size  => 4096,
      blocks    => 0,
      dev       => 234881026,
      gid       => 501,
      uid       => 0,
      inode     => 2828759,
      num_links => 1,
      rdev      => 0,
      size      => 123,
      error     => '',
    },
    expect => {
      mode          => 0x000081a4 ^ 0x000040c9,
      ctime         => 10,
      mtime         => -40,
      gid           => 501,
      uid           => -501,
      size          => 123,
      files_created => [],
      files_deleted => [],
    }
  },
  {
    name     => 'All files deleted',
    old_info => {
      mode      => 0x000040c9,
      atime     => 1170281385,
      ctime     => 1170281365,
      mtime     => 1170281315,
      blk_size  => 4096,
      blocks    => 0,
      dev       => 234881026,
      gid       => 501,
      uid       => 0,
      inode     => 2828759,
      num_links => 1,
      rdev      => 0,
      size      => 123,
      error     => '',
      files     => [ 'a', 'b', 'c' ],
    },
    new_info => {
      mode      => 0x000081a4,
      atime     => 1170281355,
      ctime     => 1170281355,
      mtime     => 1170281355,
      blk_size  => 4096,
      blocks    => 0,
      dev       => 234881026,
      gid       => 0,
      uid       => 501,
      inode     => 2828759,
      num_links => 1,
      rdev      => 0,
      size      => 0,
      error     => '',

      # files missing
    },
    expect => {
      mode          => 0x000081a4 ^ 0x000040c9,
      ctime         => -10,
      mtime         => 40,
      gid           => -501,
      uid           => 501,
      size          => -123,
      files_created => [],
      files_deleted => [ 'a', 'b', 'c' ],
    }
  },
  {
    name     => 'Deleted and created',
    old_info => {
      mode      => 0x000040c9,
      atime     => 1170281385,
      ctime     => 1170281365,
      mtime     => 1170281315,
      blk_size  => 4096,
      blocks    => 0,
      dev       => 234881026,
      gid       => 501,
      uid       => 0,
      inode     => 2828759,
      num_links => 1,
      rdev      => 0,
      size      => 123,
      error     => '',
      files     => [ 'b', 'a', 'd', 'c', 'e' ],
    },
    new_info => {
      mode      => 0x000081a4,
      atime     => 1170281355,
      ctime     => 1170281355,
      mtime     => 1170281355,
      blk_size  => 4096,
      blocks    => 0,
      dev       => 234881026,
      gid       => 0,
      uid       => 501,
      inode     => 2828759,
      num_links => 1,
      rdev      => 0,
      size      => 0,
      error     => '',
      files     => [ 'g', 'f', 'z', 'a', 'd', 'e' ],
    },
    expect => {
      files_created => [ 'f', 'g', 'z' ],
      files_deleted => [ 'b', 'c' ],
    }
  }
);

my @read_only_attr = qw(
 old_dev old_inode old_mode old_num_links old_uid old_gid old_rdev
 old_size old_mtime old_ctime old_blk_size old_blocks old_error
 old_files new_dev new_inode new_mode new_num_links new_uid new_gid
 new_rdev new_size new_mtime new_ctime new_blk_size new_blocks
 new_error new_files created deleted mtime ctime uid gid mode size
 files_created files_deleted name
);

for my $test ( @tests ) {
  my $test_name = $test->{name};

  ok my $monitor = File::Monitor->new;
  ok my $object
   = File::Monitor::Object->new( { name => '.', owner => $monitor } );
  isa_ok $object, 'File::Monitor::Object';

  ok my $change = File::Monitor::Delta->new(
    {
      object   => $object,
      old_info => $test->{old_info},
      new_info => $test->{new_info}
    }
  );

  isa_ok $change, 'File::Monitor::Delta';

  for my $ro ( @read_only_attr ) {
    can_ok $change, $ro;
    eval { $change->$ro() };
    ok !$@, "read $ro OK";
    eval { $change->$ro( 'ouch' ) };
    like $@, qr/read\W+only/, "can't write $ro";
  }

  while ( my ( $attr, $value ) = each %{ $test->{expect} } ) {
    if ( $attr =~ /^files_/ ) {
      my @got = $change->$attr();
      is_deeply \@got, $value, "$test_name: $attr OK";
    }
    else {
      my $got = $change->$attr();
      is_deeply $got, $value, "$test_name: $attr OK";
    }
  }
}