raap 0.3.0 → 0.4.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 +29 -0
- data/README.md +12 -1
- data/Rakefile +10 -1
- data/exe/raap +3 -1
- data/lib/raap/bind_call.rb +18 -6
- data/lib/raap/cli.rb +188 -118
- data/lib/raap/function_type.rb +14 -10
- data/lib/raap/method_property.rb +60 -28
- data/lib/raap/method_type.rb +13 -6
- data/lib/raap/minitest.rb +7 -3
- data/lib/raap/rbs.rb +19 -0
- data/lib/raap/result.rb +84 -8
- data/lib/raap/sized.rb +2 -0
- data/lib/raap/symbolic_caller.rb +38 -26
- data/lib/raap/type.rb +85 -69
- data/lib/raap/type_substitution.rb +2 -1
- data/lib/raap/value/interface.rb +15 -7
- data/lib/raap/value/intersection.rb +22 -10
- data/lib/raap/value/module.rb +46 -7
- data/lib/raap/value/variable.rb +10 -1
- data/lib/raap/version.rb +1 -1
- data/lib/raap.rb +3 -2
- data/public/jacket.webp +0 -0
- data/rbs_collection.lock.yaml +61 -1
- data/rbs_collection.yaml +0 -1
- data/sig/raap.rbs +64 -35
- data/sig/shims.rbs +4 -0
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 312e27904176673d6962904901cb3e8d31c6b613b8efdf669c877d4670cf9d15
|
4
|
+
data.tar.gz: fe940b9d2928a54bfbba8a4842c097cb2a8efe6cf0b873baa383f757de37d017
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55070cb0335ae161e3a1f6e62d9faa9d205e0b1c92186d2e81eaea2547d476d092fa90a9c6607d2d4ad11cf1f0a0bab723539e90cc4932d49bc297e069e07632
|
7
|
+
data.tar.gz: 771e2f640454bfcd8774ccc0d1ac3079df7e6f1edb7d209327881fea2febb6bbfe04af937481e3e6d81bf9b05046860fc7d861af38b523872d1af8d62a0717da
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.3
|
3
|
+
NewCops: enable
|
4
|
+
Include:
|
5
|
+
- 'lib/**/*.rb'
|
6
|
+
|
7
|
+
Lint:
|
8
|
+
Enabled: true
|
9
|
+
Lint/EmptyBlock:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Style:
|
13
|
+
Enabled: false
|
14
|
+
Style/HashSyntax:
|
15
|
+
EnforcedShorthandSyntax: always
|
16
|
+
Enabled: true
|
17
|
+
|
18
|
+
Metrics:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Layout:
|
22
|
+
Enabled: true
|
23
|
+
Layout/FirstArrayElementIndentation:
|
24
|
+
EnforcedStyle: consistent
|
25
|
+
Layout/LineLength:
|
26
|
+
Max: 150
|
27
|
+
|
28
|
+
Naming:
|
29
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# RaaP
|
2
2
|
|
3
|
+

