ronin-exploits 1.0.0.beta2 → 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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -0
  3. data/README.md +29 -13
  4. data/gemspec.yml +10 -8
  5. data/lib/ronin/exploits/cli/commands/new.rb +1 -1
  6. data/lib/ronin/exploits/cli/commands/run.rb +55 -5
  7. data/lib/ronin/exploits/exploit.rb +7 -5
  8. data/lib/ronin/exploits/lfi.rb +1 -1
  9. data/lib/ronin/exploits/metadata/arch.rb +1 -1
  10. data/lib/ronin/exploits/metadata/default_filename.rb +1 -1
  11. data/lib/ronin/exploits/metadata/default_port.rb +1 -1
  12. data/lib/ronin/exploits/mixins/file_builder.rb +2 -2
  13. data/lib/ronin/exploits/mixins/nops.rb +1 -1
  14. data/lib/ronin/exploits/params/base_url.rb +1 -1
  15. data/lib/ronin/exploits/version.rb +1 -1
  16. data/ronin-exploits.gemspec +2 -1
  17. metadata +24 -129
  18. data/spec/advisory_spec.rb +0 -71
  19. data/spec/cli/exploit_command_spec.rb +0 -68
  20. data/spec/cli/exploit_methods_spec.rb +0 -208
  21. data/spec/cli/ruby_shell_spec.rb +0 -14
  22. data/spec/client_side_web_vuln_spec.rb +0 -117
  23. data/spec/exploit_spec.rb +0 -538
  24. data/spec/exploits_spec.rb +0 -8
  25. data/spec/heap_overflow_spec.rb +0 -14
  26. data/spec/lfi_spec.rb +0 -162
  27. data/spec/loot/file_spec.rb +0 -131
  28. data/spec/loot_spec.rb +0 -138
  29. data/spec/memory_corruption_spec.rb +0 -22
  30. data/spec/metadata/arch_spec.rb +0 -82
  31. data/spec/metadata/cookie_param_spec.rb +0 -67
  32. data/spec/metadata/default_filename_spec.rb +0 -62
  33. data/spec/metadata/default_port_spec.rb +0 -62
  34. data/spec/metadata/header_name_spec.rb +0 -67
  35. data/spec/metadata/os_spec.rb +0 -164
  36. data/spec/metadata/shouts_spec.rb +0 -100
  37. data/spec/metadata/url_path_spec.rb +0 -67
  38. data/spec/metadata/url_query_param_spec.rb +0 -67
  39. data/spec/mixins/binary_spec.rb +0 -129
  40. data/spec/mixins/build_dir.rb +0 -66
  41. data/spec/mixins/file_builder_spec.rb +0 -67
  42. data/spec/mixins/format_string_spec.rb +0 -44
  43. data/spec/mixins/has_payload_spec.rb +0 -333
  44. data/spec/mixins/has_targets_spec.rb +0 -434
  45. data/spec/mixins/html_spec.rb +0 -772
  46. data/spec/mixins/http_spec.rb +0 -1227
  47. data/spec/mixins/loot_spec.rb +0 -20
  48. data/spec/mixins/nops_spec.rb +0 -165
  49. data/spec/mixins/remote_tcp_spec.rb +0 -217
  50. data/spec/mixins/remote_udp_spec.rb +0 -217
  51. data/spec/mixins/seh_spec.rb +0 -89
  52. data/spec/mixins/stack_overflow_spec.rb +0 -87
  53. data/spec/mixins/text_spec.rb +0 -43
  54. data/spec/open_redirect_spec.rb +0 -71
  55. data/spec/params/base_url_spec.rb +0 -71
  56. data/spec/params/bind_host_spec.rb +0 -34
  57. data/spec/params/bind_port_spec.rb +0 -35
  58. data/spec/params/filename_spec.rb +0 -77
  59. data/spec/params/host_spec.rb +0 -34
  60. data/spec/params/port_spec.rb +0 -77
  61. data/spec/rfi_spec.rb +0 -107
  62. data/spec/seh_overflow_spec.rb +0 -18
  63. data/spec/spec_helper.rb +0 -8
  64. data/spec/sqli_spec.rb +0 -306
  65. data/spec/ssti_spec.rb +0 -121
  66. data/spec/stack_overflow_spec.rb +0 -18
  67. data/spec/target_spec.rb +0 -92
  68. data/spec/test_result_spec.rb +0 -32
  69. data/spec/use_after_free_spec.rb +0 -14
  70. data/spec/web_spec.rb +0 -12
  71. data/spec/web_vuln_spec.rb +0 -854
  72. data/spec/xss_spec.rb +0 -69
