Module: RBS::UnitTest::TypeAssertions
- Defined in:
- sig/unit_test/type_assertions.rbs,
lib/rbs/unit_test/type_assertions.rb
Overview
TypeAssertions provides assertions to test RBS type definitions in unit test
class FooInstanceTest < Test::Unit::TestCase
include RBS::UnitTest::TypeAssertions
testing "::Foo"
def test_foo
assert_send_type(
"(String) -> Integer",
Foo.new, :foo, "hello"
)
end
end
The module provides four assertions:
assert_send_typeto confirm if a method call has the expected method typerefute_send_typeto confirm if a method call doesn't have the method typeassert_const_typeto confirm if a constant has an expected typeassert_typeto confirm a Ruby value has a RBS type
See .testing and .library methods to set up RBS type testing.
Defined Under Namespace
Modules: ClassMethods, _BaseAssertions
Class Method Summary collapse
Instance Method Summary collapse
-
#allow_non_simple_method_type { ... } ⇒ void
Allow non simple-type method types given to
assert_send_typeandrefute_send_type. - #allows_error(*errors) { ... } ⇒ void
-
#assert_const_type(type, constant_name) ⇒ void
Asserts if the constant
constant_namehasconstant_type, and the RBS definition has compatible type. -
#assert_send_type ⇒ void
Calls a method
method_nameand validates if it's compatible with RBS type definition. -
#assert_send_type_error ⇒ void
Calls a method
method_name, validates if it's compatible with RBS type definition, and ensures it raises theexceptionclass. -
#assert_type(type, value) ⇒ void
Asserts if given
valuehas a type ofvalue_type. -
#assert_visibility(visibility, method) ⇒ void
Asserts if RBS definition declares given
method_namewithvisibility. -
#break_from_block(value = nil) ⇒ void
Break from
assert_send_typeorrefute_send_type. - #builder ⇒ DefinitionBuilder
-
#class_class ⇒ Class
The singleton class object that is associated to the
classtype of the testing type. - #env ⇒ Environment
-
#instance_class ⇒ Class
The class object that is associated to the
instancetype of the testing type. - #method_defs(method) ⇒ Array[Definition::Method::TypeDef]
- #method_types(method) ⇒ Array[MethodType]
- #pass(message = nil) ⇒ void
-
#refute_send_type ⇒ void
Calls a method
method_nameand validates if it's not compatible with RBS type definition. - #send_setup(method_type, receiver, method, args, proc) {|mt, last_trace, result, exception| ... } ⇒ void
- #target ⇒ [target_type, Definition]
- #targets ⇒ Array[[target_type, Definition]]
- #testing(type_or_string) ⇒ void
- #validate_simple_method_type(type) ⇒ void
Class Method Details
.included(base) ⇒ void
This method returns an undefined value.
57 58 59 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 57 def self.included(base) base.extend ClassMethods end |
Instance Method Details
#allow_non_simple_method_type { ... } ⇒ void
This method returns an undefined value.
Allow non simple-type method types given to assert_send_type and refute_send_type
allow_non_simple_method_type do
assert_send_type("() -> self", ...)
end
194 195 196 197 198 199 200 201 |
# File 'sig/unit_test/type_assertions.rbs', line 194 def allow_non_simple_method_type() begin @allows_non_simple_method_type = true yield rescue @allows_non_simple_method_type = false end end |
#allows_error(*errors) { ... } ⇒ void
This method returns an undefined value.
279 280 281 282 283 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 279 def allows_error(*errors) yield rescue *errors => exn notify "Error allowed: #{exn.inspect}" end |
#assert_const_type(type, constant_name) ⇒ void
This method returns an undefined value.
Asserts if the constant constant_name has constant_type, and the RBS definition has compatible type
assert_const_type("Array[String]", "::Foo::Bar")
The assertion above succeeds if ::Foo::Bar is ["foo"] and RBS contains ::Foo::Bar: [untyped].
It fails if ::Foo::Bar is [2], or the RBS definition is ::Foo::Bar: String.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'sig/unit_test/type_assertions.rbs', line 176 def assert_const_type(type, constant_name) constant = Object.const_get(constant_name) typecheck = RBS::Test::TypeCheck.new( self_class: constant.class, instance_class: instance_class, class_class: class_class, builder: builder, sample_size: 100, unchecked_classes: [] ) value_type = case type when String RBS::Parser.parse_type(type, variables: []) || raise else type end assert typecheck.value(constant, value_type), "`#{constant_name}` (#{constant.inspect}) must be compatible with given type `#{value_type}`" type_name = TypeName.parse(constant_name).absolute! definition = env.constant_entry(type_name) assert definition, "Cannot find RBS type definition of `#{constant_name}`" case definition when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry definition_type = RBS::Types::ClassSingleton.new(name: type_name, location: nil) when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry type_name = env.normalize_type_name!(type_name) definition_type = RBS::Types::ClassSingleton.new(name: type_name, location: nil) when RBS::Environment::ConstantEntry definition_type = definition.decl.type end assert definition_type, "Cannot find RBS entry for `#{constant_name}`" definition_type or raise assert typecheck.value(constant, definition_type), "`#{constant_name}` (#{constant.inspect}) must be compatible with RBS type definition `#{definition_type}`" end |
#assert_send_type ⇒ void
This method returns an undefined value.
Calls a method method_name and validates if it's compatible with RBS type definition
- It calls
method_namewithreceiverpassingargsand given block, - Validates if it's compatible with given
method_type, and - Validates if it's also compatible with one of the overloads defined in RBS type definition
assert_send_type(
"(::Integer) -> ::Integer",
[], :sum, 8
)
To test methods that takes a block, pass a block to assert_send_type.
We recommend using &proc { ... } syntax for textual representation and prevent from using break from the block.
assert_send_type(
"() { () -> void } -> void",
self, :loop, &proc { break_from_block }
)
Exiting from the block using break and return skips assertions.
Use break_from_block instead.
method_type must be simple.
It raises an exception if it's not simple.
When you really need non-simple method_type, wrap the calls inside allow_non_simple_method_type.
See docs/stdlib.md for the details.
144 |
# File 'sig/unit_test/type_assertions.rbs', line 144
def assert_send_type: (String | MethodType method_type, untyped receiver, Symbol method_name, *untyped args) ?{ () -> untyped } -> void
|
#assert_send_type_error ⇒ void
This method returns an undefined value.
Calls a method method_name, validates if it's compatible with RBS type definition, and ensures it raises the exception class.
- It calls
method_namewithreceiverpassingargsand given block, - Validates if it's compatible with given
method_type, and - Validates if it's compatible with one of the overloads defined in RBS type definition
- Ensures that
exceptionis thrown
See assert_send_type for the details.
165 |
# File 'sig/unit_test/type_assertions.rbs', line 165
def assert_send_type_error: (String | MethodType method_type, Class exception, untyped receiver, Symbol method_name, *untyped args) ?{ () -> untyped } -> void
|
#assert_type(type, value) ⇒ void
This method returns an undefined value.
Asserts if given value has a type of value_type
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'sig/unit_test/type_assertions.rbs', line 180 def assert_type(type, value) typecheck = RBS::Test::TypeCheck.new( self_class: value.class, instance_class: _ = "No `instance` class allowed", class_class: _ = "No `class` class allowed", builder: builder, sample_size: 100, unchecked_classes: [] ) type = case type when String RBS::Parser.parse_type(type, variables: []) or raise else type end assert typecheck.value(value, type), "`#{value.inspect}` must be compatible with given type `#{type}`" end |
#assert_visibility(visibility, method) ⇒ void
This method returns an undefined value.
Asserts if RBS definition declares given method_name with visibility
184 185 186 187 188 189 190 191 |
# File 'sig/unit_test/type_assertions.rbs', line 184 def assert_visibility(visibility, method) _, definition = target method_entry = definition.methods[method] assert method_entry, "Method `#{method}` not found in RBS definition" assert visibility == method_entry.accessibility, "Expected `#{method}` to be #{visibility}, but was #{method_entry.accessibility}" end |
#break_from_block(value = nil) ⇒ void
This method returns an undefined value.
Break from assert_send_type or refute_send_type
202 203 204 205 |
# File 'sig/unit_test/type_assertions.rbs', line 202 def break_from_block(value = nil) raise "Cannot break without `@break_tag`" unless @break_tag throw @break_tag, value end |
#builder ⇒ DefinitionBuilder
65 66 67 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 65 def builder (_ = self.class).builder end |
#class_class ⇒ Class
The singleton class object that is associated to the class type of the testing type
105 106 107 108 109 110 111 112 |
# File 'sig/unit_test/type_assertions.rbs', line 105 def class_class type, _ = target case type when RBS::Types::ClassSingleton, RBS::Types::ClassInstance Object.const_get(type.name.to_s).singleton_class end end |
#env ⇒ Environment
61 62 63 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 61 def env (_ = self.class).env end |
#instance_class ⇒ Class
The class object that is associated to the instance type of the testing type
101 102 103 104 105 106 107 108 |
# File 'sig/unit_test/type_assertions.rbs', line 101 def instance_class type, _ = target case type when RBS::Types::ClassSingleton, RBS::Types::ClassInstance Object.const_get(type.name.to_s) end end |
#method_defs(method) ⇒ Array[Definition::Method::TypeDef]
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 255 def method_defs(method) type, definition = target case type when Types::ClassInstance, Types::ClassSingleton if type.is_a?(Types::ClassSingleton) && type.args.empty? definition.methods[method].defs else subst = RBS::Substitution.build(definition.type_params, type.args) definition.methods[method].defs.map do |type_def| type_def.update( type: type_def.type.sub(subst) ) end end else raise end end |
#method_types(method) ⇒ Array[MethodType]
275 276 277 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 275 def method_types(method) method_defs(method).map(&:type) end |
#pass(message = nil) ⇒ void
This method returns an undefined value.
378 379 380 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 378 def pass( = nil) assert true, end |
#refute_send_type ⇒ void
This method returns an undefined value.
Calls a method method_name and validates if it's not compatible with RBS type definition
- It calls
method_namewithreceiverpassingargsand given block, - Validates if it's compatible with given
method_type, and - Validates if it's not compatible with none of the overloads defined in RBS type definition
See assert_send_type for the details.
154 |
# File 'sig/unit_test/type_assertions.rbs', line 154
def refute_send_type: (String | MethodType method_type, untyped receiver, Symbol method_name, *untyped args) ?{ () -> untyped } -> void
|
#send_setup(method_type, receiver, method, args, proc) {|mt, last_trace, result, exception| ... } ⇒ void
This method returns an undefined value.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 130 def send_setup(method_type, receiver, method, args, proc) mt = case method_type when String RBS::Parser.parse_method_type(method_type, variables: []) || raise when RBS::MethodType method_type end validate_simple_method_type(mt) trace = [] #: Array[Test::CallTrace] spy = Spy.wrap(receiver, method) spy.callback = -> (result) { trace << result } result = nil #: untyped exception = nil #: Exception? non_jump_exit = true begin result = catch do |tag| @break_tag = tag spy.wrapped_object.__send__(method, *args, &proc) ensure @break_tag = nil end non_jump_exit = false rescue Exception => exn exception = exn ensure if non_jump_exit && !exception raise "`break` nor `return` from blocks given to `assert_send_type` are prohibited. Use `#break_from_block` instead." end end last_trace = trace.last or raise "empty trace" yield(mt, last_trace, result, exception) end |
#target ⇒ [target_type, Definition]
73 74 75 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 73 def target targets.last || (_ = self.class).target end |
#targets ⇒ Array[[target_type, Definition]]
69 70 71 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 69 def targets @targets ||= [] end |
#testing(type_or_string) ⇒ void
This method returns an undefined value.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 77 def testing(type_or_string) type = case type_or_string when String RBS::Parser.parse_type(type_or_string, variables: []) else type_or_string end definition = case type when RBS::Types::ClassInstance builder.build_instance(type.name) when RBS::Types::ClassSingleton builder.build_singleton(type.name) else raise "Test target should be class instance or class singleton: #{type}" end targets.push( [ type, #: target_type definition ] ) if block_given? begin yield ensure targets.pop end else [type, definition] end end |
#validate_simple_method_type(type) ⇒ void
This method returns an undefined value.
365 366 367 368 369 370 371 |
# File 'lib/rbs/unit_test/type_assertions.rb', line 365 def validate_simple_method_type(type) return if @allows_non_simple_method_type refute_predicate type, :has_self_type?, "`self` types is prohibited in method type: `#{type}`" refute_predicate type, :has_classish_type?, "`instance` and `class` types is prohibited in method type: `#{type}`" refute_predicate type, :with_nonreturn_void?, "`void` is only allowed at return type or generics parameters: `#{type}`" end |