|
4
|
+
|
3
5
|
## RBS as a Property
|
4
6
|
|
5
7
|
RaaP is a property based testing tool.
|
@@ -55,7 +57,7 @@ Finally, you get the perfect RBS!
|
|
55
57
|
|
56
58
|
Install the gem and add to the application's Gemfile by executing:
|
57
59
|
|
58
|
-
$ bundle add raap
|
60
|
+
$ bundle add raap --require false
|
59
61
|
|
60
62
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
61
63
|
|
@@ -123,6 +125,10 @@ You can specify size of end.
|
|
123
125
|
|
124
126
|
You can specify size of step like `Integer#step: (to: Integer, by: Integer)`.
|
125
127
|
|
128
|
+
## First support is CLI
|
129
|
+
|
130
|
+
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.
|
131
|
+
|
126
132
|
## Achievements
|
127
133
|
|
128
134
|
RaaP has already found many RBS mistakes and bug in CRuby during the development phase.
|
@@ -134,6 +140,11 @@ RaaP has already found many RBS mistakes and bug in CRuby during the development
|
|
134
140
|
* https://github.com/ruby/rbs/pull/1769
|
135
141
|
* https://github.com/ruby/rbs/pull/1770
|
136
142
|
* https://github.com/ruby/rbs/pull/1771
|
143
|
+
* https://github.com/ruby/rbs/pull/1779
|
144
|
+
* https://github.com/ruby/rbs/pull/1783
|
145
|
+
* https://github.com/ruby/rbs/pull/1789
|
146
|
+
* https://github.com/ruby/rbs/pull/1790
|
147
|
+
* https://github.com/ruby/rbs/pull/1793
|
137
148
|
|
138
149
|
## Development
|
139
150
|
|
data/Rakefile
CHANGED
@@ -2,7 +2,16 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "minitest/test_task"
|
5
|
+
require "rubocop/rake_task"
|
5
6
|
|
6
7
|
Minitest::TestTask.create
|
7
8
|
|
8
|
-
|
9
|
+
RuboCop::RakeTask.new
|
10
|
+
|
11
|
+
namespace :steep do
|
12
|
+
task :check do
|
13
|
+
sh "bundle exec steep check"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task default: [:test, :rubocop, 'steep:check']
|
data/exe/raap
CHANGED
data/lib/raap/bind_call.rb
CHANGED
@@ -11,19 +11,31 @@ module RaaP
|
|
11
11
|
def public_send(...) = ::Kernel.instance_method(:public_send).bind_call(...)
|
12
12
|
|
13
13
|
def class(obj)
|
14
|
-
if
|
15
|
-
obj.class
|
16
|
-
else
|
14
|
+
if instance_of?(obj, BasicObject)
|
17
15
|
::Kernel.instance_method(:class).bind_call(obj)
|
16
|
+
else
|
17
|
+
obj.class
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
def inspect(obj)
|
22
|
-
if
|
23
|
-
obj.inspect
|
24
|
-
else
|
22
|
+
if instance_of?(obj, BasicObject)
|
25
23
|
::Kernel.instance_method(:inspect).bind_call(obj)
|
24
|
+
else
|
25
|
+
case obj
|
26
|
+
when Hash
|
27
|
+
body = obj.map do |k, v|
|
28
|
+
"#{inspect(k)} => #{inspect(v)}"
|
29
|
+
end
|
30
|
+
"{#{body.join(', ')}}"
|
31
|
+
when Array
|
32
|
+
"[#{obj.map { |o| inspect(o) }.join(', ')}]"
|
33
|
+
else
|
34
|
+
obj.inspect
|
35
|
+
end
|
26
36
|
end
|
37
|
+
rescue NoMethodError
|
38
|
+
"#<#{self.class(obj)}>"
|
27
39
|
end
|
28
40
|
end
|
29
41
|
end
|
data/lib/raap/cli.rb
CHANGED
@@ -2,12 +2,7 @@
|
|
2
2
|
|
3
3
|
module RaaP
|
4
4
|
# $ raap Integer#pow
|
5
|
-
# $ raap -I sig RaaP::Type
|
6
5
|
class CLI
|
7
|
-
class << self
|
8
|
-
attr_accessor :option
|
9
|
-
end
|
10
|
-
|
11
6
|
Option = Struct.new(
|
12
7
|
:dirs,
|
13
8
|
:requires,
|
@@ -17,201 +12,263 @@ module RaaP
|
|
17
12
|
:size_to,
|
18
13
|
:size_by,
|
19
14
|
:allow_private,
|
15
|
+
:skips,
|
20
16
|
keyword_init: true
|
21
17
|
)
|
22
18
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
19
|
+
# Should skip methods has side effects
|
20
|
+
DEFAULT_SKIP = Set.new
|
21
|
+
%i[
|
22
|
+
fork system exec spawn `
|
23
|
+
abort exit exit! raise fail
|
24
|
+
load require require_relative
|
25
|
+
gem
|
26
|
+
].each do |kernel_method|
|
27
|
+
DEFAULT_SKIP << "::Kernel##{kernel_method}"
|
28
|
+
DEFAULT_SKIP << "::Kernel.#{kernel_method}"
|
29
|
+
end
|
30
|
+
%i[
|
31
|
+
delete unlink chmod lchmod chown lchown
|
32
|
+
link mkfifo new open rename truncate
|
33
|
+
].each { |m| DEFAULT_SKIP << "::File.#{m}" }
|
34
|
+
%i[flock truncate].each { |m| DEFAULT_SKIP << "::File##{m}" }
|
35
|
+
|
36
|
+
attr_accessor :option, :argv, :skip, :results
|
34
37
|
|
35
38
|
def initialize(argv)
|
39
|
+
# defaults
|
40
|
+
@option = Option.new(
|
41
|
+
dirs: [],
|
42
|
+
requires: [],
|
43
|
+
libraries: [],
|
44
|
+
timeout: 3,
|
45
|
+
size_from: 0,
|
46
|
+
size_to: 99,
|
47
|
+
size_by: 1,
|
48
|
+
skips: [],
|
49
|
+
allow_private: false,
|
50
|
+
)
|
36
51
|
@argv = argv
|
52
|
+
@skip = DEFAULT_SKIP.dup
|
53
|
+
@results = []
|
37
54
|
end
|
38
55
|
|
39
56
|
def load
|
40
57
|
OptionParser.new do |o|
|
41
58
|
o.on('-I', '--include PATH') do |path|
|
42
|
-
|
59
|
+
@option.dirs << path
|
43
60
|
end
|
44
61
|
o.on('--library lib', 'load rbs library') do |lib|
|
45
|
-
|
62
|
+
@option.libraries << lib
|
46
63
|
end
|
47
64
|
o.on('--require lib', 'require ruby library') do |lib|
|
48
|
-
|
65
|
+
@option.requires << lib
|
49
66
|
end
|
50
67
|
o.on('--log-level level', "default: warn") do |arg|
|
51
68
|
RaaP.logger.level = arg
|
52
69
|
end
|
53
|
-
o.on('--timeout sec',
|
54
|
-
|
70
|
+
o.on('--timeout sec', Float, "default: #{@option.timeout}") do |arg|
|
71
|
+
@option.timeout = arg
|
72
|
+
end
|
73
|
+
o.on('--size-from int', Integer, "default: #{@option.size_from}") do |arg|
|
74
|
+
@option.size_from = arg
|
55
75
|
end
|
56
|
-
o.on('--size-
|
57
|
-
|
76
|
+
o.on('--size-to int', Integer, "default: #{@option.size_to}") do |arg|
|
77
|
+
@option.size_to = arg
|
58
78
|
end
|
59
|
-
o.on('--size-
|
60
|
-
|
79
|
+
o.on('--size-by int', Integer, "default: #{@option.size_by}") do |arg|
|
80
|
+
@option.size_by = arg
|
61
81
|
end
|
62
|
-
o.on('--
|
63
|
-
|
82
|
+
o.on('--allow-private', "default: #{@option.allow_private}") do
|
83
|
+
@option.allow_private = true
|
64
84
|
end
|
65
|
-
o.on('--
|
66
|
-
|
85
|
+
o.on('--skip tag', "skip case (e.g. `Foo#meth`)") do |tag|
|
86
|
+
@option.skips << tag
|
67
87
|
end
|
68
88
|
end.parse!(@argv)
|
69
89
|
|
70
|
-
|
90
|
+
@option.dirs.each do |dir|
|
71
91
|
RaaP::RBS.loader.add(path: Pathname(dir))
|
72
92
|
end
|
73
|
-
|
93
|
+
@option.libraries.each do |lib|
|
74
94
|
RaaP::RBS.loader.add(library: lib, version: nil)
|
75
95
|
end
|
76
|
-
|
96
|
+
@option.requires.each do |lib|
|
77
97
|
require lib
|
78
98
|
end
|
99
|
+
@option.skips.each do |skip|
|
100
|
+
@skip << skip
|
101
|
+
end
|
102
|
+
@skip.freeze
|
79
103
|
|
80
104
|
self
|
81
105
|
end
|
82
106
|
|
83
107
|
def run
|
108
|
+
Signal.trap(:INT) do
|
109
|
+
puts "Interrupted by SIGINT"
|
110
|
+
report
|
111
|
+
exit 1
|
112
|
+
end
|
113
|
+
|
84
114
|
@argv.map do |tag|
|
85
115
|
case
|
86
116
|
when tag.include?('#')
|
87
|
-
|
117
|
+
run_by(kind: :instance, tag:)
|
88
118
|
when tag.include?('.')
|
89
|
-
|
119
|
+
run_by(kind: :singleton, tag:)
|
90
120
|
when tag.end_with?('*')
|
91
121
|
run_by_type_name_with_search(tag:)
|
92
122
|
else
|
93
123
|
run_by_type_name(tag:)
|
94
124
|
end
|
95
|
-
end.each do |ret|
|
96
|
-
ret.each do |methods|
|
97
|
-
methods.each do |status, method_name, method_type|
|
98
|
-
if status == 1
|
99
|
-
puts "Fail:"
|
100
|
-
puts "def #{method_name}: #{method_type}"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
125
|
end
|
105
126
|
|
106
|
-
|
127
|
+
report
|
107
128
|
end
|
108
129
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
130
|
+
private
|
131
|
+
|
132
|
+
def report
|
133
|
+
i = 0
|
134
|
+
exit_status = 0
|
135
|
+
@results.each do |ret|
|
136
|
+
ret => { method:, properties: }
|
137
|
+
properties.select { |status,| status == 1 }.each do |_, method_name, method_type, reason|
|
138
|
+
i += 1
|
139
|
+
location = if method.alias_of
|
140
|
+
alias_decl = RBS.find_alias_decl(method.defined_in, method_name) or raise "alias decl not found: #{method_name}"
|
141
|
+
alias_decl.location
|
142
|
+
else
|
143
|
+
method_type.location
|
144
|
+
end
|
145
|
+
prefix = method.defs.first.member.kind == :instance ? '' : 'self.'
|
146
|
+
|
147
|
+
puts "\e[41m\e[1m#\e[m\e[1m #{i}) Failure:\e[m"
|
148
|
+
puts
|
149
|
+
puts "def #{prefix}#{method_name}: #{method_type}"
|
150
|
+
puts " in #{location}"
|
151
|
+
puts
|
152
|
+
puts "## Reason"
|
153
|
+
puts
|
154
|
+
puts reason&.string
|
155
|
+
puts
|
156
|
+
exit_status = 1
|
127
157
|
end
|
128
|
-
|
158
|
+
end
|
159
|
+
exit_status
|
129
160
|
end
|
130
161
|
|
131
|
-
def
|
132
|
-
|
162
|
+
def run_by(kind:, tag:)
|
163
|
+
split = kind == :instance ? '#' : '.'
|
164
|
+
t, m = tag.split(split, 2)
|
133
165
|
t or raise
|
134
166
|
m or raise
|
135
167
|
type = RBS.parse_type(t)
|
136
168
|
raise "cannot specified #{type.class}" unless type.respond_to?(:name)
|
169
|
+
|
137
170
|
type = __skip__ = type
|
138
|
-
|
171
|
+
type_name = type.name.absolute!
|
172
|
+
type_to_s = type.to_s.start_with?('::') ? type.to_s : "::#{type}"
|
173
|
+
receiver_type = if kind == :instance
|
174
|
+
Type.new(type_to_s)
|
175
|
+
else
|
176
|
+
Type.new("singleton(#{type_name})")
|
177
|
+
end
|
139
178
|
method_name = m.to_sym
|
140
|
-
definition =
|
179
|
+
definition = if kind == :instance
|
180
|
+
RBS.builder.build_instance(type_name)
|
181
|
+
else
|
182
|
+
RBS.builder.build_singleton(type_name)
|
183
|
+
end
|
184
|
+
|
141
185
|
method = definition.methods[method_name]
|
142
|
-
type_params_decl = definition.type_params_decl
|
143
186
|
raise "`#{tag}` not found" unless method
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
187
|
+
|
188
|
+
if @skip.include?("#{type_name}#{split}#{method_name}")
|
189
|
+
raise "`#{type_name}#{split}#{method_name}` is a method to be skipped"
|
190
|
+
end
|
191
|
+
|
192
|
+
type_params_decl = definition.type_params_decl
|
193
|
+
type_args = type.args
|
194
|
+
|
195
|
+
RaaP.logger.info("# #{type}")
|
196
|
+
@results << {
|
197
|
+
method:,
|
198
|
+
properties: method.method_types.map do |method_type|
|
199
|
+
property(receiver_type:, type_params_decl:, type_args:, method_type:, method_name:)
|
149
200
|
end
|
150
|
-
|
201
|
+
}
|
151
202
|
end
|
152
203
|
|
153
204
|
def run_by_type_name_with_search(tag:)
|
154
205
|
first, _last = tag.split('::')
|
155
|
-
|
156
|
-
RBS.env.class_decls.each do |name, entry|
|
206
|
+
RBS.env.class_decls.each do |name, _entry|
|
157
207
|
if ['', '::'].any? { |pre| name.to_s.match?(/\A#{pre}#{first}\b/) }
|
158
|
-
|
208
|
+
run_by_type_name(tag: name.to_s)
|
159
209
|
end
|
160
210
|
end
|
161
|
-
ret.flatten(1)
|
162
211
|
end
|
163
212
|
|
164
213
|
def run_by_type_name(tag:)
|
165
214
|
type = RBS.parse_type(tag)
|
166
215
|
type = __skip__ = type
|
167
216
|
raise "cannot specified #{type.class}" unless type.respond_to?(:name)
|
168
|
-
type_name = type.name.absolute!
|
169
217
|
|
170
|
-
|
218
|
+
type_name = type.name.absolute!
|
219
|
+
type_args = type.args
|
171
220
|
|
172
221
|
definition = RBS.builder.build_singleton(type_name)
|
173
222
|
type_params_decl = definition.type_params_decl
|
174
223
|
definition.methods.filter_map do |method_name, method|
|
224
|
+
next if @skip.include?("#{type_name.absolute!}.#{method_name}")
|
175
225
|
next unless method.accessibility == :public
|
176
226
|
next if method.defined_in != type_name
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
227
|
+
|
228
|
+
RaaP.logger.info("# #{type_name}.#{method_name}")
|
229
|
+
@results << {
|
230
|
+
method:,
|
231
|
+
properties: method.method_types.map do |method_type|
|
232
|
+
property(receiver_type: Type.new("singleton(#{type.name})"), type_params_decl:, type_args:, method_type:, method_name:)
|
233
|
+
end
|
234
|
+
}
|
183
235
|
end
|
184
236
|
|
185
237
|
definition = RBS.builder.build_instance(type_name)
|
186
238
|
type_params_decl = definition.type_params_decl
|
187
239
|
definition.methods.filter_map do |method_name, method|
|
240
|
+
next if @skip.include?("#{type_name.absolute!}##{method_name}")
|
188
241
|
next unless method.accessibility == :public
|
189
242
|
next if method.defined_in != type_name
|
190
|
-
next if method_name == :fork || method_name == :spawn # TODO: skip solution
|
191
|
-
puts "# #{type_name}##{method_name}"
|
192
|
-
puts
|
193
|
-
ret << method.method_types.map do |method_type|
|
194
|
-
property(receiver_type: Type.new(type.to_s), type_params_decl:, method_type:, method_name:)
|
195
|
-
end
|
196
|
-
end
|
197
243
|
|
198
|
-
|
244
|
+
RaaP.logger.info("# #{type_name}##{method_name}")
|
245
|
+
@results << {
|
246
|
+
method:,
|
247
|
+
properties: method.method_types.map do |method_type|
|
248
|
+
property(receiver_type: Type.new(type.name), type_params_decl:, type_args:, method_type:, method_name:)
|
249
|
+
end
|
250
|
+
}
|
251
|
+
end
|
199
252
|
end
|
200
253
|
|
201
|
-
def property(receiver_type:, type_params_decl:, method_type:, method_name:)
|
254
|
+
def property(receiver_type:, type_params_decl:, type_args:, method_type:, method_name:)
|
202
255
|
rtype = __skip__ = receiver_type.type
|
203
256
|
if receiver_type.type.instance_of?(::RBS::Types::ClassSingleton)
|
204
257
|
prefix = 'self.'
|
205
|
-
type_args = []
|
206
258
|
else
|
207
259
|
prefix = ''
|
208
|
-
type_args = rtype.args
|
209
260
|
end
|
210
|
-
|
261
|
+
type_params_decl.each_with_index do |_, i|
|
262
|
+
if rtype.instance_of?(::RBS::Types::ClassInstance)
|
263
|
+
rtype.args[i] = type_args[i] || ::RBS::Types::Bases::Any.new(location: nil)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
RaaP.logger.info("## def #{prefix}#{method_name}: #{method_type}")
|
211
267
|
status = 0
|
212
|
-
|
268
|
+
reason = nil
|
269
|
+
prop = MethodProperty.new(
|
213
270
|
receiver_type:,
|
214
|
-
method_name
|
271
|
+
method_name:,
|
215
272
|
method_type: MethodType.new(
|
216
273
|
method_type,
|
217
274
|
type_params_decl:,
|
@@ -220,46 +277,59 @@ module RaaP
|
|
220
277
|
instance_type: ::RBS::Types::ClassInstance.new(name: rtype.name, args: type_args, location: nil),
|
221
278
|
class_type: ::RBS::Types::ClassSingleton.new(name: rtype.name, location: nil),
|
222
279
|
),
|
223
|
-
size_step:
|
224
|
-
timeout:
|
280
|
+
size_step: @option.size_from.step(to: @option.size_to, by: @option.size_by),
|
281
|
+
timeout: @option.timeout,
|
225
282
|
allow_private: true,
|
226
|
-
)
|
283
|
+
)
|
284
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
285
|
+
stats = prop.run do |called|
|
227
286
|
case called
|
228
287
|
in Result::Success => s
|
229
288
|
print '.'
|
230
289
|
RaaP.logger.debug { "Success: #{s.called_str}" }
|
231
290
|
in Result::Failure => f
|
232
291
|
puts 'F'
|
233
|
-
|
234
|
-
if e = f.exception
|
292
|
+
if (e = f.exception)
|
235
293
|
RaaP.logger.debug { "Failure: [#{e.class}] #{e.message}" }
|
294
|
+
RaaP.logger.debug { e.backtrace.join("\n") }
|
236
295
|
end
|
237
|
-
puts
|
238
296
|
RaaP.logger.debug { PP.pp(f.symbolic_call, ''.dup) }
|
239
|
-
|
240
|
-
puts
|
241
|
-
puts
|
242
|
-
puts
|
243
|
-
puts
|
297
|
+
reason = StringIO.new
|
298
|
+
reason.puts "Failed in case of `#{f.called_str}`"
|
299
|
+
reason.puts
|
300
|
+
reason.puts "### Repro"
|
301
|
+
reason.puts
|
302
|
+
reason.puts "```rb"
|
303
|
+
reason.puts SymbolicCaller.new(f.symbolic_call).to_lines.join("\n")
|
304
|
+
reason.puts "```"
|
244
305
|
status = 1
|
245
306
|
throw :break
|
246
307
|
in Result::Skip => s
|
247
308
|
print 'S'
|
248
|
-
RaaP.logger.debug {
|
249
|
-
RaaP.logger.debug("Skip:
|
309
|
+
RaaP.logger.debug { "\n```\n#{SymbolicCaller.new(s.symbolic_call).to_lines.join("\n")}\n```" }
|
310
|
+
RaaP.logger.debug("Skip: #{s.exception.detailed_message}")
|
250
311
|
RaaP.logger.debug(s.exception.backtrace.join("\n"))
|
251
312
|
in Result::Exception => e
|
252
313
|
print 'E'
|
253
|
-
RaaP.logger.debug {
|
254
|
-
RaaP.logger.debug("Exception:
|
314
|
+
RaaP.logger.debug { "\n```\n#{SymbolicCaller.new(e.symbolic_call).to_lines.join("\n")}\n```" }
|
315
|
+
RaaP.logger.debug("Exception: #{e.exception.detailed_message}")
|
255
316
|
RaaP.logger.debug(e.exception.backtrace.join("\n"))
|
256
317
|
end
|
257
318
|
end
|
319
|
+
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
258
320
|
puts
|
259
|
-
|
260
|
-
|
321
|
+
time_diff = end_time - start_time
|
322
|
+
time = ", time: #{(time_diff * 1000).round}ms"
|
323
|
+
stats_log = "success: #{stats.success}, skip: #{stats.skip}, exception: #{stats.exception}#{time}"
|
324
|
+
RaaP.logger.info(stats_log)
|
325
|
+
|
326
|
+
if status == 0 && stats.success.zero? && !stats.break
|
327
|
+
status = 1
|
328
|
+
reason = StringIO.new
|
329
|
+
reason.puts "Never succeeded => #{stats_log}"
|
330
|
+
end
|
261
331
|
|
262
|
-
[status, method_name, method_type]
|
332
|
+
[status, method_name, method_type, reason]
|
263
333
|
end
|
264
334
|
end
|
265
335
|
end
|
data/lib/raap/function_type.rb
CHANGED
@@ -6,35 +6,39 @@ module RaaP
|
|
6
6
|
@fun = fun
|
7
7
|
end
|
8
8
|
|
9
|
-
def pick_arguments(size: 10
|
10
|
-
|
11
|
-
|
9
|
+
def pick_arguments(size: 10)
|
10
|
+
SymbolicCaller.new(arguments_to_symbolic_call(size:)).eval
|
11
|
+
end
|
12
|
+
|
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:)
|
12
16
|
|
13
17
|
[a, k]
|
14
18
|
end
|
15
19
|
|
16
20
|
private
|
17
21
|
|
18
|
-
def
|
22
|
+
def to_symbolic_call_recursive(type, size:)
|
19
23
|
case
|
20
24
|
when type.nil?
|
21
25
|
nil
|
22
26
|
when type.respond_to?(:each_pair)
|
23
|
-
type.each_pair.to_h { |k, v| [k,
|
27
|
+
type.each_pair.to_h { |k, v| [k, to_symbolic_call_recursive(v, size:)] }
|
24
28
|
when type.respond_to?(:each)
|
25
|
-
type.each.map { |v|
|
29
|
+
type.each.map { |v| to_symbolic_call_recursive(v, size:) }
|
26
30
|
else
|
27
|
-
type.
|
31
|
+
type.to_symbolic_call(size:)
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
31
35
|
def build_args_type
|
32
36
|
reqs = @fun.required_positionals.map { |param| Type.new(param.type) }
|
33
37
|
tras = @fun.trailing_positionals.map { |param| Type.new(param.type) }
|
34
|
-
sampled_optional_positionals = @fun.optional_positionals.
|
38
|
+
sampled_optional_positionals = @fun.optional_positionals.take(Random.rand(@fun.optional_positionals.length + 1))
|
35
39
|
opts = sampled_optional_positionals.map { |param| Type.new(param.type) }
|
36
40
|
rest = []
|
37
|
-
if param = @fun.rest_positionals
|
41
|
+
if (param = @fun.rest_positionals)
|
38
42
|
rest = Array.new(Random.rand(0..3)) { Type.new(param.type) }
|
39
43
|
end
|
40
44
|
[reqs, opts, rest, tras].flatten
|
@@ -45,7 +49,7 @@ module RaaP
|
|
45
49
|
rand = Random.rand(@fun.optional_keywords.length + 1)
|
46
50
|
opts = @fun.optional_keywords.to_a.sample(rand).to_h { |name, param| [name, Type.new(param.type)] }
|
47
51
|
kwargs = reqs.to_h.merge(opts)
|
48
|
-
if param = @fun.rest_keywords
|
52
|
+
if (param = @fun.rest_keywords)
|
49
53
|
keys = Array.new(Random.rand(0..3)) do
|
50
54
|
random_key = nil
|
51
55
|
loop do
|