tng 0.1.6 ā 0.2.1
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/LICENSE.md +1 -1
- data/README.md +6 -20
- data/bin/tng +238 -472
- data/binaries/tng.bundle +0 -0
- data/binaries/tng.so +0 -0
- data/lib/tng/analyzers/model.rb +9 -0
- data/lib/tng/analyzers/other.rb +277 -0
- data/lib/tng/analyzers/service.rb +1 -0
- data/lib/tng/api/http_client.rb +21 -23
- data/lib/tng/services/direct_generation.rb +320 -0
- data/lib/tng/services/extract_methods.rb +39 -0
- data/lib/tng/services/test_generator.rb +232 -104
- data/lib/tng/services/testng.rb +2 -2
- data/lib/tng/services/user_app_config.rb +5 -6
- data/lib/tng/ui/about_display.rb +7 -5
- data/lib/tng/ui/controller_test_flow_display.rb +0 -17
- data/lib/tng/ui/model_test_flow_display.rb +0 -17
- data/lib/tng/ui/other_test_flow_display.rb +78 -0
- data/lib/tng/ui/post_install_box.rb +7 -9
- data/lib/tng/ui/service_test_flow_display.rb +0 -17
- data/lib/tng/ui/show_help.rb +11 -68
- data/lib/tng/utils.rb +67 -5
- data/lib/tng/version.rb +1 -1
- metadata +15 -11
data/lib/tng/ui/show_help.rb
CHANGED
@@ -24,89 +24,32 @@ class ShowHelp
|
|
24
24
|
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Usage:"),
|
25
25
|
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
26
26
|
" bundle exec tng") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
27
|
-
" # Interactive mode"),
|
28
|
-
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
29
|
-
" bundle exec tng --type=TYPE --file=FILE") + @pastel.public_send(
|
30
|
-
Tng::UI::Theme.color(:muted), " # Direct mode"
|
31
|
-
),
|
32
|
-
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
33
|
-
" bundle exec tng -t TYPE -f FILE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
34
|
-
" # Short aliases"),
|
35
|
-
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
36
|
-
" bundle exec tng -t=TYPE f=FILE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
37
|
-
" # Mixed format"),
|
27
|
+
" # Interactive mode only"),
|
38
28
|
"",
|
39
|
-
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("
|
40
|
-
@pastel.public_send(Tng::UI::Theme.color(:success),
|
41
|
-
" bundle exec tng -t c -f ping") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
42
|
-
" # Controller test"),
|
29
|
+
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Features:"),
|
43
30
|
@pastel.public_send(Tng::UI::Theme.color(:success),
|
44
|
-
"
|
45
|
-
" # Mixed format"),
|
31
|
+
" #{Tng::UI::Theme.icon(:bullet)} Controllers, Models, Services"),
|
46
32
|
@pastel.public_send(Tng::UI::Theme.color(:success),
|
47
|
-
"
|
48
|
-
" # Model test"),
|
33
|
+
" #{Tng::UI::Theme.icon(:bullet)} 17+ other file types (Jobs, Helpers, Lib, Policies, Presenters, Mailers, GraphQL, etc.)"),
|
49
34
|
@pastel.public_send(Tng::UI::Theme.color(:success),
|
50
|
-
"
|
51
|
-
" # Service test"),
|
35
|
+
" #{Tng::UI::Theme.icon(:bullet)} Per-method test generation"),
|
52
36
|
@pastel.public_send(Tng::UI::Theme.color(:success),
|
53
|
-
"
|
54
|
-
@pastel.public_send(Tng::UI::Theme.color(:success),
|
55
|
-
" bundle exec tng -t c -f \"admin/users_controller\"") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
56
|
-
" # Namespaced"),
|
37
|
+
" #{Tng::UI::Theme.icon(:bullet)} Searchable method lists"),
|
57
38
|
"",
|
58
39
|
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Options:"),
|
59
|
-
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
60
|
-
" -t, --type=TYPE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
61
|
-
" Test type (controller, model, service)"),
|
62
|
-
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
63
|
-
" -f, --file=FILE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
64
|
-
" File name (without .rb extension)"),
|
65
|
-
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
66
|
-
" -m, --method=METHOD") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
67
|
-
" Method name (for per-method tests)"),
|
68
40
|
@pastel.public_send(Tng::UI::Theme.color(:primary),
|
69
41
|
" -h, --help") + @pastel.public_send(Tng::UI::Theme.color(:muted),
|
70
42
|
" Show this help message"),
|
71
43
|
"",
|
72
|
-
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("
|
44
|
+
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("How to Use:"),
|
73
45
|
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
74
|
-
" #{Tng::UI::Theme.icon(:bullet)}
|
75
|
-
"c, controller"),
|
76
|
-
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
77
|
-
" #{Tng::UI::Theme.icon(:bullet)} Models: ") + @pastel.public_send(
|
78
|
-
Tng::UI::Theme.color(:secondary), "m, mo, model"
|
79
|
-
),
|
80
|
-
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
81
|
-
" #{Tng::UI::Theme.icon(:bullet)} Services: ") + @pastel.public_send(
|
82
|
-
Tng::UI::Theme.color(:secondary), "s, se, service"
|
83
|
-
),
|
84
|
-
"",
|
85
|
-
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("File Format:"),
|
86
|
-
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
87
|
-
" #{Tng::UI::Theme.icon(:bullet)} Controllers: ") + @pastel.public_send(Tng::UI::Theme.color(:success),
|
88
|
-
"users_controller, api/v1/posts_controller"),
|
89
|
-
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
90
|
-
" #{Tng::UI::Theme.icon(:bullet)} Models: ") + @pastel.public_send(
|
91
|
-
Tng::UI::Theme.color(:success), "user, blog/post"
|
92
|
-
),
|
93
|
-
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
94
|
-
" #{Tng::UI::Theme.icon(:bullet)} Services: ") + @pastel.public_send(
|
95
|
-
Tng::UI::Theme.color(:success), "user_service, payment/stripe_service"
|
96
|
-
),
|
97
|
-
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
98
|
-
" #{Tng::UI::Theme.icon(:bullet)} Don't include .rb extension"),
|
99
|
-
"",
|
100
|
-
@pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Pro Tips:"),
|
46
|
+
" #{Tng::UI::Theme.icon(:bullet)} Run 'bundle exec tng' to start the interactive interface"),
|
101
47
|
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
102
|
-
" #{Tng::UI::Theme.icon(:bullet)}
|
103
|
-
"-t=c f=ping") + @pastel.public_send(
|
104
|
-
Tng::UI::Theme.color(:muted), " works perfectly"
|
105
|
-
),
|
48
|
+
" #{Tng::UI::Theme.icon(:bullet)} Select Controller, Model, Service, or Other to test"),
|
106
49
|
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
107
|
-
" #{Tng::UI::Theme.icon(:bullet)}
|
50
|
+
" #{Tng::UI::Theme.icon(:bullet)} Choose a specific method from the list"),
|
108
51
|
@pastel.public_send(Tng::UI::Theme.color(:muted),
|
109
|
-
" #{Tng::UI::Theme.icon(:bullet)}
|
52
|
+
" #{Tng::UI::Theme.icon(:bullet)} Use search/filter to find methods quickly"),
|
110
53
|
"",
|
111
54
|
@pastel.public_send(Tng::UI::Theme.color(:secondary)).bold("Happy testing! ") + @pastel.public_send(
|
112
55
|
Tng::UI::Theme.color(:accent), "ā
"
|
data/lib/tng/utils.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require "yaml"
|
2
2
|
require "json"
|
3
|
+
require "fileutils"
|
4
|
+
require "prism"
|
3
5
|
|
4
6
|
module Tng
|
5
7
|
module Utils
|
@@ -98,26 +100,39 @@ module Tng
|
|
98
100
|
puts "š Raw API response: #{test_content[0..200]}..." if ENV["DEBUG"]
|
99
101
|
parsed_response = JSON.parse(test_content)
|
100
102
|
|
103
|
+
if parsed_response["error"]
|
104
|
+
puts "ā API responded with an error: #{parsed_response["error"]}"
|
105
|
+
return
|
106
|
+
end
|
101
107
|
# Validate required fields
|
102
108
|
unless parsed_response["file_content"]
|
103
109
|
puts "ā API response missing file_content field"
|
104
110
|
puts "š Response keys: #{parsed_response.keys.inspect}"
|
105
|
-
return
|
111
|
+
return
|
106
112
|
end
|
107
113
|
|
108
114
|
# Handle both possible field names for file path
|
109
|
-
file_path = parsed_response["test_file_path"] || parsed_response["file_path"]
|
115
|
+
file_path = parsed_response["test_file_path"] || parsed_response["file_path"] || parsed_response["file_name"] || parsed_response["file"]
|
110
116
|
unless file_path
|
111
117
|
puts "ā API response missing test_file_path or file_path field"
|
112
118
|
puts "š Response keys: #{parsed_response.keys.inspect}"
|
113
|
-
return
|
119
|
+
return
|
114
120
|
end
|
115
121
|
|
116
|
-
|
122
|
+
begin
|
123
|
+
File.write(file_path, parsed_response["file_content"])
|
124
|
+
rescue Errno::ENOENT
|
125
|
+
# Create directory if it doesn't exist
|
126
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
127
|
+
File.write(file_path, parsed_response["file_content"])
|
128
|
+
end
|
117
129
|
puts "ā
Test generated successfully!"
|
118
130
|
absolute_path = File.expand_path(file_path)
|
119
131
|
puts "Please review the generated tests at \e]8;;file://#{absolute_path}\e\\#{file_path}\e]8;;\e\\"
|
120
132
|
|
133
|
+
# Count tests in the generated file
|
134
|
+
test_count = count_tests_in_file(file_path)
|
135
|
+
|
121
136
|
# Determine run command based on test framework
|
122
137
|
run_command = if file_path.include?("/spec/")
|
123
138
|
"bundle exec rspec #{file_path}"
|
@@ -130,7 +145,8 @@ module Tng
|
|
130
145
|
file_path: file_path,
|
131
146
|
absolute_path: absolute_path,
|
132
147
|
run_command: run_command,
|
133
|
-
test_class_name: parsed_response["test_class_name"]
|
148
|
+
test_class_name: parsed_response["test_class_name"],
|
149
|
+
test_count: test_count
|
134
150
|
}
|
135
151
|
end
|
136
152
|
|
@@ -259,5 +275,51 @@ module Tng
|
|
259
275
|
def self.load_all_active_record_data
|
260
276
|
[]
|
261
277
|
end
|
278
|
+
|
279
|
+
def self.count_tests_in_file(file_path)
|
280
|
+
return 0 unless File.exist?(file_path)
|
281
|
+
|
282
|
+
begin
|
283
|
+
content = File.read(file_path)
|
284
|
+
result = Prism.parse(content)
|
285
|
+
return 0 unless result.success?
|
286
|
+
|
287
|
+
count_test_nodes(result.value)
|
288
|
+
rescue StandardError => e
|
289
|
+
puts "ā ļø Warning: Could not parse #{file_path}: #{e.message}" if ENV["DEBUG"]
|
290
|
+
0
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
private_class_method def self.count_test_nodes(node)
|
295
|
+
return 0 unless node.respond_to?(:child_nodes)
|
296
|
+
|
297
|
+
count = 0
|
298
|
+
|
299
|
+
# Check if current node is a test
|
300
|
+
count += 1 if test_node?(node)
|
301
|
+
|
302
|
+
# Recursively check child nodes
|
303
|
+
node.child_nodes.each do |child|
|
304
|
+
count += count_test_nodes(child) if child
|
305
|
+
end
|
306
|
+
|
307
|
+
count
|
308
|
+
end
|
309
|
+
|
310
|
+
private_class_method def self.test_node?(node)
|
311
|
+
case node
|
312
|
+
when Prism::DefNode
|
313
|
+
# Minitest: def test_something
|
314
|
+
node.name.to_s.start_with?("test_")
|
315
|
+
when Prism::CallNode
|
316
|
+
# RSpec: it "...", specify "..."
|
317
|
+
# Minitest: test "..."
|
318
|
+
method_name = node.name.to_s
|
319
|
+
%w[it specify test].include?(method_name)
|
320
|
+
else
|
321
|
+
false
|
322
|
+
end
|
323
|
+
end
|
262
324
|
end
|
263
325
|
end
|
data/lib/tng/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tng
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ralucab
|
@@ -214,9 +214,12 @@ files:
|
|
214
214
|
- lib/tng.rb
|
215
215
|
- lib/tng/analyzers/controller.rb
|
216
216
|
- lib/tng/analyzers/model.rb
|
217
|
+
- lib/tng/analyzers/other.rb
|
217
218
|
- lib/tng/analyzers/service.rb
|
218
219
|
- lib/tng/api/http_client.rb
|
219
220
|
- lib/tng/railtie.rb
|
221
|
+
- lib/tng/services/direct_generation.rb
|
222
|
+
- lib/tng/services/extract_methods.rb
|
220
223
|
- lib/tng/services/test_generator.rb
|
221
224
|
- lib/tng/services/testng.rb
|
222
225
|
- lib/tng/services/user_app_config.rb
|
@@ -227,6 +230,7 @@ files:
|
|
227
230
|
- lib/tng/ui/display_banner.rb
|
228
231
|
- lib/tng/ui/goodbye_display.rb
|
229
232
|
- lib/tng/ui/model_test_flow_display.rb
|
233
|
+
- lib/tng/ui/other_test_flow_display.rb
|
230
234
|
- lib/tng/ui/post_install_box.rb
|
231
235
|
- lib/tng/ui/service_test_flow_display.rb
|
232
236
|
- lib/tng/ui/show_help.rb
|
@@ -259,16 +263,16 @@ post_install_message: "ā TNG āāāāāāāāāāāāāāāā
|
|
259
263
|
\ ā\nā \U0001F680
|
260
264
|
Usage: ā\nā ā\nā
|
261
265
|
\ Interactive mode: ā\nā ⢠bundle
|
262
|
-
exec tng -
|
263
|
-
\
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
\
|
268
|
-
|
269
|
-
|
270
|
-
\
|
271
|
-
v0.1
|
266
|
+
exec tng - Interactive CLI with method selection ā\nā ā\nā
|
267
|
+
\ Features: ā\nā ⢠Test
|
268
|
+
20+ file types: Controllers, Models, Services + Jobs, ā\nā Helpers, Lib, Policies,
|
269
|
+
Presenters, Mailers, GraphQL, and more ā\nā ⢠Select specific methods to test
|
270
|
+
\ ā\nā ⢠Search and filter through methods ā\nā
|
271
|
+
\ ā\nā Help:
|
272
|
+
\ ā\nā ⢠bundle exec
|
273
|
+
tng --help - Show help information ā\nā ā\nā
|
274
|
+
\ \U0001F4A1 Generate tests for individual methods with precision ā\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
275
|
+
v0.2.1 ā\n"
|
272
276
|
rdoc_options: []
|
273
277
|
require_paths:
|
274
278
|
- lib
|