raap 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94f0ec4ff924c5089f8e307002dd5f3cd778f04e686acd8b46466139c3c1aebd
4
- data.tar.gz: e9a06fb3c71cfc6cd605031fe8cb899a123dc82a94ef00586d39e8329c45beac
3
+ metadata.gz: 13f734d53db009621045979dfc7d705b14c2f378625ff36067784995e8889134
4
+ data.tar.gz: 472adf32ff8ea739d83a5b41c6a62e80149b29e34d44536df844010eb2e8cb90
5
5
  SHA512:
6
- metadata.gz: ed0d647fefa8591c0a03981232c84d64bf7c70bcf9207d2dd6471a9f3369747b5dd3adcc3cd60a8e1d65f0e1543ed7a5f5108eef6523c7d306cfc399d0bc63e4
7
- data.tar.gz: 537c5dfbb65bb12064e46c47fb75a60321ee0f16296f1272ef27d68927f4f9f3d5875ea6f3ac2225c76a2d274fbe393bff20f573b8d138b52a6ced8027528e1f
6
+ metadata.gz: cc3782c7a65e098eef727163ccc069ca27b339eeaadc7be44abd2eac94c78fa74443c413364e579998dd49aa11c5be38bd27f6504f92759580ec893dd54a3e97
7
+ data.tar.gz: 68e133fa67a03d4c84ab264c1e0fd1c40204da8995a552e99912eb61c1cddb14d9c81bac26c4aa04615d9833dfa74ad64bd212071dd3195dacad6ae85bd23b54
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 3.3
2
+ TargetRubyVersion: 3.0
3
3
  NewCops: enable
4
4
  Include:
5
5
  - 'lib/**/*.rb'
@@ -8,6 +8,8 @@ Lint:
8
8
  Enabled: true
9
9
  Lint/EmptyBlock:
10
10
  Enabled: false
11
+ Lint/SymbolConversion:
12
+ Enabled: false
11
13
 
12
14
  Style:
13
15
  Enabled: false
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RaaP
2
2
 
3
- <img src="https://raw.githubusercontent.com/ksss/raap/main/public/jacket.webp" width=400/>
3
+ <img src="https://raw.githubusercontent.com/ksss/raap/main/public/jacket.webp" width=500/>
4
4
 
5
5
  ## RBS as a Property
6
6
 
@@ -14,6 +14,10 @@ The return value of the method is checked to see if it matches the type, if not,
14
14
 
15
15
  If you write an RBS, it becomes a test case.
16
16
 
17
+ ## Example
18
+
19
+ <img src="https://raw.githubusercontent.com/ksss/raap/main/public/example.webp" width=700/>
20
+
17
21
  ## Concept
18
22
 
19
23
  If you has next signature.
@@ -70,7 +74,7 @@ $ raap 'MyClass' # Run only RBS of MyClass
70
74
  $ raap 'MyClass::*' # Run each class under MyClass
71
75
  $ raap 'MyClass.singleton_method' # Run only MyClass.singleton_method
72
76
  $ raap 'MyClass#instance_method' # Run only MyClass#instance_method
73
- $ raap 'MyClass' '!MyClass#skip' # Run method MyClass without #skip
77
+ $ raap 'MyClass' '!MyClass#skip' # Run methods MyClass without #skip
74
78
  ```
75
79
 
76
80
  ```
@@ -81,6 +85,27 @@ MyClass
81
85
  $ raap $(cat test/raap.txt) # You can manage the methods to be tested in a file
82
86
  ```
83
87
 
88
+ ## Log level definition
89
+
90
+ - error: Information on status of inability to continue execution.
91
+ - warn: Information on partial corrections required.
92
+ - info: A somewhat visualized representation of the execution state.
93
+ - debug: All information including stack traces.
94
+
95
+ ## Coverage
96
+
97
+ RaaP randomly selects a type and generates a value for optional and union types.
98
+
99
+ By default, displays the coverage of the type that actually produced the value.
100
+
101
+ The coverage display can help you determine if a correction is needed.
102
+
103
+ ### Meaning of colored types
104
+
105
+ - 🔴 Red: A type that has never been used to generate or validate a value.
106
+ - 🟡 Yellow: It is systematically difficult to determine if the type was used or not. (FIXME)
107
+ - 🟢 Green: The type used to generate and validate the value.
108
+
84
109
  ## Size
85
110
 
86
111
  Random values are determined based on size.
@@ -143,6 +168,42 @@ You can specify size of step like `Integer#step: (to: Integer, by: Integer)`.
143
168
  By default, raap only validates public methods.
