tng 0.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 +7 -0
- data/Gemfile +15 -0
- data/LICENSE.md +32 -0
- data/README.md +506 -0
- data/Rakefile +124 -0
- data/bin/load_dev +22 -0
- data/bin/tng +1096 -0
- data/binaries/tng.bundle +0 -0
- data/binaries/tng.so +0 -0
- data/lib/generators/tng/install_generator.rb +228 -0
- data/lib/tng/analyzers/controller.rb +114 -0
- data/lib/tng/analyzers/model.rb +122 -0
- data/lib/tng/analyzers/service.rb +149 -0
- data/lib/tng/api/http_client.rb +102 -0
- data/lib/tng/railtie.rb +11 -0
- data/lib/tng/services/test_generator.rb +159 -0
- data/lib/tng/services/testng.rb +100 -0
- data/lib/tng/services/user_app_config.rb +77 -0
- data/lib/tng/ui/about_display.rb +71 -0
- data/lib/tng/ui/configuration_display.rb +46 -0
- data/lib/tng/ui/controller_test_flow_display.rb +89 -0
- data/lib/tng/ui/display_banner.rb +54 -0
- data/lib/tng/ui/goodbye_display.rb +50 -0
- data/lib/tng/ui/model_test_flow_display.rb +95 -0
- data/lib/tng/ui/post_install_box.rb +73 -0
- data/lib/tng/ui/service_test_flow_display.rb +89 -0
- data/lib/tng/ui/show_help.rb +89 -0
- data/lib/tng/ui/system_status_display.rb +57 -0
- data/lib/tng/ui/user_stats_display.rb +153 -0
- data/lib/tng/utils.rb +263 -0
- data/lib/tng/version.rb +6 -0
- data/lib/tng.rb +294 -0
- data/tng.gemspec +54 -0
- metadata +283 -0
data/lib/tng/utils.rb
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Tng
|
5
|
+
module Utils
|
6
|
+
def clear_screen
|
7
|
+
system("clear") || system("cls")
|
8
|
+
end
|
9
|
+
|
10
|
+
def center_text(text, width = nil)
|
11
|
+
width ||= @terminal_width || 80 # Use fallback if still nil
|
12
|
+
lines = text.split("\n")
|
13
|
+
lines.map do |line|
|
14
|
+
# Remove ANSI color codes for length calculation
|
15
|
+
clean_line = line.gsub(/\e\[[0-9;]*m/, "")
|
16
|
+
padding = [(width - clean_line.length) / 2, 0].max
|
17
|
+
" " * padding + line
|
18
|
+
end.join("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
def copy_to_clipboard(text)
|
22
|
+
# Try to copy to clipboard
|
23
|
+
if system("which pbcopy > /dev/null 2>&1")
|
24
|
+
system("echo '#{text}' | pbcopy")
|
25
|
+
success_msg = @pastel.green("✅ Command copied to clipboard!")
|
26
|
+
elsif system("which xclip > /dev/null 2>&1")
|
27
|
+
system("echo '#{text}' | xclip -selection clipboard")
|
28
|
+
success_msg = @pastel.green("✅ Command copied to clipboard!")
|
29
|
+
else
|
30
|
+
success_msg = @pastel.yellow("📋 Copy this command:")
|
31
|
+
puts center_text(success_msg)
|
32
|
+
puts center_text(@pastel.bright_white(text))
|
33
|
+
@prompt.keypress(center_text(@pastel.dim("Press any key to continue...")))
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
puts center_text(success_msg)
|
38
|
+
@prompt.keypress(center_text(@pastel.dim("Press any key to continue...")))
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_rails_environment
|
42
|
+
# Use bundler environment to avoid gem conflicts
|
43
|
+
require "bundler/setup"
|
44
|
+
require "./config/environment"
|
45
|
+
true
|
46
|
+
rescue LoadError => e
|
47
|
+
puts "Failed to load Rails: #{e.message}"
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_rails_root
|
52
|
+
current_dir = Dir.pwd
|
53
|
+
while current_dir != "/"
|
54
|
+
return current_dir if File.exist?(File.join(current_dir, "config", "application.rb"))
|
55
|
+
|
56
|
+
current_dir = File.dirname(current_dir)
|
57
|
+
end
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def camelize(str, first_letter = :upper)
|
62
|
+
# Use Rails' camelize method if available, otherwise use custom implementation
|
63
|
+
if defined?(ActiveSupport::Inflector) && ActiveSupport::Inflector.respond_to?(:camelize)
|
64
|
+
case first_letter
|
65
|
+
when :upper
|
66
|
+
ActiveSupport::Inflector.camelize(str, true)
|
67
|
+
when :lower
|
68
|
+
ActiveSupport::Inflector.camelize(str, false)
|
69
|
+
else
|
70
|
+
raise ArgumentError, "Invalid option, use either :upper or :lower."
|
71
|
+
end
|
72
|
+
elsif str.respond_to?(:camelize)
|
73
|
+
str.camelize(first_letter)
|
74
|
+
else
|
75
|
+
# Custom implementation
|
76
|
+
result = str.gsub(/(?:^|_)([a-z])/) { Regexp.last_match(1).upcase }
|
77
|
+
case first_letter
|
78
|
+
when :upper
|
79
|
+
result
|
80
|
+
when :lower
|
81
|
+
result[0].downcase + result[1..] if result.length.positive?
|
82
|
+
else
|
83
|
+
raise ArgumentError, "Invalid option, use either :upper or :lower."
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.has_gem?(gem_name)
|
89
|
+
return false unless defined?(Bundler)
|
90
|
+
|
91
|
+
gemfile_specs = Bundler.load.specs
|
92
|
+
gemfile_specs.any? { |spec| spec.name == gem_name }
|
93
|
+
rescue StandardError
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.save_test_file(test_content)
|
98
|
+
puts "📋 Raw API response: #{test_content[0..200]}..." if ENV["DEBUG"]
|
99
|
+
parsed_response = JSON.parse(test_content)
|
100
|
+
|
101
|
+
# Validate required fields
|
102
|
+
unless parsed_response["file_content"]
|
103
|
+
puts "❌ API response missing file_content field"
|
104
|
+
puts "📋 Response keys: #{parsed_response.keys.inspect}"
|
105
|
+
return nil
|
106
|
+
end
|
107
|
+
|
108
|
+
# Handle both possible field names for file path
|
109
|
+
file_path = parsed_response["test_file_path"] || parsed_response["file_path"]
|
110
|
+
unless file_path
|
111
|
+
puts "❌ API response missing test_file_path or file_path field"
|
112
|
+
puts "📋 Response keys: #{parsed_response.keys.inspect}"
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
|
116
|
+
File.write(file_path, parsed_response["file_content"])
|
117
|
+
puts "✅ Test generated successfully!"
|
118
|
+
absolute_path = File.expand_path(file_path)
|
119
|
+
puts "Please review the generated tests at \e]8;;file://#{absolute_path}\e\\#{file_path}\e]8;;\e\\"
|
120
|
+
|
121
|
+
# Determine run command based on test framework
|
122
|
+
run_command = if file_path.include?("/spec/")
|
123
|
+
"bundle exec rspec #{file_path}"
|
124
|
+
else
|
125
|
+
"bundle exec rails test #{file_path}"
|
126
|
+
end
|
127
|
+
|
128
|
+
# Return file information for CLI to use
|
129
|
+
{
|
130
|
+
file_path: file_path,
|
131
|
+
absolute_path: absolute_path,
|
132
|
+
run_command: run_command,
|
133
|
+
test_class_name: parsed_response["test_class_name"]
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.fixture_content
|
138
|
+
factory_library = Tng.factory_library || "active_record"
|
139
|
+
|
140
|
+
case factory_library.downcase
|
141
|
+
when "fixtures"
|
142
|
+
load_all_fixtures_data
|
143
|
+
when "fabrication", "fabricator"
|
144
|
+
load_all_fabricator_data
|
145
|
+
when "factory_girl", "factory_bot"
|
146
|
+
load_all_factory_data
|
147
|
+
when "active_record"
|
148
|
+
load_all_active_record_data
|
149
|
+
else
|
150
|
+
puts "⚠️ Warning: Unknown factory library '#{factory_library}'. Using Active Record object creation as fallback."
|
151
|
+
load_all_fixtures_data
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.load_all_fixtures_data
|
156
|
+
fixture_data = {}
|
157
|
+
# TODO: Load proper folder for Rspec. This is only valid for minitest.
|
158
|
+
fixtures_dir = Rails.root.join("test", "fixtures")
|
159
|
+
|
160
|
+
return fixture_data unless Dir.exist?(fixtures_dir)
|
161
|
+
|
162
|
+
fixture_files = Dir.glob("#{fixtures_dir}/*.yml")
|
163
|
+
|
164
|
+
fixture_files.each do |fixture_file|
|
165
|
+
model_name = File.basename(fixture_file, ".yml")
|
166
|
+
|
167
|
+
begin
|
168
|
+
fixtures = YAML.load_file(fixture_file)
|
169
|
+
fixture_data[model_name] = fixtures
|
170
|
+
rescue StandardError => e
|
171
|
+
puts "⚠️ Warning: Could not load fixture file #{fixture_file}: #{e.message}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
fixture_data
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.load_all_fabricator_data
|
179
|
+
fabricator_data = {}
|
180
|
+
fabricators_dir = Rails.root.join("spec", "fabricators")
|
181
|
+
|
182
|
+
return fabricator_data unless Dir.exist?(fabricators_dir)
|
183
|
+
|
184
|
+
Dir.glob("#{fabricators_dir}/*_fabricator.rb").each do |fabricator_file|
|
185
|
+
model_name = File.basename(fabricator_file, "_fabricator.rb")
|
186
|
+
|
187
|
+
begin
|
188
|
+
content = File.read(fabricator_file)
|
189
|
+
fabricator_data[model_name] = parse_fabricator_structure(content, model_name)
|
190
|
+
rescue StandardError => e
|
191
|
+
puts "⚠️ Warning: Could not load fabricator file #{fabricator_file}: #{e.message}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
fabricator_data
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.load_all_factory_data
|
199
|
+
factory_data = {}
|
200
|
+
factory_dirs = [
|
201
|
+
Rails.root.join("spec", "factories"),
|
202
|
+
Rails.root.join("test", "factories")
|
203
|
+
]
|
204
|
+
|
205
|
+
factory_dirs.each do |factory_dir|
|
206
|
+
next unless Dir.exist?(factory_dir)
|
207
|
+
|
208
|
+
Dir.glob("#{factory_dir}/*.rb").each do |factory_file|
|
209
|
+
content = File.read(factory_file)
|
210
|
+
|
211
|
+
begin
|
212
|
+
# Extract all factory definitions from the file
|
213
|
+
content.scan(/factory\s+:(\w+)\s+do/) do |match|
|
214
|
+
model_name = match[0]
|
215
|
+
factory_data[model_name] = parse_factory_structure(content, model_name)
|
216
|
+
end
|
217
|
+
rescue StandardError => e
|
218
|
+
puts "⚠️ Warning: Could not load factory file #{factory_file}: #{e.message}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
factory_data
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.parse_fabricator_structure(content, model_name)
|
227
|
+
# Parse fabricator file to extract attribute structure
|
228
|
+
attributes = {}
|
229
|
+
|
230
|
+
# Look for Fabricator definitions
|
231
|
+
content.scan(/Fabricator\(:#{model_name}\) do \|f\|(.*?)end/m) do |block|
|
232
|
+
block[0].scan(/f\.(\w+)\s+(.+)/) do |attr, value|
|
233
|
+
attributes[attr] = parse_attribute_value(value)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
{ "attributes" => attributes, "type" => "fabricator" }
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.parse_factory_structure(content, model_name)
|
241
|
+
# Parse factory file to extract attribute structure
|
242
|
+
attributes = {}
|
243
|
+
|
244
|
+
# Look for factory definitions
|
245
|
+
content.scan(/factory :#{model_name} do(.*?)end/m) do |block|
|
246
|
+
block[0].scan(/(\w+)\s+(.+)/) do |attr, value|
|
247
|
+
attributes[attr] = parse_attribute_value(value)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
{ "attributes" => attributes, "type" => "factory" }
|
252
|
+
end
|
253
|
+
|
254
|
+
def self.parse_attribute_value(value)
|
255
|
+
# Clean up and parse attribute values
|
256
|
+
value.strip.gsub(/^["']|["']$/, "")
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.load_all_active_record_data
|
260
|
+
[]
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
data/lib/tng/version.rb
ADDED
data/lib/tng.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$VERBOSE = nil
|
4
|
+
|
5
|
+
require_relative "tng/version"
|
6
|
+
require_relative "tng/utils"
|
7
|
+
require_relative "tng/api/http_client"
|
8
|
+
require_relative "tng/ui/post_install_box"
|
9
|
+
require_relative "tng/services/test_generator"
|
10
|
+
|
11
|
+
require_relative "tng/railtie" if defined?(Rails)
|
12
|
+
|
13
|
+
begin
|
14
|
+
platform = RUBY_PLATFORM
|
15
|
+
binary_name = if platform.include?("darwin") # macOS
|
16
|
+
"tng.bundle"
|
17
|
+
elsif platform.include?("linux")
|
18
|
+
"tng.so"
|
19
|
+
else
|
20
|
+
raise "Unsupported platform: #{platform}"
|
21
|
+
end
|
22
|
+
|
23
|
+
binary_paths = [
|
24
|
+
File.expand_path("../binaries/#{binary_name}", __dir__), # From gem root
|
25
|
+
File.expand_path("../../binaries/#{binary_name}", __FILE__), # Alternative path
|
26
|
+
File.expand_path("binaries/#{binary_name}", __dir__) # Direct from lib
|
27
|
+
]
|
28
|
+
|
29
|
+
loaded = false
|
30
|
+
binary_paths.each do |path|
|
31
|
+
next unless File.exist?(path)
|
32
|
+
|
33
|
+
require path
|
34
|
+
loaded = true
|
35
|
+
break
|
36
|
+
end
|
37
|
+
|
38
|
+
raise LoadError, "Could not find binary at any of: #{binary_paths.join(", ")}" unless loaded
|
39
|
+
rescue LoadError => e
|
40
|
+
puts "Warning: Could not load native extension: #{e.message}"
|
41
|
+
puts "Some functionality may not be available."
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load Ruby analyzers after native binary to ensure Rust classes are available
|
45
|
+
# Ruby analyzers depend on Rust classes (e.g., Tng::Analyzer::Controller)
|
46
|
+
require_relative "tng/analyzers/controller"
|
47
|
+
require_relative "tng/analyzers/model"
|
48
|
+
require_relative "tng/analyzers/service"
|
49
|
+
|
50
|
+
module Tng
|
51
|
+
class Error < StandardError; end
|
52
|
+
|
53
|
+
@config = {
|
54
|
+
api_key: nil,
|
55
|
+
base_url: "https://app.tng.sh/",
|
56
|
+
read_source_code: true,
|
57
|
+
read_test_code: true,
|
58
|
+
testing_framework: "minitest",
|
59
|
+
authentication_enabled: false,
|
60
|
+
authorization_library: nil,
|
61
|
+
authentication_library: nil,
|
62
|
+
authentication_methods: [],
|
63
|
+
mock_library: "minitest/mock",
|
64
|
+
http_mock_library: "webmock",
|
65
|
+
factory_library: "active_record"
|
66
|
+
}
|
67
|
+
|
68
|
+
def self.configure
|
69
|
+
yield(self) if block_given?
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.config
|
73
|
+
@config
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.api_key=(value)
|
77
|
+
@config[:api_key] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.api_key
|
81
|
+
@config[:api_key]
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.base_url=(value)
|
85
|
+
@config[:base_url] = value
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.base_url
|
89
|
+
@config[:base_url]
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.read_source_code=(value)
|
93
|
+
@config[:read_source_code] = value
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.read_source_code
|
97
|
+
@config[:read_source_code]
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.read_test_code=(value)
|
101
|
+
@config[:read_test_code] = value
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.read_test_code
|
105
|
+
@config[:read_test_code]
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.testing_framework=(value)
|
109
|
+
@config[:testing_framework] = value
|
110
|
+
initialize_framework_defaults(value)
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.testing_framework
|
114
|
+
@config[:testing_framework]
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.authentication_enabled=(value)
|
118
|
+
@config[:authentication_enabled] = value
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.authentication_enabled
|
122
|
+
@config[:authentication_enabled]
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.authentication_library=(value)
|
126
|
+
@config[:authentication_library] = value
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.authentication_library
|
130
|
+
@config[:authentication_library]
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.authorization_library=(value)
|
134
|
+
@config[:authorization_library] = value
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.authorization_library
|
138
|
+
@config[:authorization_library]
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.authentication_methods=(value)
|
142
|
+
@config[:authentication_methods] = value
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.authentication_methods
|
146
|
+
@config[:authentication_methods]
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.mock_library=(value)
|
150
|
+
@config[:mock_library] = value
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.mock_library
|
154
|
+
@config[:mock_library]
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.http_mock_library=(value)
|
158
|
+
@config[:http_mock_library] = value
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.http_mock_library
|
162
|
+
@config[:http_mock_library]
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.factory_library=(value)
|
166
|
+
@config[:factory_library] = value
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.factory_library
|
170
|
+
@config[:factory_library]
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.test_style=(value)
|
174
|
+
@config[:test_style] = value
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.test_style
|
178
|
+
@config[:test_style]
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.setup_style=(value)
|
182
|
+
@config[:setup_style] = value
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.setup_style
|
186
|
+
@config[:setup_style]
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.assertion_style=(value)
|
190
|
+
@config[:assertion_style] = value
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.assertion_style
|
194
|
+
@config[:assertion_style]
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.teardown_style=(value)
|
198
|
+
@config[:teardown_style] = value
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.teardown_style
|
202
|
+
@config[:teardown_style]
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.describe_style=(value)
|
206
|
+
@config[:describe_style] = value
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.describe_style
|
210
|
+
@config[:describe_style]
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.context_style=(value)
|
214
|
+
@config[:context_style] = value
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.context_style
|
218
|
+
@config[:context_style]
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.it_style=(value)
|
222
|
+
@config[:it_style] = value
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.it_style
|
226
|
+
@config[:it_style]
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.before_style=(value)
|
230
|
+
@config[:before_style] = value
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.before_style
|
234
|
+
@config[:before_style]
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.after_style=(value)
|
238
|
+
@config[:after_style] = value
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.after_style
|
242
|
+
@config[:after_style]
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.let_style=(value)
|
246
|
+
@config[:let_style] = value
|
247
|
+
end
|
248
|
+
|
249
|
+
def self.let_style
|
250
|
+
@config[:let_style]
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.subject_style=(value)
|
254
|
+
@config[:subject_style] = value
|
255
|
+
end
|
256
|
+
|
257
|
+
def self.subject_style
|
258
|
+
@config[:subject_style]
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.initialize_framework_defaults(framework)
|
262
|
+
if framework == "minitest"
|
263
|
+
@config.merge!({
|
264
|
+
test_style: "spec",
|
265
|
+
setup_style: false,
|
266
|
+
assertion_style: "assert",
|
267
|
+
teardown_style: false
|
268
|
+
})
|
269
|
+
@config.delete(:describe_style)
|
270
|
+
@config.delete(:context_style)
|
271
|
+
@config.delete(:it_style)
|
272
|
+
@config.delete(:before_style)
|
273
|
+
@config.delete(:after_style)
|
274
|
+
@config.delete(:let_style)
|
275
|
+
@config.delete(:subject_style)
|
276
|
+
elsif framework == "rspec"
|
277
|
+
@config.merge!({
|
278
|
+
describe_style: true,
|
279
|
+
context_style: "context",
|
280
|
+
it_style: "it",
|
281
|
+
before_style: "before",
|
282
|
+
after_style: "after",
|
283
|
+
let_style: true,
|
284
|
+
subject_style: true
|
285
|
+
})
|
286
|
+
@config.delete(:test_style)
|
287
|
+
@config.delete(:setup_style)
|
288
|
+
@config.delete(:assertion_style)
|
289
|
+
@config.delete(:teardown_style)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
initialize_framework_defaults(@config[:testing_framework])
|
294
|
+
end
|
data/tng.gemspec
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/tng/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "tng"
|
7
|
+
spec.version = Tng::VERSION
|
8
|
+
spec.authors = ["claudiug"]
|
9
|
+
spec.email = ["claudiu.garba@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "TNG is a library for working with the TNG format."
|
12
|
+
spec.description = "TNG is a library for working with the TNG format."
|
13
|
+
spec.homepage = "https://github.com/claudiug/tng"
|
14
|
+
spec.required_ruby_version = ">= 3.1.0"
|
15
|
+
spec.required_rubygems_version = ">= 3.3.11"
|
16
|
+
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/claudiug/tng"
|
20
|
+
|
21
|
+
# Package pre-compiled binaries and exclude the Rust source code.
|
22
|
+
spec.files = Dir.glob("lib/**/*.rb") +
|
23
|
+
Dir.glob("binaries/*") +
|
24
|
+
Dir.glob("bin/**/*") +
|
25
|
+
["LICENSE.md", "README.md", "Gemfile", "Rakefile", "tng.gemspec"]
|
26
|
+
|
27
|
+
spec.bindir = "bin"
|
28
|
+
spec.executables = spec.files.grep(%r{\Abin/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
spec.extensions = []
|
31
|
+
|
32
|
+
spec.add_dependency "httpx", "~> 1.5"
|
33
|
+
spec.add_dependency "pastel", "~> 0.8.0"
|
34
|
+
spec.add_dependency "prism", "~> 1.4.0"
|
35
|
+
spec.add_dependency "rb_sys", "~> 0.9.91"
|
36
|
+
spec.add_dependency "tty-box", "~> 0.7"
|
37
|
+
spec.add_dependency "tty-file", "~> 0.10"
|
38
|
+
spec.add_dependency "tty-option", "~> 0.3"
|
39
|
+
spec.add_dependency "tty-progressbar", "~> 0.18.3"
|
40
|
+
spec.add_dependency "tty-prompt", "~> 0.23"
|
41
|
+
spec.add_dependency "tty-reader", "~> 0.9"
|
42
|
+
spec.add_dependency "tty-screen", "~> 0.8"
|
43
|
+
spec.add_dependency "tty-spinner", "~> 0.9.3"
|
44
|
+
spec.add_dependency "tty-table", "~> 0.12"
|
45
|
+
|
46
|
+
spec.post_install_message = begin
|
47
|
+
require_relative "lib/tng/ui/post_install_box"
|
48
|
+
PostInstallBox.new(spec.version).render
|
49
|
+
rescue LoadError, StandardError
|
50
|
+
"TestNG v#{spec.version} installed successfully!\n" +
|
51
|
+
"Run 'rails g tng:install' to get started.\n" +
|
52
|
+
"Use 'bundle exec tng --help' for usage information."
|
53
|
+
end
|
54
|
+
end
|