police-dataflow 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,144 +2,271 @@ require File.expand_path('../helper.rb', File.dirname(__FILE__))
2
2
 
3
3
  describe Police::DataFlow::ProxyBase do
4
4
  before do
5
- @label = AutoFlowFixture.new
6
- @label_set = {}
7
- @autoflow_set = {}
8
- Police::DataFlow::Labeling.add_label_to_set @label, @label_set,
9
- @autoflow_set
5
+ Police::DataFlow::Proxies.clear_cache
6
+
7
+ @sticky_label = StickyFixture.new
8
+ @hook_label = HooksFlowFixture.new
9
+
10
10
  @proxied = ProxyingFixture.new
11
- @proxy_class = Police::DataFlow::Proxies.for ProxyingFixture, @label_set
12
- @proxy = @proxy_class.new @proxied, @proxy_class, @label_set, @autoflow_set
11
+
12
+ @sticky_label_set = {}
13
+ Police::DataFlow::Labeling.add_label_to_set @sticky_label,
14
+ @sticky_label_set
15
+ @sticky_proxy_class = ::Police::DataFlow::Proxies.for ProxyingFixture,
16
+ @sticky_label_set
17
+ @sticky_proxy = @sticky_proxy_class.new @proxied, @sticky_proxy_class,
18
+ @sticky_label_set
19
+
20
+ @hook_label_set = {}
21
+ Police::DataFlow::Labeling.add_label_to_set @hook_label, @hook_label_set
22
+ @hook_proxy_class = ::Police::DataFlow::Proxies.for ProxyingFixture,
23
+ @hook_label_set
24
+ @hook_proxy = @hook_proxy_class.new @proxied, @hook_proxy_class,
25
+ @hook_label_set
13
26
  end
14
27
  after { Police::DataFlow::Proxies.clear_cache }
15
-
16
- it 'proxies public methods' do
17
- # NOTE: this test exercises the slow path in method_missing
18
- @proxy.route('One', 'Two').must_equal ['One', 'Two']
28
+
29
+ it 'proxies public methods through sticky labels' do
30
+ # NOTE: this test exercises the define-and-call path in method_missing
31
+ @sticky_proxy.route('One', 'Two').must_equal ['One', 'Two']
19
32
  end
20
-
21
- it 'allows labels to filter the return value of public methods' do
22
- # NOTE: this test exercises the slow path in method_missing
23
- Police::DataFlow.labels(@proxy.route('One', 'Two')).must_equal [@label]
33
+
34
+ it 'proxies public methods through hook labels' do
35
+ # NOTE: this test exercises the define-and-call path in method_missing
36
+ @hook_proxy.route('One', 'Two').must_equal ['One', 'Two']
24
37
  end
25
-
38
+
39
+ it 'allows labels to stick to the return value of public methods' do
40
+ # NOTE: this test exercises the define-and-call path in method_missing
41
+ Police::DataFlow.labels(@sticky_proxy.route('One', 'Two')).must_equal(
42
+ [@sticky_label])
43
+ end
44
+
45
+ it 'allows labels to hook into the return value of public methods' do
46
+ # NOTE: this test exercises the define-and-call path in method_missing
47
+ Police::DataFlow.labels(@hook_proxy.route('One', 'Two')).must_equal(
48
+ [@hook_label])
49
+ end
50
+
26
51
  describe 'after proxying public methods' do
27
- before { @proxy.route 'One', 'Two' }
28
-
52
+ before do
53
+ @sticky_proxy.route 'One', 'Two'
54
+ @hook_proxy.route 'One', 'Two'
55
+ end
56
+
29
57
  it 'defines proxied methods on the fly' do
30
- @proxy_class.public_method_defined?(:route).must_equal true
31
- @proxy_class.instance_method(:route).owner.must_equal @proxy_class
58
+ @sticky_proxy_class.public_method_defined?(:route).must_equal true
59
+ @sticky_proxy_class.instance_method(:route).owner.must_equal(
60
+ @sticky_proxy_class)
61
+ @hook_proxy_class.public_method_defined?(:route).must_equal true
62
+ @hook_proxy_class.instance_method(:route).owner.must_equal(
63
+ @hook_proxy_class)
32
64
  end
33
65
 
34
66
  it 'still proxies public methods' do
35
67
  # NOTE: this test exercises the auto-generated proxy method's fast path
36
- @proxy.route('One', 'Two').must_equal ['One', 'Two']
68
+ @sticky_proxy.route('One', 'Two').must_equal ['One', 'Two']
69
+ @hook_proxy.route('One', 'Two').must_equal ['One', 'Two']
37
70
  end
38
-
39
- it 'still allows labels to filter the return value of public methods' do
71
+
72
+ it 'still allows labels to stick to the return value of methods' do
73
+ # NOTE: this test exercises the auto-generated proxy method's fast path
74
+ Police::DataFlow.labels(@sticky_proxy.route('One', 'Two')).must_equal(
75
+ [@sticky_label])
76
+ end
77
+
78
+ it 'still allows labels to hook into the return value of methods' do
40
79
  # NOTE: this test exercises the auto-generated proxy method's fast path
41
- Police::DataFlow.labels(@proxy.route('One', 'Two')).must_equal [@label]
80
+ Police::DataFlow.labels(@hook_proxy.route('One', 'Two')).must_equal(
81
+ [@hook_label])
42
82
  end
43
83
 
44
84
  it 'can still build proxies' do
45
- other_proxy = @proxy_class.new ProxyingFixture.new, @proxy_class,
46
- @label_set, @autoflow_set
47
- other_proxy.route('One', 'Two').must_equal ['One', 'Two']
85
+ other_sticky_proxy = @sticky_proxy_class.new ProxyingFixture.new,
86
+ @proxy_class, @sticky_label_set
87
+ other_sticky_proxy.route('One', 'Two').must_equal ['One', 'Two']
88
+
89
+ other_hook_proxy = @hook_proxy_class.new ProxyingFixture.new,
90
+ @proxy_class, @hook_label_set
91
+ other_hook_proxy.route('One', 'Two').must_equal ['One', 'Two']
48
92
  end