144
169
  However, by setting this option, it is possible to intentionally validate private methods in the RBS.
145
170
 
171
+ ### `--preload path`
172
+
173
+ Simply call `Kernel.load`.
174
+ However, this simplifies the preliminary preparation.
175
+
176
+ #### Preload examples
177
+
178
+ 1) Check signature of aws-sdk-s3
179
+
180
+ ```rb
181
+ $ cat preload.rb
182
+ require 'aws-sdk-s3'
183
+
184
+ # Register initialize of `Aws::S3::Client` class.
185
+ RaaP::Type.register("Aws::S3::Client") do
186
+ [:call, Aws::S3::Client, :new, [], { stub_responses: true }, nil]
187
+ end
188
+
189
+ $ raap --preload ./preload.rb 'Aws::S3::Client#get_object'
190
+ ```
191
+
192
+ 2) Output ruby coverage by simplecov
193
+
194
+ ```rb
195
+ $ cat preload.rb
196
+ require 'simplecov'
197
+
198
+ SimpleCov.command_name 'raap'
199
+ SimpleCov.start do
200
+ enable_coverage :branch
201
+ add_filter "/test/"
202
+ end
203
+
204
+ $ bundle exec raap --preload ./preload.rb -r my_class 'MyClass'
205
+ ```
206
+
146
207
  ## First support is CLI
147
208
 
148
209
  In RaaP, usage through the CLI is the primary support focus, and efforts are made to maintain compatibility. The use of the library's code (such as `RaaP::Type`) does not guarantee compatibility.
data/Rakefile CHANGED
@@ -4,7 +4,9 @@ require "bundler/gem_tasks"
4
4
  require "minitest/test_task"
5
5
  require "rubocop/rake_task"
6
6
 
7
- Minitest::TestTask.create
7
+ Minitest::TestTask.create do |t|
8
+ t.test_prelude = 'require "test/test_helper"'
9
+ end
8
10
 
9
11
  RuboCop::RakeTask.new
10
12
 
data/lib/raap/cli.rb CHANGED
@@ -12,6 +12,7 @@ module RaaP
12
12
  :size_to,
13
13
  :size_by,
14
14
  :allow_private,
15
+ :coverage,
15
16
  keyword_init: true
16
17
  )
17
18
 
@@ -44,6 +45,7 @@ module RaaP
44
45
  size_from: 0,
45
46
  size_to: 99,
46
47
  size_by: 1,
48
+ coverage: true,
47
49
  allow_private: false,
48
50
  )
49
51
  @argv = argv
@@ -80,6 +82,12 @@ module RaaP
80
82
  o.on('--allow-private', "default: #{@option.allow_private}") do
81
83
  @option.allow_private = true
82
84
  end
85
+ o.on('--preload path', 'Kernel.load path') do |path|
86
+ Kernel.load path
87
+ end
88
+ o.on('--[no-]coverage', "Show coverage for RBS (default: #{@option.coverage})") do |arg|
89
+ @option.coverage = arg
90
+ end
83
91
  end.parse!(@argv)
84
92
 
85
93
  @option.dirs.each do |dir|
@@ -104,7 +112,7 @@ module RaaP
104
112
 
105
113
  # Search skip tag
106
114
  @argv.each do |tag|
107
- if tag.start_with?('!') && (tag.include?('#') || tag.include?('.'))
115
+ if tag.start_with?('!')
108
116
  t = tag[1..] or raise
109
117
  t = "::#{t}" unless t.start_with?('::')
110
118
  t or raise
@@ -118,13 +126,13 @@ module RaaP
118
126
 
119
127
  case
120
128
  when tag.include?('#')
121
- run_by(kind: :instance, tag:)
129
+ run_by(kind: :instance, tag: tag)
122
130
  when tag.include?('.')
123
- run_by(kind: :singleton, tag:)
131
+ run_by(kind: :singleton, tag: tag)
124
132
  when tag.end_with?('*')
125
- run_by_type_name_with_search(tag:)
133
+ run_by_type_name_with_search(tag: tag)
126
134
  else
