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