49
93
  end
50
-
51
- it 'proxies public methods with blocks' do
94
+
95
+ it 'proxies public methods with blocks through sticky labels' do
52
96
  # NOTE: this test exercises the slow path in method_missing
53
97
  result = []
54
- @proxy.route('One', 'Two') { |*args| result << args }
98
+ @sticky_proxy.route('One', 'Two') { |*args| result << args }
55
99
  result.must_equal [['One', 'Two']]
56
100
  end
57
-
58
- it 'allows labels to filter the yielded values of public methods' do
101
+
102
+ it 'proxies public methods with blocks through hook labels' do
103
+ result = []
104
+ @hook_proxy.route('One', 'Two') { |*args| result << args }
105
+ result.must_equal [['One', 'Two']]
106
+ end
107
+
108
+ it 'allows labels to stick to the yielded values of public methods' do
109
+ # NOTE: this test exercises the slow path in method_missing
110
+ @sticky_proxy.route('One', 'Two') do |*args|
111
+ args.each do |arg|
112
+ Police::DataFlow.labels(arg).must_equal [@sticky_label]
113
+ end
114
+ end
115
+ end
116
+
117
+ it 'allows labels to hook into the yielded values of public methods' do
59
118
  # NOTE: this test exercises the slow path in method_missing
60
- @proxy.route('One', 'Two') do |*args|
61
- args.each { |arg| Police::DataFlow.labels(arg).must_equal [@label] }
119
+ @hook_proxy.route('One', 'Two') do |*args|
120
+ args.each { |arg| Police::DataFlow.labels(arg).must_equal [@hook_label] }
62
121
  end
63
122
  end
64
123
 
65
124
  describe 'after proxying public methods with blocks' do
66
- before { @proxy.route('One', 'Two') { |*args| } }
67
-
125
+ before do
126
+ @sticky_proxy.route('One', 'Two') { |*args| }
127
+ @hook_proxy.route('One', 'Two') { |*args| }
128
+ end
129
+
68
130
  it 'defines proxied methods on the fly' do
69
- @proxy_class.public_method_defined?(:route).must_equal true
70
- @proxy_class.instance_method(:route).owner.must_equal @proxy_class
131
+ @sticky_proxy_class.public_method_defined?(:route).must_equal true
132
+ @sticky_proxy_class.instance_method(:route).owner.must_equal(
133
+ @sticky_proxy_class)
134
+ @hook_proxy_class.public_method_defined?(:route).must_equal true
135
+ @hook_proxy_class.instance_method(:route).owner.must_equal(
136
+ @hook_proxy_class)
137
+ end
138
+
139
+ it 'still proxies public methods with blocks through sticky labels' do
140
+ # NOTE: this test exercises the auto-generated proxy method's fast path
141
+ result = []
142
+ @sticky_proxy.route('One', 'Two') { |*args| result << args }
143
+ result.must_equal [['One', 'Two']]
71
144
  end
72
145
 
73
- it 'still proxies public methods with blocks' do
146
+ it 'still proxies public methods with blocks through hook labels' do
74
147
  # NOTE: this test exercises the auto-generated proxy method's fast path
75
148
  result = []
76
- @proxy.route('One', 'Two') { |*args| result << args }
149
+ @hook_proxy.route('One', 'Two') { |*args| result << args }
77
150
  result.must_equal [['One', 'Two']]
78
151
  end
79
152
 
80
- it 'still allows labels to filter the yielded values of public methods' do
153
+ it 'still allows labels to stick to the yielded values of methods' do
154
+ # NOTE: this test exercises the auto-generated proxy method's fast path
155
+ @hook_proxy.route('One', 'Two') do |*args|
156
+ args.each do |arg|
157
+ Police::DataFlow.labels(arg).must_equal [@hook_label]
158
+ end
159
+ end
160
+ end
161
+
162
+ it 'still allows labels to hook into the yielded values of methods' do
81
163
  # NOTE: this test exercises the auto-generated proxy method's fast path
82
- @proxy.route('One', 'Two') do |*args|
83
- args.each { |arg| Police::DataFlow.labels(arg).must_equal [@label] }
164
+ @hook_proxy.route('One', 'Two') do |*args|
165
+ args.each do |arg|
166
+ Police::DataFlow.labels(arg).must_equal [@hook_label]
167
+ end
84
168
  end
85
169
  end
86
- end
170
+ end
87
171
 
88
172
  it 'proxies protected methods' do
89
173
  # NOTE: this test exercises the slow path in method_missing
90
- @proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
174
+ @sticky_proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
175
+ @hook_proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
91
176
  end
92
177
 
93
- it 'allows labels to filter the return value of protected methods' do
178
+ it 'allows labels to hook into the return value of protected methods' do
94
179
  # NOTE: this test exercises the slow path in method_missing
95
- Police::DataFlow.labels(@proxy.__send__(:add, 'One', 'Two')).
96
- must_equal [@label]
180
+ Police::DataFlow.labels(@sticky_proxy.__send__(:add, 'One', 'Two')).
181
+ must_equal [@sticky_label]
97
182
  end
98
-
99
-
183
+
184
+ it 'allows labels to hook into the return value of protected methods' do
185
+ # NOTE: this test exercises the slow path in method_missing
186
+ Police::DataFlow.labels(@hook_proxy.__send__(:add, 'One', 'Two')).
187
+ must_equal [@hook_label]
188
+ end
189
+
100
190
  describe 'after proxying protected methods' do
