require 'unit_spec_helper'

describe Shoulda::Matchers::ActiveModel::ValidateComparisonOfMatcher, type: :model do
  context 'passing multiple attributes' do
    it 'accepts when every attribute has the validation' do
      model = define_model 'Example', attr1: :integer, attr2: :integer do
        validates_comparison_of :attr1, :attr2, greater_than: 18
      end

      expect(model.new).
        to validate_comparison_of(:attr1, :attr2).is_greater_than(18)
    end

    it 'rejects when one attribute has the validation and one does not' do
      model = define_model 'Example', attr1: :integer, attr2: :integer do
        validates_comparison_of :attr1, greater_than: 18, allow_nil: true
      end

      assertion = lambda do
        expect(model.new).
          to validate_comparison_of(:attr1, :attr2).is_greater_than(18)
      end

      message = <<-MESSAGE
Expected Example to validate that :attr2 looks like a value greater than
18, but this could not be proved.
  After setting :attr2 to ‹18›, the matcher expected the Example to be
  invalid, but it was valid instead.
      MESSAGE

      expect(&assertion).to fail_with_message(message)
    end

    it 'rejects when no attribute has the validation' do
      model = define_model 'Example', attr1: :integer, attr2: :integer

      assertion = lambda do
        expect(model.new).
          to validate_comparison_of(:attr1, :attr2).is_greater_than(18)
      end

      message = <<-MESSAGE
Expected Example to validate that :attr1 looks like a value greater than
18 and validate that :attr2 looks like a value greater than 18, but this
could not be proved.
  After setting :attr1 to ‹18›, the matcher expected the Example to be
  invalid, but it was valid instead.
  After setting :attr2 to ‹18›, the matcher expected the Example to be
  invalid, but it was valid instead.
      MESSAGE

      expect(&assertion).to fail_with_message(message)
    end
  end

  context 'with combinations of qualifiers together' do
    context 'when the qualifiers do not match the validation options' do
      specify 'such as validating greater_than_or_equal_to but testing that greater_than is validated' do
        record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: 18)
        assertion = lambda { expect(record).to validate_comparison.is_greater_than(18) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
18, but this could not be proved.
  After setting :attr to ‹18›, the matcher expected the Example to be
  invalid, but it was valid instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end

      specify 'such as validating greater_than_or_equal_to but testing that is_less_than_or_equal_to is validated' do
        record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: 18)
        assertion = lambda { expect(record).to validate_comparison.is_less_than_or_equal_to(18) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value less than or
equal to 18, but this could not be proved.
  After setting :attr to ‹19›, the matcher expected the Example to be
  invalid, but it was valid instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end
    end

    context 'when qualifiers match the validation options but the values are different' do
      specify 'such as testing greater_than with lower value' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 19)

        assertion = lambda { expect(record).to validate_comparison.is_greater_than(18) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
18, but this could not be proved.
  After setting :attr to ‹18›, the matcher expected the Example to be
  invalid and to produce the validation error "must be greater than 18"
  on :attr. The record was indeed invalid, but it produced these
  validation errors instead:

  * attr: ["must be greater than 19"]
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end

      specify 'such as testing greater_than with higher value' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 18)

        assertion = lambda { expect(record).to validate_comparison.is_greater_than(19) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
19, but this could not be proved.
  After setting :attr to ‹19›, the matcher expected the Example to be
  invalid, but it was valid instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end

      specify 'such as testing less_than_or_equal_to with lower value' do
        record = build_record_validating_comparison(column_type: :integer, less_than_or_equal_to: 18)

        assertion = lambda do
          expect(record).
            to validate_comparison.
            is_less_than_or_equal_to(17)
        end

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value less than or
equal to 17, but this could not be proved.
  After setting :attr to ‹18›, the matcher expected the Example to be
  invalid, but it was valid instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end

      specify 'such as testing less_than_or_equal_to with higher value' do
        record = build_record_validating_comparison(
          column_type: :integer,
          less_than_or_equal_to: 18,
        )

        assertion = lambda { expect(record).to validate_comparison.is_less_than_or_equal_to(19) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value less than or
equal to 19, but this could not be proved.
  After setting :attr to ‹20›, the matcher expected the Example to be
  invalid and to produce the validation error "must be less than or
  equal to 19" on :attr. The record was indeed invalid, but it produced
  these validation errors instead:

  * attr: ["must be less than or equal to 18"]
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end

      specify 'such as testing greater_than (+ less_than) with lower value' do
        record = build_record_validating_comparison(
          column_type: :integer,
          greater_than: 19,
          less_than: 99,
        )

        assertion = lambda { expect(record).to validate_comparison.is_greater_than(18).is_less_than(99) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
18 and less than 99, but this could not be proved.
  After setting :attr to ‹18›, the matcher expected the Example to be
  invalid and to produce the validation error "must be greater than 18"
  on :attr. The record was indeed invalid, but it produced these
  validation errors instead:

  * attr: ["must be greater than 19"]
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end

      specify 'such as testing less_than (+ only_integer + greater_than) with higher value' do
        record = build_record_validating_comparison(
          column_type: :integer,
          greater_than: 18,
          less_than: 100,
        )

        assertion = lambda { expect(record).to validate_comparison.is_greater_than(18).is_less_than(99) }

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
18 and less than 99, but this could not be proved.
  After setting :attr to ‹100›, the matcher expected the Example to be
  invalid and to produce the validation error "must be less than 99" on
  :attr. The record was indeed invalid, but it produced these validation
  errors instead:

  * attr: ["must be less than 100"]
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end
    end
  end

  context 'when comparing with an integer' do
    context 'qualified with is_other_than' do
      context 'and validating with other_than' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, other_than: 10)

          expect(record).to validate_comparison_of(:attr).is_other_than(10)
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :integer, other_than: 10)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_other_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value other
than 10, but this could not be proved.
  After setting :attr to ‹11›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :integer,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value other than
10, but this could not be proved.
  After setting :attr to ‹10› -- which was read back as ‹11› -- the
  matcher expected the Example to be invalid, but it was valid instead.

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { other_than: 10 })
          end

          def configure_validation_matcher(matcher)
            matcher.is_other_than(10)
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :integer, other_than: 10)

          expect(record).to validate_comparison_of(:attr).is_other_than(10)
        end
      end

      context 'when comparison value is a proc returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, other_than: -> (_record) { 10 })

          expect(record).to validate_comparison_of(:attr).is_other_than(-> (_record) { 10 })
        end
      end

      context 'when comparison value is a method returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, other_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(10)

          expect(record).to validate_comparison_of(:attr).is_other_than(:comparison_value)
        end
      end

      context 'when the column is an string column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :string, other_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_other_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value other than