127
- run_by_type_name(tag:)
135
+ run_by_type_name(tag: tag)
128
136
  end
129
137
  end
130
138
 
@@ -198,9 +206,10 @@ module RaaP
198
206
 
199
207
  RaaP.logger.info("# #{type}")
200
208
  @results << {
201
- method:,
209
+ method: method,
202
210
  properties: method.method_types.map do |method_type|
203
- property(receiver_type:, type_params_decl:, type_args:, method_type:, method_name:)
211
+ property(receiver_type: receiver_type, type_params_decl: type_params_decl, type_args: type_args, method_type: method_type,
212
+ method_name: method_name)
204
213
  end
205
214
  }
206
215
  end
@@ -238,9 +247,10 @@ module RaaP
238
247
 
239
248
  RaaP.logger.info("# #{type_name}.#{method_name}")
240
249
  @results << {
241
- method:,
250
+ method: method,
242
251
  properties: method.method_types.map do |method_type|
243
- property(receiver_type: Type.new("singleton(#{type.name})"), type_params_decl:, type_args:, method_type:, method_name:)
252
+ property(receiver_type: Type.new("singleton(#{type.name})"), type_params_decl: type_params_decl, type_args: type_args,
253
+ method_type: method_type, method_name: method_name)
244
254
  end
245
255
  }
246
256
  end
@@ -257,9 +267,10 @@ module RaaP
257
267
 
258
268
  RaaP.logger.info("# #{type_name}##{method_name}")
259
269
  @results << {
260
- method:,
270
+ method: method,
261
271
  properties: method.method_types.map do |method_type|
262
- property(receiver_type: Type.new(type.name), type_params_decl:, type_args:, method_type:, method_name:)
272
+ property(receiver_type: Type.new(type.name), type_params_decl: type_params_decl, type_args: type_args, method_type: method_type,
273
+ method_name: method_name)
263
274
  end
264
275
  }
265
276
  end
@@ -283,12 +294,12 @@ module RaaP
283
294
  status = 0
284
295
  reason = nil
