create_tests 1.1.0 → 1.2.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/README.md +39 -7
- data/bin/create_tests +17 -0
- data/lib/create-tests/create_helper.rb +66 -0
- data/lib/create-tests/create_test.rb +264 -70
- data/lib/create-tests/from.rb +47 -12
- data/lib/create-tests/resource_chain.rb +14 -2
- data/lib/create-tests/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: adf779b9d966308976925449218e2f71071441bc665a7c5ecdd79c9ec25c477e
|
|
4
|
+
data.tar.gz: 49cd07ebd23c1dd406ee5db3af61c3a761615ecec746c451d059717ad8a668dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 948a204d7595c2b5e5ddbd42e18029b870f0fd9212df3a20dd970b29416d69306332b2f31ecd57fc9b82d8a1ad3b6e15424312248a5c80d26f9ae0ca14e90f00
|
|
7
|
+
data.tar.gz: 9510e4c3f35eba997841db074bd32b8ef07712bacd88cda7bb49581deea70d1381148d833e3791c5b3c8b21a2d7259fb2fffacfae157dfd15080ad46ca9e5d9c
|
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|

|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
Create RSpec tests automatically from Request Hash files. Perfect to be used with the result from importing a Swagger / OpenAPI file using the [open_api_import](https://github.com/MarioRuiz/open_api_import) gem.
|
|
11
|
+
Create RSpec or Minitest tests automatically from Request Hash files. Perfect to be used with the result from importing a Swagger / OpenAPI file using the [open_api_import](https://github.com/MarioRuiz/open_api_import) gem.
|
|
12
12
|
|
|
13
13
|
We strongly recommend using [nice_http](https://github.com/MarioRuiz/nice_http) for your tests together with [nice_hash](https://github.com/MarioRuiz/nice_hash) and [string_pattern](https://github.com/MarioRuiz/string_pattern).
|
|
14
14
|
|
|
@@ -29,8 +29,8 @@ The gem uses [rufo](https://github.com/ruby-formatter/rufo) to format generated
|
|
|
29
29
|
After installation you can run using the command line executable or from Ruby code.
|
|
30
30
|
|
|
31
31
|
The execution will create:
|
|
32
|
-
- A `spec/` folder with one RSpec test file per API endpoint
|
|
33
|
-
- A `spec/helper.rb` with stub methods for required parameters
|
|
32
|
+
- A `spec/` folder with one RSpec test file per API endpoint (or `test/` with `*_test.rb` when using Minitest)
|
|
33
|
+
- A `spec/helper.rb` (or `test/helper.rb`) with stub methods for required parameters
|
|
34
34
|
- A `settings/general.rb` with NiceHttp configuration boilerplate
|
|
35
35
|
|
|
36
36
|
### Command line
|
|
@@ -44,6 +44,10 @@ Usage: create_tests [requests_file] [options]
|
|
|
44
44
|
-d, --dry_run Preview which files would be created or modified
|
|
45
45
|
--cleanup_each Generate cleanup in after(:each) instead of after(:all)
|
|
46
46
|
--no_cleanup Do not generate setup/cleanup hooks
|
|
47
|
+
--spec_dir DIR Output directory for test files (default: ./spec, or ./test with --minitest)
|
|
48
|
+
--settings_dir DIR Output directory for settings (default: ./settings)
|
|
49
|
+
--only KIND Generate only these test kinds (repeatable or comma-separated)
|
|
50
|
+
--minitest Generate Minitest tests instead of RSpec
|
|
47
51
|
-v, --version Show version
|
|
48
52
|
```
|
|
49
53
|
|
|
@@ -93,7 +97,7 @@ Required keyword parameters from open_api_import `create_constants: true` (e.g.
|
|
|
93
97
|
|
|
94
98
|
Accepts three options: `:overwrite`, `:dont_overwrite` and `:append`. Default: `:append`.
|
|
95
99
|
|
|
96
|
-
- **append**: If the test file already exists, only missing tests will be added. Existing content is preserved
|
|
100
|
+
- **append**: If the test file already exists, only missing tests will be added. Existing content is preserved. For `helper/setup.rb` and `helper/cleanup.rb`, only missing `setup_*` / `cleanup_*` methods are inserted; existing method bodies are left alone. If every method already exists, the file is not rewritten. If the file doesn't exist, it will be created with all tests.
|
|
97
101
|
|
|
98
102
|
- **dont_overwrite**: If the test file exists, no changes will be made. If it doesn't exist, it will be created.
|
|
99
103
|
|
|
@@ -122,12 +126,40 @@ result.each { |path, content| puts "#{path}: #{content.length} bytes" }
|
|
|
122
126
|
|
|
123
127
|
### spec_dir / settings_dir
|
|
124
128
|
|
|
125
|
-
Custom output directories (default: `./spec` and `./settings`).
|
|
129
|
+
Custom output directories (default: `./spec` and `./settings`). With `test: :minitest`, the default test directory is `./test` unless you pass an explicit `spec_dir`.
|
|
126
130
|
|
|
127
131
|
```ruby
|
|
128
132
|
CreateTests.from "./requests/uber.yaml.rb", spec_dir: "./test/spec", settings_dir: "./test/config"
|
|
129
133
|
```
|
|
130
134
|
|
|
135
|
+
### only
|
|
136
|
+
|
|
137
|
+
Limit which example kinds are generated. Default `nil` means all kinds. Accepts a symbol, an array, or a comma-separated string. Unknown kinds raise.
|
|
138
|
+
|
|
139
|
+
Kinds: `success`, `auth`, `required_params`, `mock`, `variations`, `invalid_fields`, `required_data`.
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
CreateTests.from "./requests/uber.yaml.rb", only: [:success, :auth]
|
|
143
|
+
CreateTests.from "./requests/uber.yaml.rb", only: "success,mock"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
create_tests ./requests/uber.yaml.rb --only success --only auth
|
|
148
|
+
create_tests ./requests/uber.yaml.rb --only success,auth
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### test / Minitest
|
|
152
|
+
|
|
153
|
+
Default is `:rspec`. Pass `test: :minitest` (or `--minitest`) to generate Minitest files (`*_test.rb`) with `setup` / `teardown` instead of RSpec hooks, and `assert_*` / `refute_*` instead of `expect`.
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
CreateTests.from "./requests/uber.yaml.rb", test: :minitest
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
create_tests ./requests/uber.yaml.rb --minitest
|
|
161
|
+
```
|
|
162
|
+
|
|
131
163
|
### cleanup
|
|
132
164
|
|
|
133
165
|
Controls whether and how prerequisite setup/cleanup hooks are generated. Default: `:after_all`.
|
|
@@ -145,7 +177,7 @@ CreateTests.from "./requests/netapp.json.rb", cleanup: false # no cleanup
|
|
|
145
177
|
```ruby
|
|
146
178
|
before(:all) do
|
|
147
179
|
@http = NiceHttp.new()
|
|
148
|
-
@volume_name = @volume_name + "-
|
|
180
|
+
@volume_name = @volume_name + "-createorupda"
|
|
149
181
|
expect(Helper.setup_capacity_pools(@http, ...).state).to eq "Succeeded"
|
|
150
182
|
@request = Volumes.create_or_update(...)
|
|
151
183
|
end
|
|
@@ -160,7 +192,7 @@ end
|
|
|
160
192
|
|
|
161
193
|
```ruby
|
|
162
194
|
before(:all) do
|
|
163
|
-
@snapshot_name = @snapshot_name + "-
|
|
195
|
+
@snapshot_name = @snapshot_name + "-delete"
|
|
164
196
|
expect(Helper.setup_volumes(@http, ...).state).to eq "Succeeded"
|
|
165
197
|
@request = Snapshots.delete(...)
|
|
166
198
|
end
|
data/bin/create_tests
CHANGED
|
@@ -37,6 +37,23 @@ optparse = OptionParser.new do |opts|
|
|
|
37
37
|
options[:cleanup] = false
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
opts.on("--spec_dir DIR", "Output directory for generated test files (default: ./spec, or ./test with --minitest)") do |dir|
|
|
41
|
+
options[:spec_dir] = dir
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
opts.on("--settings_dir DIR", "Output directory for generated settings files (default: ./settings)") do |dir|
|
|
45
|
+
options[:settings_dir] = dir
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
opts.on("--only KIND", "Generate only these test kinds (repeatable or comma-separated). Kinds: success, auth, required_params, mock, variations, invalid_fields, required_data") do |kind|
|
|
49
|
+
options[:only] ||= []
|
|
50
|
+
options[:only].concat(kind.split(",").map { |s| s.strip.to_sym })
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
opts.on("--minitest", "Generate Minitest tests instead of RSpec") do
|
|
54
|
+
options[:test] = :minitest
|
|
55
|
+
end
|
|
56
|
+
|
|
40
57
|
opts.on("-v", "--version", "Show version") do
|
|
41
58
|
puts "create_tests #{CreateTests::VERSION}"
|
|
42
59
|
exit
|
|
@@ -125,5 +125,71 @@ class CreateTests
|
|
|
125
125
|
end
|
|
126
126
|
best
|
|
127
127
|
end
|
|
128
|
+
|
|
129
|
+
# Append only missing setup_/cleanup_ methods from generated content into an
|
|
130
|
+
# existing file. Existing method bodies are left untouched.
|
|
131
|
+
# @return [Array(String, Boolean)] merged content and whether anything was added
|
|
132
|
+
private def append_missing_chain_methods(existing_txt, generated_txt)
|
|
133
|
+
method_blocks = extract_chain_method_blocks(generated_txt)
|
|
134
|
+
missing = method_blocks.reject { |blk| existing_txt.include?("def self.#{blk[:name]}(") }
|
|
135
|
+
return [existing_txt, false] if missing.empty?
|
|
136
|
+
|
|
137
|
+
output = existing_txt.dup
|
|
138
|
+
insert = missing.map { |blk| blk[:text] }.join
|
|
139
|
+
|
|
140
|
+
if output.match?(/\bmodule\s+Helper\b/)
|
|
141
|
+
if output.match?(/\s*end\s*\Z/)
|
|
142
|
+
output.sub!(/\s*end\s*\Z/, "\n#{insert}\nend\n")
|
|
143
|
+
else
|
|
144
|
+
output << "\n#{insert}"
|
|
145
|
+
end
|
|
146
|
+
else
|
|
147
|
+
# Preserve leading require (e.g. ostruct) from generated content when wrapping.
|
|
148
|
+
require_line = generated_txt[/^require[^\n]*\n/]
|
|
149
|
+
prefix = require_line && !output.include?(require_line.strip) ? require_line : ""
|
|
150
|
+
output = "#{prefix}module Helper\n#{output.chomp}\n#{insert}\nend\n"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
[output, true]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private def extract_chain_method_blocks(generated_txt)
|
|
157
|
+
blocks = []
|
|
158
|
+
lines = generated_txt.lines
|
|
159
|
+
i = 0
|
|
160
|
+
while i < lines.size
|
|
161
|
+
if lines[i] =~ /\A#/
|
|
162
|
+
comment_start = i
|
|
163
|
+
i += 1 while i < lines.size && lines[i] =~ /\A#/
|
|
164
|
+
if i < lines.size && lines[i] =~ /\Adef self\.(setup_\w+|cleanup_\w+)\(/
|
|
165
|
+
name = $1
|
|
166
|
+
start = comment_start
|
|
167
|
+
i += 1
|
|
168
|
+
depth = 1
|
|
169
|
+
while i < lines.size && depth > 0
|
|
170
|
+
depth += 1 if lines[i] =~ /\A\s*def\b/
|
|
171
|
+
depth -= 1 if lines[i] =~ /\Aend\b/
|
|
172
|
+
i += 1
|
|
173
|
+
end
|
|
174
|
+
blocks << { name: name, text: lines[start...i].join }
|
|
175
|
+
next
|
|
176
|
+
end
|
|
177
|
+
elsif lines[i] =~ /\Adef self\.(setup_\w+|cleanup_\w+)\(/
|
|
178
|
+
name = $1
|
|
179
|
+
start = i
|
|
180
|
+
i += 1
|
|
181
|
+
depth = 1
|
|
182
|
+
while i < lines.size && depth > 0
|
|
183
|
+
depth += 1 if lines[i] =~ /\A\s*def\b/
|
|
184
|
+
depth -= 1 if lines[i] =~ /\Aend\b/
|
|
185
|
+
i += 1
|
|
186
|
+
end
|
|
187
|
+
blocks << { name: name, text: lines[start...i].join }
|
|
188
|
+
next
|
|
189
|
+
end
|
|
190
|
+
i += 1
|
|
191
|
+
end
|
|
192
|
+
blocks
|
|
193
|
+
end
|
|
128
194
|
end
|
|
129
195
|
end
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
|
|
2
2
|
class CreateTests
|
|
3
3
|
|
|
4
|
+
TEST_KINDS = %i[
|
|
5
|
+
success auth required_params mock variations invalid_fields required_data
|
|
6
|
+
].freeze
|
|
7
|
+
|
|
4
8
|
class << self
|
|
5
9
|
|
|
6
10
|
# Return true or false and the test source code
|
|
7
|
-
private def create_test(module_txt, method_txt, method_obj, test_txt, settings_relative_path: '../../settings/general', cleanup: :after_all)
|
|
11
|
+
private def create_test(module_txt, method_txt, method_obj, test_txt, settings_relative_path: '../../settings/general', cleanup: :after_all, test: :rspec, only: nil)
|
|
8
12
|
unless cleanup == false || [:after_all, :after_each].include?(cleanup)
|
|
9
13
|
message = "** Wrong cleanup parameter: #{cleanup}"
|
|
10
14
|
raise message
|
|
11
15
|
end
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
only_kinds = normalize_only(only)
|
|
18
|
+
|
|
19
|
+
modified = false
|
|
14
20
|
mod_name = module_txt.scan(/::(\w+)$/).join
|
|
15
21
|
req_txt = "#{method_txt}("
|
|
16
22
|
params = []
|
|
@@ -38,7 +44,7 @@ class CreateTests
|
|
|
38
44
|
|
|
39
45
|
req_txt = "#{mod_name}.#{req_txt}"
|
|
40
46
|
params_declaration_txt = ""
|
|
41
|
-
## todo: add param in case of :append
|
|
47
|
+
## todo: add param in case of :append
|
|
42
48
|
params.each do |p|
|
|
43
49
|
params_declaration_txt << "#{p} = Helper.#{p.gsub('@','')}(@http)\n"
|
|
44
50
|
@params << p
|
|
@@ -58,8 +64,7 @@ class CreateTests
|
|
|
58
64
|
needs_target_setup = target_resource && [:delete, :get, :patch].include?(request[:method])
|
|
59
65
|
parent_resource = resource_chain.last
|
|
60
66
|
|
|
61
|
-
method_suffix = method_txt.to_s.
|
|
62
|
-
method_suffix = "-#{method_suffix}"
|
|
67
|
+
method_suffix = "-#{method_txt.to_s.gsub('_', '')[0, 12]}"
|
|
63
68
|
|
|
64
69
|
setup_before_all_txt = ""
|
|
65
70
|
setup_before_each_txt = ""
|
|
@@ -67,33 +72,39 @@ class CreateTests
|
|
|
67
72
|
after_all_txt = ""
|
|
68
73
|
|
|
69
74
|
if is_delete && target_resource && parent_resource
|
|
70
|
-
setup_before_all_txt = "
|
|
71
|
-
setup_before_each_txt = "
|
|
75
|
+
setup_before_all_txt = "#{assert_eq("Helper.setup_#{parent_resource[:resource]}(@http, #{parent_resource[:params_up_to].join(', ')}).state", "'Succeeded'", test)}\n"
|
|
76
|
+
setup_before_each_txt = "#{assert_eq("Helper.setup_#{target_resource[:resource]}(@http, #{target_resource[:params_up_to].join(', ')}).state", "'Succeeded'", test)}\n"
|
|
72
77
|
if cleanup
|
|
73
|
-
after_each_txt =
|
|
74
|
-
after_all_txt =
|
|
78
|
+
after_each_txt = framework_hook(:after_each, "Helper.cleanup_#{target_resource[:resource]}(@http, #{target_resource[:params_up_to].join(', ')})\n", test)
|
|
79
|
+
after_all_txt = framework_hook(:after_all, "unless defined?(DONT_DELETE) && DONT_DELETE\nHelper.cleanup_#{parent_resource[:resource]}(@http, #{parent_resource[:params_up_to].join(', ')})\nend\n", test)
|
|
75
80
|
end
|
|
76
81
|
elsif needs_target_setup && target_resource
|
|
77
|
-
setup_before_all_txt = "
|
|
82
|
+
setup_before_all_txt = "#{assert_eq("Helper.setup_#{target_resource[:resource]}(@http, #{target_resource[:params_up_to].join(', ')}).state", "'Succeeded'", test)}\n"
|
|
78
83
|
if cleanup
|
|
79
|
-
after_all_txt =
|
|
84
|
+
after_all_txt = framework_hook(:after_all, "unless defined?(DONT_DELETE) && DONT_DELETE\nHelper.cleanup_#{target_resource[:resource]}(@http, #{target_resource[:params_up_to].join(', ')})\nend\n", test)
|
|
80
85
|
end
|
|
81
86
|
elsif parent_resource
|
|
82
|
-
setup_before_all_txt = "
|
|
87
|
+
setup_before_all_txt = "#{assert_eq("Helper.setup_#{parent_resource[:resource]}(@http, #{parent_resource[:params_up_to].join(', ')}).state", "'Succeeded'", test)}\n"
|
|
83
88
|
if cleanup && target_resource
|
|
84
|
-
after_each_txt =
|
|
85
|
-
after_all_txt =
|
|
89
|
+
after_each_txt = framework_hook(:after_each, "Helper.cleanup_#{target_resource[:resource]}(@http, #{target_resource[:params_up_to].join(', ')})\n", test)
|
|
90
|
+
after_all_txt = framework_hook(:after_all, "unless defined?(DONT_DELETE) && DONT_DELETE\nHelper.cleanup_#{parent_resource[:resource]}(@http, #{parent_resource[:params_up_to].join(', ')})\nend\n", test)
|
|
86
91
|
elsif cleanup
|
|
87
|
-
after_all_txt =
|
|
92
|
+
after_all_txt = framework_hook(:after_all, "unless defined?(DONT_DELETE) && DONT_DELETE\nHelper.cleanup_#{parent_resource[:resource]}(@http, #{parent_resource[:params_up_to].join(', ')})\nend\n", test)
|
|
88
93
|
end
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
if cleanup == :after_each && !after_all_txt.empty?
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
if test == :minitest
|
|
98
|
+
# Minitest folds after(:all) into teardown; after_each mode just uses teardown body once.
|
|
99
|
+
after_each_txt += after_all_txt
|
|
100
|
+
after_all_txt = ""
|
|
101
|
+
else
|
|
102
|
+
after_each_txt += after_all_txt.sub("after(:all)", "after(:each)")
|
|
103
|
+
after_all_txt = ""
|
|
104
|
+
end
|
|
94
105
|
end
|
|
95
106
|
|
|
96
|
-
if test_txt ==""
|
|
107
|
+
if test_txt == ""
|
|
97
108
|
modified = true
|
|
98
109
|
|
|
99
110
|
suffix_txt = ""
|
|
@@ -102,12 +113,15 @@ class CreateTests
|
|
|
102
113
|
suffix_txt = "#{target_param} = #{target_param} + \"#{method_suffix}\"\n"
|
|
103
114
|
end
|
|
104
115
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
if test == :minitest
|
|
117
|
+
output = build_minitest_skeleton(mod_name, method_txt, settings_relative_path, params_declaration_txt, suffix_txt, setup_before_all_txt, setup_before_each_txt, after_each_txt, after_all_txt, req_txt, is_delete, target_resource)
|
|
118
|
+
else
|
|
119
|
+
before_each_block = "before(:each) do |example|\n"
|
|
120
|
+
before_each_block << "@http = NiceHttp.new()\n" if is_delete && target_resource
|
|
121
|
+
before_each_block << setup_before_each_txt
|
|
122
|
+
before_each_block << "@http.logger.info(\"\\n\\n\#{'='*100}\\nTest: \#{example.description}\\n\#{'-'*100}\")\nend\n"
|
|
109
123
|
|
|
110
|
-
|
|
124
|
+
output = "
|
|
111
125
|
require_relative '#{settings_relative_path}'
|
|
112
126
|
if defined?(#{mod_name}) and defined?(#{mod_name}.#{method_txt})
|
|
113
127
|
RSpec.describe #{mod_name}, '##{method_txt}' do
|
|
@@ -117,12 +131,15 @@ class CreateTests
|
|
|
117
131
|
@http.logger.info(\"\\n\#{'+'*50} Before All ends \#{'+'*50}\")
|
|
118
132
|
end
|
|
119
133
|
#{after_all_txt}#{after_each_txt}#{before_each_block}\n"
|
|
134
|
+
end
|
|
120
135
|
else
|
|
121
136
|
output = test_txt
|
|
122
|
-
if
|
|
123
|
-
output.gsub!(/\s*end\s
|
|
137
|
+
if test == :minitest
|
|
138
|
+
output.gsub!(/\s*end\s*\Z/, "\n")
|
|
139
|
+
elsif output.match?(/\s*end\s*end\s*end\s*\Z/)
|
|
140
|
+
output.gsub!(/\s*end\s*end\s*\Z/, "\n")
|
|
124
141
|
else
|
|
125
|
-
output.gsub!(/\s*end\s*\Z/,"\n")
|
|
142
|
+
output.gsub!(/\s*end\s*\Z/, "\n")
|
|
126
143
|
end
|
|
127
144
|
end
|
|
128
145
|
|
|
@@ -140,113 +157,115 @@ class CreateTests
|
|
|
140
157
|
end
|
|
141
158
|
|
|
142
159
|
# first response on responses is the one expected to be returned when success
|
|
143
|
-
if request.key?(:responses) and request[:responses].size > 0
|
|
160
|
+
if include_kind?(only_kinds, :success) && request.key?(:responses) and request[:responses].size > 0
|
|
144
161
|
code = request[:responses].keys[0]
|
|
145
|
-
title="
|
|
162
|
+
title = example_title("has correct structure in successful response", test, trailing_space: true)
|
|
146
163
|
if !request.key?(:data) && has_data_examples
|
|
147
164
|
tests[title] = "do
|
|
148
165
|
request = @request.deep_copy
|
|
149
166
|
request[:data] = @request[:data_examples].first
|
|
150
167
|
resp = @http.#{request[:method]}(request)
|
|
151
|
-
|
|
168
|
+
#{assert_eq('resp.code', code, test)}\n"
|
|
152
169
|
if request[:responses][code].is_a?(Hash) and request[:responses][code].key?(:data)
|
|
153
170
|
tests[title] +="result = NiceHttp.validate_response(resp, @request.responses._#{code}.data, include_diff: true)\n"
|
|
154
|
-
tests[title] +="
|
|
171
|
+
tests[title] += "#{assert_be_true('result[:ok]', 'Structure mismatch: #{result[:diff]}', test)}\n"
|
|
155
172
|
end
|
|
156
173
|
tests[title] += "end\n"
|
|
157
174
|
else
|
|
158
175
|
tests[title] = "do
|
|
159
176
|
resp = @http.#{request[:method]}(@request)
|
|
160
|
-
|
|
177
|
+
#{assert_eq('resp.code', code, test)}\n"
|
|
161
178
|
|
|
162
179
|
if request[:responses][code].is_a?(Hash) and request[:responses][code].key?(:data)
|
|
163
180
|
tests[title] +="result = NiceHttp.validate_response(resp, @request.responses._#{code}.data, include_diff: true)\n"
|
|
164
|
-
tests[title] +="
|
|
181
|
+
tests[title] += "#{assert_be_true('result[:ok]', 'Structure mismatch: #{result[:diff]}', test)}\n"
|
|
165
182
|
end
|
|
166
183
|
tests[title] += "end\n"
|
|
167
184
|
end
|
|
168
185
|
end
|
|
169
186
|
|
|
170
|
-
|
|
171
|
-
|
|
187
|
+
if include_kind?(only_kinds, :auth)
|
|
188
|
+
title = example_title("doesn\\'t retrieve data if not authenticated", test)
|
|
189
|
+
tests[title] = "do
|
|
172
190
|
http = NiceHttp.new()
|
|
173
191
|
http.headers = {}
|
|
174
192
|
resp = http.#{request[:method]}(@request)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
193
|
+
#{assert_between('resp.code', "'400'", "'499'", test)}\n"
|
|
194
|
+
if request.key?(:responses) and (request[:responses].keys.select{|c| c.to_s.to_i>=400&&c.to_s.to_i<=499}).size>0
|
|
195
|
+
tests[title] += "#{assert_eq('NiceHash.compare_structure(@request.responses[resp.code.to_sym].data, resp.data.json)', 'true', test)}
|
|
196
|
+
#{assert_eq('resp.message', '@request.responses[resp.code.to_sym].message', test)}\n"
|
|
197
|
+
end
|
|
198
|
+
tests[title] += "end\n"
|
|
179
199
|
end
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if params.size > 0 or keywords_required.size >0
|
|
200
|
+
|
|
201
|
+
if include_kind?(only_kinds, :required_params) && (params.size > 0 or keywords_required.size >0)
|
|
183
202
|
empty_param = ""
|
|
184
203
|
params.each do |p|
|
|
185
204
|
r = req_txt.gsub(/#{p}([),])/, '""\1')
|
|
186
205
|
empty_param += "
|
|
187
206
|
request = #{r}
|
|
188
207
|
resp = @http.#{request[:method]}(request)
|
|
189
|
-
|
|
208
|
+
#{assert_between('resp.code', "'400'", "'499'", test)}\n"
|
|
190
209
|
if request.key?(:responses) and (request[:responses].keys.select{|c| c.to_s.to_i>=400&&c.to_s.to_i<=499}).size>0
|
|
191
|
-
empty_param += "
|
|
210
|
+
empty_param += "#{assert_match('resp.message', '/\#{request.responses[resp.code.to_sym].message}/i', test)}\n"
|
|
192
211
|
end
|
|
193
212
|
end
|
|
194
|
-
if keywords_required.size > 0
|
|
213
|
+
if keywords_required.size > 0
|
|
195
214
|
r = req_txt.scan(/(.+)\(/).join
|
|
196
215
|
empty_param += "
|
|
197
216
|
[:#{keywords_required.join(', :')}].each do |kw|
|
|
198
217
|
request = #{r}(kw => '')
|
|
199
218
|
resp = @http.#{request[:method]}(request)
|
|
200
|
-
|
|
219
|
+
#{assert_between('resp.code', "'400'", "'499'", test)}\n"
|
|
201
220
|
if request.key?(:responses) and (request[:responses].keys.select{|c| c.to_s.to_i>=400&&c.to_s.to_i<=499}).size>0
|
|
202
|
-
empty_param += "
|
|
221
|
+
empty_param += "#{assert_match('resp.message', '/\#{request.responses[resp.code.to_sym].message}/i', test)}\n"
|
|
203
222
|
end
|
|
204
223
|
empty_param += "end\n"
|
|
205
224
|
end
|
|
206
225
|
empty_param += "end\n"
|
|
207
|
-
tests["
|
|
226
|
+
tests[example_title("returns error if required parameter empty", test, trailing_space: true)] = "do\n#{empty_param}"
|
|
208
227
|
end
|
|
209
228
|
|
|
210
|
-
if request.key?(:mock_response)
|
|
211
|
-
title = "
|
|
229
|
+
if include_kind?(only_kinds, :mock) && request.key?(:mock_response)
|
|
230
|
+
title = example_title("returns expected mock response", test, trailing_space: true)
|
|
212
231
|
tests[title] = "do
|
|
213
232
|
@http_mock = NiceHttp.new()
|
|
214
233
|
@http_mock.use_mocks = true
|
|
215
234
|
resp = @http_mock.#{request[:method]}(@request)
|
|
216
|
-
|
|
217
|
-
|
|
235
|
+
#{assert_eq('resp.code', '@request[:mock_response][:code]', test)}
|
|
236
|
+
#{assert_eq('resp.message', '@request[:mock_response][:message]', test)}\n"
|
|
218
237
|
if request[:mock_response].key?(:data)
|
|
219
|
-
tests[title] += "
|
|
238
|
+
tests[title] += "#{assert_be_true('NiceHash.compare_structure(@request[:mock_response][:data], resp.data.json, true)', nil, test)}\n"
|
|
220
239
|
end
|
|
221
240
|
tests[title] += "end\n"
|
|
222
241
|
end
|
|
223
242
|
|
|
224
|
-
if payload_source && [:post, :put, :patch].include?(request[:method])
|
|
225
|
-
title = "
|
|
243
|
+
if include_kind?(only_kinds, :variations) && payload_source && [:post, :put, :patch].include?(request[:method])
|
|
244
|
+
title = example_title("handles multiple valid data variations", test, trailing_space: true)
|
|
226
245
|
tests[title] = "do
|
|
227
246
|
@request[#{payload_source}].generate_n(5, :correct).each do |generated_data|
|
|
228
247
|
request = @request.deep_copy
|
|
229
248
|
request[:data] = generated_data
|
|
230
249
|
resp = @http.#{request[:method]}(request)
|
|
231
|
-
|
|
250
|
+
#{assert_between('resp.code.to_i', '200', '299', test)}
|
|
232
251
|
end
|
|
233
252
|
end\n"
|
|
234
253
|
end
|
|
235
254
|
|
|
236
|
-
if payload_source
|
|
237
|
-
title = "
|
|
255
|
+
if include_kind?(only_kinds, :invalid_fields) && payload_source
|
|
256
|
+
title = example_title("returns error when individual data fields are invalid", test, trailing_space: true)
|
|
238
257
|
tests[title] = "do
|
|
239
258
|
wrong = @request[#{payload_source}].generate(:correct, errors: :min_length)
|
|
240
259
|
NiceHash.change_one_by_one([@request[#{payload_source}], :correct], wrong).each do |one_wrong|
|
|
241
260
|
request = @request.deep_copy
|
|
242
261
|
request[:data] = one_wrong
|
|
243
262
|
resp = @http.#{request[:method]}(request)
|
|
244
|
-
|
|
263
|
+
#{assert_between('resp.code.to_i', '200', '299', test, negate: true)}
|
|
245
264
|
end
|
|
246
265
|
end\n"
|
|
247
266
|
end
|
|
248
267
|
|
|
249
|
-
if request.key?(:data_required) && (request.key?(:data) || has_data_examples)
|
|
268
|
+
if include_kind?(only_kinds, :required_data) && request.key?(:data_required) && (request.key?(:data) || has_data_examples)
|
|
250
269
|
seed_data_line = if !request.key?(:data) && has_data_examples
|
|
251
270
|
"request[:data] = request[:data_examples].first\n "
|
|
252
271
|
else
|
|
@@ -258,14 +277,14 @@ class CreateTests
|
|
|
258
277
|
request = @request.deep_copy
|
|
259
278
|
#{seed_data_line}request.values_for[p] = ''
|
|
260
279
|
resp = @http.#{request[:method]}(request)
|
|
261
|
-
|
|
280
|
+
#{assert_between('resp.code', "'200'", "'299'", test, negate: true)}
|
|
262
281
|
if request.responses.key?(resp.code.to_sym)
|
|
263
|
-
|
|
282
|
+
#{assert_match('resp.message', '/\#{request.responses[resp.code.to_sym].message}/i', test)}
|
|
264
283
|
end
|
|
265
284
|
end
|
|
266
285
|
"
|
|
267
286
|
empty_param_data += "end\n"
|
|
268
|
-
tests["
|
|
287
|
+
tests[example_title("returns error if required parameter on data empty", test, with_do: true)] = empty_param_data
|
|
269
288
|
|
|
270
289
|
missing_param_data = ""
|
|
271
290
|
missing_param_data += "
|
|
@@ -273,19 +292,18 @@ class CreateTests
|
|
|
273
292
|
request = @request.deep_copy
|
|
274
293
|
#{seed_data_line}NiceHash.delete_nested(request[:data], p)
|
|
275
294
|
resp = @http.#{request[:method]}(request)
|
|
276
|
-
|
|
295
|
+
#{assert_between('resp.code', "'200'", "'299'", test, negate: true)}
|
|
277
296
|
if request.responses.key?(resp.code.to_sym)
|
|
278
|
-
|
|
297
|
+
#{assert_match('resp.message', '/\#{request.responses[resp.code.to_sym].message}/i', test)}
|
|
279
298
|
end
|
|
280
299
|
end
|
|
281
300
|
"
|
|
282
301
|
missing_param_data += "end\n"
|
|
283
|
-
tests["
|
|
302
|
+
tests[example_title("returns error if required parameter on data missing", test, with_do: true)] = missing_param_data
|
|
284
303
|
end
|
|
285
304
|
|
|
286
305
|
tests.each do |k,v|
|
|
287
|
-
unless
|
|
288
|
-
output.include?(k.gsub(' "'," '").gsub('" ',"' ").gsub("\n",'').gsub(/\s+do$/,'').gsub(/^\s*it/,''))
|
|
306
|
+
unless example_already_present?(output, k, test)
|
|
289
307
|
modified = true
|
|
290
308
|
message = " = test added #{k} for #{method_txt}"
|
|
291
309
|
@logger.info message
|
|
@@ -293,15 +311,191 @@ class CreateTests
|
|
|
293
311
|
puts message
|
|
294
312
|
output +="# Appended #{Time.now.stamp}\n"
|
|
295
313
|
end
|
|
296
|
-
|
|
314
|
+
if test == :minitest
|
|
315
|
+
# keys are "def test_foo" and bodies start with "do\n...\nend"
|
|
316
|
+
body = v.sub(/\Ado\n/, "").sub(/\n?end\n?\z/, "\n")
|
|
317
|
+
output += "#{k}\n#{body}end\n"
|
|
318
|
+
else
|
|
319
|
+
output += "#{k}#{v}"
|
|
320
|
+
end
|
|
297
321
|
end
|
|
298
322
|
end
|
|
299
|
-
if
|
|
323
|
+
if test == :minitest
|
|
324
|
+
if output.include?('defined?(')
|
|
325
|
+
output += "\nend\nend"
|
|
326
|
+
else
|
|
327
|
+
output += "\nend"
|
|
328
|
+
end
|
|
329
|
+
elsif output.include?('defined?(')
|
|
300
330
|
output += "\nend\nend"
|
|
301
331
|
else
|
|
302
332
|
output +="\nend"
|
|
303
333
|
end
|
|
304
334
|
return modified, output
|
|
305
335
|
end
|
|
336
|
+
|
|
337
|
+
private def normalize_only(only)
|
|
338
|
+
return nil if only.nil?
|
|
339
|
+
list = case only
|
|
340
|
+
when Symbol then [only]
|
|
341
|
+
when String then only.split(",").map { |s| s.strip.to_sym }
|
|
342
|
+
when Array then only.map { |s| s.to_s.strip.to_sym }
|
|
343
|
+
else
|
|
344
|
+
raise "** Wrong only parameter: #{only}"
|
|
345
|
+
end
|
|
346
|
+
unknown = list - TEST_KINDS
|
|
347
|
+
unless unknown.empty?
|
|
348
|
+
raise "** Wrong only parameter: unknown kind(s) #{unknown.join(', ')}. Valid: #{TEST_KINDS.join(', ')}"
|
|
349
|
+
end
|
|
350
|
+
list
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
private def include_kind?(only_kinds, kind)
|
|
354
|
+
only_kinds.nil? || only_kinds.include?(kind)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
private def example_title(description, test, trailing_space: false, with_do: false)
|
|
358
|
+
if test == :minitest
|
|
359
|
+
"def test_#{minitest_method_name(description)}"
|
|
360
|
+
else
|
|
361
|
+
space = trailing_space ? " " : ""
|
|
362
|
+
if with_do
|
|
363
|
+
"it '#{description}' do\n"
|
|
364
|
+
else
|
|
365
|
+
"it '#{description}'#{space}"
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
private def minitest_method_name(description)
|
|
371
|
+
description.gsub("\\'", "")
|
|
372
|
+
.gsub(/[^a-zA-Z0-9]+/, "_")
|
|
373
|
+
.gsub(/\A_+|_+\z/, "")
|
|
374
|
+
.downcase
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
private def example_already_present?(output, key, test)
|
|
378
|
+
if test == :minitest
|
|
379
|
+
output.include?(key)
|
|
380
|
+
else
|
|
381
|
+
output.include?(key.gsub(" '", ' "').gsub("' ", '" ').gsub("\n", '').gsub(/\s+do$/, '').gsub(/^\s*it/, '')) ||
|
|
382
|
+
output.include?(key.gsub(' "', " '").gsub('" ', "' ").gsub("\n", '').gsub(/\s+do$/, '').gsub(/^\s*it/, ''))
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
private def assert_eq(actual, expected, test)
|
|
387
|
+
if test == :minitest
|
|
388
|
+
"assert_equal #{expected}, #{actual}"
|
|
389
|
+
else
|
|
390
|
+
"expect(#{actual}).to eq #{expected}"
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
private def assert_be_true(actual, message, test)
|
|
395
|
+
if test == :minitest
|
|
396
|
+
if message
|
|
397
|
+
"assert #{actual}, \"#{message}\""
|
|
398
|
+
else
|
|
399
|
+
"assert #{actual}"
|
|
400
|
+
end
|
|
401
|
+
else
|
|
402
|
+
if message
|
|
403
|
+
"expect(#{actual}).to be(true), \"#{message}\""
|
|
404
|
+
else
|
|
405
|
+
"expect(#{actual}).to be true"
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
private def assert_between(actual, low, high, test, negate: false)
|
|
411
|
+
if test == :minitest
|
|
412
|
+
if negate
|
|
413
|
+
"refute_includes (#{low}..#{high}), #{actual}"
|
|
414
|
+
else
|
|
415
|
+
"assert_includes (#{low}..#{high}), #{actual}"
|
|
416
|
+
end
|
|
417
|
+
else
|
|
418
|
+
if negate
|
|
419
|
+
"expect(#{actual}).not_to be_between(#{low}, #{high})"
|
|
420
|
+
else
|
|
421
|
+
"expect(#{actual}).to be_between(#{low}, #{high})"
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
private def assert_match(actual, pattern, test)
|
|
427
|
+
if test == :minitest
|
|
428
|
+
"assert_match #{pattern}, #{actual}"
|
|
429
|
+
else
|
|
430
|
+
"expect(#{actual}).to match #{pattern}"
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
private def framework_hook(kind, body, test)
|
|
435
|
+
if test == :minitest
|
|
436
|
+
# Stored as raw bodies; assembled into setup/teardown in the skeleton.
|
|
437
|
+
# Prefix with a marker so cleanup: :after_each merging can find them.
|
|
438
|
+
case kind
|
|
439
|
+
when :after_each then "TEARDOWN_EACH:#{body}"
|
|
440
|
+
when :after_all then "TEARDOWN_ALL:#{body}"
|
|
441
|
+
else body
|
|
442
|
+
end
|
|
443
|
+
else
|
|
444
|
+
case kind
|
|
445
|
+
when :after_each then "after(:each) do\n#{body}end\n"
|
|
446
|
+
when :after_all then "after(:all) do\n#{body}end\n"
|
|
447
|
+
else body
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
private def build_minitest_skeleton(mod_name, method_txt, settings_relative_path, params_declaration_txt, suffix_txt, setup_before_all_txt, setup_before_each_txt, after_each_txt, after_all_txt, req_txt, is_delete, target_resource)
|
|
453
|
+
class_name = "#{mod_name}#{camelize(method_txt.to_s)}Test"
|
|
454
|
+
|
|
455
|
+
teardown_each_body = after_each_txt.to_s.gsub(/\ATEARDOWN_EACH:/, "").gsub(/\ATEARDOWN_ALL:/, "")
|
|
456
|
+
# after_each_txt may contain both TEARDOWN_EACH and (after merge) TEARDOWN_ALL markers
|
|
457
|
+
each_parts = []
|
|
458
|
+
all_parts = []
|
|
459
|
+
[after_each_txt.to_s, after_all_txt.to_s].each do |chunk|
|
|
460
|
+
chunk.split(/(?=TEARDOWN_(?:EACH|ALL):)/).each do |part|
|
|
461
|
+
next if part.empty?
|
|
462
|
+
if part.start_with?("TEARDOWN_EACH:")
|
|
463
|
+
each_parts << part.sub(/\ATEARDOWN_EACH:/, "")
|
|
464
|
+
elsif part.start_with?("TEARDOWN_ALL:")
|
|
465
|
+
all_parts << part.sub(/\ATEARDOWN_ALL:/, "")
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
teardown_body = (each_parts + all_parts).join
|
|
471
|
+
|
|
472
|
+
setup_http = if is_delete && target_resource
|
|
473
|
+
"@http = NiceHttp.new()\n"
|
|
474
|
+
else
|
|
475
|
+
""
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# before(:all) work at start of setup; before(:each) after that.
|
|
479
|
+
# First test creates @http for non-delete; delete recreates in the each section.
|
|
480
|
+
"
|
|
481
|
+
require 'minitest/autorun'
|
|
482
|
+
require_relative '#{settings_relative_path}'
|
|
483
|
+
if defined?(#{mod_name}) and defined?(#{mod_name}.#{method_txt})
|
|
484
|
+
class #{class_name} < Minitest::Test
|
|
485
|
+
def setup
|
|
486
|
+
@http = NiceHttp.new()
|
|
487
|
+
#{params_declaration_txt}#{suffix_txt}#{setup_before_all_txt}@request = #{req_txt}
|
|
488
|
+
@http.logger.info(\"\\n\#{'+'*50} Before All ends \#{'+'*50}\")
|
|
489
|
+
#{setup_http}#{setup_before_each_txt}@http.logger.info(\"\\n\\n\#{'='*100}\\nTest: \#{name}\\n\#{'-'*100}\")
|
|
490
|
+
end
|
|
491
|
+
def teardown
|
|
492
|
+
#{teardown_body}
|
|
493
|
+
end
|
|
494
|
+
"
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
private def camelize(snake)
|
|
498
|
+
snake.to_s.split("_").map(&:capitalize).join
|
|
499
|
+
end
|
|
306
500
|
end
|
|
307
|
-
end
|
|
501
|
+
end
|
data/lib/create-tests/from.rb
CHANGED
|
@@ -6,18 +6,19 @@ class CreateTests
|
|
|
6
6
|
# More info about Request Hashes: https://github.com/MarioRuiz/Request-Hash
|
|
7
7
|
# @param requests_file [String]. Path and file name. Could be absolute or relative to project root folder.
|
|
8
8
|
# @param type [Symbol]. (default :request_hash). The kind of content that requests_file contains.
|
|
9
|
-
# @param test [Symbol]. (default :rspec). What kind of tests we want to create
|
|
9
|
+
# @param test [Symbol]. (default :rspec). What kind of tests we want to create (:rspec or :minitest).
|
|
10
10
|
# @param mode [Symbol]. (default :append). :overwrite, :append, :dont_overwrite. How we want to create the tests.
|
|
11
11
|
# :overwrite, it will overwrite the test, settings, helper... files in case they exist so you will loose your original source code.
|
|
12
12
|
# :dont_overwrite, it will create only the files that don't exist previously
|
|
13
13
|
# :append, it will append or create the tests or helpers that corrently don't exist on every file, but it won't modify any other code.
|
|
14
14
|
# @param dry_run [Boolean]. (default false). Preview which files would be created or modified without writing anything.
|
|
15
15
|
# @param return_data [Boolean]. (default false). Return a Hash with generated file paths as keys and content as values, without writing files.
|
|
16
|
-
# @param spec_dir [String]. (default './spec'). Output directory for generated test files.
|
|
16
|
+
# @param spec_dir [String]. (default './spec' for RSpec, './test' for Minitest). Output directory for generated test files.
|
|
17
17
|
# @param settings_dir [String]. (default './settings'). Output directory for generated settings files.
|
|
18
18
|
# @param cleanup [Symbol, false]. (default :after_all). :after_all, :after_each, or false. Controls cleanup hook generation.
|
|
19
|
+
# @param only [Array, Symbol, String, nil]. (default nil = all). Limit which example kinds are generated.
|
|
19
20
|
##############################################################################
|
|
20
|
-
def self.from(requests_file, type: :request_hash, test: :rspec, mode: :append, dry_run: false, return_data: false, spec_dir:
|
|
21
|
+
def self.from(requests_file, type: :request_hash, test: :rspec, mode: :append, dry_run: false, return_data: false, spec_dir: nil, settings_dir: './settings', cleanup: :after_all, only: nil)
|
|
21
22
|
no_write = dry_run || return_data
|
|
22
23
|
@generated_data = {} if return_data
|
|
23
24
|
|
|
@@ -50,12 +51,17 @@ class CreateTests
|
|
|
50
51
|
raise message
|
|
51
52
|
end
|
|
52
53
|
|
|
53
|
-
unless [:rspec].include?(test)
|
|
54
|
+
unless [:rspec, :minitest].include?(test)
|
|
54
55
|
message = "** Wrong test parameter: #{test}"
|
|
55
56
|
@logger.fatal message
|
|
56
57
|
raise message
|
|
57
58
|
end
|
|
58
59
|
|
|
60
|
+
# Default output dir depends on framework; an explicit spec_dir is always honored.
|
|
61
|
+
if spec_dir.nil?
|
|
62
|
+
spec_dir = test == :minitest ? './test' : './spec'
|
|
63
|
+
end
|
|
64
|
+
|
|
59
65
|
unless [:overwrite, :dont_overwrite, :append].include?(mode)
|
|
60
66
|
message = "** Wrong mode parameter: #{mode}"
|
|
61
67
|
@logger.fatal message
|
|
@@ -68,12 +74,16 @@ class CreateTests
|
|
|
68
74
|
raise message
|
|
69
75
|
end
|
|
70
76
|
|
|
77
|
+
# Validate only early so bad values fail before generation.
|
|
78
|
+
normalize_only(only)
|
|
79
|
+
|
|
71
80
|
if mode == :overwrite
|
|
72
81
|
message = "** Pay attention, if any of the files exist, will be overwritten"
|
|
73
82
|
@logger.warn message
|
|
74
83
|
warn message
|
|
75
84
|
elsif mode == :append
|
|
76
|
-
|
|
85
|
+
existing_tests = Dir["#{spec_dir}/*/**_spec.rb"] + Dir["#{spec_dir}/*/**_test.rb"]
|
|
86
|
+
if existing_tests.size > 0
|
|
77
87
|
message = "** Pay attention, if any of the test files exist or the help file exist only will be added the tests, methods that are missing."
|
|
78
88
|
@logger.warn message
|
|
79
89
|
warn message
|
|
@@ -94,7 +104,7 @@ class CreateTests
|
|
|
94
104
|
helper_from_settings = helper_path.relative_path_from(resolved_settings_dir).to_s
|
|
95
105
|
requests_from_settings = resolve_pathname(requests_file).relative_path_from(resolved_settings_dir).to_s
|
|
96
106
|
|
|
97
|
-
Dir.mkdir spec_dir unless no_write or
|
|
107
|
+
Dir.mkdir spec_dir unless no_write or Dir.exist?(spec_dir)
|
|
98
108
|
|
|
99
109
|
add_settings = true
|
|
100
110
|
settings_file = "#{settings_dir}/general.rb"
|
|
@@ -164,6 +174,8 @@ class CreateTests
|
|
|
164
174
|
puts message unless no_write
|
|
165
175
|
end
|
|
166
176
|
|
|
177
|
+
test_suffix = test == :minitest ? "_test.rb" : "_spec.rb"
|
|
178
|
+
|
|
167
179
|
modules.each do |mod_txt|
|
|
168
180
|
mod_name = mod_txt.scan(/::(\w+)$/).join
|
|
169
181
|
folder = "#{spec_dir}/#{mod_name}"
|
|
@@ -174,7 +186,7 @@ class CreateTests
|
|
|
174
186
|
mod_obj = Object.const_get(mod_txt)
|
|
175
187
|
mod_methods_txt = mod_obj.methods(false)
|
|
176
188
|
mod_methods_txt.each do |method_txt|
|
|
177
|
-
test_file = "#{folder}/#{method_txt}
|
|
189
|
+
test_file = "#{folder}/#{method_txt}#{test_suffix}"
|
|
178
190
|
if File.exist?(test_file) and mode==:dont_overwrite
|
|
179
191
|
message = "** The file #{test_file} already exists so no content will be added to it.\n"
|
|
180
192
|
message += " Remove the test file to be able to be generated by create_tests or set mode: :overwrite, or mode: :append"
|
|
@@ -187,7 +199,7 @@ class CreateTests
|
|
|
187
199
|
test_txt = ''
|
|
188
200
|
end
|
|
189
201
|
settings_from_test = settings_path.relative_path_from(resolve_pathname(folder)).to_s
|
|
190
|
-
modified, txt = create_test(mod_txt, method_txt, mod_obj.method(method_txt), test_txt, settings_relative_path: settings_from_test, cleanup: cleanup)
|
|
202
|
+
modified, txt = create_test(mod_txt, method_txt, mod_obj.method(method_txt), test_txt, settings_relative_path: settings_from_test, cleanup: cleanup, test: test, only: only)
|
|
191
203
|
if no_write
|
|
192
204
|
@generated_data[test_file] = txt if return_data
|
|
193
205
|
else
|
|
@@ -198,7 +210,7 @@ class CreateTests
|
|
|
198
210
|
message = "- Test #{no_write ? 'would be created' : 'created'}: #{test_file}"
|
|
199
211
|
elsif modified
|
|
200
212
|
message = "- Test #{no_write ? 'would be updated' : 'updated'}: #{test_file}"
|
|
201
|
-
else
|
|
213
|
+
else
|
|
202
214
|
message = "- Test without changes: #{test_file}"
|
|
203
215
|
end
|
|
204
216
|
@logger.info message
|
|
@@ -234,13 +246,36 @@ class CreateTests
|
|
|
234
246
|
|
|
235
247
|
if @setup_cleanup_resources.size > 0
|
|
236
248
|
write_chain_file = lambda do |path, content, label|
|
|
237
|
-
if File.exist?(path) && mode
|
|
249
|
+
if File.exist?(path) && mode == :dont_overwrite
|
|
238
250
|
message = "** The file #{path} already exists so it will be left unchanged.\n"
|
|
239
|
-
message += " Remove the file to regenerate it or set mode: :overwrite"
|
|
251
|
+
message += " Remove the file to regenerate it or set mode: :overwrite or :append"
|
|
240
252
|
@logger.warn message
|
|
241
253
|
warn message
|
|
242
254
|
return
|
|
243
255
|
end
|
|
256
|
+
|
|
257
|
+
if File.exist?(path) && mode == :append
|
|
258
|
+
existing = File.read(path)
|
|
259
|
+
merged, changed = append_missing_chain_methods(existing, content)
|
|
260
|
+
unless changed
|
|
261
|
+
message = "- #{label} without changes: #{path}"
|
|
262
|
+
@logger.info message
|
|
263
|
+
return
|
|
264
|
+
end
|
|
265
|
+
content = merged
|
|
266
|
+
if no_write
|
|
267
|
+
@generated_data[path] = content if return_data
|
|
268
|
+
puts "- #{label} (dry run): #{path}" if dry_run
|
|
269
|
+
else
|
|
270
|
+
File.open(path, "w") { |file| file.write(content) }
|
|
271
|
+
system("rufo", path, out: File::NULL, err: File::NULL)
|
|
272
|
+
message = "- #{label} updated: #{path}"
|
|
273
|
+
@logger.info message
|
|
274
|
+
puts message
|
|
275
|
+
end
|
|
276
|
+
return
|
|
277
|
+
end
|
|
278
|
+
|
|
244
279
|
if no_write
|
|
245
280
|
@generated_data[path] = content if return_data
|
|
246
281
|
puts "- #{label} (dry run): #{path}" if dry_run
|
|
@@ -279,4 +314,4 @@ class CreateTests
|
|
|
279
314
|
resolved
|
|
280
315
|
end
|
|
281
316
|
private_class_method :resolve_pathname
|
|
282
|
-
end
|
|
317
|
+
end
|
|
@@ -3,10 +3,16 @@ class CreateTests
|
|
|
3
3
|
|
|
4
4
|
class << self
|
|
5
5
|
|
|
6
|
+
SKIP_CHAIN_SEGMENTS = %w[subscriptions resource_groups providers].freeze
|
|
7
|
+
|
|
6
8
|
# Extracts the resource dependency chain from a request path.
|
|
7
9
|
# Works with both placeholder paths ({param}) and interpolated paths
|
|
8
10
|
# (where params are resolved, possibly to empty strings).
|
|
9
11
|
#
|
|
12
|
+
# Segments whose snake_case names are subscriptions, resource_groups, or
|
|
13
|
+
# providers are omitted from the setup/cleanup chain, but their parameters
|
|
14
|
+
# remain in params_up_to for later resources.
|
|
15
|
+
#
|
|
10
16
|
# @param request [Hash] Request hash containing :path and :method keys
|
|
11
17
|
# @param params [Array<String>] Positional parameter names (e.g. ["@subscription_id", "@pool_name"])
|
|
12
18
|
# @return [Array<Hash>, Hash|nil] Two values: prerequisite chain array and target resource hash (or nil).
|
|
@@ -73,8 +79,14 @@ class CreateTests
|
|
|
73
79
|
{ resource: resource_name, param: matching_param, params_up_to: params_up_to }
|
|
74
80
|
end
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
# Drop Azure infrastructure segments from the chain; keep their params in params_up_to.
|
|
83
|
+
real_entries = all_entries.reject { |e| SKIP_CHAIN_SEGMENTS.include?(e[:resource]) }
|
|
84
|
+
|
|
85
|
+
return [], nil if real_entries.empty?
|
|
86
|
+
return [], real_entries.first if real_entries.size == 1
|
|
87
|
+
|
|
88
|
+
prerequisites = real_entries[0..-2]
|
|
89
|
+
target = real_entries.last
|
|
78
90
|
|
|
79
91
|
return prerequisites, target
|
|
80
92
|
end
|
data/lib/create-tests/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: create_tests
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mario Ruiz
|
|
@@ -97,7 +97,10 @@ files:
|
|
|
97
97
|
homepage: https://github.com/MarioRuiz/create_tests
|
|
98
98
|
licenses:
|
|
99
99
|
- MIT
|
|
100
|
-
metadata:
|
|
100
|
+
metadata:
|
|
101
|
+
changelog_uri: https://github.com/MarioRuiz/create_tests/blob/master/CHANGELOG.md
|
|
102
|
+
source_code_uri: https://github.com/MarioRuiz/create_tests
|
|
103
|
+
bug_tracker_uri: https://github.com/MarioRuiz/create_tests/issues
|
|
101
104
|
post_install_message: Thanks for installing! Visit us on https://github.com/MarioRuiz/create_tests
|
|
102
105
|
rdoc_options: []
|
|
103
106
|
require_paths:
|