Module: RBS::UnitTest::TypeAssertions

Defined in:
lib/rbs/unit_test/type_assertions.rb

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



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_typeObject



314
315
316
317
318
319
320
321
# File 'lib/rbs/unit_test/type_assertions.rb', line 314

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) ⇒ Object



246
247
248
249
250
# File 'lib/rbs/unit_test/type_assertions.rb', line 246

def allows_error(*errors)
  yield
rescue *errors => exn
  notify "Error allowed: #{exn.inspect}"
end

#assert_const_type(type, constant_name) ⇒ Object



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/rbs/unit_test/type_assertions.rb', line 252

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(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_type(type, value) ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/rbs/unit_test/type_assertions.rb', line 293

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

#break_from_block(value = nil) ⇒ Object



331
332
333
334
# File 'lib/rbs/unit_test/type_assertions.rb', line 331

def break_from_block(value = nil)
  raise "Cannot break without `@break_tag`" unless @break_tag
  throw @break_tag, value
end

#builderObject



65
66
67
# File 'lib/rbs/unit_test/type_assertions.rb', line 65

def builder
  (_ = self.class).builder
end

#class_classObject



121
122
123
124
125
126
127
128
# File 'lib/rbs/unit_test/type_assertions.rb', line 121

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

#envObject



61
62
63
# File 'lib/rbs/unit_test/type_assertions.rb', line 61

def env
  (_ = self.class).env
end

#instance_classObject



112
113
114
115
116
117
118
119
# File 'lib/rbs/unit_test/type_assertions.rb', line 112

def instance_class
  type, _ = target

  case type
  when RBS::Types::ClassSingleton, RBS::Types::ClassInstance
    Object.const_get(type.name.to_s)
  end
end

#method_types(method) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/rbs/unit_test/type_assertions.rb', line 230

def method_types(method)
  type, definition = target

  case type
  when Types::ClassInstance
    subst = RBS::Substitution.build(definition.type_params, type.args)
    definition.methods[method].method_types.map do |method_type|
      method_type.sub(subst)
    end
  when Types::ClassSingleton
    definition.methods[method].method_types
  else
    raise
  end
end

#pass(message = nil) ⇒ Object



336
337
338
# File 'lib/rbs/unit_test/type_assertions.rb', line 336

def pass(message = nil)
  assert true, message
end

#send_setup(method_type, receiver, method, args, proc) {|mt, last_trace, result, exception| ... } ⇒ Object

Yields:

  • (mt, last_trace, result, exception)


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

  yield(mt, last_trace, result, exception)
end

#targetObject



73
74
75
# File 'lib/rbs/unit_test/type_assertions.rb', line 73

def target
  targets.last || (_ = self.class).target
end

#targetsObject



69
70
71
# File 'lib/rbs/unit_test/type_assertions.rb', line 69

def targets
  @targets ||= []
end

#testing(type_or_string) ⇒ Object



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) ⇒ Object



323
324
325
326
327
328
329
# File 'lib/rbs/unit_test/type_assertions.rb', line 323

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