ruby-nmap 0.9.3 → 1.0.0

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 (107) hide show
  1. checksums.yaml +5 -5
  2. data/.document +1 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +31 -0
  5. data/ChangeLog.md +122 -67
  6. data/Gemfile +11 -5
  7. data/LICENSE.txt +1 -1
  8. data/README.md +88 -50
  9. data/Rakefile +8 -3
  10. data/UPGRADING.md +47 -0
  11. data/gemspec.yml +6 -6
  12. data/lib/nmap/command.rb +765 -0
  13. data/lib/nmap/version.rb +1 -1
  14. data/lib/nmap/xml/address.rb +38 -0
  15. data/lib/nmap/xml/cpe/url.rb +80 -0
  16. data/lib/nmap/xml/cpe.rb +47 -0
  17. data/lib/nmap/xml/hop.rb +22 -0
  18. data/lib/nmap/xml/host.rb +546 -0
  19. data/lib/nmap/xml/host_script.rb +26 -0
  20. data/lib/nmap/xml/hostname.rb +44 -0
  21. data/lib/nmap/xml/ip_id_sequence.rb +26 -0
  22. data/lib/nmap/xml/os.rb +131 -0
  23. data/lib/nmap/xml/os_class.rb +86 -0
  24. data/lib/nmap/xml/os_match.rb +22 -0
  25. data/lib/nmap/xml/port.rb +114 -0
  26. data/lib/nmap/xml/postscript.rb +26 -0
  27. data/lib/nmap/xml/prescript.rb +26 -0
  28. data/lib/nmap/xml/run_stat.rb +22 -0
  29. data/lib/nmap/xml/scan.rb +38 -0
  30. data/lib/nmap/xml/scan_task.rb +55 -0
  31. data/lib/nmap/xml/scanner.rb +22 -0
  32. data/lib/nmap/xml/script.rb +110 -0
  33. data/lib/nmap/xml/scripts.rb +33 -0
  34. data/lib/nmap/xml/sequence.rb +52 -0
  35. data/lib/nmap/xml/service.rb +172 -0
  36. data/lib/nmap/xml/status.rb +22 -0
  37. data/lib/nmap/xml/tcp_sequence.rb +48 -0
  38. data/lib/nmap/xml/tcp_ts_sequence.rb +26 -0
  39. data/lib/nmap/xml/traceroute.rb +73 -0
  40. data/lib/nmap/xml/uptime.rb +22 -0
  41. data/lib/nmap/xml.rb +46 -44
  42. data/ruby-nmap.gemspec +38 -83
  43. data/spec/command_spec.rb +726 -0
  44. data/spec/fixtures/down_host_scan.xml +16 -0
  45. data/spec/{local_scan.xml → fixtures/local_scan.xml} +1 -1
  46. data/spec/{scan.xml → fixtures/scan.xml} +1 -1
  47. data/spec/spec_helper.rb +2 -2
  48. data/spec/{address_spec.rb → xml/address_spec.rb} +2 -2
  49. data/spec/{cpe → xml/cpe}/url_spec.rb +1 -1
  50. data/spec/{cpe_examples.rb → xml/cpe_examples.rb} +1 -1
  51. data/spec/{hop_spec.rb → xml/hop_spec.rb} +2 -2
  52. data/spec/{host_script_spec.rb → xml/host_script_spec.rb} +2 -2
  53. data/spec/{host_spec.rb → xml/host_spec.rb} +12 -8
  54. data/spec/{hostname_spec.rb → xml/hostname_spec.rb} +2 -2
  55. data/spec/{ip_id_sequence_spec.rb → xml/ip_id_sequence_spec.rb} +3 -3
  56. data/spec/{os_class_spec.rb → xml/os_class_spec.rb} +3 -3
  57. data/spec/{os_match_spec.rb → xml/os_match_spec.rb} +2 -2
  58. data/spec/{os_spec.rb → xml/os_spec.rb} +3 -3
  59. data/spec/{port_spec.rb → xml/port_spec.rb} +10 -5
  60. data/spec/{postscript_spec.rb → xml/postscript_spec.rb} +2 -2
  61. data/spec/{prescript_spec.rb → xml/prescript_spec.rb} +2 -2
  62. data/spec/{run_stat_spec.rb → xml/run_stat_spec.rb} +2 -2
  63. data/spec/{scan_spec.rb → xml/scan_spec.rb} +2 -2
  64. data/spec/{scan_task_spec.rb → xml/scan_task_spec.rb} +6 -6
  65. data/spec/{scanner_spec.rb → xml/scanner_spec.rb} +3 -3
  66. data/spec/xml/script_spec.rb +137 -0
  67. data/spec/xml/scripts_examples.rb +19 -0
  68. data/spec/{sequence_examples.rb → xml/sequence_examples.rb} +1 -0
  69. data/spec/{service_spec.rb → xml/service_spec.rb} +31 -5
  70. data/spec/{status_spec.rb → xml/status_spec.rb} +4 -3
  71. data/spec/{tcp_sequence_spec.rb → xml/tcp_sequence_spec.rb} +3 -3
  72. data/spec/{tcp_ts_sequence_spec.rb → xml/tcp_ts_sequence_spec.rb} +3 -3
  73. data/spec/{traceroute_spec.rb → xml/traceroute_spec.rb} +3 -3
  74. data/spec/{uptime_spec.rb → xml/uptime_spec.rb} +2 -2
  75. data/spec/xml_spec.rb +93 -45
  76. metadata +78 -99
  77. data/.travis.yml +0 -14
  78. data/lib/nmap/address.rb +0 -34
  79. data/lib/nmap/cpe/url.rb +0 -78
  80. data/lib/nmap/cpe.rb +0 -45
  81. data/lib/nmap/hop.rb +0 -20
  82. data/lib/nmap/host.rb +0 -586
  83. data/lib/nmap/host_script.rb +0 -18
  84. data/lib/nmap/hostname.rb +0 -42
  85. data/lib/nmap/ip_id_sequence.rb +0 -24
  86. data/lib/nmap/os.rb +0 -127
  87. data/lib/nmap/os_class.rb +0 -82
  88. data/lib/nmap/os_match.rb +0 -18
  89. data/lib/nmap/port.rb +0 -99
  90. data/lib/nmap/postscript.rb +0 -16
  91. data/lib/nmap/prescript.rb +0 -16
  92. data/lib/nmap/program.rb +0 -102
  93. data/lib/nmap/run_stat.rb +0 -20
  94. data/lib/nmap/scan.rb +0 -34
  95. data/lib/nmap/scan_task.rb +0 -50
  96. data/lib/nmap/scanner.rb +0 -18
  97. data/lib/nmap/scripts.rb +0 -71
  98. data/lib/nmap/sequence.rb +0 -50
  99. data/lib/nmap/service.rb +0 -170
  100. data/lib/nmap/status.rb +0 -18
  101. data/lib/nmap/task.rb +0 -381
  102. data/lib/nmap/tcp_sequence.rb +0 -46
  103. data/lib/nmap/tcp_ts_sequence.rb +0 -22
  104. data/lib/nmap/traceroute.rb +0 -71
  105. data/lib/nmap/uptime.rb +0 -20
  106. data/spec/scripts_examples.rb +0 -35
  107. data/spec/task_spec.rb +0 -150