101
- before { @proxy.__send__ :add, 'One', 'Two' }
102
-
191
+ before do
192
+ @sticky_proxy.__send__ :add, 'One', 'Two'
193
+ @hook_proxy.__send__ :add, 'One', 'Two'
194
+ end
195
+
103
196
  it 'defines proxied methods on the fly' do
104
- @proxy_class.protected_method_defined?(:add).must_equal true
105
- @proxy_class.instance_method(:add).owner.must_equal @proxy_class
197
+ @sticky_proxy_class.protected_method_defined?(:add).must_equal true
198
+ @sticky_proxy_class.instance_method(:add).owner.must_equal(
199
+ @sticky_proxy_class)
200
+ @hook_proxy_class.protected_method_defined?(:add).must_equal true
201
+ @hook_proxy_class.instance_method(:add).owner.must_equal(
202
+ @hook_proxy_class)
106
203
  end
107
204
 
108
205
  it 'still proxies protected methods' do
109
206
  # NOTE: this test exercises the auto-generated proxy method's fast path
110
- @proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
207
+ @sticky_proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
208
+ @hook_proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
209
+ end
210
+
211
+ it 'still allows labels to sticky into protected methods' do
212
+ Police::DataFlow.labels(@sticky_proxy.__send__(:add, 'One', 'Two')).
213
+ must_equal [@sticky_label]
111
214
  end
112
215
 
113
- it 'still allows labels to filter the return value of protected methods' do
216
+ it 'still allows labels to hook into protected methods' do
114
217
  # NOTE: this test exercises the auto-generated proxy method's fast path
115
- Police::DataFlow.labels(@proxy.__send__(:add, 'One', 'Two')).
116
- must_equal [@label]
218
+ Police::DataFlow.labels(@hook_proxy.__send__(:add, 'One', 'Two')).
219
+ must_equal [@hook_label]
117
220
  end
118
221
  end
119
-
120
- it 'proxies magic methods' do
121
- @proxy.magic_meth('One', 'Two').must_equal ['meth', 'One', 'Two']
222
+
223
+ it 'proxies method_missing methods' do
224
+ # NOTE: this test exercises the method_missing+send slow proxying path.
225
+ @sticky_proxy.magic_meth('One', 'Two').must_equal ['meth', 'One', 'Two']
226
+ @hook_proxy.magic_meth('One', 'Two').must_equal ['meth', 'One', 'Two']
122
227
  end
123
228
 
124
- it 'allows labels to filter the return value of magic methods' do
125
- Police::DataFlow.labels(@proxy.magic_meth('One', 'Two')).must_equal [@label]
229
+ it 'proxies method_missing methods with blocks' do
230
+ # NOTE: this test exercises the method_missing+send slow proxying path.
231
+ @sticky_proxy.magic_meth('One', 'Two') { |*args|
232
+ args.must_equal ['One', 'Two']
233
+ args
234
+ }.must_equal ['meth', ['One', 'Two']]
235
+ @hook_proxy.magic_meth('One', 'Two') { |*args|
236
+ args.must_equal ['One', 'Two']
237
+ args
238
+ }.must_equal ['meth', ['One', 'Two']]
126
239
  end
127
240
 
128
- describe 'after proxying magic methods' do
241
+ it 'allows labels to stick to method_missing methods return values' do
242
+ Police::DataFlow.labels(@sticky_proxy.magic_meth('One', 'Two')).
243
+ must_equal [@sticky_label]
244
+ end
245
+
246
+ it 'allows labels to hook into method_missing methods' do
247
+ Police::DataFlow.labels(@hook_proxy.magic_meth('One', 'Two')).
248
+ must_equal [@hook_label]
249
+ end
250
+
251
+ describe 'after proxying method_missing methods' do
129
252
  before do
130
- @proxy.magic_meth 'One', 'Two'
253
+ @sticky_proxy.magic_meth 'One', 'Two'
254
+ @hook_proxy.magic_meth 'One', 'Two'
131
255
  end
132
256
 
133
- it 'does not define magic proxied methods' do
134
- @proxy_class.public_method_defined?(:magic_meth).must_equal false
135
- end
257
+ it 'does not define proxied methods' do
258
+ @sticky_proxy_class.public_method_defined?(:magic_meth).must_equal false
259
+ @hook_proxy_class.public_method_defined?(:magic_meth).must_equal false
260
+ end
136
261
  end
137
-
262
+
138
263
  it 'proxies ==' do
139
- (@proxy == nil).must_equal '== proxied'
264
+ (@sticky_proxy == nil).must_equal '== proxied'
265
+ (@hook_proxy == nil).must_equal '== proxied'
140
266
  end
141
267
 
142
268
  it 'proxies !=' do
143
- (@proxy != nil).must_equal '!= proxied'
144
- end
269
+ (@sticky_proxy != nil).must_equal '!= proxied'
270
+ (@hook_proxy != nil).must_equal '!= proxied'
271
+ end
145
272
  end
