ronin-core 0.1.0.beta1

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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +41 -0
  4. data/.gitignore +12 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +160 -0
  7. data/.ruby-version +1 -0
  8. data/.yardopts +1 -0
  9. data/COPYING.txt +165 -0
  10. data/ChangeLog.md +11 -0
  11. data/Gemfile +30 -0
  12. data/README.md +299 -0
  13. data/Rakefile +34 -0
  14. data/examples/ruby_shell.rb +11 -0
  15. data/gemspec.yml +28 -0
  16. data/lib/ronin/core/class_registry.rb +246 -0
  17. data/lib/ronin/core/cli/command.rb +87 -0
  18. data/lib/ronin/core/cli/command_shell/command.rb +110 -0
  19. data/lib/ronin/core/cli/command_shell.rb +345 -0
  20. data/lib/ronin/core/cli/generator/options/author.rb +106 -0
  21. data/lib/ronin/core/cli/generator/options/description.rb +54 -0
  22. data/lib/ronin/core/cli/generator/options/reference.rb +60 -0
  23. data/lib/ronin/core/cli/generator/options/summary.rb +54 -0
  24. data/lib/ronin/core/cli/generator.rb +238 -0
  25. data/lib/ronin/core/cli/logging.rb +59 -0
  26. data/lib/ronin/core/cli/options/param.rb +68 -0
  27. data/lib/ronin/core/cli/options/values/arches.rb +45 -0
  28. data/lib/ronin/core/cli/options/values/oses.rb +32 -0
  29. data/lib/ronin/core/cli/printing/arch.rb +71 -0
  30. data/lib/ronin/core/cli/printing/metadata.rb +113 -0
  31. data/lib/ronin/core/cli/printing/os.rb +54 -0
  32. data/lib/ronin/core/cli/printing/params.rb +69 -0
  33. data/lib/ronin/core/cli/ruby_shell.rb +131 -0
  34. data/lib/ronin/core/cli/shell.rb +186 -0
  35. data/lib/ronin/core/git.rb +73 -0
  36. data/lib/ronin/core/home.rb +86 -0
  37. data/lib/ronin/core/metadata/authors/author.rb +241 -0
  38. data/lib/ronin/core/metadata/authors.rb +120 -0
  39. data/lib/ronin/core/metadata/description.rb +100 -0
  40. data/lib/ronin/core/metadata/id.rb +88 -0
  41. data/lib/ronin/core/metadata/references.rb +87 -0
  42. data/lib/ronin/core/metadata/summary.rb +78 -0
  43. data/lib/ronin/core/metadata/version.rb +74 -0
  44. data/lib/ronin/core/params/exceptions.rb +38 -0
  45. data/lib/ronin/core/params/mixin.rb +317 -0
  46. data/lib/ronin/core/params/param.rb +137 -0
  47. data/lib/ronin/core/params/types/boolean.rb +64 -0
  48. data/lib/ronin/core/params/types/enum.rb +107 -0
  49. data/lib/ronin/core/params/types/float.rb +68 -0
  50. data/lib/ronin/core/params/types/integer.rb +100 -0
  51. data/lib/ronin/core/params/types/numeric.rb +106 -0
  52. data/lib/ronin/core/params/types/regexp.rb +67 -0
  53. data/lib/ronin/core/params/types/string.rb +118 -0
  54. data/lib/ronin/core/params/types/type.rb +54 -0
  55. data/lib/ronin/core/params/types/uri.rb +72 -0
  56. data/lib/ronin/core/params/types.rb +62 -0
  57. data/lib/ronin/core/params.rb +19 -0
  58. data/lib/ronin/core/version.rb +24 -0
  59. data/ronin-core.gemspec +59 -0
  60. data/spec/class_registry_spec.rb +224 -0
  61. data/spec/cli/command_shell/command_spec.rb +113 -0
  62. data/spec/cli/command_shell_spec.rb +1114 -0
  63. data/spec/cli/command_spec.rb +16 -0
  64. data/spec/cli/fixtures/irb_command +8 -0
  65. data/spec/cli/fixtures/template/dir/file1.txt +1 -0
  66. data/spec/cli/fixtures/template/dir/file2.txt +1 -0
  67. data/spec/cli/fixtures/template/file.erb +1 -0
  68. data/spec/cli/fixtures/template/file.txt +1 -0
  69. data/spec/cli/generator/options/author_spec.rb +121 -0
  70. data/spec/cli/generator/options/description_spec.rb +45 -0
  71. data/spec/cli/generator/options/reference_spec.rb +53 -0
  72. data/spec/cli/generator/options/summary_spec.rb +45 -0
  73. data/spec/cli/generator_spec.rb +244 -0
  74. data/spec/cli/logging_spec.rb +95 -0
  75. data/spec/cli/options/param_spec.rb +67 -0
  76. data/spec/cli/options/values/arches_spec.rb +62 -0
  77. data/spec/cli/printing/arch_spec.rb +130 -0
  78. data/spec/cli/printing/metadata_spec.rb +211 -0
  79. data/spec/cli/printing/os_spec.rb +64 -0
  80. data/spec/cli/printing/params_spec.rb +63 -0
  81. data/spec/cli/ruby_shell.rb +99 -0
  82. data/spec/cli/shell_spec.rb +211 -0
  83. data/spec/fixtures/example_class_registry/base_class.rb +9 -0
  84. data/spec/fixtures/example_class_registry/classes/loaded_class.rb +9 -0
  85. data/spec/fixtures/example_class_registry/classes/name_mismatch.rb +9 -0
  86. data/spec/fixtures/example_class_registry/classes/no_module.rb +4 -0
  87. data/spec/fixtures/example_class_registry.rb +8 -0
  88. data/spec/git_spec.rb +58 -0
  89. data/spec/home_spec.rb +64 -0
  90. data/spec/metadata/authors/author_spec.rb +335 -0
  91. data/spec/metadata/authors_spec.rb +126 -0
  92. data/spec/metadata/description_spec.rb +74 -0
  93. data/spec/metadata/id_spec.rb +92 -0
  94. data/spec/metadata/references_spec.rb +100 -0
  95. data/spec/metadata/summary_spec.rb +74 -0
  96. data/spec/metadata/version_spec.rb +72 -0
  97. data/spec/params/mixin_spec.rb +484 -0
  98. data/spec/params/param_spec.rb +164 -0
  99. data/spec/params/types/boolean_spec.rb +56 -0
  100. data/spec/params/types/enum_spec.rb +94 -0
  101. data/spec/params/types/float_spec.rb +107 -0
  102. data/spec/params/types/integer_spec.rb +155 -0
  103. data/spec/params/types/numeric_spec.rb +138 -0
  104. data/spec/params/types/regexp_spec.rb +64 -0
  105. data/spec/params/types/string_spec.rb +174 -0
  106. data/spec/params/types/type_spec.rb +14 -0
  107. data/spec/params/types/uri_spec.rb +62 -0
  108. data/spec/spec_helper.rb +11 -0
  109. metadata +252 -0
