better_html 1.0.16 → 2.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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -0
  3. data/Rakefile +19 -14
  4. data/ext/better_html_ext/better_html.h +1 -0
  5. data/ext/better_html_ext/extconf.rb +16 -0
  6. data/ext/better_html_ext/html_tokenizer.c +12 -0
  7. data/ext/better_html_ext/html_tokenizer.h +7 -0
  8. data/ext/better_html_ext/parser.c +793 -0
  9. data/ext/better_html_ext/parser.h +93 -0
  10. data/ext/better_html_ext/tokenizer.c +717 -0
  11. data/ext/better_html_ext/tokenizer.h +80 -0
  12. data/lib/better_html/ast/iterator.rb +14 -9
  13. data/lib/better_html/ast/node.rb +4 -2
  14. data/lib/better_html/better_erb/erubi_implementation.rb +43 -39
  15. data/lib/better_html/better_erb/runtime_checks.rb +140 -133
  16. data/lib/better_html/better_erb/validated_output_buffer.rb +30 -22
  17. data/lib/better_html/better_erb.rb +58 -54
  18. data/lib/better_html/config.rb +7 -4
  19. data/lib/better_html/errors.rb +4 -2
  20. data/lib/better_html/helpers.rb +7 -3
  21. data/lib/better_html/html_attributes.rb +6 -2
  22. data/lib/better_html/parser.rb +21 -14
  23. data/lib/better_html/railtie.rb +8 -4
  24. data/lib/better_html/test_helper/ruby_node.rb +15 -10
  25. data/lib/better_html/test_helper/safe_erb/allowed_script_type.rb +8 -4
  26. data/lib/better_html/test_helper/safe_erb/base.rb +12 -9
  27. data/lib/better_html/test_helper/safe_erb/no_javascript_tag_helper.rb +7 -3
  28. data/lib/better_html/test_helper/safe_erb/no_statements.rb +7 -3
  29. data/lib/better_html/test_helper/safe_erb/script_interpolation.rb +9 -4
  30. data/lib/better_html/test_helper/safe_erb/tag_interpolation.rb +23 -20
  31. data/lib/better_html/test_helper/safe_erb_tester.rb +33 -31
  32. data/lib/better_html/test_helper/safe_lodash_tester.rb +36 -35
  33. data/lib/better_html/test_helper/safety_error.rb +2 -0
  34. data/lib/better_html/tokenizer/base_erb.rb +14 -10
  35. data/lib/better_html/tokenizer/html_erb.rb +3 -2
  36. data/lib/better_html/tokenizer/html_lodash.rb +22 -14
  37. data/lib/better_html/tokenizer/javascript_erb.rb +3 -1
  38. data/lib/better_html/tokenizer/location.rb +17 -6
  39. data/lib/better_html/tokenizer/token.rb +2 -0
  40. data/lib/better_html/tokenizer/token_array.rb +8 -8
  41. data/lib/better_html/tree/attribute.rb +10 -6
  42. data/lib/better_html/tree/attributes_list.rb +9 -5
  43. data/lib/better_html/tree/tag.rb +10 -6
  44. data/lib/better_html/version.rb +3 -1
  45. data/lib/better_html.rb +19 -17
  46. data/lib/tasks/better_html_tasks.rake +1 -0
  47. metadata +39 -147
  48. data/lib/better_html/better_erb/erubis_implementation.rb +0 -44
  49. data/test/better_html/better_erb/implementation_test.rb +0 -406
  50. data/test/better_html/errors_test.rb +0 -13
  51. data/test/better_html/helpers_test.rb +0 -49
  52. data/test/better_html/parser_test.rb +0 -314
  53. data/test/better_html/test_helper/ruby_node_test.rb +0 -288
  54. data/test/better_html/test_helper/safe_erb/allowed_script_type_test.rb +0 -46
  55. data/test/better_html/test_helper/safe_erb/no_javascript_tag_helper_test.rb +0 -37
  56. data/test/better_html/test_helper/safe_erb/no_statements_test.rb +0 -129
  57. data/test/better_html/test_helper/safe_erb/script_interpolation_test.rb +0 -149
  58. data/test/better_html/test_helper/safe_erb/tag_interpolation_test.rb +0 -303
  59. data/test/better_html/test_helper/safe_lodash_tester_test.rb +0 -90
  60. data/test/better_html/tokenizer/html_erb_test.rb +0 -180
  61. data/test/better_html/tokenizer/html_lodash_test.rb +0 -98
  62. data/test/better_html/tokenizer/location_test.rb +0 -75
  63. data/test/better_html/tokenizer/token_array_test.rb +0 -146
  64. data/test/better_html/tokenizer/token_test.rb +0 -15
  65. data/test/dummy/README.rdoc +0 -28
  66. data/test/dummy/Rakefile +0 -6
  67. data/test/dummy/app/assets/javascripts/application.js +0 -13
  68. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  69. data/test/dummy/app/controllers/application_controller.rb +0 -5
  70. data/test/dummy/app/helpers/application_helper.rb +0 -2
  71. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  72. data/test/dummy/bin/bundle +0 -3
  73. data/test/dummy/bin/rails +0 -4
  74. data/test/dummy/bin/rake +0 -4
  75. data/test/dummy/bin/setup +0 -29
  76. data/test/dummy/config/application.rb +0 -26
  77. data/test/dummy/config/boot.rb +0 -5
  78. data/test/dummy/config/database.yml +0 -25
  79. data/test/dummy/config/environment.rb +0 -5
  80. data/test/dummy/config/environments/development.rb +0 -41
  81. data/test/dummy/config/environments/production.rb +0 -79
  82. data/test/dummy/config/environments/test.rb +0 -42
  83. data/test/dummy/config/initializers/assets.rb +0 -11
  84. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  85. data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  86. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  87. data/test/dummy/config/initializers/inflections.rb +0 -16
  88. data/test/dummy/config/initializers/mime_types.rb +0 -4
  89. data/test/dummy/config/initializers/session_store.rb +0 -3
  90. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  91. data/test/dummy/config/locales/en.yml +0 -23
  92. data/test/dummy/config/routes.rb +0 -56
  93. data/test/dummy/config/secrets.yml +0 -22
  94. data/test/dummy/config.ru +0 -4
  95. data/test/dummy/public/404.html +0 -67
  96. data/test/dummy/public/422.html +0 -67
  97. data/test/dummy/public/500.html +0 -66
  98. data/test/dummy/public/favicon.ico +0 -0
  99. data/test/test_helper.rb +0 -29
