diff --git a/core/float.rbs b/core/float.rbs index d5d00a50a..dd4c1a7fd 100644 --- a/core/float.rbs +++ b/core/float.rbs @@ -1222,8 +1222,6 @@ Float::EPSILON: Float # Float::INFINITY: Float -Float::Infinity: Float - # # The number of base digits for the `double` data type. # @@ -1292,25 +1290,3 @@ Float::NAN: Float # decimal. # Float::RADIX: Integer - -# Deprecated, do not use. -# -# Represents the rounding mode for floating point addition at the start time. -# -# Usually defaults to 1, rounding to the nearest number. -# -# Other modes include: -# -# -1 -# : Indeterminable -# 0 -# : Rounding towards zero -# 1 -# : Rounding to the nearest number -# 2 -# : Rounding towards positive infinity -# 3 -# : Rounding towards negative infinity -# -# -Float::ROUNDS: Integer diff --git a/test/stdlib/Float_test.rb b/test/stdlib/Float_test.rb index 4981ac9e2..f6873779e 100644 --- a/test/stdlib/Float_test.rb +++ b/test/stdlib/Float_test.rb @@ -1,5 +1,59 @@ require_relative "test_helper" +class FloatSingletonTest < Test::Unit::TestCase + include TestHelper + + testing 'singleton(::Float)' + + def test_DIG + assert_const_type 'Integer', 'Float::DIG' + end + + def test_EPSILON + assert_const_type 'Float', 'Float::EPSILON' + end + + def test_INFINITY + assert_const_type 'Float', 'Float::INFINITY' + end + + def test_MANT_DIG + assert_const_type 'Integer', 'Float::MANT_DIG' + end + + def test_MAX + assert_const_type 'Float', 'Float::MAX' + end + + def test_MAX_10_EXP + assert_const_type 'Integer', 'Float::MAX_10_EXP' + end + + def test_MAX_EXP + assert_const_type 'Integer', 'Float::MAX_EXP' + end + + def test_MIN + assert_const_type 'Float', 'Float::MIN' + end + + def test_MIN_10_EXP + assert_const_type 'Integer', 'Float::MIN_10_EXP' + end + + def test_MIN_EXP + assert_const_type 'Integer', 'Float::MIN_EXP' + end + + def test_NAN + assert_const_type 'Float', 'Float::NAN' + end + + def test_RADIX + assert_const_type 'Integer', 'Float::RADIX' + end +end + class FloatTest < StdlibTest target Float diff --git a/test/stdlib/constant_drift_test.rb b/test/stdlib/constant_drift_test.rb new file mode 100644 index 000000000..4fb99075a --- /dev/null +++ b/test/stdlib/constant_drift_test.rb @@ -0,0 +1,77 @@ +require_relative "test_helper" + +# Guards against "constant drift" between the RBS core signatures and the actual +# runtime, in both directions: +# +# * a constant declared in RBS but no longer defined by Ruby (e.g. +# `Float::ROUNDS`, removed in Ruby 3.0), and +# * a constant defined by Ruby but missing from RBS. +# +# Only platform- and build-invariant core classes are hard-gated here. Classes +# whose constant set legitimately varies by OS or build options (`Process`, +# `Socket`, `Errno`, `Signal`, `File::Constants`, `RbConfig`, `Etc`, ...) are +# intentionally excluded: their RBS declarations cannot match any single +# platform's runtime. `Object`/`BasicObject`/`Kernel` are excluded too, since +# every top-level class shows up under `Object.constants`. +class ConstantDriftTest < Test::Unit::TestCase + # Platform/build-invariant core classes and modules whose declared constant + # set must match the runtime exactly. + HARD_GATE = [ + Float, Integer, Numeric, Rational, Complex, + Math, Comparable, + String, Symbol, + Array, Hash, Range, Struct, + NilClass, TrueClass, FalseClass + ].freeze + + # Known, intentional exceptions keyed by "::Name" => [:CONST, ...]. Use this + # for build- or platform-conditional constants (and `private_constant`s) that + # are legitimately undeclared, so the gate stays green across CI platforms + # without being weakened elsewhere. + SKIP = { + # Defined only when Ruby is built with GMP (USE_GMP): present on the Linux + # CI build, absent on e.g. macOS. + "::Integer" => [:GMP_VERSION] + }.freeze + + def env + StdlibTest::DEFAULT_ENV + end + + # Constants declared directly under `type_name` in the loaded RBS environment + # (plain constants plus nested classes/modules and their aliases), matching + # what `Module#constants(false)` returns at runtime. + def rbs_constants(type_name) + prefix = "#{type_name}::" + names = [] + [env.constant_decls, env.class_decls, env.class_alias_decls].each do |store| + store.each_key do |tn| + s = tn.to_s + next unless s.start_with?(prefix) + + rest = s.delete_prefix(prefix) + names << rest.to_sym unless rest.include?("::") + end + end + names.uniq.sort + end + + HARD_GATE.each do |klass| + define_method(:"test_no_constant_drift_#{klass.name.gsub("::", "_")}") do + type_name = "::#{klass.name}" + skip = SKIP[type_name] || [] + runtime = (klass.constants(false) - skip).sort + declared = (rbs_constants(type_name) - skip).sort + + stale = declared - runtime + missing = runtime - declared + + assert_empty stale, + "RBS declares #{type_name} constants that no longer exist at runtime: #{stale.inspect}. " \ + "Remove them from the signature (or add to ConstantDriftTest::SKIP if intentional)." + assert_empty missing, + "Runtime defines #{type_name} constants missing from RBS: #{missing.inspect}. " \ + "Add them to the signature (or add to ConstantDriftTest::SKIP if intentional)." + end + end +end