@@ -0,0 +1,484 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/params/mixin'
3
+
4
+ describe Ronin::Core::Params::Mixin do
5
+ describe "Boolean" do
6
+ it "must equal Ronin::Core::Params::Types::Boolean" do
7
+ expect(described_class::Boolean).to be(Ronin::Core::Params::Types::Boolean)
8
+ end
9
+ end
10
+
11
+ describe "Enum" do
12
+ it "must equal Ronin::Core::Params::Types::Enum" do
13
+ expect(described_class::Enum).to be(Ronin::Core::Params::Types::Enum)
14
+ end
15
+ end
16
+
17
+ describe ".params" do
18
+ subject { test_class }
19
+
20
+ context "and when params is not set in the class" do
21
+ module TestParamsMixin
22
+ class WithEmptyParams
23
+ include Ronin::Core::Params::Mixin
24
+ end
25
+ end
26
+
27
+ let(:test_class) { TestParamsMixin::WithEmptyParams }
28
+
29
+ it "must default to {}" do
30
+ expect(subject.params).to eq({})
31
+ end
32
+ end
33
+
34
+ context "and when param is called in the class" do
35
+ module TestParamsMixin
36
+ class WithParams
37
+ include Ronin::Core::Params::Mixin
38
+
39
+ param :foo, desc: 'Foo param'
40
+ end
41
+ end
42
+
43
+ let(:test_class) { TestParamsMixin::WithParams }
44
+
45
+ it "must return the set params" do
46
+ expect(subject.params).to_not be_empty
47
+ expect(subject.params[:foo]).to be_kind_of(Ronin::Core::Params::Param)
48
+ expect(subject.params[:foo].name).to eq(:foo)
49
+ end
50
+ end
51
+
52
+ context "but when params are set in the superclass" do
53
+ module TestParamsMixin
54
+ class BaseClassWithParams
55
+ include Ronin::Core::Params::Mixin
56
+
57
+ param :foo, desc: 'Foo param'
58
+ end
59
+
60
+ class OnlyInheritsParams < BaseClassWithParams
61
+ end
62
+ end
63
+
64
+ let(:test_class) { TestParamsMixin::OnlyInheritsParams }
65
+
66
+ it "must return the params set in the superclass" do
67
+ expect(subject.params).to_not be_empty
68
+ expect(subject.params[:foo]).to be_kind_of(Ronin::Core::Params::Param)
69
+ expect(subject.params[:foo].name).to eq(:foo)
70
+ end
71
+
72
+ context "and when additional params are defined in a sub-class" do
73
+ module TestParamsMixin
74
+ class AdditionalParamsDefinedInSubClass < BaseClassWithParams
75
+ param :bar, desc: 'Additional param'
76
+ end
77
+ end
78
+
79
+ let(:test_class) { TestParamsMixin::AdditionalParamsDefinedInSubClass }
80
+ let(:superclass) { TestParamsMixin::BaseClassWithParams }
81
+
82
+ it "must return both the params defined in the superclass and sub-class" do
83
+ expect(subject.params).to_not be_empty
84
+ expect(subject.params[:foo]).to be_kind_of(Ronin::Core::Params::Param)
85
+ expect(subject.params[:foo].name).to eq(:foo)
86
+
87
+ expect(subject.params[:bar]).to be_kind_of(Ronin::Core::Params::Param)
88
+ expect(subject.params[:bar].name).to eq(:bar)
89
+ end
90
+
91
+ it "must not modify the .params in the superclass" do
92
+ expect(superclass.params).to_not have_key(:bar)
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ describe ".param" do
99
+ context "when only given required arguments" do
100
+ module TestParamsMixin
101
+ class DefaultParam
102
+ include Ronin::Core::Params::Mixin
103
+
104
+ param :foo, desc: 'Foo param'
105
+ end
106
+ end
107
+
108
+ subject { TestParamsMixin::DefaultParam }
109
+
110
+ it "must define a param with the given name and description" do
111
+ expect(subject.params[:foo]).to be_kind_of(Ronin::Core::Params::Param)
112
+ expect(subject.params[:foo].name).to be(:foo)
113
+ expect(subject.params[:foo].desc).to eq('Foo param')
114
+ end
115
+ end
116
+
117
+ context "when also given the type argument" do
118
+ context "and it's a Ruby core class" do
119
+ module TestParamsMixin
120
+ class ParamWithCoreClassType
121
+ include Ronin::Core::Params::Mixin
122
+
123
+ param :foo, Integer, desc: 'Foo param'
124
+ end
125
+ end
126
+
127
+ subject { TestParamsMixin::ParamWithCoreClassType }
128
+
129
+ it "must map the core class to a Ronin::Core::Params::Types:: class" do
130
+ expect(subject.params[:foo].type).to be_kind_of(Ronin::Core::Params::Types::Integer)
131
+ end
132
+ end
133
+
134
+ context "and it's a Ronin::Core::Params::Types:: instance" do
135
+ module TestParamsMixin
136
+ class ParamWithTypeInstance
137
+ include Ronin::Core::Params::Mixin
138
+
139
+ param :foo, Enum[:bar, :baz], desc: 'Foo param'
140
+ end
141
+ end
142
+
143
+ subject { TestParamsMixin::ParamWithTypeInstance }
144
+
145
+ it "must define a param with the given Ronin::Core::Params::Types:: instance" do
146
+ expect(subject.params[:foo].type).to be_kind_of(Ronin::Core::Params::Types::Enum)
147
+ end
148
+ end
149
+
150
+ context "and when given additional keyword arguments" do
151
+ module TestParamsMixin
152
+ class ParamWithTypeAndAdditionalKwargs
153
+ include Ronin::Core::Params::Mixin
154
+
155
+ param :foo, Integer, desc: 'Foo param', min: 1, max: 10
156
+ end
157
+ end
158
+
159
+ subject { TestParamsMixin::ParamWithTypeAndAdditionalKwargs }
160
+
161
+ it "must pass them to the Ronin::Core::Params::Types:: class'es #initialize method" do
162
+ expect(subject.params[:foo].type.min).to eq(1)
163
+ expect(subject.params[:foo].type.max).to eq(10)
164
+ end
165
+ end
166
+ end
167
+
168
+ context "when also given the required: keyword argument" do
169
+ module TestParamsMixin
170
+ class ParamWithRequired
171
+ include Ronin::Core::Params::Mixin
172
+
173
+ param :foo, required: true, desc: 'Foo param'
174
+ end
175
+ end
176
+
177
+ subject { TestParamsMixin::ParamWithRequired }
178
+
179
+ it "must define a param with #required set to true" do
180
+ expect(subject.params[:foo]).to be_kind_of(Ronin::Core::Params::Param)
181
+ expect(subject.params[:foo].required).to be(true)
182
+ end
183
+ end
184
+
185
+ context "when also given the default: keyword argument" do
186
+ module TestParamsMixin
187
+ class ParamWithDefault
188
+ include Ronin::Core::Params::Mixin
189
+
190
+ param :foo, default: 42, desc: 'Foo param'
191
+ end
192
+ end
193
+
194
+ subject { TestParamsMixin::ParamWithDefault }
195
+
196
+ it "must define a param with #default set to true" do
197
+ expect(subject.params[:foo]).to be_kind_of(Ronin::Core::Params::Param)
198
+ expect(subject.params[:foo].default).to eq(42)
199
+ end
200
+ end
201
+ end
202
+
203
+ module TestParamsMixin
204
+ class TestParams
205
+ include Ronin::Core::Params::Mixin
206
+
207
+ param :foo, Integer, desc: 'Foo param'
208
+ param :bar, Integer, desc: 'Bar param'
209
+ end
210
+
211
+ class TestParamsWithDefault
212
+ include Ronin::Core::Params::Mixin
213
+
214
+ param :foo, Integer, desc: 'Foo param'
215
+ param :bar, Integer, default: 42, desc: 'Bar param'
216
+ end
217
+
218
+ class TestParamsWithRequired
219
+ include Ronin::Core::Params::Mixin
220
+
221
+ param :foo, Integer, required: true, desc: 'Foo param'
222
+ param :bar, Integer, desc: 'Bar param'
223
+ end
224
+ end
225
+
226
+ let(:test_class) { TestParamsMixin::TestParams }
227
+ subject { test_class.new }
228
+
229
+ describe "#initialize" do
230
+ context "when not given the params: keyword argument" do
231
+ it "must default #params to {}" do
232
+ expect(subject.params).to eq({})
233
+ end
234
+
235
+ context "when a param is defined with a default: value" do
236
+ let(:test_class) { TestParamsMixin::TestParamsWithDefault }
237
+
238
+ it "must initialize the param in #params with the param's default value" do
239
+ expect(subject.params[:bar]).to eq(test_class.params[:bar].default_value)
240
+ end
241
+ end
242
+ end
243
+
244
+ context "when given the params: keyword argument" do
245
+ let(:params) do
246
+ {foo: 1, bar: 2}
247
+ end
248
+
249
+ subject { test_class.new(params: params) }
250
+
251
+ it "must initialize the params using the parmms: Hash" do
252
+ expect(subject.params).to eq(params)
253
+ end
254
+
255
+ context "but when one of the required param values is missing" do
256
+ let(:test_class) { TestParamsMixin::TestParamsWithRequired }
257
+
258
+ it do
259
+ expect {
260
+ test_class.new(params: {})
261
+ }.to raise_error(Ronin::Core::Params::RequiredParam,"param 'foo' requires a value")
262
+ end
263
+ end
264
+
265
+ context "but params: values do not match the param's types" do
266
+ let(:params) do
267
+ {foo: '1', bar: '2'}
268
+ end
269
+
270
+ it "must coerce the values using the param's types" do
271
+ expect(subject.params[:foo]).to eq(params[:foo].to_i)
272
+ expect(subject.params[:bar]).to eq(params[:bar].to_i)
273
+ end
274
+
275
+ context "but the values cannot be coerced" do
276
+ let(:invalid_param) { :bar }
277
+ let(:invalid_value) { "XYZ" }
278
+ let(:params) do
279
+ {foo: 1, invalid_param => invalid_value}
280
+ end
281
+
282
+ it do
283
+ expect {
284
+ test_class.new(params: params)
285
+ }.to raise_error(Ronin::Core::Params::ValidationError,"invalid param value for param '#{invalid_param}': value contains non-numeric characters (#{invalid_value.inspect})")
286
+ end
287
+ end
288
+ end
289
+
290
+ context "but the params: value contains an unknown param" do
291
+ let(:unknown_param) { :xxx }
292
+ let(:params) do
293
+ {:foo => 1, unknown_param => 2}
294
+ end
295
+
296
+ it do
297
+ expect {
298
+ test_class.new(params: params)
299
+ }.to raise_error(Ronin::Core::Params::UnknownParam,"unknown param: #{unknown_param.inspect}")
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ describe "#params=" do
306
+ let(:params) do
307
+ {foo: 1, bar: 2}
308
+ end
309
+
310
+ it "must populate #params using the parmms Hash" do
311
+ subject.params = params
312
+
313
+ expect(subject.params).to eq(params)
314
+ end
315
+
316
+ context "but #params has been previously set" do
317
+ let(:params) do
318
+ {foo: 1}
319
+ end
320
+
321
+ before do
322
+ subject.params = {foo: 111, bar: 222}
323
+ subject.params = params
324
+ end
325
+
326
+ it "must clear #params before re-populating it" do
327
+ expect(subject.params).to eq(params)
328
+ end
329
+ end
330
+
331
+ context "when a param is defined with a default: value" do
332
+ let(:test_class) { TestParamsMixin::TestParamsWithDefault }
333
+
334
+ let(:params) do
335
+ {foo: 1}
336
+ end
337
+ before { subject.params = params }
338
+
339
+ it "must initialize the param in #params with the param's default value" do
340
+ expect(subject.params[:bar]).to eq(test_class.params[:bar].default_value)
341
+ end
342
+
343
+ it "must set the other params" do
344
+ expect(subject.params[:foo]).to eq(params[:foo])
345
+ end
346
+ end
347
+
348
+ context "but the params values do not match the param's types" do
349
+ let(:params) do
350
+ {foo: '1', bar: '2'}
351
+ end
352
+
353
+ it "must coerce the values using the param's types" do
354
+ subject.params = params
355
+
356
+ expect(subject.params[:foo]).to eq(params[:foo].to_i)
357
+ expect(subject.params[:bar]).to eq(params[:bar].to_i)
358
+ end
359
+
360
+ context "but the values cannot be coerced" do
361
+ let(:invalid_param) { :bar }
362
+ let(:invalid_value) { "XYZ" }
363
+ let(:params) do
364
+ {foo: 1, invalid_param => invalid_value}
365
+ end
366
+
367
+ it do
368
+ expect {
369
+ subject.params = params
370
+ }.to raise_error(Ronin::Core::Params::ValidationError,"invalid param value for param '#{invalid_param}': value contains non-numeric characters (#{invalid_value.inspect})")
371
+ end
372
+ end
373
+ end
374
+
375
+ context "when a param is defined with required: true" do
376
+ let(:test_class) { TestParamsMixin::TestParamsWithRequired }
377
+
378
+ let(:params) do
379
+ {bar: 1}
380
+ end
381
+
382
+ context "and the value is not given in the params Hash" do
383
+ it do
384
+ expect {
385
+ subject.params = params
386
+ }.to raise_error(Ronin::Core::Params::RequiredParam,"param 'foo' requires a value")
387
+ end
388
+ end
389
+ end
390
+
391
+ context "but the params value contains an unknown param" do
392
+ let(:unknown_param) { :xxx }
393
+ let(:params) do
394
+ {:foo => 1, unknown_param => 2}
395
+ end
396
+
397
+ it do
398
+ expect {
399
+ subject.params = params
400
+ }.to raise_error(Ronin::Core::Params::UnknownParam,"unknown param: #{unknown_param.inspect}")
401
+ end
402
+ end
403
+ end
404
+
405
+ describe "#set_param" do
406
+ let(:name) { :foo }
407
+ let(:value) { 42 }
408
+
409
+ it "must set the param with the given name and value" do
410
+ subject.set_param(name,value)
411
+
412
+ expect(subject.params[name]).to eq(value)
413
+ end
414
+
415
+ context "when the param name is not unknown" do
416
+ let(:name) { :xxx }
417
+
418
+ it do
419
+ expect {
420
+ subject.set_param(name,value)
421
+ }.to raise_error(Ronin::Core::Params::UnknownParam,"unknown param: #{name.inspect}")
422
+ end
423
+ end
424
+
425
+ context "but the param value does not match the param's type" do
426
+ let(:valie) { '42' }
427
+
428
+ it "must coerce the value using the param's type" do
429
+ subject.set_param(name,value)
430
+
431
+ expect(subject.params[name]).to eq(value.to_i)
432
+ end
433
+
434
+ context "but the values cannot be coerced" do
435
+ let(:value) { "XYZ" }
436
+
437
+ it do
438
+ expect {
439
+ subject.set_param(name,value)
440
+ }.to raise_error(Ronin::Core::Params::ValidationError,"invalid param value for param '#{name}': value contains non-numeric characters (#{value.inspect})")
441
+ end
442
+ end
443
+ end
444
+ end
445
+
446
+ describe "#validate_params" do
447
+ context "when there are required params defined" do
448
+ let(:test_class) { TestParamsMixin::ParamWithRequired }
449
+ let(:required_param) { :foo }
450
+
451
+ context "and one of them is not set in #params" do
452
+ it do
453
+ expect {
454
+ subject.validate_params
455
+ }.to raise_error(Ronin::Core::Params::ValidationError,"param '#{required_param}' requires a value")
456
+ end
457
+ end
458
+
459
+ context "and one of them is set to nil in #params" do
460
+ before { subject.params[required_param] = nil }
461
+
462
+ it do
463
+ expect {
464
+ subject.validate_params
465
+ }.to raise_error(Ronin::Core::Params::ValidationError,"param '#{required_param}' requires a value")
466
+ end
467
+ end
468
+
469
+ context "and it has a non-nil value" do
470
+ before { subject.params[required_param] = 42 }
471
+
472
+ it "must return true" do
473
+ expect(subject.validate_params).to be(true)
474
+ end
475
+ end
476
+ end
477
+
478
+ context "when there are no required params defined" do
479
+ it "must return true" do
480
+ expect(subject.validate_params).to be(true)
481
+ end
482
+ end
483
+ end
484
+ end
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/params/param'
3
+ require 'ronin/core/params/types/integer'
4
+
5
+ describe Ronin::Core::Params::Param do
6
+ let(:name) { :foo }
7
+ let(:type) { Ronin::Core::Params::Types::Integer.new }
8
+ let(:desc) { "Foo param" }
9
+
10
+ subject { described_class.new(name,type, desc: desc) }
11
+
12
+ describe "#initialize" do
13
+ it "must set #name" do
14
+ expect(subject.name).to eq(name)
15
+ end
16
+
17
+ it "must set #type" do
18
+ expect(subject.type).to eq(type)
19
+ end
20
+
21
+ it "must set #desc" do
22
+ expect(subject.desc).to eq(desc)
23
+ end
24
+
25
+ it "must require the desc: keyword argument" do
26
+ expect {
27
+ described_class.new(name,type)
28
+ }.to raise_error(ArgumentError)
29
+ end
30
+
31
+ it "must default #required to false" do
32
+ expect(subject.required).to be(false)
33
+ end
34
+
35
+ it "must default #default to nil" do
36
+ expect(subject.default).to be(nil)
37
+ end
38
+
39
+ context "when given the required: keyword argument" do
40
+ subject { described_class.new(name,type, required: true, desc: desc) }
41
+
42
+ it "must set #required" do
43
+ expect(subject.required).to be(true)
44
+ end
45
+ end
46
+
47
+ context "when given the default: keyword argument" do
48
+ let(:default) { 42 }
49
+
50
+ subject { described_class.new(name,type, default: default, desc: desc) }
51
+
52
+ it "must set #default" do
53
+ expect(subject.default).to eq(default)
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#required?" do
59
+ context "when initialized with no required: keyword argument" do
60
+ subject { described_class.new(name,type, desc: desc) }
61
+
62
+ it "must return false" do
63
+ expect(subject.required?).to be(false)
64
+ end
65
+ end
66
+
67
+ context "when initialized with required: true" do
68
+ subject { described_class.new(name,type, required: true, desc: desc) }
69
+
70
+ it "must return true" do
71
+ expect(subject.required?).to be(true)
72
+ end
73
+ end
74
+
75
+ context "when initialized with required: false" do
76
+ subject { described_class.new(name,type, required: false, desc: desc) }
77
+
78
+ it "must return false" do
79
+ expect(subject.required?).to be(false)
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "#has_default?" do
85
+ context "when initialized with no default: keyword argument" do
86
+ subject { described_class.new(name,type, desc: desc) }
87
+
88
+ it "must return false" do
89
+ expect(subject.has_default?).to be(false)
90
+ end
91
+ end
92
+
93
+ context "when initialized with the default: keyword argument" do
94
+ subject { described_class.new(name,type, default: 42, desc: desc) }
95
+
96
+ it "must return true" do
97
+ expect(subject.has_default?).to be(true)
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "#default_value" do
103
+ context "when initialized with no default: keyword argument" do
104
+ subject { described_class.new(name,type, desc: desc) }
105
+
106
+ it "must return nil" do
107
+ expect(subject.default_value).to be(nil)
108
+ end
109
+ end
110
+
111
+ context "when initialized with the default: keyword argument" do
112
+ context "and it's an Object" do
113
+ let(:default) { 'value' }
114
+
115
+ subject { described_class.new(name,type, default: default, desc: desc) }
116
+
117
+ it "must return a new copy of the default value" do
118
+ expect(subject.default_value).to eq(default)
119
+ expect(subject.default_value).to_not be(default)
120
+ end
121
+ end
122
+
123
+ context "and it's a Proc" do
124
+ let(:default) do
125
+ proc { "value" }
126
+ end
127
+
128
+ subject { described_class.new(name,type, default: default, desc: desc) }
129
+
130
+ it "must call the Proc and return the value" do
131
+ expect(subject.default_value).to eq(default.call)
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#coerce" do
138
+ let(:value) { '42' }
139
+
140
+ context "when given nil" do
141
+ context "and when initialize with required: true" do
142
+ subject { described_class.new(name,type, required: true, desc: desc) }
143
+
144
+ it do
145
+ expect {
146
+ subject.coerce(nil)
147
+ }.to raise_error(Ronin::Core::Params::ValidationError,"param requires a non-nil value")
148
+ end
149
+ end
150
+
151
+ context "and when is not initialize with required: true" do
152
+ it "must return nil" do
153
+ expect(subject.coerce(nil)).to be(nil)
154
+ end
155
+ end
156
+ end
157
+
158
+ context "when given a non-nil value" do
159
+ it "must coerce the value using #type" do
160
+ expect(subject.coerce(value)).to eq(type.coerce(value))
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/params/types/boolean'
3
+
4
+ describe Ronin::Core::Params::Types::Boolean do
5
+ describe "#coerce" do
6
+ context "when given true" do
7
+ it "must return true" do
8
+ expect(subject.coerce(true)).to be(true)
9
+ end
10
+ end
11
+
12
+ context "when given false" do
13
+ it "must return false" do
14
+ expect(subject.coerce(false)).to be(false)
15
+ end
16
+ end
17
+
18
+ context "when given a String" do
19
+ %w[true True TRUE yes Yes YES y Y on On ON].each do |value|
20
+ context "and it's #{value.inspect}" do
21
+ it "must return true" do
22
+ expect(subject.coerce(value)).to be(true)
23
+ end
24
+ end
25
+ end
26
+
27
+ %w[false False FALSE no No NO n N off Off OFF].each do |value|
28
+ context "and it's #{value.inspect}" do
29
+ it "must return false" do
30
+ expect(subject.coerce(value)).to be(false)
31
+ end
32
+ end
33
+ end
34
+
35
+ context "when given an unrecognized String" do
36
+ let(:value) { "foo" }
37
+
38
+ it do
39
+ expect {
40
+ subject.coerce(value)
41
+ }.to raise_error(Ronin::Core::Params::ValidationError,"value must be either 'true', 'false', 'yes', 'no', 'y', 'n', 'on', or 'off' (#{value.inspect})")
42
+ end
43
+ end
44
+ end
45
+
46
+ context "when given a non-Boolean and non-String object" do
47
+ let(:value) { Object.new }
48
+
49
+ it do
50
+ expect {
51
+ subject.coerce(value)
52
+ }.to raise_error(Ronin::Core::Params::ValidationError,"value must be either true, false, or a String (#{value.inspect})")
53
+ end
54
+ end
55
+ end
56
+ end