10, but this could not be proved.
  After setting :attr to ‹"10"›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, other_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_other_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value other than
10, but this could not be proved.
  After setting :attr to ‹"10"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be other than 10" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is an integer column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :integer,
            other_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_other_than(10)
        end
      end

      context 'when the column is a float column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :float,
            other_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_other_than(10)
        end
      end

      context 'when the column is a decimal column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :decimal,
            other_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_other_than(10)
        end
      end
    end

    context 'qualified with is_equal_to' do
      context 'and validating with equal_to' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, equal_to: 10)

          expect(record).to validate_comparison_of(:attr).is_equal_to(10)
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :integer, equal_to: 10)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value equal to
10, but this could not be proved.
  After setting :attr to ‹11›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be equal to 10"]
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :integer,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value equal to 10,
but this could not be proved.
  After setting :attr to ‹10› -- which was read back as ‹11› -- the
  matcher expected the Example to be valid, but it was invalid instead,
  producing these validation errors:

  * attr: ["must be equal to 10"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { equal_to: 10 })
          end

          def configure_validation_matcher(matcher)
            matcher.is_equal_to(10)
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :integer, equal_to: 10)

          expect(record).to validate_comparison_of(:attr).is_equal_to(10)
        end
      end

      context 'when comparison value is a proc returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, equal_to: -> (_record) { 10 })

          expect(record).to validate_comparison_of(:attr).is_equal_to(-> (_record) { 10 })
        end
      end

      context 'when comparison value is a method returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(10)

          expect(record).to validate_comparison_of(:attr).is_equal_to(:comparison_value)
        end
      end

      context 'when the column is an string column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :string, equal_to: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value equal to 10,
but this could not be proved.
  After setting :attr to ‹"10"›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be equal to 10"]
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, equal_to: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value equal to 10,
but this could not be proved.
  After setting :attr to ‹"11"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be equal to 10" on :attr. The record was indeed
  invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is an integer column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :integer,
            equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_equal_to(10)
        end
      end

      context 'when the column is a float column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :float,
            equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_equal_to(10)
        end
      end

      context 'when the column is a decimal column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :decimal,
            equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_equal_to(10)
        end
      end
    end

    context 'qualified with less_than_or_equal_to' do
      context 'and validating with is_less_than_or_equal_to' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, less_than_or_equal_to: 10)

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(10)
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :integer, less_than_or_equal_to: 10)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_less_than_or_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value less than
or equal to 10, but this could not be proved.
  After setting :attr to ‹11›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be less than or equal to 10"]
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :integer,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value less than or
equal to 10, but this could not be proved.
  After setting :attr to ‹10› -- which was read back as ‹11› -- the
  matcher expected the Example to be valid, but it was invalid instead,
  producing these validation errors:

  * attr: ["must be less than or equal to 10"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { less_than_or_equal_to: 10 })
          end

          def configure_validation_matcher(matcher)
            matcher.is_less_than_or_equal_to(10)
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :integer, less_than_or_equal_to: 10)

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(10)
        end
      end

      context 'when comparison value is a proc returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, less_than_or_equal_to: -> (_record) { 10 })

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(-> (_record) { 10 })
        end
      end

      context 'when comparison value is a method returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, less_than_or_equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(10)

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(:comparison_value)
        end
      end

      context 'when the column is an string column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :string, less_than_or_equal_to: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than or