@@ -0,0 +1,45 @@
1
+ require File.expand_path('../helper.rb', File.dirname(__FILE__))
2
+
3
+ describe Police::DataFlow::ProxyNumeric do
4
+ before do
5
+ Police::DataFlow::Proxies.clear_cache
6
+ @label = StickyFixture.new
7
+ @label_set = {}
8
+ Police::DataFlow::Labeling.add_label_to_set @label, @label_set
9
+ @proxied = 21
10
+ @proxy_class = Police::DataFlow::Proxies.for @proxied.class, @label_set
11
+ @proxy = @proxy_class.new @proxied, @proxy_class, @label_set
12
+ end
13
+ after { Police::DataFlow::Proxies.clear_cache }
14
+
15
+ it 'defines coerce' do
16
+ @proxy_class.instance_methods.must_include :coerce
17
+ end
18
+
19
+ it 'returns a two-element Array from coerce' do
20
+ coerced = @proxy.coerce 42
21
+ coerced.class.must_equal Array
22
+ coerced.length.must_equal 2
23
+ end
24
+
25
+ it 'proxies the argument when coercing' do
26
+ coerced = @proxy.coerce 42
27
+ coerced[0].must_equal 42
28
+ coerced[0].__id__.wont_equal 42.__id__
29
+ end
30
+
31
+ it 'returns self correctly when coercing' do
32
+ coerced = @proxy.coerce 42
33
+ coerced[1].__id__.must_equal @proxy.__id__
34
+ end
35
+
36
+ it 'does not double-proxy' do
37
+ @proxied2 = 22
38
+ @proxy2 = @proxy_class.new @proxied2, @proxy_class, @label_set
39
+ coerced = @proxy.coerce @proxy2
40
+ coerced[0].__id__.must_equal @proxy2.__id__
41
+ coerced[1].__id__.must_equal @proxy.__id__
42
+ coerced.class.must_equal Array
43
+ coerced.length.must_equal 2
44
+ end
45
+ end
@@ -1,7 +1,7 @@
1
1
  require File.expand_path('../helper.rb', File.dirname(__FILE__))
2
2
 
3
3
  describe Police::DataFlow::Proxying do
4
- describe '#add_class_methods' do
4
+ describe '#add_instance_methods' do
5
5
  before do
6
6
  @proxy_class = Class.new BasicObject do
7
7
  def self.__police_classes__
@@ -13,9 +13,10 @@ describe Police::DataFlow::Proxying do
13
13
  @proxy = @proxy_class.new
14
14
  @proxy.instance_exec(@proxied) { |p| @__police_proxied__ = p }
15
15
 
16
- Police::DataFlow::Proxying.add_class_methods @proxy_class, ProxyingFixture
16
+ Police::DataFlow::Proxying.add_instance_methods @proxy_class,
17
+ ProxyingFixture
17
18
  end
18
-
19
+
19
20
  it 'adds public methods' do
20
21
  @proxy_class.public_method_defined?(:length).must_equal true
21
22
  @proxy_class.public_method_defined?(:==).must_equal true
@@ -25,13 +26,13 @@ describe Police::DataFlow::Proxying do
25
26
  it 'adds a protected method' do
26
27
  @proxy_class.protected_method_defined?(:add).must_equal true
27
28
  end
28
-
29
+
29
30
  it 'adds a private method' do
30
31
  @proxy_class.private_method_defined?(:log).must_equal true
31
32
  end
32
33
  end
33
-
34
- describe '#add_class_method' do
34
+
35
+ describe '#add_instance_method' do
35
36
  before do
36
37
  @proxy_class = Class.new BasicObject do
37
38
  def self.__police_classes__
@@ -42,42 +43,42 @@ describe Police::DataFlow::Proxying do
42
43
  @proxy = @proxy_class.new
43
44
  @proxy.instance_exec(@proxied) { |p| @__police_proxied__ = p }
44
45
  end
45
-
46
+
46
47
  describe 'with protected method with arguments' do
47
48
  before do
48
49
  @method = ProxyingFixture.instance_method :add
49
- Police::DataFlow::Proxying.add_class_method @proxy_class, @method,
50
- :protected
50
+ Police::DataFlow::Proxying.add_instance_method @proxy_class, @method,
51
+ :protected
51
52
  end
52
-
53
+
53
54
  it 'defines the proxying method' do
54
- @proxy_class.protected_method_defined?(:add).must_equal true
55
+ @proxy_class.protected_method_defined?(:add).must_equal true
55
56
  end
56
-
57
+
57
58
  it "has the proxying method's arity match the original" do
58
- @proxy_class.instance_method(:add).arity.must_equal @method.arity
59
+ @proxy_class.instance_method(:add).arity.must_equal @method.arity
59
60
  end
60
-
61
+
61
62
  it 'proxies the method' do
62
63
  @proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
63
64
  end
64
65
  end
65
-
66
+
66
67
  describe 'with public method with variable arguments and blocks' do
67
68
  before do
68
69
  @method = ProxyingFixture.instance_method :route
69
- Police::DataFlow::Proxying.add_class_method @proxy_class, @method,
70
- :public
70
+ Police::DataFlow::Proxying.add_instance_method @proxy_class, @method,
71
+ :public
71
72
  end
72
-
73
+
73
74
  it 'defines the proxying method' do
74
- @proxy_class.public_method_defined?(:route).must_equal true
75
+ @proxy_class.public_method_defined?(:route).must_equal true
75
76
  end
76
-
77
+
77
78
  it "has the proxying method's arity match the original" do
78
- @proxy_class.instance_method(:route).arity.must_equal @method.arity
79
+ @proxy_class.instance_method(:route).arity.must_equal @method.arity
79
80
  end
80
-
81
+
81
82
  it 'proxies the method without a block' do
82
83
  @proxy.route('One', 'Two').must_equal ['One', 'Two']
83
84
  end
@@ -90,124 +91,171 @@ describe Police::DataFlow::Proxying do
90
91
  end
91
92
 
92
93
  it 'proxies protected methods' do
93
- Police::DataFlow::Proxying.add_class_method @proxy_class,
94
+ Police::DataFlow::Proxying.add_instance_method @proxy_class,
94
95
  ProxyingFixture.instance_method(:add), :protected
95
96
  @proxy_class.protected_method_defined?(:add).must_equal true
96
97
  @proxy.__send__(:add, 'One', 'Two').must_equal 'One, Two'
97
98
  end
98
99
  end
99
-
100
+
100
101
  describe '#proxy_method_definition' do
101
102
  it 'returns a non-empty string for a public method' do