@@ -1,406 +0,0 @@
1
- require 'test_helper'
2
- require 'ostruct'
3
- require 'better_html/better_erb'
4
- require 'json'
5
-
6
- class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
7
- test "simple template rendering" do
8
- assert_equal "<foo>some value<foo>",
9
- render("<foo><%= bar %><foo>", locals: { bar: 'some value' })
10
- end
11
-
12
- test "html_safe interpolation" do
13
- assert_equal "<foo><bar /><foo>",
14
- render("<foo><%= bar %><foo>", locals: { bar: '<bar />'.html_safe })
15
- end
16
-
17
- test "non html_safe interpolation" do
18
- assert_equal "<foo>&lt;bar /&gt;<foo>",
19
- render("<foo><%= bar %><foo>", locals: { bar: '<bar />' })
20
- end
21
-
22
- test "interpolate non-html_safe inside attribute is escaped" do
23
- assert_equal "<a href=\" &#39;&quot;&gt;x \">",
24
- render("<a href=\"<%= value %>\">", locals: { value: ' \'">x ' })
25
- end
26
-
27
- test "interpolate html_safe inside attribute is magically force-escaped" do
28
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
29
- render("<a href=\"<%= value %>\">", locals: { value: ' \'">x '.html_safe })
30
- end
31
- assert_equal "Detected invalid characters as part of the interpolation "\
32
- "into a quoted attribute value. The value cannot contain the character \".", e.message
33
- end
34
-
35
- test "interpolate html_safe inside single quoted attribute" do
36
- config = build_config(allow_single_quoted_attributes: true)
37
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
38
- render("<a href=\'<%= value %>\'>", config: config, locals: { value: ' \'">x '.html_safe })
39
- end
40
- assert_equal "Detected invalid characters as part of the interpolation "\
41
- "into a quoted attribute value. The value cannot contain the character '.", e.message
42
- end
43
-
44
- test "interpolate in attribute name" do
45
- assert_equal "<a data-safe-foo>",
46
- render("<a data-<%= value %>-foo>", locals: { value: "safe" })
47
- end
48
-
49
- test "interpolate in attribute name with unsafe value with spaces" do
50
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
51
- render("<a data-<%= value %>-foo>", locals: { value: "un safe" })
52
- end
53
- assert_equal "Detected invalid characters as part of the interpolation "\
54
- "into a attribute name around 'data-<%= value %>'.", e.message
55
- end
56
-
57
- test "interpolate in attribute name with unsafe value with equal sign" do
58
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
59
- render("<a data-<%= value %>-foo>", locals: { value: "un=safe" })
60
- end
61
- assert_equal "Detected invalid characters as part of the "\
62
- "interpolation into a attribute name around 'data-<%= value %>'.", e.message
63
- end
64
-
65
- test "interpolate in attribute name with unsafe value with quote" do
66
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
67
- render("<a data-<%= value %>-foo>", locals: { value: "un\"safe" })
68
- end
69
- assert_equal "Detected invalid characters as part of the "\
70
- "interpolation into a attribute name around 'data-<%= value %>'.", e.message
71
- end
72
-
73
- test "interpolate after an attribute name without a value" do
74
- assert_equal '<a data-foo foo="bar">',
75
- render("<a data-foo <%= html_attributes(foo: 'bar') %>>")
76
- end
77
-
78
- test "interpolate after an attribute name with equal sign" do
79
- config = build_config(allow_unquoted_attributes: true)
80
- e = assert_raises(BetterHtml::DontInterpolateHere) do
81
- render("<a data-foo= <%= html_attributes(foo: 'bar') %>>", config: config)
82
- end
83
- assert_equal "Do not interpolate without quotes after "\
84
- "attribute around 'data-foo=<%= html_attributes(foo: 'bar') %>'.", e.message
85
- end
86
-
87
- test "interpolate after an attribute value" do
88
- e = assert_raises(BetterHtml::DontInterpolateHere) do
89
- render("<a foo=\"xx\"<%= html_attributes(foo: 'bar') %>>")
90
- end
91
- assert_equal "Add a space after this attribute value. "\
92
- "Instead of <a foo=\"xx\"<%= html_attributes(foo: 'bar') %>>"\
93
- " try <a foo=\"xx\" <%= html_attributes(foo: 'bar') %>>.", e.message
94
- end
95
-
96
- test "interpolate in attribute without quotes" do
97
- config = build_config(allow_unquoted_attributes: true)
98
- e = assert_raises(BetterHtml::DontInterpolateHere) do
99
- render("<a href=<%= value %>>", config: config, locals: { value: "un safe" })
100
- end
101
- assert_equal "Do not interpolate without quotes after "\
102
- "attribute around 'href=<%= value %>'.", e.message
103
- end
104
-
105
- test "interpolate in attribute after value" do
106
- config = build_config(allow_unquoted_attributes: true)
107
- e = assert_raises(BetterHtml::DontInterpolateHere) do
108
- render("<a href=something<%= value %>>", config: config, locals: { value: "" })
109
- end
110
- assert_equal "Do not interpolate without quotes around this "\
111
- "attribute value. Instead of <a href=something<%= value %>> "\
112
- "try <a href=\"something<%= value %>\">.", e.message
113
- end
114
-
115
- test "interpolate in tag name" do
116
- assert_equal "<tag-safe-foo>",
117
- render("<tag-<%= value %>-foo>", locals: { value: "safe" })
118
- end
119
-
120
- test "interpolate in tag name with space" do
121
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
122
- render("<tag-<%= value %>-foo>", locals: { value: "un safe" })
123
- end
124
- assert_equal "Detected invalid characters as part of the interpolation "\
125
- "into a tag name around: <tag-<%= value %>>.", e.message
126
- end
127
-
128
- test "interpolate in tag name with slash" do
129
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
130
- render("<tag-<%= value %>-foo>", locals: { value: "un/safe" })
131
- end
132
- assert_equal "Detected invalid characters as part of the interpolation "\
133
- "into a tag name around: <tag-<%= value %>>.", e.message
134
- end
135
-
136
- test "interpolate in tag name with end of tag" do
137
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
138
- render("<tag-<%= value %>-foo>", locals: { value: "><script>" })
139
- end
140
- assert_equal "Detected invalid characters as part of the interpolation "\
141
- "into a tag name around: <tag-<%= value %>>.", e.message
142
- end
143
-
144
- test "interpolate in comment" do
145
- assert_equal "<!-- safe -->",
146
- render("<!-- <%= value %> -->", locals: { value: "safe" })
147
- end
148
-
149
- test "interpolate in comment with end-of-comment" do
150
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
151
- render("<!-- <%= value %> -->", locals: { value: "-->".html_safe })
152
- end
153
- assert_equal "Detected invalid characters as part of the interpolation "\
154
- "into a html comment around: <!-- <%= value %>.", e.message
155
- end
156
-
157
- test "non html_safe interpolation into comment tag" do
158
- assert_equal "<!-- --&gt; -->",
159
- render("<!-- <%= value %> -->", locals: { value: '-->' })
160
- end
161
-
162
- test "interpolate in script tag" do
163
- assert_equal "<script> foo safe bar<script>",
164
- render("<script> foo <%= value %> bar<script>", locals: { value: "safe" })
165
- end
166
-
167
- test "interpolate in script tag with start of comment" do
168
- skip "skip for now; causing problems"
169
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
170
- render("<script> foo <%= value %> bar<script>", locals: { value: "<!--".html_safe })
171
- end
172
- assert_equal "Detected invalid characters as part of the interpolation "\
173
- "into a script tag around: <script> foo <%= value %>. "\
174
- "A script tag cannot contain <script or </script anywhere inside of it.", e.message
175
- end
176
-
177
- test "interpolate in script tag with start of script" do
178
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
179
- render("<script> foo <%= value %> bar<script>", locals: { value: "<script".html_safe })
180
- end
181
- assert_equal "Detected invalid characters as part of the interpolation "\
182
- "into a script tag around: <script> foo <%= value %>. "\
183
- "A script tag cannot contain <script or </script anywhere inside of it.", e.message
184
- end
185
-
186
- test "interpolate in script tag with raw interpolation" do
187
- assert_equal "<script> x = \"foo\" </script>",
188
- render("<script> x = <%== value %> </script>", locals: { value: JSON.dump("foo") })
189
- end
190
-
191
- test "interpolate in script tag with start of script case insensitive" do
192
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
193
- render("<script> foo <%= value %> bar<script>", locals: { value: "<ScRIpT".html_safe })
194
- end
195
- assert_equal "Detected invalid characters as part of the interpolation "\
196
- "into a script tag around: <script> foo <%= value %>. "\
197
- "A script tag cannot contain <script or </script anywhere inside of it.", e.message
198
- end
199
-
200
- test "interpolate in script tag with end of script" do
201
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
202
- render("<script> foo <%= value %> bar<script>", locals: { value: "</script".html_safe })
203
- end
204
- assert_equal "Detected invalid characters as part of the interpolation "\
205
- "into a script tag around: <script> foo <%= value %>. "\
206
- "A script tag cannot contain <script or </script anywhere inside of it.", e.message
207
- end
208
-
209
- test "interpolate html_attributes" do
210
- assert_equal "<a foo=\"bar\">",
211
- render("<a <%= html_attributes(foo: 'bar') %>>")
212
- end
213
-
214
- test "interpolate without html_attributes" do
215
- e = assert_raises(BetterHtml::DontInterpolateHere) do
216
- render("<a <%= 'foo=\"bar\"' %>>")
217
- end
218
- assert_equal "Do not interpolate String in a tag. Instead "\
219
- "of <a <%= 'foo=\"bar\"' %>> please try <a <%= html_attributes(attr: value) %>>.", e.message
220
- end
221
-
222
- test "non html_safe interpolation into rawtext tag" do
223
- assert_equal "<title>&lt;/title&gt;</title>",
224
- render("<title><%= value %></title>", locals: { value: '</title>' })
225
- end
226
-
227
- test "html_safe interpolation into rawtext tag" do
228
- assert_equal "<title><safe></title>",
229
- render("<title><%= value %></title>", locals: { value: '<safe>'.html_safe })
230
- end
231
-
232
- test "html_safe interpolation terminating the current tag" do
233
- e = assert_raises(BetterHtml::UnsafeHtmlError) do
234
- render("<title><%= value %></title>", locals: { value: '</title>'.html_safe })
235
- end
236
- assert_equal "Detected invalid characters as part of the interpolation "\
237
- "into a title tag around: <title><%= value %>.", e.message
238
- end
239
-
240
- test "interpolate block in middle of tag" do
241
- e = assert_raises(BetterHtml::DontInterpolateHere) do
242
- render(<<-HTML)
243
- <a href="" <%= something do %>
244
- foo
245
- <% end %>
246
- HTML
247
- end
248
- assert_equal "Ruby statement not allowed.\n"\
249
- "In 'tag' on line 1 column 19:\n"\
250
- " <a href=\"\" <%= something do %>\n"\
251
- " ^^^^^^^^^^^^^^^^^^^", e.message
252
- end
253
-
254
- test "interpolate with output block is valid syntax" do
255
- assert_nothing_raised do
256
- render(<<-HTML)
257
- <%= capture do %>
258
- <foo>
259
- <% end %>
260
- HTML
261
- end
262
- end
263
-
264
- test "interpolate with statement block is valid syntax" do
265
- assert_nothing_raised do
266
- render(<<-HTML)
267
- <% capture do %>
268
- <foo>
269
- <% end %>
270
- HTML
271
- end
272
- end
273
-
274
- test "can interpolate method calls without parenthesis" do
275
- assert_equal "<div>foo</div>",
276
- render("<div><%= send 'value' %></div>", locals: { value: 'foo' })
277
- end
278
-
279
- test "tag names are validated against tag_name_pattern regexp" do
280
- e = assert_raises(BetterHtml::HtmlError) do
281
- render("<foo~bar></foo~bar>")
282
- end
283
- assert_equal "Invalid tag name \"foo~bar\" does not match regular expression /\\A[a-z0-9\\-\\:]+\\z/\n"\
284
- "On line 1 column 1:\n"\
285
- "<foo~bar></foo~bar>\n"\
286
- " ^^^^^^^", e.message
287
- end
288
-
289
- test "attribute names are validated against attribute_name_pattern regexp" do
290
- e = assert_raises(BetterHtml::HtmlError) do
291
- render("<foo bar_baz=\"1\">")
292
- end
293
- assert_equal "Invalid attribute name \"bar_baz\" does not match regular expression #{build_config.partial_attribute_name_pattern.inspect}\n"\
294
- "On line 1 column 5:\n"\
295
- "<foo bar_baz=\"1\">\n"\
296
- " ^^^^^^^", e.message
297
- end
298
-
299
- test "single quotes are disallowed when allow_single_quoted_attributes=false" do
300
- config = build_config(allow_single_quoted_attributes: false)
301
- e = assert_raises(BetterHtml::HtmlError) do
302
- render("<foo bar='1'>", config: config)
303
- end
304
- assert_equal "Single-quoted attributes are not allowed\n"\
305
- "On line 1 column 9:\n"\
306
- "<foo bar='1'>\n"\
307
- " ^", e.message
308
- end
309
-
310
- test "single quotes are allowed when allow_single_quoted_attributes=true" do
311
- config = build_config(allow_single_quoted_attributes: true)
312
- assert_nothing_raised do
313
- render("<foo bar='1'>", config: config)
314
- end
315
- end
316
-
317
- test "unquoted values are disallowed when allow_unquoted_attributes=false" do
318
- config = build_config(allow_unquoted_attributes: false)
319
- e = assert_raises(BetterHtml::HtmlError) do
320
- render("<foo bar=1>", config: config)
321
- end
322
- assert_equal "Unquoted attribute values are not allowed\n"\
323
- "On line 1 column 9:\n"\
324
- "<foo bar=1>\n"\
325
- " ^", e.message
326
- end
327
-
328
- test "unquoted values are allowed when allow_unquoted_attributes=true" do
329
- config = build_config(allow_unquoted_attributes: true)
330
- assert_nothing_raised do
331
- render("<foo bar=1>", config: config)
332
- end
333
- end
334
-
335
- test "capture works as intended" do
336
- output = render(<<-HTML)
337
- <%- foo = capture do -%>
338
- <foo>
339
- <%- end -%>
340
- <bar><%= foo %></bar>
341
- HTML
342
-
343
- assert_equal " <bar> <foo>\n</bar>\n", output
344
- end
345
-
346
- test "validate! raises when tag is not terminated at end of document" do
347
- document = compile("<foo")
348
- e = assert_raises(BetterHtml::HtmlError) do
349
- document.validate!
350
- end
351
- assert_equal "Detected an open tag at the end of this document.", e.message
352
- end
353
-
354
- test "validate! raises when rawtext tag is not terminated at end of document" do
355
- document = compile("<script>")
356
- e = assert_raises(BetterHtml::HtmlError) do
357
- document.validate!
358
- end
359
- assert_equal "Detected an open tag at the end of this document.", e.message
360
- end
361
-
362
- test "validate! raises parsing error for attribute name" do
363
- document = compile("<foo bar~baz=\"1\">")
364
- e = assert_raises(BetterHtml::HtmlError) do
365
- document.validate!
366
- end
367
- assert_equal "expected whitespace, '>', attribute name or value\n"\
368
- "On line 1 column 8:\n"\
369
- "<foo bar~baz=\"1\">\n"\
370
- " ^^^^^^^^^", e.message
371
- end
372
-
373
- private
374
-
375
- class ViewContext < OpenStruct
376
- include(ActionView::Helpers)
377
- include(BetterHtml::Helpers)
378
- attr_accessor :output_buffer
379
-
380
- def get_binding
381
- binding
382
- end
383
- end
384
-
385
- def build_config(**options)
386
- BetterHtml::Config.new(**options)
387
- end
388
-
389
- def render(source, config: build_config, locals: {})
390
- context = ViewContext.new(locals)
391
- impl = compile(source, config: config)
392
- if ActionView.version < Gem::Version.new("5.1")
393
- impl.result(context.get_binding)
394
- else
395
- impl.evaluate(context)
396
- end
397
- end
398
-
399
- def compile(source, config: build_config)
400
- if ActionView.version < Gem::Version.new("5.1")
401
- BetterHtml::BetterErb::ErubisImplementation.new(source, config: config)
402
- else
403
- BetterHtml::BetterErb::ErubiImplementation.new(source, config: config)
404
- end
405
- end
406
- end
@@ -1,13 +0,0 @@
1
- require 'test_helper'
2
- require 'better_html/errors'
3
-
4
- module BetterHtml
5
- class ErrorsTest < ActiveSupport::TestCase
6
- test "add" do
7
- e = Errors.new
8
- e.add("foo")
9
- assert_equal 1, e.size
10
- assert_equal "foo", e.first
11
- end
12
- end
13
- end
@@ -1,49 +0,0 @@
1
- require 'test_helper'
2
-
3
- class BetterHtml::HelpersTest < ActiveSupport::TestCase
4
- include BetterHtml::Helpers
5
-
6
- test "html_attributes return a HtmlAttributes object" do
7
- assert_equal BetterHtml::HtmlAttributes, html_attributes(foo: "bar").class
8
- end
9
-
10
- test "html_attributes are formatted as string" do
11
- assert_equal 'foo="bar" baz="qux"',
12
- html_attributes(foo: "bar", baz: "qux").to_s
13
- end
14
-
15
- test "html_attributes keys cannot contain invalid characters" do
16
- e = assert_raises(ArgumentError) do
17
- html_attributes("invalid key": "bar", baz: "qux").to_s
18
- end
19
- assert_equal "Attribute names must match the pattern /\\A[a-zA-Z0-9\\-\\:]+\\z/", e.message
20
- end
21
-
22
- test "#html_attributes does not accept incorrectly escaped html_safe values" do
23
- e = assert_raises(ArgumentError) do
24
- html_attributes('something': 'with "> double quote'.html_safe).to_s
25
- end
26
- assert_equal "The value provided for attribute 'something' contains a `\"` character which is not allowed. "\
27
- "Did you call .html_safe without properly escaping this data?", e.message
28
- end
29
-
30
- test "#html_attributes accepts correctly escaped html_safe values" do
31
- assert_equal 'something="with &quot;&gt; double quote"',
32
- html_attributes('something': CGI.escapeHTML('with "> double quote').html_safe).to_s
33
- end
34
-
35
- test "#html_attributes escapes non-html_safe values" do
36
- assert_equal 'something="with &quot;&gt; double quote"',
37
- html_attributes('something': 'with "> double quote').to_s
38
- end
39
-
40
- test "#html_attributes accepts nil values as value-less attributes" do
41
- assert_equal 'data-thing data-other-thing',
42
- html_attributes('data-thing': nil, 'data-other-thing': nil).to_s
43
- end
44
-
45
- test "#html_attributes empty string value is output" do
46
- assert_equal 'data-thing="" data-other-thing=""',
47
- html_attributes('data-thing': "", 'data-other-thing': "").to_s
48
- end
49
- end