equal to 10, but this could not be proved.
  After setting :attr to ‹"11"›, the matcher expected the Example to be
  invalid and to produce the validation error "must be less than or
  equal to 10" on :attr. The record was indeed invalid, but it produced
  these validation errors instead:

  * attr: ["comparison of String with 10 failed"]
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, less_than_or_equal_to: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than or
equal to 10, but this could not be proved.
  After setting :attr to ‹"11"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be less than or equal to 10" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is an integer column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :integer,
            less_than_or_equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_less_than_or_equal_to(10)
        end
      end

      context 'when the column is a float column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :float,
            less_than_or_equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_less_than_or_equal_to(10)
        end
      end

      context 'when the column is a decimal column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :decimal,
            less_than_or_equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_less_than_or_equal_to(10)
        end
      end
    end

    context 'qualified with is_less_than' do
      context 'and validating with less_than' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, less_than: 10)

          expect(record).to validate_comparison_of(:attr).is_less_than(10)
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :integer, less_than: 10)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_less_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value less than
10, but this could not be proved.
  After setting :attr to ‹11›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be less than 10"]
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :integer,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value less than 10,
but this could not be proved.
  After setting :attr to ‹9› -- which was read back as ‹10› -- the
  matcher expected the Example to be valid, but it was invalid instead,
  producing these validation errors:

  * attr: ["must be less than 10"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { less_than: 10 })
          end

          def configure_validation_matcher(matcher)
            matcher.is_less_than(10)
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :integer, less_than: 10)

          expect(record).to validate_comparison_of(:attr).is_less_than(10)
        end
      end

      context 'when comparison value is a proc returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, less_than: -> (_record) { 10 })

          expect(record).to validate_comparison_of(:attr).is_less_than(-> (_record) { 10 })
        end
      end

      context 'when comparison value is a method returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, less_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(10)

          expect(record).to validate_comparison_of(:attr).is_less_than(:comparison_value)
        end
      end

      context 'when the column is an string column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :string, less_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than 10,
but this could not be proved.
  After setting :attr to ‹"11"›, the matcher expected the Example to be
  invalid and to produce the validation error "must be less than 10" on
  :attr. The record was indeed invalid, but it produced these validation
  errors instead:

  * attr: ["comparison of String with 10 failed"]
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, less_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than 10,
but this could not be proved.
  After setting :attr to ‹"11"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be less than 10" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is an integer column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :integer,
            less_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_less_than(10)
        end
      end

      context 'when the column is a float column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :float,
            less_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_less_than(10)
        end
      end

      context 'when the column is a decimal column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :decimal,
            less_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_less_than(10)
        end
      end
    end

    context 'qualified with is_greater_than' do
      context 'and validating with greater_than' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, greater_than: 10)

          expect(record).to validate_comparison_of(:attr).is_greater_than(10)
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :integer, greater_than: 10)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_greater_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value greater
than 10, but this could not be proved.
  After setting :attr to ‹11›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :integer,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value greater than
10, but this could not be proved.
  After setting :attr to ‹11› -- which was read back as ‹1› -- the
  matcher expected the Example to be valid, but it was invalid instead,
  producing these validation errors:

  * attr: ["must be greater than 10"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { greater_than: 10 })
          end

          def configure_validation_matcher(matcher)
            matcher.is_greater_than(10)
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :integer, greater_than: 10)

          expect(record).to validate_comparison_of(:attr).is_greater_than(10)
        end
      end

      context 'when comparison value is a proc returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, greater_than: -> (_record) { 10 })

          expect(record).to validate_comparison_of(:attr).is_greater_than(-> (_record) { 10 })
        end
      end

      context 'when comparison value is a method returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, greater_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(10)

          expect(record).to validate_comparison_of(:attr).is_greater_than(:comparison_value)
        end
      end

      context 'when the column is an string column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :string, greater_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
10, but this could not be proved.
  After setting :attr to ‹"10"›, the matcher expected the Example to be
  invalid and to produce the validation error "must be greater than 10"
  on :attr. The record was indeed invalid, but it produced these
  validation errors instead:

  * attr: ["comparison of String with 10 failed"]
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, greater_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
10, but this could not be proved.
  After setting :attr to ‹"10"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be greater than 10" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is an integer column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :integer,
            greater_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_greater_than(10)
        end
      end

      context 'when the column is a float column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :float,
            greater_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_greater_than(10)
        end
      end

      context 'when the column is a decimal column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :decimal,
            greater_than: 10,
          )

          expect(record).
            to validate_comparison.
            is_greater_than(10)
        end
      end
    end

    context 'qualified with is_greater_than_or_equal_to' do
      context 'and validating with greater_than_or_equal_to' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: 10)

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(10)
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: 10)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_greater_than_or_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value greater
than or equal to 10, but this could not be proved.
  After setting :attr to ‹11›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :integer,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value greater than