@@ -0,0 +1,726 @@
1
+ require 'spec_helper'
2
+ require 'nmap/command'
3
+
4
+ describe Nmap::Command do
5
+ describe described_class::Port do
6
+ describe "#validate" do
7
+ context "when given an Integer" do
8
+ let(:value) { 443 }
9
+
10
+ it "must return true" do
11
+ expect(subject.validate(value)).to be(true)
12
+ end
13
+
14
+ context "but it's less than 1" do
15
+ let(:value) { 0 }
16
+
17
+ it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
18
+ expect(subject.validate(value)).to eq(
19
+ [false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
20
+ )
21
+ end
22
+ end
23
+
24
+ context "but it's greater than 65535" do
25
+ let(:value) { 65536 }
26
+
27
+ it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
28
+ expect(subject.validate(value)).to eq(
29
+ [false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
30
+ )
31
+ end
32
+ end
33
+ end
34
+
35
+ context "when given a String" do
36
+ context "and it's a number" do
37
+ let(:value) { '443' }
38
+
39
+ it "must return true" do
40
+ expect(subject.validate(value)).to be(true)
41
+ end
42
+
43
+ context "but it's less than 1" do
44
+ let(:value) { '0' }
45
+
46
+ it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
47
+ expect(subject.validate(value)).to eq(
48
+ [false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
49
+ )
50
+ end
51
+ end
52
+
53
+ context "but it's greater than 65535" do
54
+ let(:value) { '65536' }
55
+
56
+ it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
57
+ expect(subject.validate(value)).to eq(
58
+ [false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
59
+ )
60
+ end
61
+ end
62
+ end
63
+
64
+ context "and it's a service name" do
65
+ let(:value) { "http" }
66
+
67
+ it "must return true" do
68
+ expect(subject.validate(value)).to be(true)
69
+ end
70
+
71
+ context "and it ends with a '*' character" do
72
+ let(:value) { "http*" }
73
+
74
+ it "must return true" do
75
+ expect(subject.validate(value)).to be(true)
76
+ end
77
+ end
78
+
79
+ context "and it contains uppercase letters" do
80
+ let(:value) { "XmlIpcRegSvc" }
81
+
82
+ it "must return true" do
83
+ expect(subject.validate(value)).to be(true)
84
+ end
85
+ end
86
+
87
+ context "and it starts with digits" do
88
+ let(:value) { "1ci-smcs" }
89
+
90
+ it "must return true" do
91
+ expect(subject.validate(value)).to be(true)
92
+ end
93
+ end
94
+
95
+ context "and it contains digits" do
96
+ let(:value) { "neo4j" }
97
+
98
+ it "must return true" do
99
+ expect(subject.validate(value)).to be(true)
100
+ end
101
+ end
102
+
103
+ context "and it contains a '-' character" do
104
+ let(:value) { "3gpp-cbsp" }
105
+
106
+ it "must return true" do
107
+ expect(subject.validate(value)).to be(true)
108
+ end
109
+ end
110
+
111
+ context "but it starts with a '-' character" do
112
+ let(:value) { "-foo" }
113
+
114
+ it "must return [false, \"must be a port number or service name (...)\"]" do
115
+ expect(subject.validate(value)).to eq(
116
+ [false, "must be a port number or service name (#{value.inspect})"]
117
+ )
118
+ end
119
+ end
120
+
121
+ context "but it ends with a '-' character" do
122
+ let(:value) { "foo-" }
123
+
124
+ it "must return [false, \"must be a port number or service name (...)\"]" do
125
+ expect(subject.validate(value)).to eq(
126
+ [false, "must be a port number or service name (#{value.inspect})"]
127
+ )
128
+ end
129
+ end
130
+
131
+ context "and it contains a '_' character" do
132
+ let(:value) { "kerberos_master" }
133
+
134
+ it "must return true" do
135
+ expect(subject.validate(value)).to be(true)
136
+ end
137
+ end
138
+
139
+ context "but it starts with a '_' character" do
140
+ let(:value) { "_foo" }
141
+
142
+ it "must return [false, \"must be a port number or service name (...)\"]" do
143
+ expect(subject.validate(value)).to eq(
144
+ [false, "must be a port number or service name (#{value.inspect})"]
145
+ )
146
+ end
147
+ end
148
+
149
+ context "but it ends with a '_' character" do
150
+ let(:value) { "foo_" }
151
+
152
+ it "must return [false, \"must be a port number or service name (...)\"]" do
153
+ expect(subject.validate(value)).to eq(
154
+ [false, "must be a port number or service name (#{value.inspect})"]
155
+ )
156
+ end
157
+ end
158
+
159
+ context "and it contain's a '/' character" do
160
+ let(:value) { "cl/1" }
161
+
162
+ it "must return true" do
163
+ expect(subject.validate(value)).to be(true)
164
+ end
165
+ end
166
+
167
+ context "but it starts with a '/' character" do
168
+ let(:value) { "/foo" }
169
+
170
+ it "must return [false, \"must be a port number or service name (...)\"]" do
171
+ expect(subject.validate(value)).to eq(
172
+ [false, "must be a port number or service name (#{value.inspect})"]
173
+ )
174
+ end
175
+ end
176
+
177
+ context "but it starts with a '/' character" do
178
+ let(:value) { "foo/" }
179
+
180
+ it "must return [false, \"must be a port number or service name (...)\"]" do
181
+ expect(subject.validate(value)).to eq(
182
+ [false, "must be a port number or service name (#{value.inspect})"]
183
+ )
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ describe described_class::PortRange do
192
+ describe "#validate" do
193
+ context "when given an Integer value" do
194
+ end
195
+
196
+ context "when given a String value" do
197
+ end
198
+
199
+ context "when given a Range of port numbers" do
200
+ let(:value) { (1..1024) }
201
+
202
+ it "must return true" do
203
+ expect(subject.validate(value)).to be(true)
204
+ end
205
+ end
206
+ end
207
+
208
+ describe "#format" do
209
+ context "when given a single port number" do
210
+ let(:value) { 443 }
211
+
212
+ it "must return the formatted port number" do
213
+ expect(subject.format(value)).to eq(value.to_s)
214
+ end
215
+ end
216
+
217
+ context "when given a Range of port numbers" do
218
+ let(:value) { 1..1024 }
219
+
220
+ it "must return the formatted port number range (ex: 1-102)" do
221
+ expect(subject.format(value)).to eq("#{value.begin}-#{value.end}")
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ describe described_class::PortRangeList do
228
+ describe "#validate" do
229
+ context "when given a single port number" do
230
+ let(:value) { 443 }
231
+
232
+ it "must return true" do
233
+ expect(subject.validate(value)).to be(true)
234
+ end
235
+ end
236
+
237
+ context "when given a Range of port numbers" do
238
+ let(:value) { (1..1024) }
239
+
240
+ it "must return true" do
241
+ expect(subject.validate(value)).to be(true)
242
+ end
243
+ end
244
+
245
+ context "when given an Array of port numbers" do
246
+ let(:value) { [80, 443] }
247
+
248
+ it "must return true" do
249
+ expect(subject.validate(value)).to be(true)
250
+ end
251
+
252
+ context "but the Array is empty" do
253
+ let(:value) { [] }
254
+
255
+ it "must return [false, \"cannot be empty\"]" do
256
+ expect(subject.validate(value)).to eq(
257
+ [false, "cannot be empty"]
258
+ )
259
+ end
260
+ end
261
+
262
+ context "and the Array contains Ranges" do
263
+ let(:value) { [80, (1..42), 443] }
264
+
265
+ it "must return true" do
266
+ expect(subject.validate(value)).to be(true)
267
+ end
268
+ end
269
+ end
270
+
271
+ context "when given a Hash of protocols and port numbers" do
272
+ let(:value) do
273
+ {tcp: [1,2,3,4], udp: [1,2,3,4], sctp: [1,2,3,4]}
274
+ end
275
+
276
+ it "must return true" do
277
+ expect(subject.validate(value)).to be(true)
278
+ end
279
+
280
+ context "but the Hash is empty" do
281
+ let(:value) { {} }
282
+
283
+ it "must return [false, \"cannot be empty\"]" do
284
+ expect(subject.validate(value)).to eq(
285
+ [false, "cannot be empty"]
286
+ )
287
+ end
288
+ end
289
+
290
+ context "but one of the keys is not a known protocol" do
291
+ let(:protocol) { :foo }
292
+ let(:value) do
293
+ {tcp: [1,2,3,4], protocol => [1,2,3,4]}
294
+ end
295
+
296
+ it "must return [false, \"unknown protocol (...) must be :tcp, :udp, :sctp\"]" do
297
+ expect(subject.validate(value)).to eq(
298
+ [false, "unknown protocol (#{protocol.inspect}) must be :tcp, :udp, or :sctp"]
299
+ )
300
+ end
301
+ end
302
+
303
+ context "but one of the Hash values is not a valid port list class" do
304
+ let(:bad_port_list) { Object.new }
305
+ let(:value) do
306
+ {tcp: [1,2,3,4], udp: bad_port_list, sctp: [1,2,3,4]}
307
+ end
308
+
309
+ it "must return [false, \"cannot be converted into an Integer\"]" do
310
+ expect(subject.validate(value)).to eq(
311
+ [false, "element cannot be converted into an Integer (#{bad_port_list.inspect})"]
312
+ )
313
+ end
314
+ end
315
+
316
+ context "but one of the elements within the port list is not a port" do
317
+ let(:bad_port) { "" }
318
+ let(:value) do
319
+ {tcp: [1,2,3,4], udp: [1, bad_port, 3], sctp: [1,2,3,4]}
320
+ end
321
+
322
+ it "must return [false, \"element not a valid port range (...)\"]" do
323
+ expect(subject.validate(value)).to eq(
324
+ [false, "element not a valid port range (#{bad_port.inspect})"]
325
+ )
326
+ end
327
+ end
328
+ end
329
+ end
330
+
331
+ describe "#format" do
332
+ context "when given a single port number" do
333
+ let(:value) { 443 }
334
+
335
+ it "must return the formatted port number" do
336
+ expect(subject.format(value)).to eq(value.to_s)
337
+ end
338
+ end
339
+
340
+ context "when given a Range of port numbers" do
341
+ let(:value) { (1..1024) }
342
+
343
+ it "must return the formatted port number range (ex: 1-102)" do
344
+ expect(subject.format(value)).to eq("#{value.begin}-#{value.end}")
345
+ end
346
+ end
347
+
348
+ context "when given an Array of port numbers" do
349
+ let(:value) { [80, 443] }
350
+
351
+ it "must return the formatted list of port numbers" do
352
+ expect(subject.format(value)).to eq(value.join(','))
353
+ end
354
+
355
+ context "and the Array contains Ranges" do
356
+ let(:value) { [80, (1..42), 443] }
357
+
358
+ it "must return the formatted list of port numbers and port ranges" do
359
+ expect(subject.format(value)).to eq("#{value[0]},#{value[1].begin}-#{value[1].end},#{value[2]}")
360
+ end
361
+ end
362
+ end
363
+
364
+ context "when given a Hash of protocols and port numbers" do
365
+ let(:value) do
366
+ {tcp: [1,2,3,4], udp: [1,2,3,4], sctp: [1,2,3,4]}
367
+ end
368
+
369
+ it "must convert the keys to capital protocol letters and format the values" do
370
+ expect(subject.format(value)).to eq(
371
+ "T:#{subject.format(value[:tcp])},U:#{subject.format(value[:udp])},S:#{subject.format(value[:sctp])}"
372
+ )
373
+ end
374
+ end
375
+ end
376
+ end
377
+
378
+ describe described_class::Time do
379
+ describe "#validate" do
380
+ context "when given nil" do
381
+ let(:value) { nil }
382
+
383
+ it "must return [false, \"cannot be nil\"]" do
384
+ expect(subject.validate(value)).to eq(
385
+ [false, "cannot be nil"]
386
+ )
387
+ end
388
+ end
389
+
390
+ context "when given an Integer" do
391
+ let(:value) { 10 }
392
+
393
+ it "must return true" do
394
+ expect(subject.validate(value)).to be(true)
395
+ end
396
+ end
397
+
398
+ context "when given a String" do
399
+ context "when given an empty String" do
400
+ let(:value) { "" }
401
+
402
+ it "must return [false, \"does not allow an empty value\"]" do
403
+ expect(subject.validate(value)).to eq(
404
+ [false, "does not allow an empty value"]
405
+ )
406
+ end
407
+ end
408
+
409
+ context "when given a number" do
410
+ let(:value) { "10" }
411
+
412
+ it "must return true" do
413
+ expect(subject.validate(value)).to be(true)
414
+ end
415
+ end
416
+
417
+ context "when given a number that ends with 'ms'" do
418
+ let(:value) { "10ms" }
419
+
420
+ it "must return true" do
421
+ expect(subject.validate(value)).to be(true)
422
+ end
423
+ end
424
+
425
+ context "when given a number that ends with 's'" do
426
+ let(:value) { "10s" }
427
+
428
+ it "must return true" do
429
+ expect(subject.validate(value)).to be(true)
430
+ end
431
+ end
432
+
433
+ context "when given a number that ends with 'm'" do
434
+ let(:value) { "10m" }
435
+
436
+ it "must return true" do
437
+ expect(subject.validate(value)).to be(true)
438
+ end
439
+ end
440
+
441
+ context "when given a number that ends with 'h'" do
442
+ let(:value) { "10h" }
443
+
444
+ it "must return true" do
445
+ expect(subject.validate(value)).to be(true)
446
+ end
447
+ end
448
+
449
+ context "when given a number that ends with an unrecognized unit" do
450
+ let(:value) { "10x" }
451
+
452
+ it "must return [false, \"must be a number and end with 'ms', 's', 'm', or 'h'\"]" do
453
+ expect(subject.validate(value)).to eq(
454
+ [false, "must be a number and end with 'ms', 's', 'm', or 'h'"]
455
+ )
456
+ end
457
+ end
458
+ end
459
+ end
460
+ end
461
+
462
+ describe described_class::HexString do
463
+ describe "#validate" do
464
+ context "when given nil" do
465
+ let(:value) { nil }
466
+
467
+ it "must return [false, \"cannot be nil\"]" do
468
+ expect(subject.validate(value)).to eq(
469
+ [false, "cannot be nil"]
470
+ )
471
+ end
472
+ end
473
+
474
+ context "when given a String" do
475
+ context "but it's empty" do
476
+ let(:value) { '' }
477
+
478
+ it "must return [false, \"does not allow an empty value\"]" do
479
+ expect(subject.validate(value)).to eq(
480
+ [false, "does not allow an empty value"]
481
+ )
482
+ end
483
+ end
484
+
485
+ context "and it's of the format 0xAABBCCDDEEFF" do
486
+ let(:value) { "0xAABBCCDDEEFF" }
487
+
488
+ it "must return true" do
489
+ expect(subject.validate(value)).to be(true)
490
+ end
491
+ end
492
+
493
+ context "and it's of the format AABBCCDDEEFF" do
494
+ let(:value) { "AABBCCDDEEFF" }
495
+
496
+ it "must return true" do
497
+ expect(subject.validate(value)).to be(true)
498
+ end
499
+ end
500
+
501
+ context "and it's of the format \\xAA\\xBB\\xCC\\xDD\\xEE\\xFF" do
502
+ let(:value) { "\\xAA\\xBB\\xCC\\xDD\\xEE\\xFF" }
503
+
504
+ it "must return true" do
505
+ expect(subject.validate(value)).to be(true)
506
+ end
507
+ end
508
+
509
+ context "but it contains non-hex characters" do
510
+ let(:value) { "abcxyz123" }
511
+
512
+ it "must return [false, \"must be of the format 0xAABBCCDDEEFF..., AABBCCDDEEFF..., or \\\\xAA\\\\xBB\\\\xCC\\\\xDD\\\\xEE\\\\xFF...\"]" do
513
+ expect(subject.validate(value)).to eq(
514
+ [false, "must be of the format 0xAABBCCDDEEFF..., AABBCCDDEEFF..., or \\xAA\\xBB\\xCC\\xDD\\xEE\\xFF..."]
515
+ )
516
+ end
517
+ end
518
+ end
519
+ end
520
+ end
521
+
522
+ describe described_class::ScanFlags do
523
+ describe "#validate" do
524
+ context "when given nil" do
525
+ let(:value) { nil }
526
+
527
+ it "must return [false, \"cannot be nil\"]" do
528
+ expect(subject.validate(value)).to eq(
529
+ [false, "cannot be nil"]
530
+ )
531
+ end
532
+ end
533
+
534
+ context "when given a String" do
535
+ context "but it's empty" do
536
+ let(:value) { '' }
537
+
538
+ it "must return [false, \"does not allow an empty value\"]" do
539
+ expect(subject.validate(value)).to eq(
540
+ [false, "does not allow an empty value"]
541
+ )
542
+ end
543
+ end
544
+
545
+ context "and it's made up of 'URG', 'ACK', 'PSH', 'RST', 'SYN', and 'FIN'" do
546
+ let(:value) { 'URGACKPSHRSTSYNFIN' }
547
+
548
+ it "must return true" do
549
+ expect(subject.validate(value)).to be(true)
550
+ end
551
+ end
552
+
553
+ context "but it contains other sub-strings besides 'URG', 'ACK', 'PSH', 'RST', 'SYN', and 'FIN'" do
554
+ let(:value) { 'URGACKPSHRSTSYNFINXXX' }
555
+
556
+ it "must return [false, \"must only contain URG, ACK, PSH, RST, SYN, or FIN\"]" do
557
+ expect(subject.validate(value)).to eq(
558
+ [false, "must only contain URG, ACK, PSH, RST, SYN, or FIN"]
559
+ )
560
+ end
561
+ end
562
+
563
+ context "and it's numeric" do
564
+ let(:value) { '9' }
565
+
566
+ it "must return true" do
567
+ expect(subject.validate(value)).to be(true)
568
+ end
569
+ end
570
+ end
571
+
572
+ context "when given an Integer" do
573
+ let(:value) { 9 }
574
+
575
+ it "must return true" do
576
+ expect(subject.validate(value)).to be(true)
577
+ end
578
+ end
579
+
580
+ context "when given an Array" do
581
+ context "but it's empty" do
582
+ let(:value) { [] }
583
+
584
+ it "must return [false, \"Array value cannot be empty\"]" do
585
+ expect(subject.validate(value)).to eq(
586
+ [false, "Array value cannot be empty"]
587
+ )
588
+ end
589
+ end
590
+
591
+ context "and it contains :urg, :ack, :psh, :rst, :syn, or :fin" do
592
+ let(:value) { [:urg, :ack, :psh, :rst, :syn, :fin] }
593
+
594
+ it "must return true" do
595
+ expect(subject.validate(value)).to be(true)
596
+ end
597
+ end
598
+
599
+ context "but it contains other values besides :urg, :ack, :psh, :rst, :syn, and :fin" do
600
+ let(:other) { :foo }
601
+ let(:value) { [:urg, :ack, :psh, :rst, :syn, :fin, other] }
602
+
603
+ it "must return true" do
604
+ expect(subject.validate(value)).to eq(
605
+ [false, "Array must only contain the values :urg, :ack, :psh, :rst, :syn, or :fin"]
606
+ )
607
+ end
608
+ end
609
+ end
610
+
611
+ context "when given a Hash" do
612
+ context "but it's empty" do
613
+ let(:value) { {} }
614
+
615
+ it "must return [false, \"Hash value cannot be empty\"]" do
616
+ expect(subject.validate(value)).to eq(
617
+ [false, "Hash value cannot be empty"]
618
+ )
619
+ end
620
+ end
621
+
622
+ context "and it's keys contain :urg, :ack, :psh, :rst, :syn, or :fin" do
623
+ context "and it's values are all Boolean" do
624
+ let(:value) do
625
+ {
626
+ urg: true,
627
+ ack: true,
628
+ psh: false,
629
+ rst: nil,
630
+ syn: true,
631
+ fin: true
632
+ }
633
+ end
634
+
635
+ it "must return true" do
636
+ expect(subject.validate(value)).to be(true)
637
+ end
638
+ end
639
+
640
+ context "but one of it's values is not a Boolean value" do
641
+ let(:value) do
642
+ {
643
+ urg: true,
644
+ ack: true,
645
+ psh: false,
646
+ rst: nil,
647
+ syn: true,
648
+ fin: "foo"
649
+ }
650
+ end
651
+
652
+ it "must return [false, \"must only contain the Boolean values\"]" do
653
+ expect(subject.validate(value)).to eq(
654
+ [false, "Hash must only contain the values true, false, or nil"]
655
+ )
656
+ end
657
+ end
658
+ end
659
+
660
+ context "but it's keys contains other values besides :urg, :ack, :psh, :rst, :syn, and :fin" do
661
+ let(:other) { :foo }
662
+ let(:value) do
663
+ {
664
+ urg: true,
665
+ ack: true,
666
+ psh: true,
667
+ rst: true,
668
+ syn: true,
669
+ fin: true,
670
+ other => true
671
+ }
672
+ end
673
+
674
+ it "must return [false, \"must only contain the keys :urg, :ack, :psh, :rst, :syn, or :fin\"]" do
675
+ expect(subject.validate(value)).to eq(
676
+ [false, "Hash must only contain the keys :urg, :ack, :psh, :rst, :syn, or :fin"]
677
+ )
678
+ end
679
+ end
680
+ end
681
+ end
682
+
683
+ describe "#format" do
684
+ context "when given a String" do
685
+ let(:value) { 'PSHFIN' }
686
+
687
+ it "must return the String" do
688
+ expect(subject.format(value)).to eq(value)
689
+ end
690
+ end
691
+
692
+ context "when given an Integer" do
693
+ let(:value) { 9 }
694
+
695
+ it "must return the String version of the Integer" do
696
+ expect(subject.format(value)).to eq(value.to_s)
697
+ end
698
+ end
699
+
700
+ context "when given an Array" do
701
+ let(:value) { [:urg, :ack, :psh, :rst, :syn, :fin] }
702
+
703
+ it "must map each Symbol to their flag names value and join them together" do
704
+ expect(subject.format(value)).to eq("URGACKPSHRSTSYNFIN")
705
+ end
706
+ end
707
+
708
+ context "when given a Hash" do
709
+ let(:value) do
710
+ {
711
+ urg: true,
712
+ ack: true,
713
+ psh: false,
714
+ rst: nil,
715
+ syn: true,
716
+ fin: true
717
+ }
718
+ end
719
+
720
+ it "must map the keys with true values to their flag names and join them together" do
721
+ expect(subject.format(value)).to eq("URGACKSYNFIN")
722
+ end
723
+ end
724
+ end
725
+ end
726
+ end