@@ -1,772 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/exploits/mixins/html'
3
-
4
- require 'ronin/exploits/exploit'
5
-
6
- describe Ronin::Exploits::Mixins::HTML do
7
- module TestHTMLMixin
8
- class TestExploit < Ronin::Exploits::Exploit
9
- include Ronin::Exploits::Mixins::HTML
10
- end
11
- end
12
-
13
- let(:test_exploit) { TestHTMLMixin::TestExploit }
14
- subject { test_exploit.new }
15
-
16
- describe "#attr_name" do
17
- let(:name) { 'foo' }
18
-
19
- it "must return the name as is" do
20
- expect(subject.attr_name(name)).to eq(name)
21
- end
22
-
23
- context "when given a Symbol" do
24
- let(:name) { :foo }
25
-
26
- it "must return the String version of the Symbol" do
27
- expect(subject.attr_name(name)).to eq(name.to_s)
28
- end
29
- end
30
-
31
- context "when given `name_case: :lower`" do
32
- let(:name) { 'FOO' }
33
-
34
- it "must convert the name to lower-case" do
35
- expect(subject.attr_name(name, name_case: :lower)).to eq(name.downcase)
36
- end
37
- end
38
-
39
- context "when given `name_case: :upper`" do
40
- it "must convert the name to upper-case" do
41
- expect(subject.attr_name(name, name_case: :upper)).to eq(name.upcase)
42
- end
43
- end
44
-
45
- context "when given `name_case: :random`" do
46
- it "must randomize the case of the name" do
47
- expect(subject.attr_name(name, name_case: :random)).to match(
48
- /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)\z/
49
- )
50
- end
51
- end
52
- end
53
-
54
- describe "#attr" do
55
- let(:name) { 'foo' }
56
- let(:value) { 'bar' }
57
-
58
- it "must return name=\"value\"" do
59
- expect(subject.attr(name,value)).to eq("#{name}=\"#{value}\"")
60
- end
61
-
62
- context "when given a Symbol for the name" do
63
- let(:name) { :foo }
64
-
65
- it "must accept a Symbol for the name" do
66
- expect(subject.attr(name,value)).to eq("#{name}=\"#{value}\"")
67
- end
68
- end
69
-
70
- context "when given a non-String for the value" do
71
- let(:value) { 42 }
72
-
73
- it "must accept a non-String for the value" do
74
- expect(subject.attr(name,value)).to eq("#{name}=\"#{value}\"")
75
- end
76
- end
77
-
78
- context "when given `name_case: :lower`" do
79
- let(:name) { 'FOO' }
80
-
81
- it "must convert the name to lower-case" do
82
- expect(subject.attr(name,value, name_case: :lower)).to eq(
83
- "#{name.downcase}=\"#{value}\""
84
- )
85
- end
86
- end
87
-
88
- context "when given `name_case: :upper`" do
89
- it "must convert the name to upper-case" do
90
- expect(subject.attr(name,value, name_case: :upper)).to eq(
91
- "#{name.upcase}=\"#{value}\""
92
- )
93
- end
94
- end
95
-
96
- context "when given `name_case: :random`" do
97
- it "must randomize the case of the name" do
98
- expect(subject.attr(name,value, name_case: :random)).to match(
99
- /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value}\"\z/
100
- )
101
- end
102
- end
103
-
104
- context "when given `quote: double`" do
105
- it "must quote the value with double quotes" do
106
- expect(subject.attr(name,value, quote: :double)).to eq(
107
- "#{name}=\"#{value}\""
108
- )
109
- end
110
-
111
- context "and when the value contains a double quote" do
112
- let(:value) { "bar\"baz" }
113
-
114
- it "must replace any double quotes with &quot;" do
115
- expect(subject.attr(name,value)).to eq("#{name}=\"bar&quot;baz\"")
116
- end
117
- end
118
- end
119
-
120
- context "when given `quote: single`" do
121
- it "must quote the value with single quotes" do
122
- expect(subject.attr(name,value, quote: :single)).to eq(
123
- "#{name}='#{value}'"
124
- )
125
- end
126
-
127
- context "and when the value contains a single quote" do
128
- let(:value) { "bar'baz" }
129
-
130
- it "must replace any double quotes with &#39;;" do
131
- expect(subject.attr(name,value, quote: :single)).to eq(
132
- "#{name}='bar&#39;baz'"
133
- )
134
- end
135
- end
136
- end
137
-
138
- context "when given `quote: backtick`" do
139
- it "must quote the value with backticks" do
140
- expect(subject.attr(name,value, quote: :backtick)).to eq(
141
- "#{name}=`#{value}`"
142
- )
143
- end
144
- end
145
-
146
- context "when given `quote: nil`" do
147
- it "must not quote the value" do
148
- expect(subject.attr(name,value, quote: nil)).to eq(
149
- "#{name}=#{value}"
150
- )
151
- end
152
-
153
- context "and when the value contains a space" do
154
- let(:value) { "bar baz" }
155
-
156
- it "must replace any spaces with &#nbsp;;" do
157
- expect(subject.attr(name,value, quote: nil)).to eq(
158
- "#{name}=bar&nbsp;baz"
159
- )
160
- end
161
- end
162
- end
163
- end
164
-
165
- describe "#attr_list" do
166
- let(:name1) { 'foo' }
167
- let(:value1) { 'bar' }
168
- let(:name2) { 'baz' }
169
- let(:value2) { 'qux' }
170
- let(:attrs) { {name1 => value1, name2 => value2} }
171
-
172
- it "must return name=\"value\" ..." do
173
- expect(subject.attr_list(attrs)).to eq(
174
- "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\""
175
- )
176
- end
177
-
178
- context "when the attributes have Symbol names" do
179
- let(:name1) { :foo }
180
- let(:name2) { :baz }
181
-
182
- it "must accept Symbols for attribute names" do
183
- expect(subject.attr_list(attrs)).to eq(
184
- "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\""
185
- )
186
- end
187
- end
188
-
189
- context "when the attributes contains non-String values" do
190
- let(:value1) { 42 }
191
- let(:value2) { :qux }
192
-
193
- it "must accept non-Strings for attribute values" do
194
- expect(subject.attr_list(attrs)).to eq(
195
- "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\""
196
- )
197
- end
198
- end
199
-
200
- context "when given `name_case: :lower`" do
201
- let(:name1) { 'FOO' }
202
- let(:name2) { 'BAZ' }
203
-
204
- it "must convert the attribute names to lower-case" do
205
- expect(subject.attr_list(attrs, name_case: :lower)).to eq(
206
- "#{name1.downcase}=\"#{value1}\" #{name2.downcase}=\"#{value2}\""
207
- )
208
- end
209
- end
210
-
211
- context "when given `name_case: :upper`" do
212
- it "must convert the attribute names to upper-case" do
213
- expect(subject.attr_list(attrs, name_case: :upper)).to eq(
214
- "#{name1.upcase}=\"#{value1}\" #{name2.upcase}=\"#{value2}\""
215
- )
216
- end
217
- end
218
-
219
- context "when given `name_case: :random`" do
220
- it "must randomize the case of each attribute name" do
221
- expect(subject.attr_list(attrs, name_case: :random)).to match(
222
- /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\"\z/
223
- )
224
- end
225
- end
226
-
227
- context "when given `quote: double`" do
228
- it "must quote the attribute values with double quotes" do
229
- expect(subject.attr_list(attrs, quote: :double)).to eq(
230
- "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\""
231
- )
232
- end
233
-
234
- context "and when an attribute value contains a double quote" do
235
- let(:value1) { "bar\"baz" }
236
-
237
- it "must replace any double quotes with &quot;" do
238
- expect(subject.attr_list(attrs)).to eq(
239
- "#{name1}=\"bar&quot;baz\" #{name2}=\"#{value2}\""
240
- )
241
- end
242
- end
243
- end
244
-
245
- context "when given `quote: single`" do
246
- it "must quote the attribute values with single quotes" do
247
- expect(subject.attr_list(attrs, quote: :single)).to eq(
248
- "#{name1}='#{value1}' #{name2}='#{value2}'"
249
- )
250
- end
251
-
252
- context "and when an attribute value contains a single quote" do
253
- let(:value1) { "bar'baz" }
254
-
255
- it "must replace any double quotes with &#39;;" do
256
- expect(subject.attr_list(attrs, quote: :single)).to eq(
257
- "#{name1}='bar&#39;baz' #{name2}='#{value2}'"
258
- )
259
- end
260
- end
261
- end
262
-
263
- context "when given `quote: backtick`" do
264
- it "must quote the attribute values with backticks" do
265
- expect(subject.attr_list(attrs, quote: :backtick)).to eq(
266
- "#{name1}=`#{value1}` #{name2}=`#{value2}`"
267
- )
268
- end
269
- end
270
-
271
- context "when given `quote: nil`" do
272
- it "must not quote the attribute values" do
273
- expect(subject.attr_list(attrs, quote: nil)).to eq(
274
- "#{name1}=#{value1} #{name2}=#{value2}"
275
- )
276
- end
277
-
278
- context "and when the value contains a space" do
279
- let(:value1) { "bar baz" }
280
-
281
- it "must replace any spaces with &#nbsp;;" do
282
- expect(subject.attr_list(attrs, quote: nil)).to eq(
283
- "#{name1}=bar&nbsp;baz #{name2}=#{value2}"
284
- )
285
- end
286
- end
287
- end
288
- end
289
-
290
- describe "#tag_name" do
291
- let(:name) { 'foo' }
292
-
293
- it "must return the name as is" do
294
- expect(subject.tag_name(name)).to eq(name)
295
- end
296
-
297
- context "when given a Symbol" do
298
- let(:name) { :foo }
299
-
300
- it "must return the String version of the Symbol" do
301
- expect(subject.tag_name(name)).to eq(name.to_s)
302
- end
303
- end
304
-
305
- context "when given `name_case: :lower`" do
306
- let(:name) { 'FOO' }
307
-
308
- it "must convert the name to lower-case" do
309
- expect(subject.tag_name(name, name_case: :lower)).to eq(name.downcase)
310
- end
311
- end
312
-
313
- context "when given `name_case: :upper`" do
314
- it "must convert the name to upper-case" do
315
- expect(subject.tag_name(name, name_case: :upper)).to eq(name.upcase)
316
- end
317
- end
318
-
319
- context "when given `name_case: :random`" do
320
- it "must randomize the case of the name" do
321
- expect(subject.tag_name(name, name_case: :random)).to match(
322
- /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)\z/
323
- )
324
- end
325
- end
326
- end
327
-
328
- describe "#tag" do
329
- let(:name) { 'div' }
330
-
331
- context "when no block or the `text:` keyword argument is given" do
332
- it "must return <name/>" do
333
- expect(subject.tag(name)).to eq("<#{name}/>")
334
- end
335
-
336
- context "when given a Symbol" do
337
- let(:name) { :div }
338
-
339
- it "must return the String version of the Symbol" do
340
- expect(subject.tag(name)).to eq("<#{name}/>")
341
- end
342
- end
343
-
344
- context "when given `tag_case: :lower`" do
345
- let(:name) { 'DIV' }
346
-
347
- it "must convert the name to lower-case" do
348
- expect(subject.tag(name, tag_case: :lower)).to eq("<#{name.downcase}/>")
349
- end
350
- end
351
-
352
- context "when given `tag_case: :upper`" do
353
- it "must convert the name to upper-case" do
354
- expect(subject.tag(name, tag_case: :upper)).to eq("<#{name.upcase}/>")
355
- end
356
- end
357
-
358
- context "when given `tag_case: :random`" do
359
- it "must randomize the case of the name" do
360
- expect(subject.tag(name, tag_case: :random)).to match(
361
- /\A<(?:Div|dIv|diV|DIv|DiV|dIV|DIV)\/>\z/
362
- )
363
- end
364
- end
365
-
366
- context "when additional attributes are given" do
367
- let(:attr1) { :foo }
368
- let(:value1) { 'bar' }
369
- let(:attr2) { :baz }
370
- let(:value2) { 'qux' }
371
- let(:attrs) do
372
- {attr1 => value1, attr2 => value2}
373
- end
374
-
375
- it "must add an attributes list after the tag name" do
376
- expect(subject.tag(name,**attrs)).to eq("<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\"/>")
377
- end
378
-
379
- context "when given `attr_case: :lower`" do
380
- let(:attr1) { :FOO }
381
- let(:attr2) { :BAZ }
382
-
383
- it "must convert the attribute names to lower-case" do
384
- expect(subject.tag(name, **attrs, attr_case: :lower)).to eq(
385
- "<#{name} #{attr1.downcase}=\"#{value1}\" #{attr2.downcase}=\"#{value2}\"/>"
386
- )
387
- end
388
- end
389
-
390
- context "when given `attr_case: :upper`" do
391
- it "must convert the attribute names to upper-case" do
392
- expect(subject.tag(name, **attrs, attr_case: :upper)).to eq(
393
- "<#{name} #{attr1.upcase}=\"#{value1}\" #{attr2.upcase}=\"#{value2}\"/>"
394
- )
395
- end
396
- end
397
-
398
- context "when given `attr_case: :random`" do
399
- it "must randomize the case of each attribute name" do
400
- expect(subject.tag(name, **attrs, attr_case: :random)).to match(
401
- /\A<#{name} (?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\"\/>\z/
402
- )
403
- end
404
- end
405
-
406
- context "when given `attr_quote: double`" do
407
- it "must quote the attribute values with double quotes" do
408
- expect(subject.tag(name, **attrs, attr_quote: :double)).to eq(
409
- "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\"/>"
410
- )
411
- end
412
-
413
- context "and when an attribute value contains a double quote" do
414
- let(:value1) { "bar\"baz" }
415
-
416
- it "must replace any double quotes with &quot;" do
417
- expect(subject.tag(name, **attrs)).to eq(
418
- "<#{name} #{attr1}=\"bar&quot;baz\" #{attr2}=\"#{value2}\"/>"
419
- )
420
- end
421
- end
422
- end
423
-
424
- context "when given `attr_quote: single`" do
425
- it "must quote the attribute values with single quotes" do
426
- expect(subject.tag(name, **attrs, attr_quote: :single)).to eq(
427
- "<#{name} #{attr1}='#{value1}' #{attr2}='#{value2}'/>"
428
- )
429
- end
430
-
431
- context "and when an attribute value contains a single quote" do
432
- let(:value1) { "bar'baz" }
433
-
434
- it "must replace any double quotes with &#39;;" do
435
- expect(subject.tag(name, **attrs, attr_quote: :single)).to eq(
436
- "<#{name} #{attr1}='bar&#39;baz' #{attr2}='#{value2}'/>"
437
- )
438
- end
439
- end
440
- end
441
-
442
- context "when given `attr_quote: :backtick`" do
443
- it "must quote the attribute values with backticks" do
444
- expect(subject.tag(name, **attrs, attr_quote: :backtick)).to eq(
445
- "<#{name} #{attr1}=`#{value1}` #{attr2}=`#{value2}`/>"
446
- )
447
- end
448
- end
449
-
450
- context "when given `attr_quote: nil`" do
451
- it "must not quote the attribute values" do
452
- expect(subject.tag(name, **attrs, attr_quote: nil)).to eq(
453
- "<#{name} #{attr1}=#{value1} #{attr2}=#{value2}/>"
454
- )
455
- end
456
-
457
- context "and when the value contains a space" do
458
- let(:value1) { "bar baz" }
459
-
460
- it "must replace any spaces with &#nbsp;;" do
461
- expect(subject.tag(name, **attrs, attr_quote: nil)).to eq(
462
- "<#{name} #{attr1}=bar&nbsp;baz #{attr2}=#{value2}/>"
463
- )
464
- end
465
- end
466
- end
467
- end
468
- end
469
-
470
- context "when given the `text:` keyword argument" do
471
- let(:inner_text) { 'loren ipsum' }
472
-
473
- it "must return <name>...</name>" do
474
- expect(subject.tag(name, text: inner_text)).to eq(
475
- "<#{name}>#{inner_text}</#{name}>"
476
- )
477
- end
478
-
479
- context "when given a Symbol" do
480
- let(:name) { :div }
481
-
482
- it "must return the String version of the Symbol" do
483
- expect(subject.tag(name, text: inner_text)).to eq(
484
- "<#{name}>#{inner_text}</#{name}>"
485
- )
486
- end
487
- end
488
-
489
- context "when given `tag_case: :lower`" do
490
- let(:name) { 'DIV' }
491
-
492
- it "must convert the tag names to lower-case" do
493
- expect(subject.tag(name, tag_case: :lower, text: inner_text)).to eq(
494
- "<#{name.downcase}>#{inner_text}</#{name.downcase}>"
495
- )
496
- end
497
- end
498
-
499
- context "when given `tag_case: :upper`" do
500
- it "must convert the tag names to upper-case" do
501
- expect(subject.tag(name, tag_case: :upper, text: inner_text)).to eq(
502
- "<#{name.upcase}>#{inner_text}</#{name.upcase}>"
503
- )
504
- end
505
- end
506
-
507
- context "when given `tag_case: :random`" do
508
- it "must randomize the case of the tag names" do
509
- expect(subject.tag(name, tag_case: :random, text: inner_text)).to match(
510
- /\A<(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>#{inner_text}<\/(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>\z/
511
- )
512
- end
513
- end
514
-
515
- context "when additional attributes are given" do
516
- let(:attr1) { :foo }
517
- let(:value1) { 'bar' }
518
- let(:attr2) { :baz }
519
- let(:value2) { 'qux' }
520
- let(:attrs) do
521
- {attr1 => value1, attr2 => value2}
522
- end
523
-
524
- it "must add an attributes list after the tag name" do
525
- expect(subject.tag(name,**attrs, text: inner_text)).to eq(
526
- "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_text}</#{name}>"
527
- )
528
- end
529
-
530
- context "when given `attr_case: :lower`" do
531
- let(:attr1) { :FOO }
532
- let(:attr2) { :BAZ }
533
-
534
- it "must convert the attribute names to lower-case" do
535
- expect(subject.tag(name, **attrs, attr_case: :lower, text: inner_text)).to eq(
536
- "<#{name} #{attr1.downcase}=\"#{value1}\" #{attr2.downcase}=\"#{value2}\">#{inner_text}</#{name}>"
537
- )
538
- end
539
- end
540
-
541
- context "when given `attr_case: :upper`" do
542
- it "must convert the attribute names to upper-case" do
543
- expect(subject.tag(name, **attrs, attr_case: :upper, text: inner_text)).to eq(
544
- "<#{name} #{attr1.upcase}=\"#{value1}\" #{attr2.upcase}=\"#{value2}\">#{inner_text}</#{name}>"
545
- )
546
- end
547
- end
548
-
549
- context "when given `attr_case: :random`" do
550
- it "must randomize the case of each attribute name" do
551
- expect(subject.tag(name, **attrs, attr_case: :random, text: inner_text)).to match(
552
- /\A<#{name} (?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\">#{inner_text}<\/#{name}>\z/
553
- )
554
- end
555
- end
556
-
557
- context "when given `attr_quote: double`" do
558
- it "must quote the attribute values with double quotes" do
559
- expect(subject.tag(name, **attrs, attr_quote: :double, text: inner_text)).to eq(
560
- "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_text}</#{name}>"
561
- )
562
- end
563
-
564
- context "and when an attribute value contains a double quote" do
565
- let(:value1) { "bar\"baz" }
566
-
567
- it "must replace any double quotes with &quot;" do
568
- expect(subject.tag(name, **attrs, text: inner_text)).to eq(
569
- "<#{name} #{attr1}=\"bar&quot;baz\" #{attr2}=\"#{value2}\">#{inner_text}</#{name}>"
570
- )
571
- end
572
- end
573
- end
574
-
575
- context "when given `attr_quote: single`" do
576
- it "must quote the attribute values with single quotes" do
577
- expect(subject.tag(name, **attrs, attr_quote: :single, text: inner_text)).to eq(
578
- "<#{name} #{attr1}='#{value1}' #{attr2}='#{value2}'>#{inner_text}</#{name}>"
579
- )
580
- end
581
-
582
- context "and when an attribute value contains a single quote" do
583
- let(:value1) { "bar'baz" }
584
-
585
- it "must replace any double quotes with &#39;;" do
586
- expect(subject.tag(name, **attrs, attr_quote: :single, text: inner_text)).to eq(
587
- "<#{name} #{attr1}='bar&#39;baz' #{attr2}='#{value2}'>#{inner_text}</#{name}>"
588
- )
589
- end
590
- end
591
- end
592
-
593
- context "when given `attr_quote: :backtick`" do
594
- it "must quote the attribute values with backticks" do
595
- expect(subject.tag(name, **attrs, attr_quote: :backtick, text: inner_text)).to eq(
596
- "<#{name} #{attr1}=`#{value1}` #{attr2}=`#{value2}`>#{inner_text}</#{name}>"
597
- )
598
- end
599
- end
600
-
601
- context "when given `attr_quote: nil`" do
602
- it "must not quote the attribute values" do
603
- expect(subject.tag(name, **attrs, attr_quote: nil, text: inner_text)).to eq(
604
- "<#{name} #{attr1}=#{value1} #{attr2}=#{value2}>#{inner_text}</#{name}>"
605
- )
606
- end
607
-
608
- context "and when the value contains a space" do
609
- let(:value1) { "bar baz" }
610
-
611
- it "must replace any spaces with &#nbsp;;" do
612
- expect(subject.tag(name, **attrs, attr_quote: nil, text: inner_text)).to eq(
613
- "<#{name} #{attr1}=bar&nbsp;baz #{attr2}=#{value2}>#{inner_text}</#{name}>"
614
- )
615
- end
616
- end
617
- end
618
- end
619
- end
620
-
621
- context "when given a block" do
622
- let(:inner_html) { '<a href="http://example.com/>link</a>' }
623
-
624
- it "must return <name>...</name>" do
625
- expect(subject.tag(name) { inner_html }).to eq(
626
- "<#{name}>#{inner_html}</#{name}>"
627
- )
628
- end
629
-
630
- context "when given a Symbol" do
631
- let(:name) { :div }
632
-
633
- it "must return the String version of the Symbol" do
634
- expect(subject.tag(name) { inner_html }).to eq(
635
- "<#{name}>#{inner_html}</#{name}>"
636
- )
637
- end
638
- end
639
-
640
- context "when given `tag_case: :lower`" do
641
- let(:name) { 'DIV' }
642
-
643
- it "must convert the tag names to lower-case" do
644
- expect(subject.tag(name, tag_case: :lower) { inner_html }).to eq(
645
- "<#{name.downcase}>#{inner_html}</#{name.downcase}>"
646
- )
647
- end
648
- end
649
-
650
- context "when given `tag_case: :upper`" do
651
- it "must convert the tag names to upper-case" do
652
- expect(subject.tag(name, tag_case: :upper) { inner_html }).to eq(
653
- "<#{name.upcase}>#{inner_html}</#{name.upcase}>"
654
- )
655
- end
656
- end
657
-
658
- context "when given `tag_case: :random`" do
659
- it "must randomize the case of the tag names" do
660
- expect(subject.tag(name, tag_case: :random) { inner_html }).to match(
661
- /\A<(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>#{inner_html}<\/(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>\z/
662
- )
663
- end
664
- end
665
-
666
- context "when additional attributes are given" do
667
- let(:attr1) { :foo }
668
- let(:value1) { 'bar' }
669
- let(:attr2) { :baz }
670
- let(:value2) { 'qux' }
671
- let(:attrs) do
672
- {attr1 => value1, attr2 => value2}
673
- end
674
-
675
- it "must add an attributes list after the tag name" do
676
- expect(subject.tag(name,**attrs) { inner_html }).to eq(
677
- "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_html}</#{name}>"
678
- )
679
- end
680
-
681
- context "when given `attr_case: :lower`" do
682
- let(:attr1) { :FOO }
683
- let(:attr2) { :BAZ }
684
-
685
- it "must convert the attribute names to lower-case" do
686
- expect(subject.tag(name, **attrs, attr_case: :lower) { inner_html }).to eq(
687
- "<#{name} #{attr1.downcase}=\"#{value1}\" #{attr2.downcase}=\"#{value2}\">#{inner_html}</#{name}>"
688
- )
689
- end
690
- end
691
-
692
- context "when given `attr_case: :upper`" do
693
- it "must convert the attribute names to upper-case" do
694
- expect(subject.tag(name, **attrs, attr_case: :upper) { inner_html }).to eq(
695
- "<#{name} #{attr1.upcase}=\"#{value1}\" #{attr2.upcase}=\"#{value2}\">#{inner_html}</#{name}>"
696
- )
697
- end
698
- end
699
-
700
- context "when given `attr_case: :random`" do
701
- it "must randomize the case of each attribute name" do
702
- expect(subject.tag(name, **attrs, attr_case: :random) { inner_html }).to match(
703
- /\A<#{name} (?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\">#{inner_html}<\/#{name}>\z/
704
- )
705
- end
706
- end
707
-
708
- context "when given `attr_quote: double`" do
709
- it "must quote the attribute values with double quotes" do
710
- expect(subject.tag(name, **attrs, attr_quote: :double) { inner_html }).to eq(
711
- "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_html}</#{name}>"
712
- )
713
- end
714
-
715
- context "and when an attribute value contains a double quote" do
716
- let(:value1) { "bar\"baz" }
717
-
718
- it "must replace any double quotes with &quot;" do
719
- expect(subject.tag(name, **attrs) { inner_html }).to eq(
720
- "<#{name} #{attr1}=\"bar&quot;baz\" #{attr2}=\"#{value2}\">#{inner_html}</#{name}>"
721
- )
722
- end
723
- end
724
- end
725
-
726
- context "when given `attr_quote: single`" do
727
- it "must quote the attribute values with single quotes" do
728
- expect(subject.tag(name, **attrs, attr_quote: :single) { inner_html }).to eq(
729
- "<#{name} #{attr1}='#{value1}' #{attr2}='#{value2}'>#{inner_html}</#{name}>"
730
- )
731
- end
732
-
733
- context "and when an attribute value contains a single quote" do
734
- let(:value1) { "bar'baz" }
735
-
736
- it "must replace any double quotes with &#39;;" do
737
- expect(subject.tag(name, **attrs, attr_quote: :single) { inner_html }).to eq(
738
- "<#{name} #{attr1}='bar&#39;baz' #{attr2}='#{value2}'>#{inner_html}</#{name}>"
739
- )
740
- end
741
- end
742
- end
743
-
744
- context "when given `attr_quote: :backtick`" do
745
- it "must quote the attribute values with backticks" do
746
- expect(subject.tag(name, **attrs, attr_quote: :backtick) { inner_html }).to eq(
747
- "<#{name} #{attr1}=`#{value1}` #{attr2}=`#{value2}`>#{inner_html}</#{name}>"
748
- )
749
- end
750
- end
751
-
752
- context "when given `attr_quote: nil`" do
753
- it "must not quote the attribute values" do
754
- expect(subject.tag(name, **attrs, attr_quote: nil) { inner_html }).to eq(
755
- "<#{name} #{attr1}=#{value1} #{attr2}=#{value2}>#{inner_html}</#{name}>"
756
- )
757
- end
758
-
759
- context "and when the value contains a space" do
760
- let(:value1) { "bar baz" }
761
-
762
- it "must replace any spaces with &#nbsp;;" do
763
- expect(subject.tag(name, **attrs, attr_quote: nil) { inner_html }).to eq(
764
- "<#{name} #{attr1}=bar&nbsp;baz #{attr2}=#{value2}>#{inner_html}</#{name}>"
765
- )
766
- end
767
- end
768
- end
769
- end
770
- end
771
- end
772
- end