File: 02-lowlevel.t

package info (click to toggle)
libhash-safekeys-perl 0.04-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 112 kB
  • sloc: perl: 220; makefile: 3
file content (154 lines) | stat: -rw-r--r-- 3,837 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use Hash::SafeKeys ':all';
use Test::More tests => 18;
use strict;
use warnings;

# exercise the low-level iterator functions  save_iterator_state  and
# restore_iterator_state

my %hash = (
    foo => 123,
    bar => "456",
    baz => [ 3, 17, "Alpha", { "Bravo" => "Charlie", "Delta" => "Echo" },
	     [ "Foxtrot", "Golf", "Hotel" ], *STDERR,
	     sub { my($i,$j,$k) = @_; return 42*$i+$j/$k; } ],
    quux => { "Lima" => "Mike",
	      "November" => *Oscar,
	      "Papa" => sub { "Quebec" },
	      "Romeo" => [ qw(Sierra Tango Uniform) ],
	      "Victor" => { "Whiskey" => { "X-ray" => "Yankee" } },
	      "Zulu" => undef }
    );
close *Oscar if 0; # suppress "used only once" warning

#############################################################################

my @k1 = keys %hash;
my @v1 = values %hash;
my @k2 = safekeys %hash;
my @v2 = safevalues %hash;

my $it = save_iterator_state(\%hash);
my @k3 = keys %hash;
my @v3 = values %hash;
restore_iterator_state(\%hash, $it);

ok("@k1" eq "@k3", 'keys from new iterator match keys');
ok("@k2" eq "@k3", 'keys from new iterator match safekeys');

ok("@v1" eq "@v3", 'keys from new iterator match values');
ok("@v2" eq "@v3", 'keys from new iterator match safevalues');


my @it = map { save_iterator_state(\%hash) } 0 .. 100;
ok(1, 'multiple calls to save_iterator_state does not crash');
my $z = 0;
$z += restore_iterator_state(\%hash, $_) for reverse @it;
ok($z == @it, 'all restore calls successful');
ok(!restore_iterator_state(\%hash, $it[20]),
   'extraneous restore_iterator_state is returns false');



# save way to call keys inside each

my $c = 0;
my %foo = (abc => 123, def => 456);
while (each %foo) {
    last if $c++ > 100;
    keys %foo;
}
ok($c >= 100, 'builtin keys inside each makes infinite loop');

keys %foo;
$c = 0;
while (each %foo) {
    last if $c++ > 100;
    my $it = save_iterator_state(\%foo);
    keys %foo;
    restore_iterator_state(\%foo,$it);    
}
ok($c < 100, 'builtin keys with iterator_state guard safe inside each');



# safely modify values
my %bar = ('aa' .. 'zz');
$c = 0;
while (each %bar) {
    foreach (values %bar) {
        s/ez/EZ/g;
    }
    last if $c++ > 1000;
}
ok($c >= 1000, 'builtin values inside each makes infinite loop');
ok($bar{"ey"} eq 'EZ', 'values modified');

$c = 0;
keys %bar;
while (each %bar) {
    foreach (safevalues %bar) {
        s/in/IN/;
    }
    last if $c++ > 1000;
}
ok($c < 1000, 'safevalues inside each is safe');
ok($bar{"im"} eq "in" && $bar{"im"} ne "IN", 'safevalues not modified');

keys %bar;
$c = 0;
while (each %bar) {
    my $it = save_iterator_state(\%bar);
    foreach (values %bar) {
        s/xz/XZ/;
    }
    restore_iterator_state(\%bar,$it);
    last if $c++ > 1000;
}
ok($c < 1000, 'values inside each is safe with iterator_state guard');
ok($bar{"xy"} eq 'XZ', 'values modified');



# nested each
my $hash2 = { 1 .. 10 };
my $hash3 = { 1 .. 10 };
my $count = 0;
my %r;
EACH1: while (my ($k2,$v2) = each %$hash2) {
    while (my ($k3,$v3) = each %$hash3) {
        $count++;
        last EACH1 if $count > 100;
        $r{"$k2:$k3"}++;
    }
}
ok($count < 100, 'nested each ok for different hash');
keys %$hash2;

$count = 0;
my $hash4 = $hash2;
EACH2: while (my ($k2,$v2) = each %$hash2) {
    while (my ($k4,$v4) = each %$hash4) {
        $count++;
        last EACH2 if $count > 100;
        $r{"$k2:$k4"}++;
    }
}
ok($count >= 100, 'nested each not ok for same hash');
keys %$hash2;

$count = 0;
EACH3: while (my ($k2,$v2) = each %$hash2) {
    my $it = Hash::SafeKeys::save_iterator_state($hash4);
    while (my ($k4,$v4) = each %$hash4) {
        $count++;
        last EACH3 if $count > 100;
        $r{"$k2:$k4"}++;
    }
    Hash::SafeKeys::restore_iterator_state($hash4, $it);
}
ok($count < 100, 'safe nested hash ok for same hash');
keys %$hash2;