diff --git a/lib/rbs/test.rb b/lib/rbs/test.rb index e24e1e412..a69423b45 100644 --- a/lib/rbs/test.rb +++ b/lib/rbs/test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "securerandom" +require "rbs/test/guaranteed" require "rbs/test/observer" require "rbs/test/spy" require "rbs/test/errors" @@ -23,6 +24,8 @@ module Test METHODS = Kernel.instance_method(:methods) class ArgumentsReturn + include Guaranteed::Inspect + attr_reader :arguments attr_reader :exit_value attr_reader :exit_type diff --git a/lib/rbs/test/guaranteed.rb b/lib/rbs/test/guaranteed.rb new file mode 100644 index 000000000..4a1e34e6a --- /dev/null +++ b/lib/rbs/test/guaranteed.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module RBS + module Test + module Guaranteed + module Inspect + EQUAL = ::BasicObject.instance_method(:equal?) + INSPECT = ::Kernel.instance_method(:inspect) + private_constant :EQUAL, :INSPECT + + module_function def guaranteed_inspect(obj) + obj.inspect + rescue NoMethodError => err + raise unless err.name == :inspect && EQUAL.bind_call(obj, err.receiver) + INSPECT.bind_call(obj) + end + + def inspect + string = "<#{self.class.name}:" + + instance_variables.each_with_index do |variable, index| + string.concat ', ' unless index.zero? + string.concat "#{variable}: #{guaranteed_inspect(variable)}" + end + + string.concat '>' + end + end + end + end +end diff --git a/lib/rbs/test/type_check.rb b/lib/rbs/test/type_check.rb index e369f5f82..ac0edbc35 100644 --- a/lib/rbs/test/type_check.rb +++ b/lib/rbs/test/type_check.rb @@ -136,7 +136,7 @@ def zip_keyword_args(hash, fun) end def keyword?(value) - value.is_a?(Hash) && value.keys.all? {|key| key.is_a?(Symbol) } + Hash === value && value.each_key.all?(Symbol) end def zip_args(args, fun, &block) @@ -310,7 +310,7 @@ def value(val, type) when Types::Variable true when Types::Literal - val == type.literal + type.literal == val when Types::Union type.types.any? {|type| value(val, type) } when Types::Intersection diff --git a/test/stdlib/Pathname_test.rb b/test/stdlib/Pathname_test.rb index f11449fd8..e2433508a 100644 --- a/test/stdlib/Pathname_test.rb +++ b/test/stdlib/Pathname_test.rb @@ -606,8 +606,9 @@ def test_relative_path_from Pathname('.'), :relative_path_from, Pathname('.') assert_send_type '(String) -> Pathname', Pathname('.'), :relative_path_from, '.' - assert_send_type '(ToStr) -> Pathname', - Pathname('.'), :relative_path_from, ToStr.new('.') + + assert_send_type '(_ToStr) -> Pathname', + Pathname('.'), :relative_path_from, ToStr.new('.').__with_object_methods(:is_a?) end def test_rename diff --git a/test/stdlib/ThreadQueue_test.rb b/test/stdlib/ThreadQueue_test.rb index 389c4569e..c8769bc83 100644 --- a/test/stdlib/ThreadQueue_test.rb +++ b/test/stdlib/ThreadQueue_test.rb @@ -63,7 +63,7 @@ def test_pop q.pop(true) q.pop(false) q.pop(timeout: 0.2) - q.pop(timeout: ToF.new(0.1)) + q.pop(timeout: ToF.new(0.1).__with_object_methods(:==)) end def test_push diff --git a/test/stdlib/ThreadSizedQueue_test.rb b/test/stdlib/ThreadSizedQueue_test.rb index 7a83cd8c7..a42633f4d 100644 --- a/test/stdlib/ThreadSizedQueue_test.rb +++ b/test/stdlib/ThreadSizedQueue_test.rb @@ -37,6 +37,6 @@ def test_push q.push(:a, true) q.push(:a, false) q.push(:a, timeout: 0.1) - q.push(:a, timeout: ToF.new(0.1)) + q.push(:a, timeout: ToF.new(0.1).__with_object_methods(:==)) end end diff --git a/test/stdlib/Warning_test.rb b/test/stdlib/Warning_test.rb index e7d89ebd4..e8b612bc2 100644 --- a/test/stdlib/Warning_test.rb +++ b/test/stdlib/Warning_test.rb @@ -16,7 +16,7 @@ def test_aref refute_send_type "(Symbol) -> bool", Warning, :[], :unknown_category - refute_send_type "(ToSym) -> bool", + refute_send_type "(_ToSym) -> bool", Warning, :[], ToSym.new(WARNING_CATEGORIES.first) end @@ -29,7 +29,7 @@ def test_aset refute_send_type "(Symbol, Rational) -> Rational", Warning, :[]=, :unknown_category, 1r - refute_send_type "(ToSym, Rational) -> Rational", + refute_send_type "(_ToSym, Rational) -> Rational", Warning, :[]=, ToSym.new(WARNING_CATEGORIES.first), 1r end end @@ -66,7 +66,7 @@ def test_warn assert_send_type "(::String, category: nil) -> nil", Warning, :warn, 'message', category: nil - refute_send_type "(::String, category: ToSym) -> nil", + refute_send_type "(::String, category: _ToSym) -> nil", Warning, :warn, 'message', category: ToSym.new(WARNING_CATEGORIES.first) refute_send_type "(::String, category: ::Symbol) -> nil", diff --git a/test/stdlib/json/JSON_test.rb b/test/stdlib/json/JSON_test.rb index b4a3a00d5..66504f8d4 100644 --- a/test/stdlib/json/JSON_test.rb +++ b/test/stdlib/json/JSON_test.rb @@ -1,6 +1,26 @@ require_relative "../test_helper" require "json" +class JsonToStr + def initialize(value = "") + @value = value + end + + def to_str + @value + end +end + +class JsonToS + def initialize(value = "") + @value = value + end + + def to_s + @value + end +end + class JSONSingletonTest < Test::Unit::TestCase include TypeAssertions @@ -9,26 +29,26 @@ class JSONSingletonTest < Test::Unit::TestCase def test_aref assert_send_type "(String) -> 42", JSON, :[], "42" - assert_send_type "(ToStr) -> 42", JSON, :[], ToStr.new("42") + assert_send_type "(_ToStr) -> 42", JSON, :[], JsonToStr.new("42") assert_send_type "(ToJson) -> String", JSON, :[], ToJson.new assert_send_type "(ToJson, indent: String) -> String", JSON, :[], ToJson.new, { indent: "\t" } end def test_create_id - JSON.create_id = ToS.new("json_class") - assert_send_type "() -> ToS", JSON, :create_id + JSON.create_id = JsonToS.new("json_class") + assert_send_type "() -> _ToS", JSON, :create_id JSON.create_id = "json_class" assert_send_type "() -> String", JSON, :create_id end def test_create_id_eq - assert_send_type "(ToS) -> ToS", JSON, :create_id=, ToS.new("json_class") + assert_send_type "(_ToS) -> _ToS", JSON, :create_id=, JsonToS.new("json_class") assert_send_type "(String) -> String", JSON, :create_id=, "json_class" end def test_deep_const_get assert_send_type "(String) -> String", JSON, :deep_const_get, "File::SEPARATOR" - assert_send_type "(ToS) -> String", JSON, :deep_const_get, ToS.new("File::SEPARATOR") + assert_send_type "(_ToS) -> String", JSON, :deep_const_get, JsonToS.new("File::SEPARATOR") end def test_dump @@ -76,12 +96,12 @@ def test_generator= def test_iconv assert_send_type "(Encoding, Encoding, String) -> String", JSON, :iconv, Encoding::UTF_8, Encoding::UTF_16, "".encode(Encoding::UTF_16) assert_send_type "(String, String, String) -> String", JSON, :iconv, 'UTF-8', 'UTF-16', "".encode(Encoding::UTF_16) - assert_send_type "(ToStr, ToStr, String) -> String", JSON, :iconv, ToStr.new('UTF-8'), ToStr.new('UTF-16'), "".encode(Encoding::UTF_16) + assert_send_type "(_ToStr, _ToStr, String) -> String", JSON, :iconv, JsonToStr.new('UTF-8'), JsonToStr.new('UTF-16'), "".encode(Encoding::UTF_16) end def test_load assert_send_type "(String) -> 42", JSON, :load, "42" - assert_send_type "(ToStr) -> 42", JSON, :load, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", JSON, :load, JsonToStr.new("42") assert_send_type "(JsonToReadableIO) -> 42", JSON, :load, JsonToReadableIO.new assert_send_type "(JsonRead) -> 42", JSON, :load, JsonRead.new assert_send_type "(String, Proc) -> 42", JSON, :load, "42", proc { } @@ -98,13 +118,13 @@ def test_load_default_options_eq def test_parse assert_send_type "(String) -> 42", JSON, :parse, "42" - assert_send_type "(ToStr) -> 42", JSON, :parse, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", JSON, :parse, JsonToStr.new("42") assert_send_type "(String, Hash[untyped, untyped]) -> 42", JSON, :parse, "42", { allow_nan: true } end def test_parse! assert_send_type "(String) -> 42", JSON, :parse!, "42" - assert_send_type "(ToStr) -> 42", JSON, :parse!, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", JSON, :parse!, JsonToStr.new("42") assert_send_type "(String, Hash[untyped, untyped]) -> 42", JSON, :parse!, "42", { allow_nan: true } end @@ -132,7 +152,7 @@ def test_recurse_proc def test_restore assert_send_type "(String) -> 42", JSON, :restore, "42" - assert_send_type "(ToStr) -> 42", JSON, :restore, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", JSON, :restore, JsonToStr.new("42") assert_send_type "(JsonToReadableIO) -> 42", JSON, :restore, JsonToReadableIO.new assert_send_type "(JsonRead) -> 42", JSON, :restore, JsonRead.new assert_send_type "(String, Proc) -> 42", JSON, :restore, "42", proc { } @@ -192,7 +212,7 @@ def test_generate def test_load assert_send_type "(String) -> 42", MyJSON.new, :load, "42" - assert_send_type "(ToStr) -> 42", MyJSON.new, :load, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", MyJSON.new, :load, JsonToStr.new("42") assert_send_type "(JsonToReadableIO) -> 42", MyJSON.new, :load, JsonToReadableIO.new assert_send_type "(JsonRead) -> 42", MyJSON.new, :load, JsonRead.new assert_send_type "(String, Proc) -> 42", MyJSON.new, :load, "42", proc { } @@ -201,13 +221,13 @@ def test_load def test_parse assert_send_type "(String) -> 42", MyJSON.new, :parse, "42" - assert_send_type "(ToStr) -> 42", MyJSON.new, :parse, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", MyJSON.new, :parse, JsonToStr.new("42") assert_send_type "(String, Hash[untyped, untyped]) -> 42", MyJSON.new, :parse, "42", { allow_nan: true } end def test_parse! assert_send_type "(String) -> 42", MyJSON.new, :parse!, "42" - assert_send_type "(ToStr) -> 42", MyJSON.new, :parse!, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", MyJSON.new, :parse!, JsonToStr.new("42") assert_send_type "(String, Hash[untyped, untyped]) -> 42", MyJSON.new, :parse!, "42", { allow_nan: true } end @@ -227,7 +247,7 @@ def test_recurse_proc def test_restore assert_send_type "(String) -> 42", MyJSON.new, :restore, "42" - assert_send_type "(ToStr) -> 42", MyJSON.new, :restore, ToStr.new("42") + assert_send_type "(_ToStr) -> 42", MyJSON.new, :restore, JsonToStr.new("42") assert_send_type "(JsonToReadableIO) -> 42", MyJSON.new, :restore, JsonToReadableIO.new assert_send_type "(JsonRead) -> 42", MyJSON.new, :restore, JsonRead.new assert_send_type "(String, Proc) -> 42", MyJSON.new, :restore, "42", proc { } diff --git a/test/stdlib/rubygems/GemVersion_test.rb b/test/stdlib/rubygems/GemVersion_test.rb index 5f8b9abb1..1db502253 100644 --- a/test/stdlib/rubygems/GemVersion_test.rb +++ b/test/stdlib/rubygems/GemVersion_test.rb @@ -8,15 +8,15 @@ class GemVersionSingletonTest < Test::Unit::TestCase def test_correct? assert_send_type "(String) -> bool", Gem::Version, :correct?, "1.2.3" - assert_send_type "(ToS) -> bool", - Gem::Version, :correct?, ToS.new + assert_send_type "(_ToS) -> bool", + Gem::Version, :correct?, ToS.new.__with_object_methods(:respond_to?, :nil?) end def test_create assert_send_type "(String) -> Gem::Version", Gem::Version, :create, "1.2.3" - assert_send_type "(ToS) -> Gem::Version", - Gem::Version, :create, ToS.new("1.2.3") + assert_send_type "(_ToS) -> Gem::Version", + Gem::Version, :create, ToS.new("1.2.3").__with_object_methods(:respond_to?, :hash, :nil?, :is_a?) assert_send_type "(Gem::Version) -> Gem::Version", Gem::Version, :create, Gem::Version.new("1.2.3") end @@ -24,8 +24,8 @@ def test_create def test_new assert_send_type "(String) -> Gem::Version", Gem::Version, :new, "1.2.3" - assert_send_type "(ToS) -> Gem::Version", - Gem::Version, :new, ToS.new("1.2.3") + assert_send_type "(_ToS) -> Gem::Version", + Gem::Version, :new, ToS.new("1.2.3").__with_object_methods(:respond_to?, :hash, :nil?, :is_a?) end end diff --git a/test/stdlib/test_helper.rb b/test/stdlib/test_helper.rb index 2224d8ae5..0851d5fbe 100644 --- a/test/stdlib/test_helper.rb +++ b/test/stdlib/test_helper.rb @@ -525,7 +525,24 @@ def assert_type(type, value) end end -class ToIO +class BlankSlate < BasicObject + instance_methods.each do |im| + next if %i[__send__ __id__].include? im + undef_method im + end + + def __with_object_methods(*methods) + methods.each do |method| + singleton_class = ::Object.instance_method(:singleton_class).bind_call(self) + singleton_class.instance_eval do + define_method method, ::Object.instance_method(method) + end + end + self + end +end + +class ToIO < BlankSlate def initialize(io = $stdout) @io = io end @@ -535,7 +552,7 @@ def to_io end end -class ToI +class ToI < BlankSlate def initialize(value = 3) @value = value end @@ -545,7 +562,7 @@ def to_i end end -class ToInt +class ToInt < BlankSlate def initialize(value = 3) @value = value end @@ -555,7 +572,7 @@ def to_int end end -class ToF +class ToF < BlankSlate def initialize(value = 0.1) @value = value end @@ -565,7 +582,7 @@ def to_f end end -class ToStr +class ToStr < BlankSlate def initialize(value = "") @value = value end @@ -575,7 +592,7 @@ def to_str end end -class ToS +class ToS < BlankSlate def initialize(value = "") @value = value end @@ -585,8 +602,7 @@ def to_s end end - -class ToSym +class ToSym < BlankSlate def initialize(value = :&) @value = value end @@ -596,7 +612,7 @@ def to_sym end end -class ToA +class ToA < BlankSlate def initialize(*args) @args = args end @@ -606,7 +622,7 @@ def to_a end end -class ToArray +class ToArray < BlankSlate def initialize(*args) @args = args end @@ -616,7 +632,7 @@ def to_ary end end -class ToHash +class ToHash < BlankSlate def initialize(hash = { 'hello' => 'world' }) @hash = hash end @@ -626,7 +642,7 @@ def to_hash end end -class ToPath +class ToPath < BlankSlate def initialize(value = "") @value = value end @@ -636,7 +652,7 @@ def to_path end end -class Each +class Each < BlankSlate def initialize(*args) @args = args end @@ -661,7 +677,7 @@ def write(*vals) class ToJson end -class Rand +class Rand < BlankSlate def rand(max) max - 1 end @@ -690,19 +706,19 @@ def to_io end end -class Enum +class Enum < BlankSlate def initialize(*args) @args = args end - include Enumerable + include ::Enumerable def each(&block) @args.each(&block) end end -class ArefFromStringToString +class ArefFromStringToString < BlankSlate def [](str) "!" end