I needed to safely update a state file (after a disk-full error caused a corruption) - added some notes here Programming_Notes/PerlProgramming/HandyModules.

These tests (which failed for IO::AtomicFile) showed me the IO::File::AtomicChange module does what I need it to do:

Test code:

use warnings;

use Test::More qw(no_plan);

use File::Temp qw(tempdir);
use IO::File::AtomicChange;

#
# Checking out IO::AtomicFile
#

############################################################
# Set-up
#

my $dir = tempdir( CLEANUP => 1 );

my $test_content = "aaa\nbbb\nccc";
my $test_filepath = "${dir}/testfile";

############################################################
# Tests
#

# Create a new file
my $fh = IO::File::AtomicChange->new($test_filepath, "w");
$fh->print($test_content);
$fh->close();
is( slurp($test_filepath), $test_content, "Create a new file and write to it - content matches" );

# Create a new file but fail
eval {
  my $fh = IO::File::AtomicChange->new($test_filepath, "w");
  $fh->print("lose this content");
  die;
};
is( slurp($test_filepath), $test_content, "Start to overwrite the file but abort - no changes" );

# Update a file but fail
reset_testfile();
eval {
  my $fh = IO::File::AtomicChange->new($test_filepath, "a");
  $fh->print("lose this content");
  die;
};
is( slurp($test_filepath), $test_content, "Start to update the file but abort - no changes" );

# Update a file successfully
reset_testfile();
my $fh = IO::File::AtomicChange->new($test_filepath, "a");
$fh->print("more");
$fh->close();
is( slurp($test_filepath), "${test_content}more", "Update the file - changes made" );

############################################################
# Functions
#

sub reset_testfile {
  open my $fh, ">", $test_filepath or die "open failed: $!";
  print $fh $test_content or die "print failed: $!";
  close $fh or die "close failed: $!";
}

sub slurp { open my $fh, "<", shift; local $/; <$fh> }

Test results:

$ prove -v atomic.t 
atomic.t .. "my" variable $fh masks earlier declaration in same scope at atomic.t line 52.

ok 1 - Create a new file and write to it - content matches
[CAUTION] disposed object without closing file handle. at atomic.t line 34
ok 2 - Start to overwrite the file but abort - no changes
[CAUTION] disposed object without closing file handle. at atomic.t line 43
ok 3 - Start to update the file but abort - no changes
ok 4 - Update the file - changes made
1..4
ok
All tests successful.
Files=1, Tests=4,  0 wallclock secs ( 0.04 usr  0.03 sys +  0.06 cusr  0.06 csys =  0.19 CPU)
Result: PASS

BradsWiki: IoFileAtomicChangeTest (last edited 2011-10-21 06:45:17 by BradleyDean)