metasploit-model 0.25.7 → 0.26.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +8 -8
  2. data/app/models/metasploit/model/search/operation/association.rb +57 -0
  3. data/app/models/metasploit/model/search/operator/association.rb +24 -14
  4. data/app/models/metasploit/model/search/operator/base.rb +19 -3
  5. data/app/models/metasploit/model/search/operator/single.rb +21 -1
  6. data/app/models/metasploit/model/search/query.rb +20 -1
  7. data/lib/metasploit/model/association/tree.rb +130 -0
  8. data/lib/metasploit/model/search.rb +61 -27
  9. data/lib/metasploit/model/search/association.rb +152 -8
  10. data/lib/metasploit/model/search/attribute.rb +112 -22
  11. data/lib/metasploit/model/search/operator.rb +53 -1
  12. data/lib/metasploit/model/search/operator/help.rb +39 -1
  13. data/lib/metasploit/model/search/with.rb +44 -1
  14. data/lib/metasploit/model/version.rb +2 -2
  15. data/spec/app/models/metasploit/model/search/operation/association_spec.rb +67 -0
  16. data/spec/app/models/metasploit/model/search/operator/association_spec.rb +76 -76
  17. data/spec/app/models/metasploit/model/search/operator/deprecated/author_spec.rb +54 -18
  18. data/spec/app/models/metasploit/model/search/operator/deprecated/authority_spec.rb +20 -8
  19. data/spec/app/models/metasploit/model/search/operator/deprecated/platform_spec.rb +20 -8
  20. data/spec/app/models/metasploit/model/search/operator/deprecated/ref_spec.rb +86 -26
  21. data/spec/app/models/metasploit/model/search/operator/deprecated/text_spec.rb +63 -21
  22. data/spec/lib/metasploit/model/search/association/tree_spec.rb +385 -0
  23. data/spec/lib/metasploit/model/search/association_spec.rb +99 -10
  24. data/spec/lib/metasploit/model/search_spec.rb +48 -107
  25. data/spec/support/shared/examples/search/query/metasploit/model/search/operator/deprecated/authority.rb +19 -7
  26. metadata +7 -1
@@ -55,8 +55,8 @@ describe Metasploit::Model::Search::Operator::Deprecated::Platform do
55
55
  let(:platforms_fully_qualified_name_operator) do
56
56
  Metasploit::Model::Search::Operator::Association.new(
57
57
  :association => :platforms,
58
- :attribute_operator => platform_fully_qualified_name_operator,
59
- :klass => klass
58
+ :klass => klass,
59
+ :source_operator => platform_fully_qualified_name_operator
60
60
  )
61
61
  end
62
62
 
@@ -75,8 +75,8 @@ describe Metasploit::Model::Search::Operator::Deprecated::Platform do
75
75
  let(:targets_name_operator) do
76
76
  Metasploit::Model::Search::Operator::Association.new(
77
77
  :association => :targets,
78
- :attribute_operator => target_name_operator,
79
- :klass => klass
78
+ :klass => klass,
79
+ :source_operator => target_name_operator
80
80
  )
81
81
  end
82
82
 
@@ -94,8 +94,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Platform do
94
94
  child('platforms.fully_qualified_name')
95
95
  end
96
96
 
97
- it 'should use formatted value for value' do
98
- operation.value.should == formatted_value
97
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
98
+ subject(:source_operation) {
99
+ operation.source_operation
100
+ }
101
+
102
+ it 'uses formatted value for value' do
103
+ expect(source_operation.value).to eq(formatted_value)
104
+ end
99
105
  end
100
106
  end
101
107
 
@@ -104,8 +110,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Platform do
104
110
  child('targets.name')
105
111
  end
106
112
 
107
- it 'should use formatted value for value' do
108
- operation.value.should == formatted_value
113
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
114
+ subject(:source_operation) {
115
+ operation.source_operation
116
+ }
117
+
118
+ it 'uses formatted value for value' do
119
+ expect(source_operation.value).to eq(formatted_value)
120
+ end
109
121
  end
