File: 11_pointcut_call.t

package info (click to toggle)
libaspect-perl 1.04-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 720 kB
  • sloc: perl: 6,846; makefile: 2
file content (156 lines) | stat: -rw-r--r-- 4,169 bytes parent folder | download | duplicates (4)
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
155
156
#!/usr/bin/perl

use strict;
BEGIN {
	$|  = 1;
	$^W = 1;
}

use Test::More tests => 35;
use Test::NoWarnings;
use Aspect;

my $good = 'SomePackage::some_method';
my $bad  = 'SomePackage::no_method';

pointcut_ok( string => 'SomePackage::some_method' );
pointcut_ok( re     => qr/some_method/            );
pointcut_ok( code   => sub { shift eq $good }     );

sub pointcut_ok {
	my $type      = shift;
	my $subject   = Aspect::Pointcut::Call->new(shift);

	# Do we get a compiled match function?
	my $compiled1 = $subject->compiled_weave;
	is( ref($compiled1), 'CODE', '->compiled_weave returns a CODE reference' );

	# Does it match the expected functions?
	my $good_matches = do { local $_ = $good; $compiled1->() };
	my $bad_matches  = do { local $_ = $bad;  $compiled1->() };
	ok(   $good_matches, "$type match"    );
	ok( ! $bad_matches,  "$type no match" );

	# Does it curry away to nothing?
	my $curried = $subject->curry_runtime;
	is( $curried, undef, 'Simple call curries away to nothing' );

	# Do we produce an appropriate compiled run-time function
	my $compiled2 = $subject->compiled_runtime;
	is( ref($compiled2), 'CODE', '->compiled_runtime returns a CODE reference' );

	# Does the compiled code work properly?
	my $good_match = do {
		local $Aspect::POINT = { sub_name => $good };
		$compiled2->();
	};
	my $bad_match = do {
		local $Aspect::POINT = { sub_name => $bad };
		$compiled2->();
	};
	ok(   $good_match, "$type match"    );
	ok( ! $bad_match,  "$type no match" );
}





######################################################################
# Overloading Tests

# Pointcut currying code will need to do boolean context checks on
# pointcuts, as will some user code.
# Validate we can actually be used in boolean context (and provide an
# entry point to examine where this overloads to in the debugger).
my $pointcut = call 'Foo::bar';
isa_ok( $pointcut, 'Aspect::Pointcut::Call' );
ok( $pointcut, 'Pointcut is usable in boolean context' );

# Test that negation creates a not pointcut
isa_ok( ! $pointcut, 'Aspect::Pointcut::Not' );





######################################################################
# Regression: Validate that the "not call and call" pattern works.

# The following package has two methods.
# A pointcut that defines "Not one and any method" should match two but
# not match one. And this rule should apply BOTH to the match_all
# define-time rule AND for the runtime rule.
SCOPE: {
	package One;

	sub one { }

	sub two { }
}

my $not_call_and_call = ! call('One::one') & call(qr/^One::/);
isa_ok( $not_call_and_call, 'Aspect::Pointcut::And' );

# Does match_all find only the second method?
is_deeply(
	[ $not_call_and_call->match_all ],
	[ 'One::two' ],
	'->match_all works as expected',
);

# Create the runtime-curried pointcut
my $curried = $not_call_and_call->curry_runtime;
is( $curried, undef, 'A call-only pointcut curries away to nothing' );





######################################################################
# Regression: Nested logic and nested call and run-time

# Combining nested logic with a mix of call and non-call pointcuts
# results in a situation where call pointcuts need to be retained
# at run-time so that we can limit calls to run-time pointcuts to the
# correct subset of cases to apply the run-time tests to.
SCOPE: {
	package Two;

	sub one { 1 }

	sub two { 2 }
}

my $complex = call qr/^Two::/ & (
	call qr/::one\z/
	| (
		wantscalar & call qr/::two\z/
	)
);
isa_ok( $complex, 'Aspect::Pointcut' );

ok(
	scalar $complex->match_contains('Aspect::Pointcut::Wantarray'),
	'Pointcut contains the Wantarray pointcut',
);

# We should match_all both functions
is_deeply(
	[ sort $complex->match_all ], #sort for new hash randomization
	[ 'Two::one', 'Two::two' ],
	'->match_all works as expected',
);

# Bind the aspect
before {
	$_[0]->return_value(0);
} $complex;

# Both functions should match in scalar context
is( scalar(Two::one()), 0, 'Scalar one matches' );
is( scalar(Two::two()), 0, 'Scalar two matches' );

# Only one should match in list context
is_deeply( [ Two::one() ], [ 0 ], 'List one matches' );
is_deeply( [ Two::two() ], [ 2 ], 'List two does not match' );