or equal to 10, but this could not be proved.
  After setting :attr to ‹11› -- which was read back as ‹1› -- the
  matcher expected the Example to be valid, but it was invalid instead,
  producing these validation errors:

  * attr: ["must be greater than or equal to 10"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { greater_than_or_equal_to: 10 })
          end

          def configure_validation_matcher(matcher)
            matcher.is_greater_than_or_equal_to(10)
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :integer, greater_than_or_equal_to: 10)

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(10)
        end
      end

      context 'when comparison value is a proc returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: -> (_record) { 10 })

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(-> (_record) { 10 })
        end
      end

      context 'when comparison value is a method returning an integer' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(10)

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(:comparison_value)
        end
      end

      context 'when the column is an string column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :string, greater_than_or_equal_to: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
or equal to 10, but this could not be proved.
  After setting :attr to ‹"9"›, the matcher expected the Example to be
  invalid and to produce the validation error "must be greater than or
  equal to 10" on :attr. The record was indeed invalid, but it produced
  these validation errors instead:

  * attr: ["comparison of String with 10 failed"]
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, greater_than_or_equal_to: 10)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(10)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
or equal to 10, but this could not be proved.
  After setting :attr to ‹"9"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be greater than or equal to 10" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is an integer column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :integer,
            greater_than_or_equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_greater_than_or_equal_to(10)
        end
      end

      context 'when the column is a float column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :float,
            greater_than_or_equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_greater_than_or_equal_to(10)
        end
      end

      context 'when the column is a decimal column' do
        it 'accepts (and does not raise an error)' do
          record = build_record_validating_comparison(
            column_type: :decimal,
            greater_than_or_equal_to: 10,
          )

          expect(record).
            to validate_comparison.
            is_greater_than_or_equal_to(10)
        end
      end
    end
  end

  context 'when comparing with an string' do
    context 'qualified with is_other_than' do
      context 'and validating with other_than' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, other_than: 'cat')

          expect(record).to validate_comparison_of(:attr).is_other_than('cat')
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :string, other_than: 'cat')

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_other_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value other
than cat, but this could not be proved.
  After setting :attr to ‹"cau"›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :string,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value other than
cat, but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹"cau"› --
  the matcher expected the Example to be invalid, but it was valid
  instead.

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { other_than: 'cat' })
          end

          def configure_validation_matcher(matcher)
            matcher.is_other_than('cat')
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :string, other_than: 'cat')

          expect(record).to validate_comparison_of(:attr).is_other_than('cat')
        end
      end

      context 'when comparison value is a proc returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, other_than: -> (_record) { 'cat' })

          expect(record).to validate_comparison_of(:attr).is_other_than(-> (_record) { 'cat' })
        end
      end

      context 'when comparison value is a method returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, other_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return('cat')

          expect(record).to validate_comparison_of(:attr).is_other_than(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :integer, other_than: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_other_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value other than
cat, but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹0› -- the
  matcher expected the Example to be invalid, but it was valid instead.

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, other_than: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_other_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value other than
cat, but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be other than cat" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with is_equal_to' do
      context 'and validating with equal_to' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, equal_to: 'cat')

          expect(record).to validate_comparison_of(:attr).is_equal_to('cat')
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :string, equal_to: 'cat')

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value equal to
cat, but this could not be proved.
  After setting :attr to ‹"cau"›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be equal to cat"]
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :string,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value equal to cat,
but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹"cau"› --
  the matcher expected the Example to be valid, but it was invalid
  instead, producing these validation errors:

  * attr: ["must be equal to cat"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { equal_to: 'cat' })
          end

          def configure_validation_matcher(matcher)
            matcher.is_equal_to('cat')
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :string, equal_to: 'cat')

          expect(record).to validate_comparison_of(:attr).is_equal_to('cat')
        end
      end

      context 'when comparison value is a proc returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, equal_to: -> (_record) { 'cat' })

          expect(record).to validate_comparison_of(:attr).is_equal_to(-> (_record) { 'cat' })
        end
      end

      context 'when comparison value is a method returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return('cat')

          expect(record).to validate_comparison_of(:attr).is_equal_to(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :integer, equal_to: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value equal to cat,
but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹0› -- the
  matcher expected the Example to be valid, but it was invalid instead,
  producing these validation errors:

  * attr: ["must be equal to cat"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, equal_to: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value equal to cat,
but this could not be proved.
  After setting :attr to ‹"cau"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be equal to cat" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with is_less_than_or_equal_to' do
      context 'and validating with less_than_or_equal_to' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, less_than_or_equal_to: 'cat')

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to('cat')
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :string, less_than_or_equal_to: 'cat')

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_less_than_or_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value less than
or equal to cat, but this could not be proved.
  After setting :attr to ‹"cau"›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be less than or equal to cat"]
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :string,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value less than or
equal to cat, but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹"cau"› --
  the matcher expected the Example to be valid, but it was invalid
  instead, producing these validation errors:

  * attr: ["must be less than or equal to cat"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { less_than_or_equal_to: 'cat' })
          end

          def configure_validation_matcher(matcher)
            matcher.is_less_than_or_equal_to('cat')
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :string, less_than_or_equal_to: 'cat')

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to('cat')
        end
      end

      context 'when comparison value is a proc returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, less_than_or_equal_to: -> (_record) { 'cat' })

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(-> (_record) { 'cat' })
        end
      end

      context 'when comparison value is a method returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, less_than_or_equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return('cat')

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(:comparison_value)
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, less_than_or_equal_to: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than or
equal to cat, but this could not be proved.
  After setting :attr to ‹"cau"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be less than or equal to cat" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with is_less_than' do
      context 'and validating with less_than' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, less_than: 'cat')

          expect(record).to validate_comparison_of(:attr).is_less_than('cat')
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :string, less_than: 'cat')

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_less_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value less than
cat, but this could not be proved.
  After setting :attr to ‹"cau"›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["must be less than cat"]
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :string,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value less than
cat, but this could not be proved.
  After setting :attr to ‹"cas"› -- which was read back as ‹"cat"› --
  the matcher expected the Example to be valid, but it was invalid
  instead, producing these validation errors:

  * attr: ["must be less than cat"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { less_than: 'cat' })
          end

          def configure_validation_matcher(matcher)
            matcher.is_less_than('cat')
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :string, less_than: 'cat')

          expect(record).to validate_comparison_of(:attr).is_less_than('cat')
        end
      end

      context 'when comparison value is a proc returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, less_than: -> (_record) { 'cat' })

          expect(record).to validate_comparison_of(:attr).is_less_than(-> (_record) { 'cat' })
        end
      end

      context 'when comparison value is a method returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, less_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return('cat')

          expect(record).to validate_comparison_of(:attr).is_less_than(:comparison_value)
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, less_than: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than
cat, but this could not be proved.
  After setting :attr to ‹"cau"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be less than cat" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with is_greater_than' do
      context 'and validating with greater_than' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, greater_than: 'cat')

          expect(record).to validate_comparison_of(:attr).is_greater_than('cat')
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :string, greater_than: 'cat')

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_greater_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value greater
than cat, but this could not be proved.
  After setting :attr to ‹"cau"›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :string,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :previous_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value greater than