285
296
  prop = MethodProperty.new(
286
- receiver_type:,
287
- method_name:,
297
+ receiver_type: receiver_type,
298
+ method_name: method_name,
288
299
  method_type: MethodType.new(
289
300
  method_type,
290
- type_params_decl:,
291
- type_args:,
301
+ type_params_decl: type_params_decl,
302
+ type_args: type_args,
292
303
  self_type: rtype,
293
304
  instance_type: ::RBS::Types::ClassInstance.new(name: rtype.name, args: type_args, location: nil),
294
305
  class_type: ::RBS::Types::ClassSingleton.new(name: rtype.name, location: nil),
@@ -297,6 +308,7 @@ module RaaP
297
308
  timeout: @option.timeout,
298
309
  allow_private: @option.allow_private,
299
310
  )
311
+ RaaP::Coverage.start(method_type) if @option.coverage
300
312
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
301
313
  stats = prop.run do |called|
302
314
  case called
@@ -334,6 +346,9 @@ module RaaP
334
346
  end
335
347
  end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
336
348
  puts
349
+ RaaP::Coverage.show($stdout) if @option.coverage
350
+ puts
351
+
337
352
  time_diff = end_time - start_time
338
353
  time = ", time: #{(time_diff * 1000).round}ms"
339
354
  stats_log = "success: #{stats.success}, skip: #{stats.skip}, exception: #{stats.exception}#{time}"
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RaaP
4
+ module Coverage
5
+ class Writer
6
+ def initialize(method_type, cov)
7
+ @method_type = method_type
8
+ @cov = cov
9
+ @cur = 0
10
+ end
11
+
12
+ def write(io)
13
+ RaaP.logger.debug { "Coverage: #{@cov}" }
14
+ ml = @method_type.location
15
+ unless ml
16
+ RaaP.logger.warn("No location information for `#{@method_type}`")
17
+ return
18
+ end
19
+ if ml.key?(:keyword)
20
+ # attr_{reader,writer,accessor}
21
+ phantom_member = RBS.parse_member(ml.source)
22
+ case phantom_member
23
+ when ::RBS::AST::Members::Attribute
24
+ unless phantom_member.location
25
+ RaaP.logger.warn("No location information for `#{phantom_member}`")
26
+ return
27
+ end
28
+ write_type(io, "return", phantom_member.type, :abs)
29
+ io.write(slice(@cur, @cur...phantom_member.location.end_pos))
30
+ else
31
+ RaaP.logger.error("#{phantom_member.class} is not supported")
32
+ return
33
+ end
34
+ else
35
+ # def name: () -> type
36
+ phantom_method_type = RBS.parse_method_type(ml.source)
37
+ phantom_method_type.type.yield_self do |fun|
38
+ case fun
39
+ when ::RBS::Types::Function
40
+ fun.required_positionals.each_with_index { |param, i| write_param(io, "req_#{i}", param, :abs) }
41
+ fun.optional_positionals.each_with_index { |param, i| write_param(io, "opt_#{i}", param, :opt) }
42
+ fun.rest_positionals&.yield_self { |param| write_param(io, "rest", param, :opt) }
43
+ fun.trailing_positionals.each_with_index { |param, i| write_param(io, "trail_#{i}", param, :abs) }
44
+ fun.required_keywords.each { |key, param| write_param(io, "keyreq_#{key}", param, :abs) }
45
+ fun.optional_keywords.each { |key, param| write_param(io, "key_#{key}", param, :opt) }
46
+ fun.rest_keywords&.yield_self { |param| write_param(io, "keyrest", param, :opt) }
47
+ # when ::RBS::Types::UntypedFunction
48
+ end
49
+ end
50
+
51
+ phantom_method_type.block&.yield_self do |b|
52
+ b.type.each_param.with_index { |param, i| write_param(io, "block_param_#{i}", param, :opt) }
53
+ write_type(io, "block_return", b.type.return_type, :abs)
54
+ end
55
+ write_type(io, "return", phantom_method_type.type.return_type, :abs)
56
+ raise unless phantom_method_type.location
57
+
58
+ io.write(slice(@cur, @cur...phantom_method_type.location.end_pos))
59
+ end
60
+
61
+ io.puts
62
+ end
63
+
64
+ private
65
+
66
+ def slice(start, range)
67
+ ml = @method_type.location
68
+ raise unless ml
69
+
70
+ ml.source[start, range.end - range.begin] or raise
71
+ end
72
+
73
+ def write_param(io, position, param, accuracy)
74
+ write_type(io, position, param.type, accuracy)
75
+ end
76
+
77
+ def write_type(io, position, type, accuracy)
78
+ unless type.location
79
+ RaaP.logger.warn("No location information for `#{type}`")
80
+ return
81
+ end
82
+ io.write(slice(@cur, @cur...type.location.start_pos))
83
+ @cur = type.location.start_pos
84
+ case type
85
+ when ::RBS::Types::Tuple, ::RBS::Types::Union
86
+ name = type.class.name.split('::').last.downcase
87
+ type.types.each_with_index do |t, i|
88
+ t.location or raise
89
+ io.write(slice(@cur, @cur...t.location.start_pos)) # ( or [
90
+ @cur = t.location.start_pos
91
+ write_type(io, "#{position}_#{name}_#{i}", t, accuracy)
92
+ end
93
+ when ::RBS::Types::Optional
94
+ raise unless type.location
95
+
96
+ write_type(io, "#{position}_optional_left", type.type, accuracy)
97
+ io.write(slice(@cur, @cur...(type.location.end_pos - 1)))
98
+ @cur = type.location.end_pos - 1
99
+ if @cov.include?("#{position}_optional_right".to_sym)
100
+ io.write(green('?'))
101
+ else
102
+ io.write(red('?'))
103
+ end
104
+ raise unless type.location
105
+
106
+ @cur = type.location.end_pos
107
+ when ::RBS::Types::Variable
108
+ case accuracy
109
+ when :abs
110
+ io.write(green(type.name.to_s))
111
+ when :opt
112
+ # Variables are substed so raap don't know if they've been used.
113
+ io.write(yellow(type.name.to_s))
114
+ end
115
+ raise unless type.location
116
+
117
+ @cur = type.location.end_pos
118
+ else
119
+ raise unless type.location
120
+
121
+ if @cov.include?(position.to_sym)
122
+ io.write(green(type.location.source))
123
+ else
124
+ io.write(red(type.location.source))
125
+ end
126
+ @cur = type.location.end_pos
127
+ end
128
+ end
129
+
130
+ def green(str) = "\e[32m#{str}\e[0m"
131
+ def red(str) = "\e[1;4;41m#{str}\e[0m"
132
+ def yellow(str) = "\e[93m#{str}\e[0m"
133
+ end
134
+
135
+ class << self
136
+ def start(method_type)
137
+ @cov = Set.new
138
+ @method_type = method_type
139
+ end
140
+
141
+ def running?
142
+ !!@cov
143
+ end
144
+
145
+ # position: req_0
146
+ # type: union_1
147
+ def log(position)
148
+ return unless running?
149
+
150
+ cov << position.to_sym
151
+ end
152
+
153
+ def cov
154
+ @cov or raise
155
+ end
156
+
157
+ def show(io)
158
+ return unless running?
159
+
160
+ writer = Writer.new(@method_type, cov)
161
+ writer.write(io)
162
+ end
163
+
164
+ def new_type_with_log(position, type)
165
+ case type
166
+ when ::RBS::Types::Tuple
167
+ # FIXME: Support Union in Tuple
168
+ type.types.each_with_index do |_t, i|
169
+ log("#{position}_tuple_#{i}")
170
+ end
171
+ Type.new(type)
172
+ when ::RBS::Types::Union
173
+ i = Random.rand(type.types.length)
174
+ new_type_with_log("#{position}_union_#{i}", type.types[i])
175
+ when ::RBS::Types::Optional
176
+ if Random.rand(2).zero?
177
+ new_type_with_log("#{position}_optional_left", type.type)
178
+ else
179
+ new_type_with_log("#{position}_optional_right", ::RBS::Types::Bases::Nil.new(location: nil))
180
+ end
181
+ else
182
+ log(position)
183
+ Type.new(type)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -7,12 +7,12 @@ module RaaP
7
7
  end
8
8
 
9
9
  def pick_arguments(size: 10)
10
- SymbolicCaller.new(arguments_to_symbolic_call(size:)).eval
10
+ SymbolicCaller.new(arguments_to_symbolic_call(size: size)).eval
11
11
  end
12
12
 
13
13
  def arguments_to_symbolic_call(size: 10)
14
- a = to_symbolic_call_recursive(build_args_type, size:)
15
- k = to_symbolic_call_recursive(build_kwargs_type, size:)
14
+ a = to_symbolic_call_recursive(build_args_type, size: size)
15
+ k = to_symbolic_call_recursive(build_kwargs_type, size: size)
16
16
 
17
17
  [a, k]
18
18
  end
@@ -24,44 +24,64 @@ module RaaP
24
24
  when type.nil?
25
25
  nil
26
26
  when type.respond_to?(:each_pair)
27
- type.each_pair.to_h { |k, v| [k, to_symbolic_call_recursive(v, size:)] }
27
+ type.each_pair.to_h { |k, v| [k, to_symbolic_call_recursive(v, size: size)] }
28
28
  when type.respond_to?(:each)
29
- type.each.map { |v| to_symbolic_call_recursive(v, size:) }
29
+ type.map { |v| to_symbolic_call_recursive(v, size: size) }
30
30
  else
31
- type.to_symbolic_call(size:)
31
+ type.to_symbolic_call(size: size)
32
32
  end
33
33
  end
34
34
 
35
35
  def build_args_type
36
- reqs = @fun.required_positionals.map { |param| Type.new(param.type) }
37
- tras = @fun.trailing_positionals.map { |param| Type.new(param.type) }
38
- sampled_optional_positionals = @fun.optional_positionals.take(Random.rand(@fun.optional_positionals.length + 1))
39
- opts = sampled_optional_positionals.map { |param| Type.new(param.type) }
36
+ reqs = @fun.required_positionals.map.with_index do |param, i|
37
+ build_type_with_coverage("req_#{i}", param)
38
+ end
39
+
40
+ take_num = Random.rand(@fun.optional_positionals.length + 1)
41
+ opts = @fun.optional_positionals.take(take_num).map.each_with_index do |param, i|
42
+ build_type_with_coverage("opt_#{i}", param)
43
+ end
44
+
40
45
  rest = []
41
- if (param = @fun.rest_positionals)
42
- rest = Array.new(Random.rand(0..3)) { Type.new(param.type) }
46
+ if (rest_param = @fun.rest_positionals)
47
+ rest = Array.new(Random.rand(4)) do
48
+ build_type_with_coverage("rest", rest_param)
49
+ end
50
+ end
51
+
52
+ tras = @fun.trailing_positionals.map.with_index do |param, i|
53
+ build_type_with_coverage("trail_#{i}", param)
43
54
  end
55
+
44
56
  [reqs, opts, rest, tras].flatten
45
57
  end
46
58
 
47
59
  def build_kwargs_type
48
- reqs = @fun.required_keywords.transform_values { |param| Type.new(param.type) }
60
+ reqs = @fun.required_keywords.keys.to_h do |key|
61
+ [key, build_type_with_coverage("keyreq_#{key}", @fun.required_keywords[key])]
62
+ end
49
63
  rand = Random.rand(@fun.optional_keywords.length + 1)
50
- opts = @fun.optional_keywords.to_a.sample(rand).to_h { |name, param| [name, Type.new(param.type)] }
64
+ opts = @fun.optional_keywords.to_a.sample(rand).to_h do |key, param|
65
+ [key, build_type_with_coverage("key_#{key}", param)]
66
+ end
51
67
  kwargs = reqs.to_h.merge(opts)
52
68
  if (param = @fun.rest_keywords)
53
- keys = Array.new(Random.rand(0..3)) do
69
+ keys = Array.new(Random.rand(4)) do
54
70
  random_key = nil
55
71
  loop do
56
72
  # @type var random_key: Symbol
57
73
  random_key = Type.new("Symbol").pick(size: 6)
58
74
  break unless kwargs.key?(random_key)
59
75
  end
60
- [random_key, Type.new(param.type)]
76
+ [random_key, build_type_with_coverage("keyrest", param)]
61
77
  end
62
78
  kwargs.merge!(keys.to_h)
63
79
  end
64
80
  kwargs
65
81
  end
82
+
83
+ def build_type_with_coverage(position, param)
84
+ Coverage.new_type_with_log(position, param.type)
85
+ end
66
86
  end
67
87
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RaaP
4
4
  class MethodProperty
5
- class Stats < Struct.new(:success, :skip, :exception, :break)
5
+ class Stats < Struct.new(:success, :skip, :exception, :break, keyword_init: true)
6
6
  def initialize(success: 0, skip: 0, exception: 0, break: false)
7
7
  super
8
8
  end
@@ -23,7 +23,7 @@ module RaaP
23
23
  Timeout.timeout(@timeout) do
24
24
  catch(:break) do
25
25
  @size_step.each do |size|
26
- call(size:, stats:).tap do |ret|
26
+ call(size: size, stats: stats).tap do |ret|
27
27
  case ret
28
28
  when Result::Success
29
29
  stats.success += 1
@@ -55,8 +55,8 @@ module RaaP
55
55
  stats.break = true
56
56
  throw :break
57
57
  end
58
- receiver_value = @receiver_type.to_symbolic_call(size:)
59
- args, kwargs, block = @method_type.arguments_to_symbolic_call(size:)
58
+ receiver_value = @receiver_type.to_symbolic_call(size: size)
59
+ args, kwargs, block = @method_type.arguments_to_symbolic_call(size: size)
60
60
  # @type var symbolic_call: symbolic_call
61
61
  symbolic_call = [:call, receiver_value, @method_name, args, kwargs, block]
62
62
  symbolic_caller = SymbolicCaller.new(symbolic_call, allow_private: @allow_private)
@@ -67,8 +67,9 @@ module RaaP
67
67
  begin
68
68
  return_value = symbolic_caller.eval
69
69
  rescue StandardError, NotImplementedError
70
- check = [:success]
71
70
  return_value = Value::Bottom.new
71
+ coverage("return", return_value, return_type)
72
+ check = [:success]
72
73
  rescue Timeout::ExitException
73
74
  raise
74
75
  rescue Exception => e # rubocop:disable Lint/RescueException
@@ -77,25 +78,25 @@ module RaaP
77
78
  end
78
79
  else
79
80
  return_value = symbolic_caller.eval
80
- check = check_return(receiver_value:, return_value:)
81
+ check = check_return(receiver_value: receiver_value, return_value: return_value)
81
82
  end
82
83
  case check
83
84
  in [:success]
84
- Result::Success.new(symbolic_call:, return_value:)
85
+ Result::Success.new(symbolic_call: symbolic_call, return_value: return_value)
85
86
  in [:failure]
86
- Result::Failure.new(symbolic_call:, return_value:)
87
+ Result::Failure.new(symbolic_call: symbolic_call, return_value: return_value)
87
88
  in [:exception, exception]
88
- Result::Exception.new(symbolic_call:, exception:)
89
+ Result::Exception.new(symbolic_call: symbolic_call, exception: exception)
89
90
  end
90
91
  rescue TypeError => exception
91
- Result::Failure.new(symbolic_call:, return_value:, exception:)
92
+ Result::Failure.new(symbolic_call: symbolic_call, return_value: return_value, exception: exception)
92
93
  end
93
94
 
94
95
  # not ensure symbolic_call
95
96
  rescue NoMethodError, NotImplementedError => exception
96
- Result::Skip.new(symbolic_call:, exception:)
97
+ Result::Skip.new(symbolic_call: symbolic_call, exception: exception)
97
98
  rescue NameError => e
98
- RaaP.logger.error("[#{e.class}] #{e.detailed_message}")
99
+ RaaP.logger.warn("[#{e.class}] #{e.detailed_message}")
99
100
  msg = e.name.nil? ? '' : "for `#{BindCall.to_s(e.receiver)}::#{e.name}`"
100
101
  RaaP.logger.warn("Implementation is not found #{msg} maybe.")
101
102
  RaaP.logger.debug(e.backtrace&.join("\n"))
@@ -103,9 +104,9 @@ module RaaP
103
104
  throw :break
104
105
  rescue SystemStackError => exception
105
106
  RaaP.logger.info "Found recursive type definition."
106
- Result::Skip.new(symbolic_call:, exception:)
107
+ Result::Skip.new(symbolic_call: symbolic_call, exception: exception)
107
108
  rescue => exception
108
- Result::Exception.new(symbolic_call:, exception:)
109
+ Result::Exception.new(symbolic_call: symbolic_call, exception: exception)
109
110
  end
110
111
 
111
112
  def check_return(receiver_value:, return_value:)
@@ -113,6 +114,7 @@ module RaaP
113
114
  if BindCall.is_a?(return_type, ::RBS::Types::ClassSingleton)
114
115
  # ::RBS::Test::TypeCheck cannot support to check singleton class
115
116
  if receiver_value == return_value
117
+ coverage("return", return_value, return_type)
116
118
  [:success]
117
119
  else
118
120
  [:failure]
@@ -126,8 +128,8 @@ module RaaP
126
128
  instance_class = BindCall.class(receiver_value)
127
129
  end
128
130
  type_check = ::RBS::Test::TypeCheck.new(
129
- self_class:,
130
- instance_class:,
131
+ self_class: self_class,
132
+ instance_class: instance_class,
131
133
  class_class: Module,
132
134
  builder: RBS.builder,
133
135
  sample_size: 100,
@@ -135,6 +137,7 @@ module RaaP
135
137
  )
136
138
  begin
137
139
  if type_check.value(return_value, return_type)
140
+ coverage("return", return_value, return_type, type_check)
138
141
  [:success]
139
142
  else
140
143
  [:failure]
@@ -148,5 +151,33 @@ module RaaP
148
151
  def return_type
149
152
  @method_type.rbs.type.return_type
150
153
  end
154
+
155
+ def coverage(position, return_value, return_type, type_check = nil)
156
+ return unless Coverage.running?
157
+
158
+ case return_type
159
+ when ::RBS::Types::Tuple
160
+ return_type.types.zip(return_value).each_with_index do |(type, value), i|
161
+ if type_check&.value(value, type)
162
+ coverage("#{position}_tuple_#{i}", value, type, type_check)
163
+ end
164
+ end
165
+ when ::RBS::Types::Union
166
+ return_type.types.each_with_index do |type, i|
167
+ if type_check&.value(return_value, type)
168
+ coverage("#{position}_union_#{i}", return_value, type, type_check)
169
+ break
170
+ end
171
+ end
172
+ when ::RBS::Types::Optional
173
+ if return_value.nil?
174
+ Coverage.log("#{position}_optional_right")
175
+ else
176
+ coverage("#{position}_optional_left", return_value, return_type.type, type_check)
177
+ end
178
+ else
179
+ Coverage.log(position)
180
+ end
181
+ end
151
182
  end
152
183
  end