metasploit-model 0.25.7 → 0.26.1
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.
- checksums.yaml +8 -8
- data/app/models/metasploit/model/search/operation/association.rb +57 -0
- data/app/models/metasploit/model/search/operator/association.rb +24 -14
- data/app/models/metasploit/model/search/operator/base.rb +19 -3
- data/app/models/metasploit/model/search/operator/single.rb +21 -1
- data/app/models/metasploit/model/search/query.rb +20 -1
- data/lib/metasploit/model/association/tree.rb +130 -0
- data/lib/metasploit/model/search.rb +61 -27
- data/lib/metasploit/model/search/association.rb +152 -8
- data/lib/metasploit/model/search/attribute.rb +112 -22
- data/lib/metasploit/model/search/operator.rb +53 -1
- data/lib/metasploit/model/search/operator/help.rb +39 -1
- data/lib/metasploit/model/search/with.rb +44 -1
- data/lib/metasploit/model/version.rb +2 -2
- data/spec/app/models/metasploit/model/search/operation/association_spec.rb +67 -0
- data/spec/app/models/metasploit/model/search/operator/association_spec.rb +76 -76
- data/spec/app/models/metasploit/model/search/operator/deprecated/author_spec.rb +54 -18
- data/spec/app/models/metasploit/model/search/operator/deprecated/authority_spec.rb +20 -8
- data/spec/app/models/metasploit/model/search/operator/deprecated/platform_spec.rb +20 -8
- data/spec/app/models/metasploit/model/search/operator/deprecated/ref_spec.rb +86 -26
- data/spec/app/models/metasploit/model/search/operator/deprecated/text_spec.rb +63 -21
- data/spec/lib/metasploit/model/search/association/tree_spec.rb +385 -0
- data/spec/lib/metasploit/model/search/association_spec.rb +99 -10
- data/spec/lib/metasploit/model/search_spec.rb +48 -107
- data/spec/support/shared/examples/search/query/metasploit/model/search/operator/deprecated/authority.rb +19 -7
- 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
|
-
:
|
59
|
-
:
|
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
|
-
:
|
79
|
-
:
|
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
|
-
|
98
|
-
|
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
|
-
|
108
|
-
|
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
|
-
:
|
33
|
-
:
|
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
|
-
:
|
53
|
-
:
|
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
|
-
:
|
61
|
-
:
|
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
|
-
|
128
|
-
|
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
|
-
|
164
|
-
|
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
|
-
|
186
|
-
|
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
|
-
|
196
|
-
|
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
|
-
|
222
|
-
|
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
|
-
|
254
|
-
|
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
|
-
|
264
|
-
|
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
|
-
|
301
|
-
|
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
|
-
|
311
|
-
|
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
|
-
|
321
|
-
|
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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
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
|
-
|
257
|
-
|
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
|
-
|
267
|
-
|
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
|
-
|
293
|
-
|
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
|
-
|
303
|
-
|
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
|
-
|
331
|
-
|
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
|
-
|
341
|
-
|
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
|
-
|
351
|
-
|
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
|