cat, but this could not be proved.
  After setting :attr to ‹"cau"› -- which was read back as ‹"cat"› --
  the matcher expected the Example to be valid, but it was invalid
  instead, producing these validation errors:

  * attr: ["must be greater than cat"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { greater_than: 'cat' })
          end

          def configure_validation_matcher(matcher)
            matcher.is_greater_than('cat')
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :string, greater_than: 'cat')

          expect(record).to validate_comparison_of(:attr).is_greater_than('cat')
        end
      end

      context 'when comparison value is a proc returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, greater_than: -> (_record) { 'cat' })

          expect(record).to validate_comparison_of(:attr).is_greater_than(-> (_record) { 'cat' })
        end
      end

      context 'when comparison value is a method returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, greater_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return('cat')

          expect(record).to validate_comparison_of(:attr).is_greater_than(:comparison_value)
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, greater_than: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
cat, but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be greater than cat" on :attr. The record was
  indeed invalid, but it produced these validation errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with is_greater_than_or_equal_to' do
      context 'and validating with greater_than_or_equal_to' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, greater_than_or_equal_to: 'cat')

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to('cat')
        end

        it 'rejects when used in the negative' do
          record = build_record_validating_comparison(column_type: :string, greater_than_or_equal_to: 'cat')

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_greater_than_or_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value greater
than or equal to cat, but this could not be proved.
  After setting :attr to ‹"cau"›, the matcher expected the Example to be
  invalid, but it was valid instead.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :string,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :previous_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value greater than