102
- Police::DataFlow::Proxying.proxy_method_definition([AutoFlowFixture],
103
+ Police::DataFlow::Proxying.proxy_method_definition([StickyFixture],
103
104
  ProxyingFixture.instance_method(:length), :public).length.wont_equal 0
104
105
  end
105
106
 
106
107
  it 'returns a non-empty string for a private method' do
107
- Police::DataFlow::Proxying.proxy_method_definition([AutoFlowFixture],
108
+ Police::DataFlow::Proxying.proxy_method_definition([StickyFixture],
108
109
  ProxyingFixture.instance_method(:length), :private).length.
109
110
  wont_equal 0
110
111
  end
111
-
112
+
112
113
  # NOTE: testing the actual behavior would just duplicate the tests for
113
- # add_class_method
114
+ # add_instance_method
114
115
  end
115
-
116
+
116
117
  describe '#proxy_method_call' do
117
- it 'works for a public method without a block' do
118
+ it 'works for a public method' do
118
119
  Police::DataFlow::Proxying.proxy_method_call(
119
- ProxyingFixture.instance_method(:length), :public, false).
120
+ ProxyingFixture.instance_method(:length), :public).
120
121
  must_equal '@__police_proxied__.length()'
121
122
  end
122
123
 
123
- it 'works for a protected method without a block' do
124
+ it 'works for a protected method' do
124
125
  Police::DataFlow::Proxying.proxy_method_call(
125
- ProxyingFixture.instance_method(:add), :protected, false).
126
+ ProxyingFixture.instance_method(:add), :protected).
126
127
  must_equal '@__police_proxied__.__send__(:add, arg1, arg2)'
127
128
  end
128
129
 
129
- it 'works for a public method with a block' do
130
- Police::DataFlow::Proxying.proxy_method_call(
131
- ProxyingFixture.instance_method(:length), :public, true).
132
- must_equal '@__police_proxied__.length(&block)'
133
- end
134
-
135
- it 'works for a private method with a block' do
130
+ it 'works for a private method' do
136
131
  Police::DataFlow::Proxying.proxy_method_call(
137
- ProxyingFixture.instance_method(:length), :private, true).
138
- must_equal '@__police_proxied__.__send__(:length, &block)'
132
+ ProxyingFixture.instance_method(:length), :private).
133
+ must_equal '@__police_proxied__.__send__(:length)'
139
134
  end
140
135
 
141
- it 'works for a private method with arguments and a block' do
136
+ it 'works for a private method with arguments' do
142
137
  Police::DataFlow::Proxying.proxy_method_call(
143
- ProxyingFixture.instance_method(:log), :private, true).must_equal(
144
- '@__police_proxied__.__send__(:log, arg1, arg2, *args, &block)')
138
+ ProxyingFixture.instance_method(:log), :private).must_equal(
139
+ '@__police_proxied__.__send__(:log, arg1, arg2, *args)')
145
140
  end
146
141
  end
147
-
142
+
148
143
  describe '#proxy_yield_args_decorating' do
149
144
  let(:method) { ProxyingFixture.instance_method(:add) }
150
-
151
- it 'is empty if no label class is filtering' do
145
+
146
+ it 'is empty if no label class is hooking or auto-flowing' do
152
147
  Police::DataFlow::Proxying.proxy_yield_args_decorating([NoFlowFixture],
153
148
  method).must_equal ''
154
149
  end
155
-
156
- it 'works for one filtering label class' do
150
+
151
+ it 'works for one hooking label class' do
152
+ label2_class = Class.new BasicObject do
153
+ def self.yield_args_hook(method_name)
154
+ raise RuntimeError, 'Wrong method name' unless method_name == :add
155
+ :add_yield_args_hook
156
+ end
157
+ def self.sticky?
158
+ raise RuntimeError, 'sticky? should not be called'
159
+ end
160
+ end
161
+ golden = 'labels = @__police_labels__; ' \
162
+ "labels[#{label2_class.__id__}].each { |label, _| " \
163
+ "label.add_yield_args_hook(self, yield_args, arg1, arg2) }"
164
+ Police::DataFlow::Proxying.proxy_yield_args_decorating(
165
+ [NoFlowFixture, label2_class], method).must_equal golden
166
+ end
167
+
168
+ it 'works for one sticky label class' do
169
+ label2_class = Class.new BasicObject do
170
+ def self.yield_args_hook(method_name)
171
+ raise RuntimeError, 'Wrong method name' unless method_name == :add
172
+ nil
173
+ end
174
+ def self.sticky?
175
+ true
176
+ end
177
+ end
157
178
  golden = 'labels = @__police_labels__; ' \
158
- "labels[#{AutoFlowFixture.__id__}].each { |label, _| " \
159
- "label.sample_yield_args_hook(self, yield_args, arg1, arg2) }"
179
+ "labels[#{label2_class.__id__}].each { |label, _| " \
180
+ "yield_args.map! { |arg| ::Police::DataFlow.label(arg, label) } " \
181
+ "}"
160
182
  Police::DataFlow::Proxying.proxy_yield_args_decorating(
161
- [NoFlowFixture, AutoFlowFixture], method).must_equal golden
183
+ [NoFlowFixture, label2_class], method).must_equal golden
162
184
  end
163
185
 
164
- it 'works for two filtering label classes' do
186
+ it 'works for two hooking label classes' do
165
187
  label2_class = Class.new BasicObject do
166
188
  def self.yield_args_hook(method_name)
167
189
  :"#{method_name}_ah"
168
190
  end
169
191
  end
170
192
  golden = 'labels = @__police_labels__; ' \
171
- "labels[#{AutoFlowFixture.__id__}].each { |label, _| " \
172
- "label.sample_yield_args_hook(self, yield_args, arg1, arg2) }; " \
193
+ "labels[#{HooksFlowFixture.__id__}].each { |label, _| " \
194
+ "label.generic_yield_args_hook(self, yield_args, arg1, arg2) }; " \
173
195
  "labels[#{label2_class.__id__}].each { |label, _| " \