110
122
  end
111
123
  end
@@ -29,8 +29,8 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
29
29
  let(:authorities_abbreviation_operator) do
30
30
  Metasploit::Model::Search::Operator::Association.new(
31
31
  :association => :authorities,
32
- :attribute_operator => abbreviation_operator,
33
- :klass => klass
32
+ :klass => klass,
33
+ :source_operator => abbreviation_operator
34
34
  )
35
35
  end
36
36
 
@@ -49,16 +49,16 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
49
49
  let(:references_designation_operator) do
50
50
  Metasploit::Model::Search::Operator::Association.new(
51
51
  :association => :references,
52
- :attribute_operator => designation_operator,
53
- :klass => klass
52
+ :klass => klass,
53
+ :source_operator => designation_operator
54
54
  )
55
55
  end
56
56
 
57
57
  let(:references_url_operator) do
58
58
  Metasploit::Model::Search::Operator::Association.new(
59
59
  :association => :references,
60
- :attribute_operator => url_operator,
61
- :klass => klass
60
+ :klass => klass,
61
+ :source_operator => url_operator
62
62
  )
63
63
  end
64
64
 
@@ -124,8 +124,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
124
124
  child('references.url')
125
125
  end
126
126
 
127
- it "should use portion of formatted value after 'URL-' for value" do
128
- operation.value.should == tail
127
+ context 'Metasploit::Model::Search::Operation::Association' do
128
+ subject(:source_operation) {
129
+ operation.source_operation
130
+ }
131
+
132
+ it "uses portion of formatted value after 'URL-' for value" do
133
+ expect(source_operation.value).to eq(tail)
134
+ end
129
135
  end
130
136
  end
131
137
  end
@@ -160,8 +166,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
160
166
  child('references.designation')
161
167
  end
162
168
 
163
- it "should use portion of formatted value after '-' for value" do
164
- operation.value.should == tail
169
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
170
+ subject(:source_operation) {
171
+ operation.source_operation
172
+ }
173
+
174
+ it "uses portion of formatted value after '-' for value" do
175
+ expect(source_operation.value).to eq(tail)
176
+ end
165
177
  end
166
178
  end
167
179
 
@@ -182,8 +194,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
182
194
  child('authorities.abbreviation')
183
195
  end
184
196
 
185
- it "should use portion of formatted value before '-' as value" do
186
- operation.value.should == head
197
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
198
+ subject(:source_operation) {
199
+ operation.source_operation
200
+ }
201
+
202
+ it "uses portion of formatted value before '-' as value" do
203
+ expect(source_operation.value).to eq(head)
204
+ end
187
205
  end
188
206
  end
189
207
 
@@ -192,8 +210,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
192
210
  child('references.designation')
193
211
  end
194
212
 
195
- it "should use portion of formatted value after '-' as value" do
196
- operation.value.should == tail
213
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
214
+ subject(:source_operation) {
215
+ operation.source_operation
216
+ }
217
+
218
+ it "uses portion of formatted value after '-' as value" do
219
+ expect(source_operation.value).to eq(tail)
220
+ end
197
221
  end
198
222
  end
199
223
 
@@ -218,8 +242,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
218
242
  child('authorities.abbreviation')
219
243
  end
220
244
 
221
- it "should use portion of formatted value before '-' for value" do
222
- operation.value.should == head
245
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
246
+ subject(:source_operation) {
247
+ operation.source_operation
248
+ }
249
+
250
+ it "use portion of formatted value before '-' for value" do
251
+ expect(source_operation.value).to eq(head)
252
+ end
223
253
  end
224
254
  end
225
255
 
@@ -250,8 +280,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
250
280
  child('authorities.abbreviation')
251
281
  end
252
282
 
253
- it "should use portion of format value before '-' for value" do
254
- operation.value.should == head
283
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
284
+ subject(:source_operation) {
285
+ operation.source_operation
286
+ }
287
+
288
+ it "uses portion of format value before '-' for value" do
289
+ expect(source_operation.value).to eq(head)
290
+ end
255
291
  end