or equal to cat, but this could not be proved.
  After setting :attr to ‹"cat"› -- which was read back as ‹"cas"› --
  the matcher expected the Example to be valid, but it was invalid
  instead, producing these validation errors:

  * attr: ["must be greater than or equal to cat"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { greater_than_or_equal_to: 'cat' })
          end

          def configure_validation_matcher(matcher)
            matcher.is_greater_than_or_equal_to('cat')
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :string, greater_than_or_equal_to: 'cat')

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to('cat')
        end
      end

      context 'when comparison value is a proc returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, greater_than_or_equal_to: -> (_record) { 'cat' })

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(-> (_record) { 'cat' })
        end
      end

      context 'when comparison value is a method returning an string' do
        it 'accepts' do
          record = build_record_validating_comparison(column_type: :string, greater_than_or_equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return('cat')

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(:comparison_value)
        end
      end

      context 'when the column is a date column' do
        it 'rejects and raise an error' do
          record = build_record_validating_comparison(column_type: :date, greater_than_or_equal_to: 'cat')

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to('cat')
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
or equal to cat, but this could not be proved.
  After setting :attr to ‹"cas"› -- which was read back as ‹nil› -- the
  matcher expected the Example to be invalid and to produce the
  validation error "must be greater than or equal to cat" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end
  end

  context 'when comparing with an date' do
    context 'qualified with is_other_than' do
      context 'and validating with other_than' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, other_than: date)

          expect(record).to validate_comparison_of(:attr).is_other_than(date)
        end

        it 'rejects when used in the negative' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, other_than: date)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_other_than(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value other
than 2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be invalid, but it
  was valid instead.

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :date,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :previous_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value other than
2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Sun,
  01 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be other than 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { other_than: Date.new(2023, 1, 1) })
          end

          def configure_validation_matcher(matcher)
            matcher.is_other_than(Date.new(2023, 1, 1))
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :date, other_than: date)

          expect(record).to validate_comparison_of(:attr).is_other_than(date)
        end
      end

      context 'when comparison value is a proc returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, other_than: -> (_record) { date })

          expect(record).to validate_comparison_of(:attr).is_other_than(-> (_record) { date })
        end
      end

      context 'when comparison value is a method returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, other_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(date)

          expect(record).to validate_comparison_of(:attr).is_other_than(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :integer, other_than: date)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_other_than(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value other than
2023-01-01, but this could not be proved.
  After setting :attr to ‹Sun, 01 Jan 2023› -- which was read back as
  ‹nil› -- the matcher expected the Example to be invalid and to produce
  the validation error "must be other than 2023-01-01" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with is_equal_to' do
      context 'and validating with is_equal_to' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, equal_to: date)

          expect(record).to validate_comparison_of(:attr).is_equal_to(date)
        end

        it 'rejects when used in the negative' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, equal_to: date)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_equal_to(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value equal to
2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be equal to 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :date,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value equal to
2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-01"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be equal to 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { equal_to: Date.new(2023, 1, 1) })
          end

          def configure_validation_matcher(matcher)
            matcher.is_equal_to(Date.new(2023, 1, 1))
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :date, equal_to: date)

          expect(record).to validate_comparison_of(:attr).is_equal_to(date)
        end
      end

      context 'when comparison value is a proc returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, equal_to: -> (_record) { date })

          expect(record).to validate_comparison_of(:attr).is_equal_to(-> (_record) { date })
        end
      end

      context 'when comparison value is a method returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(date)

          expect(record).to validate_comparison_of(:attr).is_equal_to(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :integer, equal_to: date)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_equal_to(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value equal to
2023-01-01, but this could not be proved.
  After setting :attr to ‹Mon, 02 Jan 2023› -- which was read back as
  ‹nil› -- the matcher expected the Example to be invalid and to produce
  the validation error "must be equal to 2023-01-01" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with less_than_or_equal_to' do
      context 'and validating with is_less_than_or_equal_to' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than_or_equal_to: date)

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(date)
        end

        it 'rejects when used in the negative' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than_or_equal_to: date)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_less_than_or_equal_to(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value less than
or equal to 2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be less than or equal to 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :date,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value_or_numeric_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value less than or
equal to 2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-01"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be less than or equal to 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { less_than_or_equal_to: Date.new(2023, 1, 1) })
          end

          def configure_validation_matcher(matcher)
            matcher.is_less_than_or_equal_to(Date.new(2023, 1, 1))
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :date, less_than_or_equal_to: date)

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(date)
        end
      end

      context 'when comparison value is a proc returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than_or_equal_to: -> (_record) { date })

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(-> (_record) { date })
        end
      end

      context 'when comparison value is a method returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than_or_equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(date)

          expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :integer, less_than_or_equal_to: date)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than_or_equal_to(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than or
equal to 2023-01-01, but this could not be proved.
  After setting :attr to ‹Mon, 02 Jan 2023› -- which was read back as
  ‹nil› -- the matcher expected the Example to be invalid and to produce
  the validation error "must be less than or equal to 2023-01-01" on
  :attr. The record was indeed invalid, but it produced these validation
  errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with less_than' do
      context 'and validating with is_less' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than: date)

          expect(record).to validate_comparison_of(:attr).is_less_than(date)
        end

        it 'rejects when used in the negative' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than: date)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_less_than(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value less than
2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be less than 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :date,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :next_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value less than
2023-01-01, but this could not be proved.
  After setting :attr to ‹"2022-12-31"› -- which was read back as ‹Sun,
  01 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be less than 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { less_than: Date.new(2023, 1, 1) })
          end

          def configure_validation_matcher(matcher)
            matcher.is_less_than(Date.new(2023, 1, 1))
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :date, less_than: date)

          expect(record).to validate_comparison_of(:attr).is_less_than(date)
        end
      end

      context 'when comparison value is a proc returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than: -> (_record) { date })

          expect(record).to validate_comparison_of(:attr).is_less_than(-> (_record) { date })
        end
      end

      context 'when comparison value is a method returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, less_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(date)

          expect(record).to validate_comparison_of(:attr).is_less_than(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :integer, less_than: date)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_less_than(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value less than
2023-01-01, but this could not be proved.
  After setting :attr to ‹Mon, 02 Jan 2023› -- which was read back as
  ‹nil› -- the matcher expected the Example to be invalid and to produce
  the validation error "must be less than 2023-01-01" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with greater_than' do
      context 'and validating with is_greater_than' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than: date)

          expect(record).to validate_comparison_of(:attr).is_greater_than(date)
        end

        it 'rejects when used in the negative' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than: date)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_greater_than(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value greater
than 2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be invalid, but it
  was valid instead.

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :date,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :previous_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value greater than
2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Sun,
  01 Jan 2023› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be greater than 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { greater_than: Date.new(2023, 1, 1) })
          end

          def configure_validation_matcher(matcher)
            matcher.is_greater_than(Date.new(2023, 1, 1))
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :date, greater_than: date)

          expect(record).to validate_comparison_of(:attr).is_greater_than(date)
        end
      end

      context 'when comparison value is a proc returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than: -> (_record) { date })

          expect(record).to validate_comparison_of(:attr).is_greater_than(-> (_record) { date })
        end
      end

      context 'when comparison value is a method returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(date)

          expect(record).to validate_comparison_of(:attr).is_greater_than(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :integer, greater_than: date)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