174
196
  "label.add_ah(self, yield_args, arg1, arg2) }"
175
197
  Police::DataFlow::Proxying.proxy_yield_args_decorating([NoFlowFixture,
176
- AutoFlowFixture, label2_class], method).must_equal golden
198
+ HooksFlowFixture, label2_class], method).must_equal golden
177
199
  end
178
200
  end
179
201
 
180
202
  describe '#proxy_return_decorating' do
181
203
  let(:method) { ProxyingFixture.instance_method(:add) }
182
-
183
- it 'is empty if no label class is filtering' do
204
+
205
+ it 'is empty if no label class is hooking or auto-flowing' do
184
206
  Police::DataFlow::Proxying.proxy_return_decorating([NoFlowFixture],
185
207
  method).must_equal ''
186
208
  end
187
-
188
- it 'works for one filtering label class' do
209
+
210
+ it 'works for one hooking label class' do
211
+ label2_class = Class.new BasicObject do
212
+ def self.return_hook(method_name)
213
+ raise RuntimeError, 'Wrong method name' unless method_name == :add
214
+ 'add_return_hook'
215
+ end
216
+ def self.sticky?(method_name)
217
+ raise RuntimeError, 'sticky? should not be called'
218
+ end
219
+ end
220
+ golden = 'labels = @__police_labels__; ' \
221
+ "labels[#{label2_class.__id__}].each { |label, _| " \
222
+ "return_value = label.add_return_hook(return_value, self, arg1, " \
223
+ "arg2) }"
224
+ Police::DataFlow::Proxying.proxy_return_decorating(
225
+ [NoFlowFixture, label2_class], method).must_equal golden
226
+ end
227
+
228
+ it 'works for one sticky label class' do
229
+ label2_class = Class.new BasicObject do
230
+ def self.return_hook(method_name)
231
+ raise RuntimeError, 'Wrong method name' unless method_name == :add
232
+ nil
233
+ end
234
+ def self.sticky?
235
+ true
236
+ end
237
+ end
189
238
  golden = 'labels = @__police_labels__; ' \
190
- "labels[#{AutoFlowFixture.__id__}].each { |label, _| " \
191
- "return_value = label.sample_return_hook(return_value, self, arg1, " \
192
- "arg2) }"
239
+ "labels[#{label2_class.__id__}].each { |label, _| " \
240
+ "return_value = ::Police::DataFlow.label(return_value, label) }"
193
241
  Police::DataFlow::Proxying.proxy_return_decorating(
194
- [NoFlowFixture, AutoFlowFixture], method).must_equal golden
242
+ [NoFlowFixture, label2_class], method).must_equal golden
195
243
  end
196
244
 
197
- it 'works for two filtering label classes' do
245
+ it 'works for two hooking label classes' do
198
246
  label2_class = Class.new BasicObject do
199
247
  def self.return_hook(method_name)
200
248
  :"#{method_name}_rh"
201
249
  end
202
250
  end
203
251
  golden = 'labels = @__police_labels__; ' \
204
- "labels[#{AutoFlowFixture.__id__}].each { |label, _| " \
205
- "return_value = label.sample_return_hook(return_value, self, arg1, " \
206
- "arg2) }; " \
252
+ "labels[#{HooksFlowFixture.__id__}].each { |label, _| " \
253
+ "return_value = label.generic_return_hook(return_value, self, "\
254
+ "arg1, arg2) }; " \
207
255
  "labels[#{label2_class.__id__}].each { |label, _| " \
208
256
  "return_value = label.add_rh(return_value, self, arg1, arg2) }"
209
257
  Police::DataFlow::Proxying.proxy_return_decorating([NoFlowFixture,
210
- AutoFlowFixture, label2_class], method).must_equal golden
258
+ HooksFlowFixture, label2_class], method).must_equal golden
211
259
  end
212
260
  end
213
261
 
@@ -217,29 +265,29 @@ describe Police::DataFlow::Proxying do
217
265
  Police::DataFlow::Proxying.proxy_argument_list(
218
266
  ProxyingFixture.instance_method(:length), false).must_equal ''
219
267
  end
220
-
268
+
221
269
  it 'works for a one-argument method' do
222
270
  Police::DataFlow::Proxying.proxy_argument_list(
223
271
  ProxyingFixture.instance_method(:==), false).must_equal 'arg1'
224
272
  end
225
-
273
+
226
274
  it 'works for a two-argument method' do
227
275
  Police::DataFlow::Proxying.proxy_argument_list(
228
276
  ProxyingFixture.instance_method(:add), false).
229
277
  must_equal 'arg1, arg2'
230
278
  end
231
-
279
+
232
280
  it 'works for a variable-argument method' do
233
281
  Police::DataFlow::Proxying.proxy_argument_list(
234
282
  ProxyingFixture.instance_method(:route), false).must_equal '*args'
235
283
  end
236
-
284
+
237
285
  it 'works for one fixed + variable-argument method' do
238
286
  Police::DataFlow::Proxying.proxy_argument_list(
239
287
  ProxyingFixture.instance_method(:<=>), false).
240
288
  must_equal 'arg1, *args'
241
289
  end
242
-
290
+
243
291
  it 'works for two fixed + variable-argument method' do
244
292
  Police::DataFlow::Proxying.proxy_argument_list(
245
293
  ProxyingFixture.instance_method(:log), false).
@@ -252,31 +300,31 @@ describe Police::DataFlow::Proxying do
252
300
  Police::DataFlow::Proxying.proxy_argument_list(
253
301
  ProxyingFixture.instance_method(:length), true).must_equal '&block'
254
302
  end
255
-
303
+
256
304
  it 'works for a one-argument method' do
