Test that unallocated gaps within arrays have zero size.
Nicholas Clark [Mon, 18 Apr 2011 11:12:37 +0000 (12:12 +0100)]
This gets to be a bit more complex than it would first seem, as Test::More's
is_deeply() gets the length of arrays using $#array syntax, and that operation
allocates structures within the array prior to 5.12. We can't use
stringification, as we need to test undefs, so roll our own minimal test
subroutine.

t/recurse.t

index 08524b1..4bebab2 100644 (file)
@@ -6,11 +6,10 @@
 # total_size([]) will NOT return the size of the ref + the array, it will only
 # return the size of the array alone!
 
-use Test::More tests => 3 + 4 *12;
+use Test::More tests => 16 + 4 *12;
 use strict;
 use Devel::Size ':all';
 
-
 #############################################################################
 # verify that pointer sizes in array slots are sensible:
 # create an array with 4 slots, 2 of them used
@@ -184,3 +183,51 @@ for my $size (2, 3, 7, 100)
   is ($full_hash, $element_size + $hash_size, 'properly handles undef/non-undef inside arrays');
 
   } # end for different sizes
+
+sub cmp_array_ro {
+    my($got, $want, $desc) = @_;
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    is(@$got, @$want, "$desc (same element count)");
+    my $i = @$want;
+    while ($i--) {
+       is($got->[$i], $want->[$i], "$desc (element $i)");
+    }
+}
+
+{
+    my $undef;
+    my $undef_size = total_size($undef);
+    cmp_ok($undef_size, '>', 0, 'non-zero size for NULL');
+
+    my $iv_size = total_size(1);
+    cmp_ok($iv_size, '>', 0, 'non-zero size for IV');
+
+    # Force the array to allocate storage for elements.
+    # This avoids making the assumption that just because it doesn't happen
+    # initially now, it won't stay that way forever.
+    my @array = 42;
+    my $array_1_size = total_size(\@array);
+    cmp_ok($array_1_size, '>', 0, 'non-zero size for array with 1 element');
+
+    $array[2] = 6 * 9;
+
+    my @copy = @array;
+
+    # This might be making too many assumptions about the current implementation
+    my $array_2_size = total_size(\@array);
+    is($array_2_size, $array_1_size + $iv_size,
+       "gaps in arrays don't allocate scalars");
+
+    # Avoid using is_deeply() as that will read $#array, which is a write
+    # action prior to 5.12. (Different writes on 5.10 and 5.8-and-earlier, but
+    # a write either way, allocating memory.
+    cmp_array_ro(\@array, \@copy, 'two arrays compare the same');
+
+    # A write action:
+    $array[1] = undef;
+
+    is(total_size(\@array), $array_2_size + $undef_size,
+       "assigning undef to a gap in an array allocates a scalar");
+
+    cmp_array_ro(\@array, \@copy, 'two arrays compare the same');
+}