2023-01-01, but this could not be proved.
  After setting :attr to ‹Sun, 01 Jan 2023› -- which was read back as
  ‹nil› -- the matcher expected the Example to be invalid and to produce
  the validation error "must be greater than 2023-01-01" on :attr. The
  record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end

    context 'qualified with greater_than_or_equal_to' do
      context 'and validating with is_greater_than_or_equal_to' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than_or_equal_to: date)

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(date)
        end

        it 'rejects when used in the negative' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than_or_equal_to: date)

          assertion = lambda do
            expect(record).not_to validate_comparison_of(:attr).is_greater_than_or_equal_to(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a value greater
than or equal to 2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-02"› -- which was read back as ‹Mon,
  02 Jan 2023› -- the matcher expected the Example to be invalid, but it
  was valid instead.

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end

        it_supports(
          'ignoring_interference_by_writer',
          column_type: :date,
          tests: {
            reject_if_qualified_but_changing_value_interferes: {
              model_name: 'Example',
              attribute_name: :attr,
              changing_values_with: :previous_value,
              expected_message: <<-MESSAGE.strip,
Expected Example to validate that :attr looks like a value greater than
or equal to 2023-01-01, but this could not be proved.
  After setting :attr to ‹"2023-01-01"› -- which was read back as ‹Sat,
  31 Dec 2022› -- the matcher expected the Example to be valid, but it
  was invalid instead, producing these validation errors:

  * attr: ["must be greater than or equal to 2023-01-01"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
              MESSAGE
            },
          },
        ) do
          def validation_matcher_scenario_args
            super.deep_merge(validation_options: { greater_than_or_equal_to: Date.new(2023, 1, 1) })
          end

          def configure_validation_matcher(matcher)
            matcher.is_greater_than_or_equal_to(Date.new(2023, 1, 1))
          end
        end
      end

      context 'when the attribute is a virtual attribute in an ActiveRecord model' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison_of_virtual_attribute(column_type: :date, greater_than_or_equal_to: date)

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(date)
        end
      end

      context 'when comparison value is a proc returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than_or_equal_to: -> (_record) { date })

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(-> (_record) { date })
        end
      end

      context 'when comparison value is a method returning an Date' do
        it 'accepts' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :date, greater_than_or_equal_to: :comparison_value)
          allow(record).to receive(:comparison_value).and_return(date)

          expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(:comparison_value)
        end
      end

      context 'when the column is an integer column' do
        it 'rejects and raise an error' do
          date = Date.new(2023, 1, 1)
          record = build_record_validating_comparison(column_type: :integer, greater_than_or_equal_to: date)

          assertion = lambda do
            expect(record).to validate_comparison_of(:attr).is_greater_than_or_equal_to(date)
          end

          expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example to validate that :attr looks like a value greater than
or equal to 2023-01-01, but this could not be proved.
  After setting :attr to ‹Sat, 31 Dec 2022› -- which was read back as
  ‹nil› -- the matcher expected the Example to be invalid and to produce
  the validation error "must be greater than or equal to 2023-01-01" on
  :attr. The record was indeed invalid, but it produced these validation
  errors instead:

  * attr: ["can't be blank"]

  As indicated in the message above, :attr seems to be changing certain
  values as they are set, and this could have something to do with why
  this test is failing. If you've overridden the writer method for this
  attribute, then you may need to change it to make this test pass, or
  do something else entirely.
          MESSAGE
        end
      end
    end
  end

  context 'qualified with allow_nil' do
    context 'and validating with allow_nil' do
      it 'accepts' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, allow_nil: true)
        expect(record).to validate_comparison.is_greater_than(10).allow_nil
      end

      context 'and not validating with allow_nil' do
        it 'rejects since it tries to treat nil as a number' do
          record = build_record_validating_comparison(column_type: :integer, greater_than: 10)

          assertion = lambda do
            expect(record).to validate_comparison.is_greater_than(10).allow_nil
          end

          message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
