Win32-Mechanize-NotepadPlusPlus/t/npp-files.t
########################################################################
# Verifies Notepad object messages / methods work
# subgroup: those necessary for file and session open/close
########################################################################
use 5.010;
use strict;
use warnings;
use version; # for getNppVersion() parsing
use Test::More;
use Win32;
use FindBin;
BEGIN { my $f = $FindBin::Bin . '/nppPath.inc'; require $f if -f $f; }
use lib $FindBin::Bin;
use myTestHelpers qw/runCodeAndClickPopup :userSession/;
use Path::Tiny 0.058 qw/path tempfile/; # 0.018 needed for rootdir and cwd; 0.058 needed for sibling
use Win32::Mechanize::NotepadPlusPlus qw/:main :vars/;
# need to choose forked (normal clicker) vs unforked (Devel::Cover cannot handle windows[fork->thread] )
# outline:
# if any unsaved buffers, HALT test and prompt user to save any critical
# files, then re-run test suite.
my $EmergencySessionHash;
BEGIN { $EmergencySessionHash = saveUserSession(); }
END { restoreUserSession( $EmergencySessionHash ); }
my $ver = version->parse( notepad->getNppVersion() );
# prepopulate any tempfile locations
our $fnew1 = tempfile( TEMPLATE => 'nppNewFile_XXXXXXXX', SUFFIX => '.txt'); note $fnew1->canonpath();
our $fnew2 = tempfile( TEMPLATE => 'nppDupFile_XXXXXXXX', SUFFIX => '.txt'); note $fnew2->canonpath();
our $knownSession = tempfile( TEMPLATE => 'nppKnownSession_XXXXXXXX', SUFFIX => '.xml'); note $knownSession->canonpath();
# ->saveCurrentSession($saveUserSession)
# => this also avoids messing up the user's current Notepad++ instance.
# STOP IMMEDIATELY IF THIS FAILS
# => attempt to reload that session on exit (END block),
# and if there's a problem with reload, point user
# to where the session file is.
{
# saveCurrentSession was actuall run during the BEGIN block;
# this just verifies the file is there and has non-zero size
my $size = $EmergencySessionHash->{session}->is_file ? $EmergencySessionHash->{session}->stat()->size : 0;
ok $size, sprintf 'saveCurrentSession(): size(file) = %d', $size;
}
# ->closeAll()
# => gives a blank slate to work with.
{
my $ret = notepad()->closeAll();
ok $ret, sprintf 'closeAll(): retval = %d', $ret;
my $nOpen = notepad()->getNumberOpenFiles($VIEW{PRIMARY_VIEW});
is $nOpen, 1, sprintf 'closeAll(): getNumberOpenFiles(PRIMARY) = %d', $nOpen;
my $fName = notepad()->getCurrentFilename();
like $fName, qr/^new \d/i, sprintf 'closeAll(): getCurrentFilename() = "%s"', $fName;
}
# ->loadSession()
# => gets us to a known state with a prebuilt session
{
# generate the session file on the fly, because it needs absolute directories, which I cannot have until the test suite runs
my @src = qw/00-load.t 01-defaults.t/;
$knownSession->append(qq{<?xml version="1.0" encoding="UTF-8" ?>\n});
$knownSession->append(qq{<NotepadPlus><Session activeView="0"><mainView activeIndex="0">\n});
my $extra = qq{scrollWidth="1" startPos="0" endPos="0" selMode="0" offset="0" wrapCount="1" encoding="-1" userReadOnly="no"};
$knownSession->append(sprintf qq{<File firstVisibleLine="0" xOffset="0" filename="%s" %s />\n}, $_, $extra)
for map { path($0)->sibling($_)->absolute->canonpath() } @src;
$knownSession->append(qq{</mainView><subView activeIndex="0" /></Session></NotepadPlus>\n});
note $knownSession->slurp();
my $ret = notepad()->loadSession( $knownSession->absolute->canonpath );
ok $ret, sprintf 'loadSession("%s"): retval = %d', $knownSession->absolute->canonpath, $ret;
my $nOpen = notepad()->getNumberOpenFiles($VIEW{PRIMARY_VIEW});
is $nOpen, 2, sprintf 'loadSession(): getNumberOpenFiles(PRIMARY) = %d', $nOpen;
my @files = map { $_->[0] } @{ notepad()->getFiles() };
for my $i (0,1) {
like $files[$i], qr/\b\Q$src[$i]\E\b/i, sprintf 'loadSession(): getFiles()->[%d][0] = "%s"', $i, $files[$i];
}
}
# ->newFile()
# => create a blank, editable document
{
my $ret = notepad()->newFile();
ok $ret, sprintf 'newFile(): retval = %d', $ret;
my $fName = notepad()->getCurrentFilename();
like $fName, qr/^new \d/i, sprintf 'newFile(): getCurrentFilename() = "%s"', $fName;
}
# ->saveAs( $fnew1 )
# => give it a name
{
my $text = sprintf 'saveAs("%s")', $fnew1->basename();
editor()->{_hwobj}->SendMessage_sendRawString( $SCIMSG{SCI_SETTEXT}, 0, $text );
my $ret = notepad()->saveAs( $fnew1->absolute->canonpath() );
ok $ret, sprintf 'saveAs(): retval = %d', $ret;
my $fName = path( notepad()->getCurrentFilename() )->basename();
is $fName, $fnew1->basename(), sprintf 'saveAs(): getCurrentFilename() = "%s"', $fName;
}
# ->saveAsCopy( $fnew2 )
# => give it a second name (but ->getCurrentFilename() should remain the same)
{
my $ret = notepad()->saveAsCopy( $fnew2->absolute->canonpath() );
ok $ret, sprintf 'saveAsCopy(): retval = %d', $ret;
my $fName = path( notepad()->getCurrentFilename() )->basename();
isnt $fName, $fnew2->basename(), sprintf 'saveAsCopy(): getCurrentFilename() = "%s"', $fName;
is $fName, $fnew1->basename(), sprintf 'saveAsCopy(): getCurrentFilename() = "%s"', $fName;
}
# ->open( $fnew2 )
# => bring it in and edit it
{
my $ret = notepad()->open( $fnew2->absolute->canonpath() );
ok $ret, sprintf 'open("%s"): retval = %d', $fnew2->absolute->canonpath(), $ret;
my $fName = path( notepad()->getCurrentFilename() )->basename();
is $fName, $fnew2->basename(), sprintf 'open(): getCurrentFilename() = "%s"', $fName;
}
# ->save()
# => edit it, and make sure that it changes on disk
{
my $origFileSize = $fnew2->stat()->size();
ok $origFileSize, sprintf 'save(): original size before edit and save: %d', $origFileSize;
my $text = "this is new text";
my $expect = length($text);
editor()->{_hwobj}->SendMessage_sendRawString( $SCIMSG{SCI_SETTEXT}, 0, $text );
my $ret = notepad()->save();
ok $ret, sprintf 'save(): retval = %d', $ret;
my $newFileSize = $fnew2->stat()->size();
is $newFileSize, $expect, sprintf 'save(): new size after edit and save: %d', $newFileSize;
}
# ->saveSession( $knownSession, @fileNameList )
# => include a subset of files; see whether they all have to be open or not
# ->getSessionFiles()
# => test to make sure it includes all the files I passed to ->saveSession
# (grouped two tests together, because the second will use the list from the first as the comparison)
{
my @fileNameList = map { $_->absolute->canonpath() } $fnew1, $fnew2;
my $ret = notepad()->saveSession( $knownSession, @fileNameList );
ok $ret, sprintf 'saveSession(%s): ret = %d', $knownSession->basename(), $ret;
#note $knownSession->slurp();
my @ret = notepad()->getSessionFiles($knownSession);
ok scalar @ret, sprintf 'getSessionFiles(%s): found %d sessions', $knownSession->basename(), scalar @ret;
is_deeply \@ret, \@fileNameList, sprintf 'getSessionFiles(): files all match the session-generator list';
}
# ->saveAllFiles()
# => _after_ editing both open files
# => need to make sure that it changes on disk
{
my $nView0 = notepad()->getNumberOpenFiles($VIEW{PRIMARY_VIEW});
is $nView0, 4, sprintf 'saveAllFiles(): first make sure expected number are open: %d', $nView0;
# last modified when?
my ($tmod1, $tmod2) = map { $_->stat()->mtime() } $fnew1, $fnew2;
ok $tmod1, sprintf 'saveAllFiles(): "%s" previously modified at %s', $fnew1->basename(), scalar localtime $tmod1;
ok $tmod2, sprintf 'saveAllFiles(): "%s" previously modified at %s', $fnew2->basename(), scalar localtime $tmod2;
# edit both files
for my $di ( $nView0-1,$nView0-2 ) {
notepad()->activateIndex(0,$di);
my $text = sprintf qq(editing "%s"\r\n%s\r\n), notepad->getCurrentFilename(), scalar localtime;
editor()->{_hwobj}->SendMessage_sendRawString( $SCIMSG{SCI_SETTEXT}, 0, $text );
sleep(1);
}
# now save them
my $ret;
my $cref = sub { $ret = notepad->saveAllFiles(); };
if( $ver < version->parse(v8.1.2) ) {
$cref->();
} elsif ( $ver <= version->parse(v8.1.4) ) { # for v8.1.2-v8.1.4, press CANCEL (which saves but doesn't change option)
runCodeAndClickPopup( $cref, qr/^Save All Confirmation/, 2 ); # press CANCEL (n=2)
} else {
runCodeAndClickPopup( $cref, qr/^Save/, 0 , 0.5); # press YES (n=0), with extra delay
}
isnt 0+$ret, 0, sprintf 'saveAllFiles(): ret = %d', $ret;
# should be more-recently modified
my ($tmod1x, $tmod2x) = map { $_->stat()->mtime() } $fnew1, $fnew2;
ok $tmod1x-$tmod1, sprintf 'saveAllFiles(): "%s" modified at %s; delta = %d', $fnew1->basename(), scalar localtime $tmod1x, $tmod1x-$tmod1;
ok $tmod2x-$tmod2, sprintf 'saveAllFiles(): "%s" modified at %s; delta = %d', $fnew2->basename(), scalar localtime $tmod2x, $tmod2x-$tmod2;
}
# ->closeAllButCurrent()
# => only one file should be there
{
diag "before closeAllButCurrent(), how many files are open? ", notepad()->getNumberOpenFiles($VIEW{PRIMARY_VIEW});
my $ret = notepad()->closeAllButCurrent();
ok $ret, sprintf 'closeAllButCurrent(): ret = %d', $ret;
my $num = notepad()->getNumberOpenFiles($VIEW{PRIMARY_VIEW});
is $num, 1, sprintf 'closeAllButCurrent(): %d file%s open', $num, $num==1?'':'s';
}
# ->close()
# => all that remains should be the "new 1" empty buffer
{
diag "before close(), how many files are open? ", notepad()->getNumberOpenFiles($VIEW{PRIMARY_VIEW});
my $oldname = notepad()->getCurrentFilename();
my $ret = notepad()->close();
ok $ret, sprintf 'close(): ret = %d', $ret;
my $name = notepad()->getCurrentFilename();
like $name, qr/^new \d/i, sprintf 'close(): filename should be /new #/: "%s"', $name;
isnt $name, $oldname, sprintf 'close(): filename should not match old name ("%s")', $oldname;
}
done_testing;