diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index ca26893537..86dfc6ce67 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,15 @@ +* The `from:` option is added to `ActiveSupport::TestCase#assert_no_changes`. + + It permits asserting on the initial value that is expected not to change. + + ```ruby + assert_no_changes -> { Status.all_good? }, from: true do + post :create, params: { status: { ok: true } } + end + ``` + + *George Claghorn* + * Deprecate `ActiveSupport::SafeBuffer`'s incorrect implicit conversion of objects into string. Except for a few methods like `String#%`, objects must implement `#to_str` @@ -73,9 +85,9 @@ Ruby requires an initializer for non-numeric type as per examples below: ```ruby - %w[foo bar].sum('') + %w[foo bar].sum('') # instead of %w[foo bar].sum - + [[1, 2], [3, 4, 5]].sum([]) #instead of [[1, 2], [3, 4, 5]].sum ``` diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index d564cad808..437fc07909 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -207,16 +207,30 @@ module ActiveSupport # post :create, params: { status: { ok: true } } # end # + # Provide the optional keyword argument :from to specify the expected + # initial value. + # + # assert_no_changes -> { Status.all_good? }, from: true do + # post :create, params: { status: { ok: true } } + # end + # # An error message can be specified. # # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do # post :create, params: { status: { ok: false } } # end - def assert_no_changes(expression, message = nil, &block) + def assert_no_changes(expression, message = nil, from: UNTRACKED, &block) exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } before = exp.call retval = assert_nothing_raised(&block) + + unless from == UNTRACKED + error = "Expected initial value of #{from.inspect}" + error = "#{message}.\n#{error}" if message + assert from === before, error + end + after = exp.call error = "#{expression.inspect} changed" diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index e6342e8382..6339792ecf 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -286,6 +286,37 @@ class AssertionsTest < ActiveSupport::TestCase end end + def test_assert_no_changes_with_from_option + assert_no_changes "@object.num", from: 0 do + # ... + end + end + + def test_assert_no_changes_with_from_option_with_wrong_value + assert_raises Minitest::Assertion do + assert_no_changes "@object.num", from: -1 do + # ... + end + end + end + + def test_assert_no_changes_with_from_option_with_nil + error = assert_raises Minitest::Assertion do + assert_no_changes "@object.num", from: nil do + @object.increment + end + end + assert_equal "Expected initial value of nil", error.message + end + + def test_assert_no_changes_with_from_and_case_operator + token = SecureRandom.hex + + assert_no_changes -> { token }, from: /\w{32}/ do + # ... + end + end + def test_assert_no_changes_with_message error = assert_raises Minitest::Assertion do assert_no_changes "@object.num", "@object.num should not change" do