256
292
  end
257
293
 
@@ -260,8 +296,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
260
296
  child('references.designation')
261
297
  end
262
298
 
263
- it "should use portion of format value after '-' for value" do
264
- operation.value.should == tail
299
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
300
+ subject(:source_operation) {
301
+ operation.source_operation
302
+ }
303
+
304
+ it "uses portion of format value after '-' for value" do
305
+ expect(source_operation.value).to eq(tail)
306
+ end
265
307
  end
266
308
  end
267
309
 
@@ -297,8 +339,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
297
339
  child('authorities.abbreviation')
298
340
  end
299
341
 
300
- it 'should use formatted value for value' do
301
- operation.value.should == formatted_value
342
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
343
+ subject(:source_operation) {
344
+ operation.source_operation
345
+ }
346
+
347
+ it 'uses formatted value for value' do
348
+ expect(source_operation.value).to eq(formatted_value)
349
+ end
302
350
  end
303
351
  end
304
352
 
@@ -307,8 +355,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
307
355
  child('references.designation')
308
356
  end
309
357
 
310
- it 'should use formatted value for value' do
311
- operation.value.should == formatted_value
358
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
359
+ subject(:source_operation) {
360
+ operation.source_operation
361
+ }
362
+
363
+ it 'uses formatted value for value' do
364
+ expect(source_operation.value).to eq(formatted_value)
365
+ end
312
366
  end
313
367
  end
314
368
 
@@ -317,8 +371,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Ref do
317
371
  child('references.url')
318
372
  end
319
373
 
320
- it 'should use formatted value for value' do
321
- operation.value.should == formatted_value
374
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
375
+ subject(:source_operation) {
376
+ operation.source_operation
377
+ }
378
+
379
+ it 'uses formatted value for value' do
380
+ expect(source_operation.value).to eq(formatted_value)
381
+ end
322
382
  end
323
383
  end
324
384
  end
@@ -54,7 +54,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
54
54
  let(:actions_name_operator) do
55
55
  Metasploit::Model::Search::Operator::Association.new(
56
56
  :association => :actions,
57
- :attribute_operator => action_name_operator,
57
+ :source_operator => action_name_operator,
58
58
  :klass => klass
59
59
  )
60
60
  end
@@ -74,7 +74,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
74
74
  let(:architectures_abbreviation_operator) do
75
75
  Metasploit::Model::Search::Operator::Association.new(
76
76
  :association => :architectures,
77
- :attribute_operator => architecture_abbreviation_operator,
77
+ :source_operator => architecture_abbreviation_operator,
78
78
  :klass => klass
79
79
  )
80
80
  end
@@ -94,7 +94,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
94
94
  let(:authorities_abbreviation_operator) do
95
95
  Metasploit::Model::Search::Operator::Association.new(
96
96
  :association => :authorities,
97
- :attribute_operator => authority_abbreviation_operator,
97
+ :source_operator => authority_abbreviation_operator,
98
98
  :klass => klass
99
99
  )
100
100
  end
@@ -141,7 +141,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
141
141
  let(:platforms_fully_qualified_name_operator) do
142
142
  Metasploit::Model::Search::Operator::Association.new(
143
143
  :association => :platforms,
144
- :attribute_operator => platform_fully_qualified_name_operator,
144
+ :source_operator => platform_fully_qualified_name_operator,
145
145
  :klass => klass
146
146
  )
147
147
  end
@@ -167,7 +167,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
167
167
  let(:references_designation_operator) do
168
168
  Metasploit::Model::Search::Operator::Association.new(
169
169
  :association => :references,
170
- :attribute_operator => reference_designation_operator,
170
+ :source_operator => reference_designation_operator,
171
171
  :klass => klass
172
172
  )
173
173
  end
@@ -183,7 +183,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
183
183
  let(:references_url_operator) do