257
305
  Police::DataFlow::Proxying.proxy_argument_list(
258
306
  ProxyingFixture.instance_method(:==), true).
259
307
  must_equal 'arg1, &block'
260
308
  end
261
-
309
+
262
310
  it 'works for a two-argument method' do
263
311
  Police::DataFlow::Proxying.proxy_argument_list(
264
312
  ProxyingFixture.instance_method(:add), true).
265
313
  must_equal 'arg1, arg2, &block'
266
314
  end
267
-
315
+
268
316
  it 'works for a variable-argument method' do
269
317
  Police::DataFlow::Proxying.proxy_argument_list(
270
318
  ProxyingFixture.instance_method(:route), true).
271
319
  must_equal '*args, &block'
272
320
  end
273
-
321
+
274
322
  it 'works for one fixed + variable-argument method' do
275
323
  Police::DataFlow::Proxying.proxy_argument_list(
276
324
  ProxyingFixture.instance_method(:<=>), true).
277
325
  must_equal 'arg1, *args, &block'
278
326
  end
279
-
327
+
280
328
  it 'works for two fixed + variable-argument method' do
281
329
  Police::DataFlow::Proxying.proxy_argument_list(
282
330
  ProxyingFixture.instance_method(:log), true).
@@ -284,4 +332,209 @@ describe Police::DataFlow::Proxying do
284
332
  end
285
333
  end
286
334
  end
