xref: /openbsd-src/gnu/usr.bin/perl/cpan/Memoize/t/cache.t (revision f2a19305cfc49ea4d1a5feb55cd6c283c6f1e031)
1*f2a19305Safresh1use strict; use warnings;
2*f2a19305Safresh1use Memoize 0.45 qw(memoize unmemoize);
3*f2a19305Safresh1use Fcntl;
4*f2a19305Safresh1use Test::More tests => 65;
5*f2a19305Safresh1
6*f2a19305Safresh1sub list { wantarray ? @_ : $_[-1] }
7*f2a19305Safresh1
8*f2a19305Safresh1# Test FAULT
9*f2a19305Safresh1sub ns {}
10*f2a19305Safresh1sub na {}
11*f2a19305Safresh1ok eval { memoize 'ns', SCALAR_CACHE => 'FAULT'; 1 }, 'SCALAR_CACHE => FAULT';
12*f2a19305Safresh1ok eval { memoize 'na', LIST_CACHE => 'FAULT'; 1 }, 'LIST_CACHE => FAULT';
13*f2a19305Safresh1is eval { scalar(ns()) }, undef, 'exception in scalar context';
14*f2a19305Safresh1is eval { list(na()) }, undef, 'exception in list context';
15*f2a19305Safresh1
16*f2a19305Safresh1# Test FAULT/FAULT
17*f2a19305Safresh1sub dummy {1}
18*f2a19305Safresh1for ([qw(FAULT FAULT)], [qw(FAULT MERGE)], [qw(MERGE FAULT)]) {
19*f2a19305Safresh1	my ($l_opt, $s_opt) = @$_;
20*f2a19305Safresh1	my $memodummy = memoize 'dummy', LIST_CACHE => $l_opt, SCALAR_CACHE => $s_opt, INSTALL => undef;
21*f2a19305Safresh1	my ($ret, $e);
22*f2a19305Safresh1	{ local $@; $ret = eval { scalar $memodummy->() }; $e = $@ }
23*f2a19305Safresh1	is $ret, undef, "scalar context fails under $l_opt/$s_opt";
24*f2a19305Safresh1	like $e, qr/^Anonymous function called in forbidden scalar context/, '... with the right error message';
25*f2a19305Safresh1	{ local $@; $ret = eval { +($memodummy->())[0] }; $e = $@ }
26*f2a19305Safresh1	is $ret, undef, "list context fails under $l_opt/$s_opt";
27*f2a19305Safresh1	like $e, qr/^Anonymous function called in forbidden list context/, '... with the right error message';
28*f2a19305Safresh1	unmemoize $memodummy;
29*f2a19305Safresh1}
30*f2a19305Safresh1
31*f2a19305Safresh1# Test HASH
32*f2a19305Safresh1my (%s, %l);
33*f2a19305Safresh1sub nul {}
34*f2a19305Safresh1ok eval { memoize 'nul', SCALAR_CACHE => [HASH => \%s], LIST_CACHE => [HASH => \%l]; 1 }, '*_CACHE => HASH';
35*f2a19305Safresh1nul('x');
36*f2a19305Safresh1nul('y');
37*f2a19305Safresh1is_deeply [sort keys %s], [qw(x y)], 'scalar context calls populate SCALAR_CACHE';
38*f2a19305Safresh1is_deeply \%l, {}, '... and does not touch the LIST_CACHE';
39*f2a19305Safresh1%s = ();
40*f2a19305Safresh1() = nul('p');
41*f2a19305Safresh1() = nul('q');
42*f2a19305Safresh1is_deeply [sort keys %l], [qw(p q)], 'list context calls populate LIST_CACHE';
43*f2a19305Safresh1is_deeply \%s, {}, '... and does not touch the SCALAR_CACHE';
44*f2a19305Safresh1
45*f2a19305Safresh1# Test MERGE
46*f2a19305Safresh1sub xx { wantarray }
47*f2a19305Safresh1ok !scalar(xx()), 'false in scalar context';
48*f2a19305Safresh1ok list(xx()), 'true in list context';
49*f2a19305Safresh1ok eval { memoize 'xx', LIST_CACHE => 'MERGE'; 1 }, 'LIST_CACHE => MERGE';
50*f2a19305Safresh1ok !scalar(xx()), 'false in scalar context again';
51*f2a19305Safresh1# Should return cached false value from previous invocation
52*f2a19305Safresh1ok !list(xx()), 'still false in list context';
53*f2a19305Safresh1
54*f2a19305Safresh1sub reff { [1,2,3] }
55*f2a19305Safresh1sub listf { (1,2,3) }
56*f2a19305Safresh1
57*f2a19305Safresh1memoize 'reff', LIST_CACHE => 'MERGE';
58*f2a19305Safresh1memoize 'listf';
59*f2a19305Safresh1
60*f2a19305Safresh1scalar reff();
61*f2a19305Safresh1is_deeply [reff()], [[1,2,3]], 'reff list context after scalar context';
62*f2a19305Safresh1
63*f2a19305Safresh1scalar listf();
64*f2a19305Safresh1is_deeply [listf()], [1,2,3], 'listf list context after scalar context';
65*f2a19305Safresh1
66*f2a19305Safresh1unmemoize 'reff';
67*f2a19305Safresh1memoize 'reff', LIST_CACHE => 'MERGE';
68*f2a19305Safresh1unmemoize 'listf';
69*f2a19305Safresh1memoize 'listf';
70*f2a19305Safresh1
71*f2a19305Safresh1is_deeply [reff()], [[1,2,3]], 'reff list context';
72*f2a19305Safresh1
73*f2a19305Safresh1is_deeply [listf()], [1,2,3], 'listf list context';
74*f2a19305Safresh1
75*f2a19305Safresh1sub f17 { return 17 }
76*f2a19305Safresh1memoize 'f17', SCALAR_CACHE => 'MERGE';
77*f2a19305Safresh1is_deeply [f17()], [17], 'f17 first call';
78*f2a19305Safresh1is_deeply [f17()], [17], 'f17 second call';
79*f2a19305Safresh1is scalar(f17()), 17, 'f17 scalar context call';
80*f2a19305Safresh1
81*f2a19305Safresh1my (%cache, $num_cache_misses);
82*f2a19305Safresh1sub cacheit {
83*f2a19305Safresh1	++$num_cache_misses;
84*f2a19305Safresh1	"cacheit result";
85*f2a19305Safresh1}
86*f2a19305Safresh1sub test_cacheit {
87*f2a19305Safresh1	is scalar(cacheit()), 'cacheit result', 'scalar context';
88*f2a19305Safresh1	is $num_cache_misses, 1, 'function called once';
89*f2a19305Safresh1
90*f2a19305Safresh1	is +(cacheit())[0], 'cacheit result', 'list context';
91*f2a19305Safresh1	is $num_cache_misses, 1, 'function not called again';
92*f2a19305Safresh1
93*f2a19305Safresh1	is_deeply [values %cache], [['cacheit result']], 'expected cached value';
94*f2a19305Safresh1
95*f2a19305Safresh1	%cache = ();
96*f2a19305Safresh1
97*f2a19305Safresh1	is +(cacheit())[0], 'cacheit result', 'list context';
98*f2a19305Safresh1	is $num_cache_misses, 2, 'function again called after clearing the cache';
99*f2a19305Safresh1
100*f2a19305Safresh1	is scalar(cacheit()), 'cacheit result', 'scalar context';
101*f2a19305Safresh1	is $num_cache_misses, 2, 'function not called again';
102*f2a19305Safresh1}
103*f2a19305Safresh1
104*f2a19305Safresh1memoize 'cacheit', LIST_CACHE => [HASH => \%cache], SCALAR_CACHE => 'MERGE';
105*f2a19305Safresh1test_cacheit;
106*f2a19305Safresh1unmemoize 'cacheit';
107*f2a19305Safresh1( $num_cache_misses, %cache ) = ();
108*f2a19305Safresh1memoize 'cacheit', SCALAR_CACHE => [HASH => \%cache], LIST_CACHE => 'MERGE';
109*f2a19305Safresh1test_cacheit;
110*f2a19305Safresh1
111*f2a19305Safresh1# Test errors
112*f2a19305Safresh1my @w;
113*f2a19305Safresh1my $sub = eval {
114*f2a19305Safresh1	local $SIG{'__WARN__'} = sub { push @w, @_ };
115*f2a19305Safresh1	memoize(sub {}, LIST_CACHE => ['TIE', 'WuggaWugga']);
116*f2a19305Safresh1};
117*f2a19305Safresh1is $sub, undef, 'bad TIE fails';
118*f2a19305Safresh1like $@, qr/^Can't locate WuggaWugga.pm in \@INC/, '... with the expected error';
119*f2a19305Safresh1like $w[0], qr/^TIE option to memoize\(\) is deprecated; use HASH instead/, '... and the expected deprecation warning';
120*f2a19305Safresh1is @w, 1, '... and no other warnings';
121*f2a19305Safresh1
122*f2a19305Safresh1is eval { memoize sub {}, LIST_CACHE => 'YOB GORGLE' }, undef, 'bad LIST_CACHE fails';
123*f2a19305Safresh1like $@, qr/^Unrecognized option to `LIST_CACHE': `YOB GORGLE'/, '... with the expected error';
124*f2a19305Safresh1
125*f2a19305Safresh1is eval { memoize sub {}, SCALAR_CACHE => ['YOB GORGLE'] }, undef, 'bad SCALAR_CACHE fails';
126*f2a19305Safresh1like $@, qr/^Unrecognized option to `SCALAR_CACHE': `YOB GORGLE'/, '... with the expected error';
127*f2a19305Safresh1
128*f2a19305Safresh1for my $option (qw(LIST_CACHE SCALAR_CACHE)) {
129*f2a19305Safresh1	is eval { memoize sub {}, $option => ['MERGE'] }, undef, "$option=>['MERGE'] fails";
130*f2a19305Safresh1	like $@, qr/^Unrecognized option to `$option': `MERGE'/, '... with the expected error';
131*f2a19305Safresh1}
132*f2a19305Safresh1
133*f2a19305Safresh1# this test needs a DBM which
134*f2a19305Safresh1# a) Memoize knows is scalar-only
135*f2a19305Safresh1# b) is always available (on all platforms, perl configs etc)
136*f2a19305Safresh1# c) never fails to load
137*f2a19305Safresh1# so we use AnyDBM_File (which fulfills (a) & (b))
138*f2a19305Safresh1# on top of a fake dummy DBM (ditto (b) & (c))
139*f2a19305Safresh1sub DummyDBM::TIEHASH { bless {}, shift }
140*f2a19305Safresh1$INC{'DummyDBM.pm'} = 1;
141*f2a19305Safresh1@AnyDBM_File::ISA = 'DummyDBM';
142*f2a19305Safresh1$sub = eval {
143*f2a19305Safresh1	no warnings;
144*f2a19305Safresh1	memoize sub {}, SCALAR_CACHE => [ TIE => 'AnyDBM_File' ], LIST_CACHE => 'MERGE';
145*f2a19305Safresh1};
146*f2a19305Safresh1is $sub, undef, 'smuggling in a scalar-only LIST_CACHE via MERGE fails';
147*f2a19305Safresh1like $@, qr/^You can't use AnyDBM_File for LIST_CACHE because it can only store scalars/,
148*f2a19305Safresh1	'... with the expected error';
149