10 and as long as it is not nil, but this could not be proved.
  After setting :attr to ‹nil›, the matcher expected the Example to be
  valid, but it was invalid instead, producing these validation errors:

  * attr: ["can't be blank"]
          MESSAGE

          expect(&assertion).to fail_with_message(message)
        end
      end
    end
  end

  context 'qualified with strict' do
    context 'and validating strictly' do
      it 'accepts' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, strict: true)

        expect(record).to validate_comparison.is_greater_than(10).strict
      end
    end

    context 'and not validating strictly' do
      it 'rejects since ActiveModel::StrictValidationFailed is never raised' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10)

        assertion = lambda do
          expect(record).to validate_comparison.is_greater_than(10).strict
        end

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
10, raising a validation exception on failure, but this could not be
proved.
  After setting :attr to ‹10›, the matcher expected the Example to be
  invalid and to raise a validation exception, but the record produced
  validation errors instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end
    end
  end

  context 'qualified with on' do
    context 'qualified with on and validating with on' do
      it 'accepts' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, on: :customizable)
        expect(record).to validate_comparison.is_greater_than(10).on(:customizable)
      end
    end

    context 'qualified with on but not validating with on' do
      it 'accepts since the validation never considers a context' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10)
        expect(record).to validate_comparison.is_greater_than(10).on(:customizable)
      end
    end

    context 'not qualified with on but validating with on' do
      it 'rejects since the validation never runs' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, on: :customizable)

        assertion = lambda do
          expect(record).to validate_comparison.is_greater_than(10)
        end

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
10, but this could not be proved.
  After setting :attr to ‹10›, the matcher expected the Example to be
  invalid, but it was valid instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end
    end

    context 'qualified with on but without another qualifier' do
      it 'rejects since the validation never runs' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, on: :customizable)

        assertion = lambda do
          expect(record).to validate_comparison.is_greater_than(10)
        end

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
10, but this could not be proved.
  After setting :attr to ‹10›, the matcher expected the Example to be
  invalid, but it was valid instead.
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end
    end
  end

  context 'qualified with with_message' do
    context 'and validating with the same message' do
      it 'accepts' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, message: 'custom')
        expect(record).to validate_comparison.is_greater_than(10).with_message(/custom/)
      end
    end

    context 'and validating with a different message' do
      it 'rejects with the correct failure message' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10, message: 'custom')

        assertion = lambda do
          expect(record).to validate_comparison.is_greater_than(10).with_message(/wrong/)
        end

        message = <<-MESSAGE
Expected Example to validate that :attr looks like a value greater than
10, producing a custom validation error on failure, but this could not
be proved.
  After setting :attr to ‹10›, the matcher expected the Example to be
  invalid and to produce a validation error matching ‹/wrong/› on :attr.
  The record was indeed invalid, but it produced these validation errors
  instead:

  * attr: ["custom"]
        MESSAGE

        expect(&assertion).to fail_with_message(message)
      end
    end

    context 'and no message is provided' do
      it 'ignores the qualifier' do
        record = build_record_validating_comparison(column_type: :integer, greater_than: 10)
        expect(record).to validate_comparison.is_greater_than(10).with_message(nil)
      end
    end
  end

  context 'when no comparison qualified is provided' do
    it 'raises error' do
      record = define_model_validating_nothing

      assertion = lambda do
        expect(record).to validate_comparison
      end

      expect(&assertion).to raise_error(ArgumentError, "matcher isn't qualified with any comparison matcher")
    end
  end

  def build_record_validating_comparison(options = {})
    define_model_validating_comparison_of_attribute(options).new
  end

  def build_record_validating_comparison_of_virtual_attribute(options = {})
    define_model_validating_comparison_of_virtual_attribute(options).new
  end

  def define_model_validating_comparison_of_virtual_attribute(options = {})
    attribute_name = options.delete(:attribute_name) { self.attribute_name }
    column_type = options.delete(:column_type) { :string }

    define_model 'Example' do |model|
      model.send(:attribute, attribute_name, column_type)
      model.validates_comparison_of(attribute_name, options)
    end
  end

  def define_model_validating_comparison_of_attribute(options = {})
    attribute_name = options.delete(:attribute_name) { self.attribute_name }
    column_type = options.delete(:column_type) { :string }

    define_model 'Example', attribute_name => { type: column_type } do |model|
      model.validates_comparison_of(attribute_name, options)
    end
  end

  def define_model_validating_nothing
    define_model('Example', attribute_name => :string)
  end

  def validate_comparison
    validate_comparison_of(attribute_name)
  end

  def attribute_name
    :attr
  end

  def validation_matcher_scenario_args
    super.deep_merge(
      matcher_name: :validate_comparison_of,
      model_creator: :active_record,
    )
  end
end