184
184
  Metasploit::Model::Search::Operator::Association.new(
185
185
  :association => :references,
186
- :attribute_operator => reference_url_operator,
186
+ :source_operator => reference_url_operator,
187
187
  :klass => klass
188
188
  )
189
189
  end
@@ -203,7 +203,7 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
203
203
  let(:targets_name_operator) do
204
204
  Metasploit::Model::Search::Operator::Association.new(
205
205
  :association => :targets,
206
- :attribute_operator => target_name_operator,
206
+ :source_operator => target_name_operator,
207
207
  :klass => klass
208
208
  )
209
209
  end
@@ -253,8 +253,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
253
253
  child('actions.name')
254
254
  end
255
255
 
256
- it 'should use formatted value for value' do
257
- operation.value.should == formatted_value
256
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
257
+ subject(:source_operation) {
258
+ operation.source_operation
259
+ }
260
+
261
+ it 'should use formatted value for value' do
262
+ expect(source_operation.value).to eq(formatted_value)
263
+ end
258
264
  end
259
265
  end
260
266
 
@@ -263,8 +269,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
263
269
  child('architectures.abbreviation')
264
270
  end
265
271
 
266
- it 'should use formatted value for value' do
267
- operation.value.should == formatted_value
272
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
273
+ subject(:source_operation) {
274
+ operation.source_operation
275
+ }
276
+
277
+ it 'should use formatted value for value' do
278
+ expect(source_operation.value).to eq(formatted_value)
279
+ end
268
280
  end
269
281
  end
270
282
 
@@ -289,8 +301,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
289
301
  grandchild('platforms.fully_qualified_name')
290
302
  end
291
303
 
292
- it 'should use formatted value for value' do
293
- grandchild_operation.value.should == formatted_value
304
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
305
+ subject(:source_operation) {
306
+ grandchild_operation.source_operation
307
+ }
308
+
309
+ it 'should use formatted value for value' do
310
+ expect(source_operation.value).to eq(formatted_value)
311
+ end
294
312
  end
295
313
  end
296
314
 
@@ -299,8 +317,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
299
317
  grandchild('targets.name')
300
318
  end
301
319
 
302
- it 'should use formatted value for value' do
303
- grandchild_operation.value.should == formatted_value
320
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
321
+ subject(:source_operation) {
322
+ grandchild_operation.source_operation
323
+ }
324
+
325
+ it 'should use formatted value for value' do
326
+ expect(source_operation.value).to eq(formatted_value)
327
+ end
304
328
  end
305
329
  end
306
330
  end
@@ -327,8 +351,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
327
351
  grandchild('authorities.abbreviation')
328
352
  end
329
353
 
330
- it 'should use formatted value for value' do
331
- grandchild_operation.value.should == formatted_value
354
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
355
+ subject(:source_operation) {
356
+ grandchild_operation.source_operation
357
+ }
358
+
359
+ it 'should use formatted value for value' do
360
+ expect(source_operation.value).to eq(formatted_value)
361
+ end
332
362
  end
333
363
  end
334
364
 
@@ -337,8 +367,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
337
367
  grandchild('references.designation')
338
368
  end
339
369
 
340
- it 'should use formatted value for value' do
341
- grandchild_operation.value.should == formatted_value
370
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
371
+ subject(:source_operation) {
372
+ grandchild_operation.source_operation
373
+ }
374
+
375
+ it 'should use formatted value for value' do
376
+ expect(source_operation.value).to eq(formatted_value)
377
+ end
342
378
  end
343
379
  end
344
380
 
@@ -347,8 +383,14 @@ describe Metasploit::Model::Search::Operator::Deprecated::Text do
347
383
  grandchild('references.url')
348
384
  end
349
385
 
350
- it 'should use formatted value for value' do
351
- grandchild_operation.value.should == formatted_value
386
+ context 'Metasploit::Model::Search::Operation::Association#source_operation' do
387
+ subject(:source_operation) {
388
+ grandchild_operation.source_operation
389
+ }
390
+
391
+ it 'should use formatted value for value' do
392
+ expect(source_operation.value).to eq(formatted_value)
393
+ end
352
394
  end