335
+
336
+ describe '#proxy_call_argument_list' do
337
+ it 'uses proxy_argument_list for Ruby methods' do
338
+ Police::DataFlow::Proxying.proxy_call_argument_list(
339
+ ProxyingFixture.instance_method(:==)).must_equal 'arg1'
340
+ end
341
+
342
+ it 'uses low_level_call_argument_list for native methods' do
343
+ golden =
344
+ '(nil == arg1.__police_labels__) ? arg1 : arg1.__police_proxied__'
345
+ Police::DataFlow::Proxying.proxy_call_argument_list(
346
+ Object.instance_method(:==)).must_equal golden
347
+ end
348
+ end
349
+
350
+ describe '#proxy_low_level_call_argument_list' do
351
+ it 'works for an argument-less method' do
352
+ Police::DataFlow::Proxying.proxy_low_level_call_argument_list(
353
+ ProxyingFixture.instance_method(:length)).must_equal ''
354
+ end
355
+
356
+ it 'works for a one-argument method' do
357
+ golden =
358
+ '(nil == arg1.__police_labels__) ? arg1 : arg1.__police_proxied__'
359
+ Police::DataFlow::Proxying.proxy_low_level_call_argument_list(
360
+ ProxyingFixture.instance_method(:==)).must_equal golden
361
+ end
362
+
363
+ it 'works for a two-argument method' do
364
+ golden =
365
+ '(nil == arg1.__police_labels__) ? arg1 : arg1.__police_proxied__, ' +
366
+ '(nil == arg2.__police_labels__) ? arg2 : arg2.__police_proxied__'
367
+ Police::DataFlow::Proxying.proxy_low_level_call_argument_list(
368
+ ProxyingFixture.instance_method(:add)).must_equal golden
369
+ end
370
+
371
+ it 'works for a variable-argument method' do
372
+ golden = '*(args.map { |a| (nil == a.__police_labels__) ? a : ' +
373
+ 'a.__police_proxied__ })'
374
+ Police::DataFlow::Proxying.proxy_low_level_call_argument_list(
375
+ ProxyingFixture.instance_method(:route)).must_equal golden
376
+ end
377
+
378
+ it 'works for one fixed + variable-argument method' do
379
+ golden =
380
+ '(nil == arg1.__police_labels__) ? arg1 : arg1.__police_proxied__, ' +
381
+ '*(args.map { |a| (nil == a.__police_labels__) ? a : ' +
382
+ 'a.__police_proxied__ })'
383
+ Police::DataFlow::Proxying.proxy_low_level_call_argument_list(
384
+ ProxyingFixture.instance_method(:<=>)).must_equal golden
385
+ end
386
+
387
+ it 'works for two fixed + variable-argument method' do
388
+ golden =
389
+ '(nil == arg1.__police_labels__) ? arg1 : arg1.__police_proxied__, ' +
390
+ '(nil == arg2.__police_labels__) ? arg2 : arg2.__police_proxied__, ' +
391
+ '*(args.map { |a| (nil == a.__police_labels__) ? a : ' +
392
+ 'a.__police_proxied__ })'
393
+ Police::DataFlow::Proxying.proxy_low_level_call_argument_list(
394
+ ProxyingFixture.instance_method(:log)).must_equal golden
395
+ end
396
+ end
397
+
398
+ describe '#proxy_sticky_fastpath_check' do
399
+ it 'works for an argument-less method' do
400
+ Police::DataFlow::Proxying.proxy_sticky_fastpath_check(
401
+ ProxyingFixture.instance_method(:length)).must_equal ''
402
+ end
403
+
404
+ it 'works for a one-argument method' do
405
+ golden =
406
+ 'fast_sticky = (nil == arg1.__police_stickies__)'
407
+ Police::DataFlow::Proxying.proxy_sticky_fastpath_check(
408
+ ProxyingFixture.instance_method(:==)).must_equal golden
409
+ end
410
+
411
+ it 'works for a two-argument method' do
412
+ golden = 'fast_sticky = ' +
413
+ '(nil == arg1.__police_stickies__) && ' +
414
+ '(nil == arg2.__police_stickies__)'
415
+ Police::DataFlow::Proxying.proxy_sticky_fastpath_check(
416
+ ProxyingFixture.instance_method(:add)).must_equal golden
417
+ end
418
+
419
+ it 'works for a variable-argument method' do
420
+ golden = 'fast_sticky = (args.all? { |a| nil == a.__police_stickies__ })'
421
+ Police::DataFlow::Proxying.proxy_sticky_fastpath_check(
422
+ ProxyingFixture.instance_method(:route)).must_equal golden
423
+ end
424
+
425
+ it 'works for one fixed + variable-argument method' do
426
+ golden =
427
+ 'fast_sticky = (nil == arg1.__police_stickies__) && ' +
428
+ '(args.all? { |a| nil == a.__police_stickies__ })'
429
+ Police::DataFlow::Proxying.proxy_sticky_fastpath_check(
430
+ ProxyingFixture.instance_method(:<=>)).must_equal golden
431
+ end
432
+
433
+ it 'works for two fixed + variable-argument method' do
434
+ golden =
435
+ 'fast_sticky = (nil == arg1.__police_stickies__) && ' +
436
+ '(nil == arg2.__police_stickies__) && ' +
437
+ '(args.all? { |a| nil == a.__police_stickies__ })'
438
+ Police::DataFlow::Proxying.proxy_sticky_fastpath_check(
439
+ ProxyingFixture.instance_method(:log)).must_equal golden
440
+ end
441
+ end
442
+
443
+ describe '#proxy_sticky_gathering' do
444
+ it 'works for an argument-less method' do
445
+ Police::DataFlow::Proxying.proxy_sticky_gathering(
446
+ ProxyingFixture.instance_method(:length)).must_equal ''
447
+ end
448
+
449
+ it 'works for a one-argument method' do
450
+ golden = 'unless fast_sticky; sticky_labels = {}; ' +
451
+ 'unless nil == arg1.__police_stickies__; ' +
452
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
453
+ 'arg1.__police_stickies__); end; end'
454
+ Police::DataFlow::Proxying.proxy_sticky_gathering(
455
+ ProxyingFixture.instance_method(:==)).must_equal golden
456
+ end
457
+
458
+ it 'works for a two-argument method' do
459
+ golden = 'unless fast_sticky; sticky_labels = {}; ' +
460
+ 'unless nil == arg1.__police_stickies__; ' +
461
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
462
+ 'arg1.__police_stickies__); end; ' +
463
+ 'unless nil == arg2.__police_stickies__; ' +
464
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
465
+ 'arg2.__police_stickies__); end; end'
466
+
467
+ Police::DataFlow::Proxying.proxy_sticky_gathering(
468
+ ProxyingFixture.instance_method(:add)).must_equal golden
469
+ end
470
+
471
+ it 'works for a variable-argument method' do
472
+ golden = 'unless fast_sticky; sticky_labels = {}; ' +
473
+ 'args.each do |a|; ' +
474
+ 'unless nil == a.__police_stickies__; ' +
475
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
476
+ 'a.__police_stickies__); end; end; end'
477
+ Police::DataFlow::Proxying.proxy_sticky_gathering(
478
+ ProxyingFixture.instance_method(:route)).must_equal golden
479
+ end
480
+
481
+ it 'works for one fixed + variable-argument method' do
482
+ golden = 'unless fast_sticky; sticky_labels = {}; ' +
483
+ 'unless nil == arg1.__police_stickies__; ' +
484
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
485
+ 'arg1.__police_stickies__); end; ' +
486
+ 'args.each do |a|; ' +
487
+ 'unless nil == a.__police_stickies__; ' +
488
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
489
+ 'a.__police_stickies__); end; end; end'
490
+ Police::DataFlow::Proxying.proxy_sticky_gathering(
491
+ ProxyingFixture.instance_method(:<=>)).must_equal golden
492
+ end
493
+
494
+ it 'works for two fixed + variable-argument method' do
495
+ golden = 'unless fast_sticky; sticky_labels = {}; ' +
496
+ 'unless nil == arg1.__police_stickies__; ' +
497
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
498
+ 'arg1.__police_stickies__); end; ' +
499
+ 'unless nil == arg2.__police_stickies__; ' +
500
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
501
+ 'arg2.__police_stickies__); end; ' +
502
+ 'args.each do |a|; ' +
503
+ 'unless nil == a.__police_stickies__; ' +
504
+ '::Police::DataFlow::Labeling.merge_sets!(sticky_labels, ' +
505
+ 'a.__police_stickies__); end; end; end'
506
+ Police::DataFlow::Proxying.proxy_sticky_gathering(
507
+ ProxyingFixture.instance_method(:log)).must_equal golden
508
+ end
509
+ end
510
+
511
+ describe '#proxy_yield_sticky_decorating' do
512
+ it 'works for an argument-less method' do
513
+ Police::DataFlow::Proxying.proxy_yield_sticky_decorating(
514
+ ProxyingFixture.instance_method(:length)).must_equal ''
515
+ end
516
+
517
+ it 'works for a one-argument method' do
518
+ golden = 'unless fast_sticky; yield_args.map! do |a|; ' +
519
+ '::Police::DataFlow::Labeling.bulk_sticky_label(' +
520
+ 'a, sticky_labels); end; end'
521
+ Police::DataFlow::Proxying.proxy_yield_sticky_decorating(
522
+ ProxyingFixture.instance_method(:==)).must_equal golden
523
+ end
524
+ end
525
+
526
+ describe '#proxy_return_sticky_decorating' do
527
+ it 'works for an argument-less method' do
528
+ Police::DataFlow::Proxying.proxy_return_sticky_decorating(
529
+ ProxyingFixture.instance_method(:length)).must_equal ''
530
+ end
531
+
532
+ it 'works for a one-argument method' do
533
+ golden = 'unless fast_sticky; return_value = ' +
534
+ '::Police::DataFlow::Labeling.bulk_sticky_label(' +
535
+ 'return_value, sticky_labels); end'
536
+ Police::DataFlow::Proxying.proxy_return_sticky_decorating(
537
+ ProxyingFixture.instance_method(:==)).must_equal golden
538
+ end
539
+ end
287
540
  end