rails_proof 1.0.0 → 1.1.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f5bc052c6972058b263ddf1afd897bd78eabda2639d407fc3ec4f652abed5eb9
|
|
4
|
+
data.tar.gz: 65317ae8a4a383083becd070161200fedbe24f2d884e7c9e0da431b09572abec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 15cfa004f2adf092a455e0d86d249364d0ff1a25fbfbced29f0a7067c22e519993013209500c86deae31e190157030723dcdc2360d42860ddbe40b3790a72bce
|
|
7
|
+
data.tar.gz: b88cc75ef1f4bd2d6bd91ba54d3288484ca0604124874f92d51ce0d45473b7428febb482a41d3b00217bfffd9d9f77288da9b0e264c5b1f38f14a2c6d3b5abf2
|
|
@@ -11,6 +11,7 @@ require "rails_proof/controller_test_coverage_plan"
|
|
|
11
11
|
require "rails_proof/controller_test_writer"
|
|
12
12
|
require "rails_proof/ai_test_planner"
|
|
13
13
|
require "rails_proof/ai_test_executor"
|
|
14
|
+
require "rails_proof/test_file_inserter"
|
|
14
15
|
|
|
15
16
|
module RailsProof
|
|
16
17
|
class TestGenerator < Rails::Generators::Base
|
|
@@ -170,10 +171,12 @@ module RailsProof
|
|
|
170
171
|
@controller_inspector = RailsProof::ControllerInspector.new(
|
|
171
172
|
@controller_class
|
|
172
173
|
)
|
|
174
|
+
|
|
173
175
|
@controller_test_plan = RailsProof::ControllerTestPlan.new(
|
|
174
176
|
@controller_inspector
|
|
175
177
|
)
|
|
176
|
-
|
|
178
|
+
|
|
179
|
+
@controller_test_coverage_plan =
|
|
177
180
|
RailsProof::ControllerTestCoveragePlan.new(
|
|
178
181
|
@controller_test_plan,
|
|
179
182
|
@test_inspector
|
|
@@ -181,7 +184,7 @@ module RailsProof
|
|
|
181
184
|
else
|
|
182
185
|
@controller_inspector = nil
|
|
183
186
|
@controller_test_plan = nil
|
|
184
|
-
@
|
|
187
|
+
@controller_test_coverage_plan = nil
|
|
185
188
|
end
|
|
186
189
|
end
|
|
187
190
|
|
|
@@ -334,10 +337,10 @@ module RailsProof
|
|
|
334
337
|
end
|
|
335
338
|
|
|
336
339
|
say "Coverage:"
|
|
337
|
-
say " Covered: #{@
|
|
338
|
-
say " Missing: #{@
|
|
340
|
+
say " Covered: #{@controller_test_coverage_plan.covered_count}"
|
|
341
|
+
say " Missing: #{@controller_test_coverage_plan.missing_count}"
|
|
339
342
|
|
|
340
|
-
@
|
|
343
|
+
@controller_test_coverage_plan.missing_concerns.each do |concern|
|
|
341
344
|
say " #{concern[:description]}"
|
|
342
345
|
end
|
|
343
346
|
end
|
|
@@ -509,10 +512,10 @@ module RailsProof
|
|
|
509
512
|
)
|
|
510
513
|
|
|
511
514
|
if @absolute_test_file_path.file?
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
"
|
|
515
|
-
|
|
515
|
+
insert_rendered_tests(
|
|
516
|
+
writer.render,
|
|
517
|
+
test_class_name: "#{@current_target.class_name}Test",
|
|
518
|
+
superclass: "ActiveSupport::TestCase"
|
|
516
519
|
)
|
|
517
520
|
else
|
|
518
521
|
create_file @test_file_path, writer.render_test_file
|
|
@@ -521,22 +524,38 @@ module RailsProof
|
|
|
521
524
|
|
|
522
525
|
def write_missing_controller_tests
|
|
523
526
|
return unless @controller_class
|
|
524
|
-
return if @
|
|
527
|
+
return if @controller_test_coverage_plan.missing_count.zero?
|
|
525
528
|
|
|
526
529
|
writer = RailsProof::ControllerTestWriter.new(
|
|
527
530
|
controller_class_name: @current_target.class_name,
|
|
528
|
-
concerns: @
|
|
531
|
+
concerns: @controller_test_coverage_plan.missing_concerns
|
|
529
532
|
)
|
|
530
533
|
|
|
531
534
|
if @absolute_test_file_path.file?
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
"
|
|
535
|
-
|
|
535
|
+
insert_rendered_tests(
|
|
536
|
+
writer.render,
|
|
537
|
+
test_class_name: "#{@current_target.class_name}Test",
|
|
538
|
+
superclass: "ActionDispatch::IntegrationTest"
|
|
536
539
|
)
|
|
537
540
|
else
|
|
538
541
|
create_file @test_file_path, writer.render_test_file
|
|
539
542
|
end
|
|
540
543
|
end
|
|
544
|
+
|
|
545
|
+
def insert_rendered_tests(
|
|
546
|
+
rendered_test,
|
|
547
|
+
test_class_name:,
|
|
548
|
+
superclass:
|
|
549
|
+
)
|
|
550
|
+
source = @absolute_test_file_path.read
|
|
551
|
+
|
|
552
|
+
updated = RailsProof::TestFileInserter.new(
|
|
553
|
+
source: source,
|
|
554
|
+
test_class_name: test_class_name,
|
|
555
|
+
superclass: superclass
|
|
556
|
+
).insert(rendered_test)
|
|
557
|
+
|
|
558
|
+
@absolute_test_file_path.write(updated)
|
|
559
|
+
end
|
|
541
560
|
end
|
|
542
561
|
end
|
|
@@ -4,6 +4,7 @@ require "rails_proof/ai_test_writer"
|
|
|
4
4
|
require "rails_proof/ai_concern_filter"
|
|
5
5
|
require "rails_proof/test_runner"
|
|
6
6
|
require "rails_proof/review_store"
|
|
7
|
+
require "rails_proof/test_file_inserter"
|
|
7
8
|
|
|
8
9
|
module RailsProof
|
|
9
10
|
class AiTestExecutor
|
|
@@ -34,13 +35,13 @@ module RailsProof
|
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
attr_reader :root,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
:target_path,
|
|
39
|
+
:test_file_path,
|
|
40
|
+
:test_class_name,
|
|
41
|
+
:superclass,
|
|
42
|
+
:concerns,
|
|
43
|
+
:runner_class,
|
|
44
|
+
:review_store
|
|
44
45
|
|
|
45
46
|
def initialize(
|
|
46
47
|
root:,
|
|
@@ -124,7 +125,10 @@ module RailsProof
|
|
|
124
125
|
test_output: test_result.output
|
|
125
126
|
)
|
|
126
127
|
|
|
127
|
-
errors = [
|
|
128
|
+
errors = [
|
|
129
|
+
"candidate test failed against application"
|
|
130
|
+
]
|
|
131
|
+
|
|
128
132
|
errors << persistence_error if persistence_error
|
|
129
133
|
|
|
130
134
|
Result.new(
|
|
@@ -199,7 +203,9 @@ module RailsProof
|
|
|
199
203
|
return unless state
|
|
200
204
|
|
|
201
205
|
if state[:existed]
|
|
202
|
-
absolute_test_file_path.write(
|
|
206
|
+
absolute_test_file_path.write(
|
|
207
|
+
state[:content]
|
|
208
|
+
)
|
|
203
209
|
elsif absolute_test_file_path.exist?
|
|
204
210
|
absolute_test_file_path.delete
|
|
205
211
|
end
|
|
@@ -213,25 +219,27 @@ module RailsProof
|
|
|
213
219
|
)
|
|
214
220
|
|
|
215
221
|
if absolute_test_file_path.file?
|
|
216
|
-
insert_into_existing_file(
|
|
222
|
+
insert_into_existing_file(
|
|
223
|
+
writer.render
|
|
224
|
+
)
|
|
217
225
|
else
|
|
218
226
|
absolute_test_file_path.dirname.mkpath
|
|
219
|
-
|
|
227
|
+
|
|
228
|
+
absolute_test_file_path.write(
|
|
229
|
+
writer.render_test_file
|
|
230
|
+
)
|
|
220
231
|
end
|
|
221
232
|
end
|
|
222
233
|
|
|
223
234
|
def insert_into_existing_file(rendered_test)
|
|
224
235
|
source = absolute_test_file_path.read
|
|
225
236
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
/^end\s*\z/,
|
|
233
|
-
"\n#{rendered_test}\nend"
|
|
234
|
-
)
|
|
237
|
+
updated =
|
|
238
|
+
RailsProof::TestFileInserter.new(
|
|
239
|
+
source: source,
|
|
240
|
+
test_class_name: test_class_name,
|
|
241
|
+
superclass: superclass
|
|
242
|
+
).insert(rendered_test)
|
|
235
243
|
|
|
236
244
|
absolute_test_file_path.write(updated)
|
|
237
245
|
end
|
|
@@ -245,7 +253,10 @@ module RailsProof
|
|
|
245
253
|
test_class_name: test_class_name
|
|
246
254
|
)
|
|
247
255
|
|
|
248
|
-
[
|
|
256
|
+
[
|
|
257
|
+
path,
|
|
258
|
+
nil
|
|
259
|
+
]
|
|
249
260
|
rescue StandardError => error
|
|
250
261
|
[
|
|
251
262
|
nil,
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module RailsProof
|
|
2
|
+
class TestFileInserter
|
|
3
|
+
class Error < StandardError
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
attr_reader :source,
|
|
7
|
+
:test_class_name,
|
|
8
|
+
:superclass
|
|
9
|
+
|
|
10
|
+
def initialize(
|
|
11
|
+
source:,
|
|
12
|
+
test_class_name:,
|
|
13
|
+
superclass:
|
|
14
|
+
)
|
|
15
|
+
@source = source
|
|
16
|
+
@test_class_name = test_class_name
|
|
17
|
+
@superclass = superclass
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def insert(rendered_test)
|
|
21
|
+
lines = source.lines
|
|
22
|
+
|
|
23
|
+
class_index, class_indent = find_test_class(lines)
|
|
24
|
+
|
|
25
|
+
closing_index = find_class_end(
|
|
26
|
+
lines,
|
|
27
|
+
class_index,
|
|
28
|
+
class_indent
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
indented_test = indent_rendered_test(
|
|
32
|
+
rendered_test,
|
|
33
|
+
class_indent
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
lines.insert(
|
|
37
|
+
closing_index,
|
|
38
|
+
"\n#{indented_test.rstrip}\n"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
lines.join
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def find_test_class(lines)
|
|
47
|
+
exact_name = test_class_name
|
|
48
|
+
short_name = test_class_name.split("::").last
|
|
49
|
+
|
|
50
|
+
exact_matches = class_matches(
|
|
51
|
+
lines,
|
|
52
|
+
exact_name
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
matches =
|
|
56
|
+
if exact_matches.any?
|
|
57
|
+
exact_matches
|
|
58
|
+
else
|
|
59
|
+
class_matches(
|
|
60
|
+
lines,
|
|
61
|
+
short_name
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if matches.empty?
|
|
66
|
+
raise Error,
|
|
67
|
+
"RailsProof could not find " \
|
|
68
|
+
"#{test_class_name} < #{superclass}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if matches.count > 1
|
|
72
|
+
raise Error,
|
|
73
|
+
"RailsProof found multiple candidate " \
|
|
74
|
+
"test classes for #{test_class_name}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
matches.first
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def class_matches(lines, class_name)
|
|
81
|
+
pattern =
|
|
82
|
+
/\A(?<indent>[ \t]*)class\s+#{Regexp.escape(class_name)}\s*<\s*#{Regexp.escape(superclass)}\s*(?:#.*)?\r?\n?\z/
|
|
83
|
+
|
|
84
|
+
lines.each_with_index.filter_map do |line, index|
|
|
85
|
+
match = line.match(pattern)
|
|
86
|
+
next unless match
|
|
87
|
+
|
|
88
|
+
[
|
|
89
|
+
index,
|
|
90
|
+
match[:indent]
|
|
91
|
+
]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def find_class_end(
|
|
96
|
+
lines,
|
|
97
|
+
class_index,
|
|
98
|
+
class_indent
|
|
99
|
+
)
|
|
100
|
+
pattern =
|
|
101
|
+
/\A#{Regexp.escape(class_indent)}end(?:\s*#.*)?\s*\z/
|
|
102
|
+
|
|
103
|
+
closing_index =
|
|
104
|
+
((class_index + 1)...lines.length).find do |index|
|
|
105
|
+
lines[index].match?(pattern)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
return closing_index if closing_index
|
|
109
|
+
|
|
110
|
+
raise Error,
|
|
111
|
+
"RailsProof could not find the end of #{test_class_name}"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def indent_rendered_test(
|
|
115
|
+
rendered_test,
|
|
116
|
+
class_indent
|
|
117
|
+
)
|
|
118
|
+
lines = rendered_test.rstrip.lines
|
|
119
|
+
|
|
120
|
+
nonblank_lines = lines.reject do |line|
|
|
121
|
+
line.strip.empty?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
source_indent =
|
|
125
|
+
nonblank_lines
|
|
126
|
+
.map { |line| line[/\A[ \t]*/].length }
|
|
127
|
+
.min || 0
|
|
128
|
+
|
|
129
|
+
target_indent = "#{class_indent} "
|
|
130
|
+
|
|
131
|
+
lines.map do |line|
|
|
132
|
+
if line.strip.empty?
|
|
133
|
+
""
|
|
134
|
+
else
|
|
135
|
+
content = line[source_indent..]
|
|
136
|
+
|
|
137
|
+
"#{target_indent}#{content.rstrip}"
|
|
138
|
+
end
|
|
139
|
+
end.join("\n")
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
data/lib/rails_proof/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_proof
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oak Harbor Ventures, LLC
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/rails_proof/review_store.rb
|
|
64
64
|
- lib/rails_proof/target_discovery.rb
|
|
65
65
|
- lib/rails_proof/test_coverage_plan.rb
|
|
66
|
+
- lib/rails_proof/test_file_inserter.rb
|
|
66
67
|
- lib/rails_proof/test_inspector.rb
|
|
67
68
|
- lib/rails_proof/test_runner.rb
|
|
68
69
|
- lib/rails_proof/test_writer.rb
|