# frozen_string_literal: true require "cases/helper" require "models/numeric_data" class NumericalityValidationTest < ActiveRecord::TestCase def setup @model_class = NumericData.dup end attr_reader :model_class def test_column_with_precision model_class.validates_numericality_of( :unscaled_bank_balance, equal_to: 10_000_000.12 ) subject = model_class.new(unscaled_bank_balance: 10_000_000.121) assert_predicate subject, :valid? end def test_column_with_precision_higher_than_double_fig model_class.validates_numericality_of( :decimal_number_big_precision, equal_to: 10_000_000.3 ) subject = model_class.new(decimal_number_big_precision: 10_000_000.3) assert_predicate subject, :valid? end def test_column_with_scale model_class.validates_numericality_of( :bank_balance, greater_than: 10 ) subject = model_class.new(bank_balance: 10.001) assert_not_predicate subject, :valid? end def test_no_column_precision model_class.validates_numericality_of( :decimal_number, equal_to: 1_000_000_000.123454 ) subject = model_class.new(decimal_number: 1_000_000_000.1234545) assert_predicate subject, :valid? end def test_virtual_attribute model_class.attribute(:virtual_decimal_number, :decimal) model_class.validates_numericality_of( :virtual_decimal_number, equal_to: 1_000_000_000.123454 ) subject = model_class.new(virtual_decimal_number: 1_000_000_000.1234545) assert_predicate subject, :valid? end def test_on_abstract_class abstract_class = Class.new(ActiveRecord::Base) do self.abstract_class = true validates(:bank_balance, numericality: { equal_to: 10_000_000.12 }) end klass = Class.new(abstract_class) do def self.table_name "numeric_data" end def self.name "MyClass" end end subject = klass.new(bank_balance: 10_000_000.12) assert_predicate(subject, :valid?) end def test_virtual_attribute_without_precision model_class.attribute(:virtual_decimal_number, :decimal) model_class.validates_numericality_of( :virtual_decimal_number, equal_to: BigDecimal("65.6") ) subject = model_class.new(virtual_decimal_number: 65.6) assert_predicate subject, :valid? end def test_virtual_attribute_with_precision_round_down model_class.attribute(:virtual_decimal_number, :decimal, precision: 5) model_class.validates_numericality_of( :virtual_decimal_number, equal_to: 123.45 ) subject = model_class.new(virtual_decimal_number: 123.454) assert_predicate subject, :valid? end def test_virtual_attribute_with_precision_round_half_even model_class.attribute(:virtual_decimal_number, :decimal, precision: 5) model_class.validates_numericality_of( :virtual_decimal_number, equal_to: 123.45 ) subject = model_class.new(virtual_decimal_number: 123.455) if 123.455.to_d(5) == BigDecimal("123.46") # BigDecimal's to_d behavior changed in BigDecimal 3.0.1, see https://github.com/ruby/bigdecimal/issues/70 # TODO: replace this with a check against BigDecimal::VERSION, currently # we just check the behaviour because both versions of BigDecimal report "3.0.0" assert_not_predicate subject, :valid? else assert_predicate subject, :valid? end end def test_virtual_attribute_with_precision_round_up model_class.attribute(:virtual_decimal_number, :decimal, precision: 5) model_class.validates_numericality_of( :virtual_decimal_number, equal_to: 123.45 ) subject = model_class.new(virtual_decimal_number: 123.456) assert_not_predicate subject, :valid? end def test_virtual_attribute_with_scale model_class.attribute(:virtual_decimal_number, :decimal, scale: 2) model_class.validates_numericality_of( :virtual_decimal_number, greater_than: 1 ) subject = model_class.new(virtual_decimal_number: 1.001) assert_not_predicate subject, :valid? end def test_virtual_attribute_with_precision_and_scale model_class.attribute(:virtual_decimal_number, :decimal, precision: 4, scale: 2) model_class.validates_numericality_of( :virtual_decimal_number, less_than_or_equal_to: 99.99 ) ["99.994", 99.994, BigDecimal("99.994")].each do |raw_value| subject = model_class.new(virtual_decimal_number: raw_value) assert_equal BigDecimal("99.99"), subject.virtual_decimal_number puts "subject = #{subject.attributes}" assert_predicate subject, :valid? end ["99.999", 99.999, BigDecimal("99.999")].each do |raw_value| subject = model_class.new(virtual_decimal_number: raw_value) assert_equal BigDecimal("100.00"), subject.virtual_decimal_number assert_not_predicate subject, :valid? end end def test_aliased_attribute model_class.validates_numericality_of(:new_bank_balance, greater_or_equal_than: 0) subject = model_class.new(new_bank_balance: "abcd") assert_not_predicate subject, :valid? end def test_allow_nil_works_for_casted_value model_class.validates_numericality_of(:bank_balance, greater_than: 0, allow_nil: true) subject = model_class.new(bank_balance: "") assert_predicate subject, :valid? end end