lib/rspec/sorbet/instance_doubles.rb in rspec-sorbet-1.0.0 vs lib/rspec/sorbet/instance_doubles.rb in rspec-sorbet-1.1.0
- old
+ new
@@ -3,15 +3,10 @@
require 'sorbet-runtime'
module RSpec
module Sorbet
module InstanceDoubles
- WHITELISTED_ERROR_MESSAGES = [
- 'RSpec::Mocks::InstanceVerifyingDouble',
- 'InstanceDouble'
- ].freeze
-
def allow_instance_doubles!
T::Configuration.inline_type_error_handler = proc do |error|
inline_type_error_handler(error)
end
@@ -20,21 +15,76 @@
end
end
private
+ INLINE_INSTANCE_DOUBLE_REGEX =
+ /T.let: Expected type (T.any\()?(?<expected_classes>[a-zA-Z:: ,]*)(\))?, got type (.*) with value #<InstanceDouble\((?<doubled_module>[a-zA-Z:: ,]*)\)/.freeze
+
def inline_type_error_handler(error)
- raise error unless error.is_a?(TypeError) && message_is_whitelisted?(error.message)
+ case error
+ when TypeError
+ message = error.message
+ return if instance_double_message_with_ellipsis?(message) || typed_array_message?(message)
+
+ _, expected_types_string, doubled_module_string = (message.match(INLINE_INSTANCE_DOUBLE_REGEX) || [])[0..2]
+ raise error unless expected_types_string && doubled_module_string
+
+ expected_types = expected_types_string.split(',').map do |expected_type_string|
+ Object.const_get(expected_type_string.strip)
+ end
+ doubled_module = Object.const_get(doubled_module_string)
+
+ valid = expected_types.any? do |expected_type|
+ doubled_module.ancestors.include?(expected_type)
+ end
+
+ raise error unless valid
+ else
+ raise error
+ end
end
- def call_validation_error_handler(_signature, opts)
- raise TypeError, opts[:pretty_message] unless message_is_whitelisted?(opts[:message])
+ INSTANCE_VERIFYING_DOUBLE_OR_INSTANCE_DOUBLE =
+ /(RSpec::Mocks::InstanceVerifyingDouble|InstanceDouble)/.freeze
+
+ def instance_double_message_with_ellipsis?(message)
+ message.include?('...') && message.match?(INSTANCE_VERIFYING_DOUBLE_OR_INSTANCE_DOUBLE)
end
- def message_is_whitelisted?(message)
- WHITELISTED_ERROR_MESSAGES.any? do |whitelisted_message|
- message.include?(whitelisted_message)
+ TYPED_ARRAY_MESSAGE = /got T::Array/.freeze
+
+ def typed_array_message?(message)
+ message.match?(TYPED_ARRAY_MESSAGE)
+ end
+
+ def call_validation_error_handler(_signature, opts)
+ should_raise = true
+
+ if opts[:pretty_message].match?(INSTANCE_VERIFYING_DOUBLE_OR_INSTANCE_DOUBLE)
+ typing = opts[:type]
+ value = opts[:value].is_a?(Array) ? opts[:value].first : opts[:value]
+ target = value.instance_variable_get(:@doubled_module).target
+
+ case typing
+ when T::Types::TypedArray
+ typing = typing.type
+ end
+
+ case typing
+ when T::Types::Simple
+ should_raise = !target.ancestors.include?(typing.raw_type)
+ when T::Types::Union
+ valid = typing.types.map(&:raw_type).any? do |type|
+ target.ancestors.include?(type)
+ end
+ should_raise = !valid
+ else
+ should_raise = !target.ancestors.include?(typing)
+ end
end
+
+ raise TypeError, opts[:pretty_message] if should_raise
end
end
end
end