rails/actionview/test/buffers_test.rb
Jean Boussier fc0db35fb1 Add OutputBuffer#raw and #capture to reduce the need to swap the buffer
Right now many helpers have to deal with two modes of operation to
capture view output.

The main one is to swap the `@output_buffer` variable with a new buffer.
But since some view implementations such as `builder` keep a reference
on the buffer they were initialized with, this doesn't always work.

So additionally, the various capturing helpers also record the buffer
length prior to executing the block, and then `slice!` the buffer back
to its original size.

This is wasteful and make the code rather unclear.

Now that `OutputBuffer` is a delegator, I'd like to refactor all this
so that:

  - @output_buffer is no longer re-assigned
  - A single OutputBuffer instance is used for the entire response rendering
  - Instead capturing is done through `OutputBuffer#capture`

Once the above is achieved, it should allow us to enabled Erubi's
`:chain_appends` option and get some reduced template size and some
performance.

Not re-assigning `@output_buffer` will also allow template to access
the local variable instead of an instance variable, which is cheaper.

But more importantly, that should make the code easier to understand
and easier to be compatible with `StreamingBuffer`.
2022-08-03 12:56:34 +02:00

90 lines
2.2 KiB
Ruby

# frozen_string_literal: true
require "abstract_unit"
module SharedBufferTests
def self.included(test_case)
test_case.test "#<< maintains HTML safety" do
@buffer << "<script>alert('pwned!')</script>"
assert_predicate @buffer, :html_safe?
assert_predicate output, :html_safe?
assert_equal "&lt;script&gt;alert(&#39;pwned!&#39;)&lt;/script&gt;", output
end
test_case.test "#safe_append= bypasses HTML safety" do
@buffer.safe_append = "<p>This is fine</p>"
assert_predicate @buffer, :html_safe?
assert_predicate output, :html_safe?
assert_equal "<p>This is fine</p>", output
end
test_case.test "#raw allow to bypass HTML escaping" do
raw_buffer = @buffer.raw
raw_buffer << "<script>alert('pwned!')</script>"
assert_predicate @buffer, :html_safe?
assert_predicate output, :html_safe?
assert_equal "<script>alert('pwned!')</script>", output
end
test_case.test "#capture allow to intercept writes" do
@buffer << "Hello"
result = @buffer.capture do
@buffer << "George!"
end
assert_equal "George!", result
assert_predicate result, :html_safe?
@buffer << " World!"
assert_equal "Hello World!", output
end
test_case.test "#raw respects #capture" do
@buffer << "Hello"
raw_buffer = @buffer.raw
result = @buffer.capture do
raw_buffer << "George!"
end
assert_equal "George!", result
assert_predicate result, :html_safe?
@buffer << " World!"
assert_equal "Hello World!", output
end
end
end
class TestOutputBuffer < ActiveSupport::TestCase
include SharedBufferTests
setup do
@buffer = ActionView::OutputBuffer.new
end
test "can be duped" do
@buffer << "Hello"
copy = @buffer.dup
copy << " World!"
assert_equal "Hello World!", copy.to_s
assert_equal "Hello", output
end
private
def output
@buffer.to_s
end
end
class TestStreamingBuffer < ActiveSupport::TestCase
include SharedBufferTests
setup do
@raw_buffer = +""
@buffer = ActionView::StreamingBuffer.new(@raw_buffer.method(:<<))
end
private
def output
@raw_buffer.html_safe
end
end