353
395
  end
354
396
  end
@@ -0,0 +1,385 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metasploit::Model::Association::Tree do
4
+ context 'expand' do
5
+ subject(:expand) {
6
+ described_class.expand(associations)
7
+ }
8
+
9
+ context 'with Array<Hash>' do
10
+ let(:associations) {
11
+ [
12
+ {
13
+ first_parent: :first_child
14
+ },
15
+ {
16
+ second_parent: :second_child
17
+ }
18
+ ]
19
+ }
20
+
21
+ it 'merges hashes' do
22
+ expect(expand).to have_key(:first_parent)
23
+
24
+ first_child_tree = expand[:first_parent]
25
+
26
+ expect(first_child_tree).to have_key(:first_child)
27
+ expect(first_child_tree[:first_child]).to be_nil
28
+
29
+ expect(expand).to have_key(:second_parent)
30
+
31
+ second_child_tree = expand[:second_parent]
32
+
33
+ expect(second_child_tree).to have_key(:second_child)
34
+ expect(second_child_tree[:second_child]).to be_nil
35
+ end
36
+ end
37
+
38
+
39
+ context 'with Array<Symbol>' do
40
+ let(:associations) {
41
+ [
42
+ :first,
43
+ :second
44
+ ]
45
+ }
46
+
47
+ it 'expands to Hash{Symbol => nil}' do
48
+ expect(expand).to have_key(:first)
49
+ expect(expand[:first]).to be_nil
50
+
51
+ expect(expand).to have_key(:second)
52
+ expect(expand[:second]).to be_nil
53
+ end
54
+ end
55
+
56
+ context 'with Hash<Symbol>' do
57
+ let(:associations) {
58
+ {
59
+ parent: :child
60
+ }
61
+ }
62
+
63
+ it 'expands to Hash{Symbol => Hash{Symbol => nil}}' do
64
+ expect(expand).to have_key(:parent)
65
+
66
+ child_tree = expand[:parent]
67
+
68
+ expect(child_tree).to have_key(:child)
69
+ expect(child_tree[:child]).to be_nil
70
+ end
71
+ end
72
+
73
+ context 'with Symbol' do
74
+ let(:associations) {
75
+ :symbol
76
+ }
77
+
78
+ it 'expands to Hash{Symbol => nil}' do
79
+ expect(expand).to have_key(:symbol)
80
+ expect(expand[:symbol]).to be_nil
81
+ end
82
+ end
83
+ end
84
+
85
+ context 'merge' do
86
+ subject(:merge) {
87
+ described_class.merge(first, second)
88
+ }
89
+
90
+ context 'first' do
91
+ context 'with nil' do
92
+ let(:first) {
93
+ nil
94
+ }
95
+
96
+ context 'second' do
97
+ context 'with nil' do
98
+ let(:second) {
99
+ nil
100
+ }
101
+
102
+ it { should be_nil }
103
+ end
104
+
105
+ context 'without nil' do
106
+ let(:second) {
107
+ double('second')
108
+ }
109
+
110
+ it 'returns second' do
111
+ expect(merge).to eq(second)
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ context 'without nil' do
118
+ let(:first) {
119
+ {
120
+ common: {
121
+ first_common_child: nil
122
+ },
123
+ first: {
124
+ first_child: nil
125
+ }
126
+ }
127
+ }
128
+
129
+ context 'second' do
130
+ context 'with nil' do
131
+ let(:second) {
132
+ nil
133
+ }
134
+
135
+ it 'returns first' do
136
+ expect(merge).to eq(first)
137
+ end
138
+ end
139
+
140
+ context 'without nil' do
141
+ let(:second) {
142
+ {
143
+ common: {
144
+ second_common_child: nil
145
+ },
146
+ second: {
147
+ second_child: nil
148
+ }
149
+ }
150
+ }
151
+
152
+ it 'merges trees under common keys' do
153
+ expect(merge).to have_key(:common)
154
+
155
+ common_tree = merge[:common]
156
+
157
+ expect(common_tree).to have_key(:first_common_child)
158
+ expect(common_tree[:first_common_child]).to be_nil
159
+ expect(common_tree).to have_key(:second_common_child)
160
+ expect(common_tree[:second_common_child]).to be_nil
161
+ end
162
+
163
+ it 'reuses uncommon keys' do
164
+ expect(merge[:first]).to eq(first[:first])
165
+ expect(merge[:second]).to eq(second[:second])
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ context 'operators' do
174
+ subject(:operators) {
175
+ described_class.operators(
176
+ expanded,
177
+ class: klass
178
+ )
179
+ }
180
+
181
+ let(:near_class) {
182
+ Class.new {
183
+ include Metasploit::Model::Search
184
+
185
+ search_attribute :near_boolean,
186
+ type: :boolean
187
+ search_attribute :near_string,
188
+ type: :string
189
+ }.tap { |klass|
190
+ stub_const('NearClass', klass)
191
+ }
192
+ }
193
+
194
+ let(:klass) {
195
+ near_class = self.near_class
196
+
197
+ Class.new do
198
+ include Metasploit::Model::Association
199
+
200
+ association :near_classes,
201
+ class_name: near_class.name
202
+ end
203
+ }
204
+
205
+ context 'with Hash{Symbol => nil}' do
206
+ let(:expanded) {
207
+ {
208
+ near_classes: nil
209
+ }
210
+ }
211
+
212
+ it 'includes a Metasploit::Model::Search::Operator::Association for each non-association operator on the associated class' do
213
+ near_classes_near_boolean = operators.find { |o| o.name == :'near_classes.near_boolean' }
214
+
215
+ expect(near_classes_near_boolean).to be_a Metasploit::Model::Search::Operator::Association
216
+ expect(near_classes_near_boolean.association).to eq(:near_classes)
217
+ expect(near_classes_near_boolean.klass).to eq(klass)
218
+
219
+ near_boolean = near_classes_near_boolean.source_operator
220
+
221
+ expect(near_boolean).to eq(near_class.search_operator_by_name.fetch(:near_boolean))
222
+
223
+ near_classes_near_string = operators.find { |o| o.name == :'near_classes.near_string' }
224
+
225
+ expect(near_classes_near_string).to be_a Metasploit::Model::Search::Operator::Association
226
+ expect(near_classes_near_string.association).to eq(:near_classes)
227
+ expect(near_classes_near_string.klass).to eq(klass)
228
+
229
+ near_string = near_classes_near_string.source_operator
230
+
231
+ expect(near_string).to eq(near_class.search_operator_by_name.fetch(:near_string))
232
+ end
233
+ end
234
+
235
+ context 'with Hash{Symbol => Hash}' do
236
+ let(:expanded) {
237
+ {
238
+ near_classes: {
239
+ far_class: nil
240
+ }
241
+ }
242
+ }
243
+
244
+ let(:far_class) {
245
+ Class.new {
246
+ include Metasploit::Model::Search
247
+
248
+ search_attribute :far_integer,
249
+ type: :integer
250
+ }.tap { |klass|
251
+ stub_const('FarClass', klass)
252
+ }
253
+ }
254
+
255
+ let(:near_class) {
256
+ super().tap { |klass|
257
+ far_class = self.far_class
258
+
259
+ klass.class_eval do
260
+ include Metasploit::Model::Association
261
+
262
+ association :far_class,
263
+ class_name: far_class.name
264
+ end
265
+ }
266
+ }
267
+
268
+ it 'includes a Metasploit::Model::Search::Operator::Association for each non-association operator on the near class' do
269
+ near_classes_near_boolean = operators.find { |o| o.name == :'near_classes.near_boolean' }
270
+
271
+ expect(near_classes_near_boolean).to be_a Metasploit::Model::Search::Operator::Association
272
+ expect(near_classes_near_boolean.association).to eq(:near_classes)
273
+ expect(near_classes_near_boolean.klass).to eq(klass)
274
+
275
+ near_boolean = near_classes_near_boolean.source_operator
276
+
277
+ expect(near_boolean).to eq(near_class.search_operator_by_name.fetch(:near_boolean))
278
+
279
+ near_classes_near_string = operators.find { |o| o.name == :'near_classes.near_string' }
280
+
281
+ expect(near_classes_near_string).to be_a Metasploit::Model::Search::Operator::Association
282
+ expect(near_classes_near_string.association).to eq(:near_classes)
283
+ expect(near_classes_near_string.klass).to eq(klass)
284
+
285
+ near_string = near_classes_near_string.source_operator
286
+
287
+ expect(near_string).to eq(near_class.search_operator_by_name.fetch(:near_string))
288
+ end
289
+
290
+ it 'includes Metasploit::Model::Search::Operator::Association for each non-association operator on the far class' do
291
+ near_classes_far_class_far_integer = operators.find { |o| o.name == :'near_classes.far_class.far_integer' }
292
+
293
+ expect(near_classes_far_class_far_integer).to be_a Metasploit::Model::Search::Operator::Association
294
+ expect(near_classes_far_class_far_integer.association).to eq(:near_classes)
295
+ expect(near_classes_far_class_far_integer.klass).to eq(klass)
296
+
297
+ far_class_far_integer = near_classes_far_class_far_integer.source_operator
298
+
299
+ expect(far_class_far_integer).to be_a Metasploit::Model::Search::Operator::Association
300
+ expect(far_class_far_integer.association).to eq(:far_class)
301
+ expect(far_class_far_integer.klass).to eq(near_class)
302
+
303
+ far_integer = far_class_far_integer.source_operator
304
+
305
+ expect(far_integer).to eq(far_class.search_operator_by_name.fetch(:far_integer))
306
+ end
307
+ end
308
+
309
+ context 'with nil' do
310
+ let(:expanded) {
311
+ nil
312
+ }
313
+
314
+ it { should == [] }
315
+ end
316
+ end
317
+
318
+
319
+ context 'reflect_on_association_on_class' do
320
+ subject(:reflect_on_association_on_class) {
321
+ described_class.reflect_on_association_on_class(association, klass)
322
+ }
323
+
324
+ let(:association) {
325
+ :associated_things
326
+ }
327
+
328
+ let(:klass) {
329
+ Class.new
330
+ }
331
+
332
+ context 'klass' do
333
+ context 'responds to reflect_on_association' do
334
+ let(:klass) {
335
+ super().tap { |klass|
336
+ klass.send(:include, Metasploit::Model::Association)
337
+ }
338
+ }
339
+
340
+ context 'with association' do
341
+ #
342
+ # lets
343
+ #
344
+
345
+ let(:associated_class) {
346
+ Class.new.tap { |klass|
347
+ stub_const('AssociatedThing', klass)
348
+ }
349
+ }
350
+
351
+ let(:klass) {
352
+ super().tap { |klass|
353
+ klass.association association, class_name: associated_class.name
354
+ }
355
+ }
356
+
357
+ it 'returns reflection with associated class as klass' do
358
+ expect(reflect_on_association_on_class.klass).to eq(associated_class)
359
+ end
360
+ end
361
+
362
+ context 'without association' do
363
+ it 'raises a Metasploit::Model::Association::Error on association and klass' do
364
+ expect {
365
+ reflect_on_association_on_class
366
+ }.to raise_error(Metasploit::Model::Association::Error) { |error|
367
+ expect(error.model).to eq(klass)
368
+ expect(error.name).to eq(association)
369
+ }
370
+ end
371
+ end
372
+ end
373
+
374
+ context 'does not respond to reflect_on_association' do
375
+ it 'raises NameError with instructions for using Metasploit::Model::Association' do
376
+ expect {
377
+ reflect_on_association_on_class
378
+ }.to raise_error(NameError) { |error|
379
+ expect(error.message).to include 'Metasploit::Model::Association'
380
+ }
381
+ end
382
+ end
383
+ end
384
+ end
385
+ end