in reply to inconistent test results when using is_deeply to test an array returned from a function

I note that in get_files_in_watched_directory you have the line
opendir(DIR,$directory_to_check) || die "cannot open directory $direct +ory_to_check: $!";
without a trailing closedir. What happens when you add that, or swap to an indirect/lexical directory handle, like
opendir(my $dir,$directory_to_check) || die "cannot open directory $di +rectory_to_check: $!"; while (defined($this_file = readdir($dir))) {
I'm just guessing you might have trouble because of the global handle.

#11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

  • Comment on Re: inconistent test results when using is_deeply to test an array returned from a function
  • Select or Download Code

Replies are listed 'Best First'.
Re^2: inconistent test results when using is_deeply to test an array returned from a function
by APGRMF (Novice) on Sep 25, 2014 at 10:00 UTC

    I've reduced the code a bit further (below) and ran the following two scenarios

    First, I increased the number of temporary files being created in the test from 2 to 5. The function, which is otherwise unchanged, now fails every time. A print to the screen of the two arrays shows that they have the same content but in a different order.

    In the second scenario, I amended the function so that the "expected" array is now passed in as a reference and then returned unchanged. The test which compares the expected array with the actual array then passes every time as expected. A print to the screen of the two arrays shows that they have the same content in the same order as would be expected.

    It appears as though is_deeply is failing the test in the first scenario because of the array order.

    Any thoughts? Thanks

    Amended test code

    note "\nTest function: get_files_in_watched_directory"; subtest 'get_files_in_watched_directory' => sub { my @got_files; my @expected_files; my $project_name = 'default'; # create a temporary directory my $temp_dir = tempdir( CLEANUP => 1 ); # create some temporary files in the directory my ($temp_file1_handle, $temp_file1) = tempfile(DIR => $temp_dir); my ($temp_file2_handle, $temp_file2) = tempfile(DIR => $temp_dir); my ($temp_file3_handle, $temp_file3) = tempfile(DIR => $temp_dir); my ($temp_file4_handle, $temp_file4) = tempfile(DIR => $temp_dir); my ($temp_file5_handle, $temp_file5) = tempfile(DIR => $temp_dir); # create an array populated with the names of the temporary files th +at we expectd to see push (@expected_files, basename($temp_file1)); push (@expected_files, basename($temp_file2)); push (@expected_files, basename($temp_file3)); push (@expected_files, basename($temp_file4)); push (@expected_files, basename($temp_file5)); # now pass the temporary directory to the the function # the function should return an array @got_files with the names of t +he files in the directory @got_files = get_files_in_watched_directory($temp_dir, $project_name +, \@expected_files); print "\n\nGOT\n"; print Dumper(@got_files); print "\n"; print "\n\nEXPECTED\n"; print Dumper(@expected_files); print "\n"; #compare the two arrays is_deeply(\@got_files, \@expected_files, 'Function should return a l +ist of directory contents that will be processed'); };

    Amemded script under test

    ###################################################################### +################################## sub get_files_in_watched_directory { my ($directory_to_check, $project_name, $original_content_ref) = @_; my @problem_files; my @content_to_process; my $this_file; print "\n\nCalled Function: get_files_in_watched_directory"; print "\n Checking $directory_to_check"; chdir ($directory_to_check) || die "cannot chdir to directory $direc +tory_to_check: $!"; # Get everything - files and directories - and decide what to do wit +h each one opendir(DIR,$directory_to_check) || die "cannot open directory $dire +ctory_to_check: $!"; while (defined($this_file = readdir(DIR))) { my $full_file_name = $directory_to_check . '/' . $this_file; # ignore the special directories "." and '.." if ($this_file =~ /^\.\.?$/) { next } # wite anything else (file or directory) to an array to be process +ed later else { print "\n found: $this_file"; push (@content_to_process, $this_file) } } closedir(DIR); print "\n\nabout to retun"; #return @content_to_process; return (@{$original_content_ref}); }

      Having read/investigated a bit more, I think my original question/title was misleading - I think the issue comes down to: how do I compare two arrays for equality. Note: the equality test needs to sort the arrays first or ignore array order

        I think the issue comes down to: how do I compare two arrays for equality. Note: the equality test needs to sort the arrays first or ignore array order

        is_deeply is the best way to compare two data structures for equality. If the order of an array doesn't matter in the test, then it's fine to sort first: is_deeply([sort @got_files], [sort @expected_files]); (or you can sort the arrays earlier if you like). The other way to hold unsorted data would be with a hash (the difference being that an array allows duplicate values while a hash does not allow duplicate keys, and that an array will keep the order of its values while a hash will not), however is_deeply can also easily compare two hashes. So e.g. my %files = map { $_ => 1 } @files; is_deeply \%files, \%expect_files;

Re^2: inconistent test results when using is_deeply to test an array returned from a function
by APGRMF (Novice) on Sep 25, 2014 at 07:38 UTC

    Thanks. Good spot.

    I've applied a closedir as suggested. However, first indications are that the test is still returning inconsistent results.