raap 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/README.md +63 -2
- data/Rakefile +3 -1
- data/lib/raap/cli.rb +30 -15
- data/lib/raap/coverage.rb +188 -0
- data/lib/raap/function_type.rb +36 -16
- data/lib/raap/method_property.rb +47 -16
- data/lib/raap/method_type.rb +17 -8
- data/lib/raap/minitest.rb +2 -2
- data/lib/raap/rbs.rb +42 -0
- data/lib/raap/symbolic_caller.rb +2 -2
- data/lib/raap/type.rb +53 -45
- data/lib/raap/type_substitution.rb +7 -3
- data/lib/raap/value/interface.rb +13 -24
- data/lib/raap/value/intersection.rb +7 -8
- data/lib/raap/value/module.rb +1 -1
- data/lib/raap/value/variable.rb +1 -1
- data/lib/raap/version.rb +1 -1
- data/lib/raap.rb +2 -0
- data/lib/shims.rb +38 -0
- data/public/example.webp +0 -0
- data/rbs_collection.lock.yaml +5 -5
- data/sig/raap.rbs +52 -11
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13f734d53db009621045979dfc7d705b14c2f378625ff36067784995e8889134
|
4
|
+
data.tar.gz: 472adf32ff8ea739d83a5b41c6a62e80149b29e34d44536df844010eb2e8cb90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc3782c7a65e098eef727163ccc069ca27b339eeaadc7be44abd2eac94c78fa74443c413364e579998dd49aa11c5be38bd27f6504f92759580ec893dd54a3e97
|
7
|
+
data.tar.gz: 68e133fa67a03d4c84ab264c1e0fd1c40204da8995a552e99912eb61c1cddb14d9c81bac26c4aa04615d9833dfa74ad64bd212071dd3195dacad6ae85bd23b54
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 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=
|
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
|
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
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?('!')
|
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
|
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
|
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
|
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
|
data/lib/raap/function_type.rb
CHANGED
@@ -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.
|
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
|
37
|
-
|
38
|
-
|
39
|
-
|
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 (
|
42
|
-
rest = Array.new(Random.rand(
|
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.
|
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
|
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(
|
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,
|
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
|
data/lib/raap/method_property.rb
CHANGED
@@ -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
|
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
|
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
|
85
|
+
Result::Success.new(symbolic_call: symbolic_call, return_value: return_value)
|
85
86
|
in [:failure]
|
86
|
-
Result::Failure.new(symbolic_call
|
87
|
+
Result::Failure.new(symbolic_call: symbolic_call, return_value: return_value)
|
87
88
|
in [:exception, exception]
|
88
|
-
Result::Exception.new(symbolic_call
|
89
|
+
Result::Exception.new(symbolic_call: symbolic_call, exception: exception)
|
89
90
|
end
|
90
91
|
rescue TypeError => exception
|
91
|
-
Result::Failure.new(symbolic_call
|
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
|
97
|
+
Result::Skip.new(symbolic_call: symbolic_call, exception: exception)
|
97
98
|
rescue NameError => e
|
98
|
-
RaaP.logger.
|
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
|
107
|
+
Result::Skip.new(symbolic_call: symbolic_call, exception: exception)
|
107
108
|
rescue => exception
|
108
|
-
Result::Exception.new(symbolic_call
|
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
|