tng 0.2.8 → 0.3.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/bin/tng +2 -2
- data/binaries/go-ui-darwin-amd64 +0 -0
- data/binaries/go-ui-darwin-arm64 +0 -0
- data/binaries/go-ui-linux-amd64 +0 -0
- data/binaries/go-ui-linux-arm64 +0 -0
- data/binaries/tng.bundle +0 -0
- data/binaries/tng.so +0 -0
- data/lib/generators/tng/install_generator.rb +7 -1
- data/lib/tng/analyzers/model.rb +60 -23
- data/lib/tng/analyzers/service.rb +1 -1
- data/lib/tng/services/test_generator.rb +4 -4
- data/lib/tng/services/user_app_config.rb +25 -0
- data/lib/tng/version.rb +1 -1
- data/lib/tng.rb +10 -1
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1565b9f82ca06425bf3e88f44f018c0d34e7f3adc5cc91c111a593689303ef77
|
|
4
|
+
data.tar.gz: 5a5868449487efa2f07d4d9d57aa3dc4ea1ac050f4b530f225e72bbb7067337a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 11945827a48c2f3e3ff40b5e7c24f356d466b00c0b1b0bcebf397188477b9ce08c10843d762d2ac1835c9ad582c2d26c283fb569eabff395981aa73273320c02
|
|
7
|
+
data.tar.gz: '0644595817a169561541f4f052b417435e2ba21629cbf3c144d92a188006cec4fc953edb638517adaaca82bcab4e648782fdfdcb59795a2c1e8bfb42d334d04e'
|
data/bin/tng
CHANGED
|
@@ -827,7 +827,7 @@ class CLI
|
|
|
827
827
|
|
|
828
828
|
info_msg = [
|
|
829
829
|
@pastel.decorate("#{Tng::UI::Theme.icon(:config)} File: #{result[:file_path]}", Tng::UI::Theme.color(:info)),
|
|
830
|
-
@pastel.decorate("#{Tng::UI::Theme.icon(:marker)} Run: #{result[:run_command]}", Tng::UI::Theme.color(:
|
|
830
|
+
@pastel.decorate("#{Tng::UI::Theme.icon(:marker)} Run: #{result[:run_command]}", Tng::UI::Theme.color(:secondary))
|
|
831
831
|
].join("\n")
|
|
832
832
|
puts center_text(info_msg)
|
|
833
833
|
puts
|
|
@@ -845,7 +845,7 @@ class CLI
|
|
|
845
845
|
|
|
846
846
|
info_msg = [
|
|
847
847
|
@pastel.decorate("#{Tng::UI::Theme.icon(:config)} File: #{result[:file_path]}", Tng::UI::Theme.color(:info)),
|
|
848
|
-
@pastel.decorate("#{Tng::UI::Theme.icon(:marker)} Run: #{result[:run_command]}", Tng::UI::Theme.color(:
|
|
848
|
+
@pastel.decorate("#{Tng::UI::Theme.icon(:marker)} Run: #{result[:run_command]}", Tng::UI::Theme.color(:secondary))
|
|
849
849
|
].join("\n")
|
|
850
850
|
puts center_text(info_msg)
|
|
851
851
|
puts
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/binaries/tng.bundle
CHANGED
|
Binary file
|
data/binaries/tng.so
CHANGED
|
Binary file
|
|
@@ -68,7 +68,7 @@ module Tng
|
|
|
68
68
|
[
|
|
69
69
|
"# frozen_string_literal: true",
|
|
70
70
|
"",
|
|
71
|
-
"return
|
|
71
|
+
"return unless Rails.env.development?",
|
|
72
72
|
"",
|
|
73
73
|
"Tng.configure do |config|",
|
|
74
74
|
" config.api_key = nil",
|
|
@@ -88,6 +88,12 @@ module Tng
|
|
|
88
88
|
" # Leave empty [] to auto-detect from project",
|
|
89
89
|
" config.test_examples = #{test_examples_config}",
|
|
90
90
|
"",
|
|
91
|
+
" # Source Code Reading Configuration",
|
|
92
|
+
" # When enabled (true), TNG will only read the file where the method is located",
|
|
93
|
+
" # and will not analyze other files in the project. This may increase the accuracy of the tests,",
|
|
94
|
+
" # but it may also increase the time it takes to generate the tests.",
|
|
95
|
+
" config.read_file_source_code = false # Options: true, false",
|
|
96
|
+
"",
|
|
91
97
|
" # Authentication#{auth_comment}",
|
|
92
98
|
" #{auth_enabled} # Options: true, false",
|
|
93
99
|
" #{auth_lib} # Options: devise, clearance, sorcery, nil",
|
data/lib/tng/analyzers/model.rb
CHANGED
|
@@ -33,32 +33,50 @@ module Tng
|
|
|
33
33
|
instance_methods = model_class.public_instance_methods(false)
|
|
34
34
|
class_methods = model_class.public_methods(false) - Class.public_methods
|
|
35
35
|
|
|
36
|
-
model_file =
|
|
36
|
+
model_file = Object.const_source_location(model_class.name)&.first
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
if model_file && File.exist?(model_file)
|
|
39
|
+
source_code = File.read(model_file)
|
|
40
|
+
result = Prism.parse(source_code)
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
defined_methods = []
|
|
43
|
+
synthetic_methods = []
|
|
44
|
+
scopes = []
|
|
45
|
+
validations = []
|
|
46
|
+
extract_method_names(result.value, defined_methods, synthetic_methods, scopes, validations)
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
filtered_instance_methods = instance_methods.select do |method_name|
|
|
49
|
+
method = model_class.instance_method(method_name)
|
|
50
|
+
next false unless method.owner == model_class
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
defined_methods.include?(method_name.to_s)
|
|
53
|
+
end
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
filtered_class_methods = class_methods.select do |method_name|
|
|
56
|
+
defined_methods.include?(method_name.to_s)
|
|
57
|
+
end
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
# Return array of hashes with type information
|
|
60
|
+
instance_method_hashes = filtered_instance_methods.map do |name|
|
|
61
|
+
{ name: name.to_s, type: "instance_method" }
|
|
62
|
+
end
|
|
63
|
+
class_method_hashes = filtered_class_methods.map do |name|
|
|
64
|
+
{ name: name.to_s, type: "class_method" }
|
|
65
|
+
end
|
|
66
|
+
synthetic_method_hashes = synthetic_methods.map do |name|
|
|
67
|
+
{ name: name.to_s, type: "synthetic" }
|
|
68
|
+
end
|
|
69
|
+
scope_hashes = scopes.map do |name|
|
|
70
|
+
{ name: name.to_s, type: "scope" }
|
|
71
|
+
end
|
|
72
|
+
validation_hashes = validations.map do |name|
|
|
73
|
+
{ name: name.to_s, type: "validation" }
|
|
74
|
+
end
|
|
60
75
|
|
|
61
|
-
|
|
76
|
+
instance_method_hashes + class_method_hashes + synthetic_method_hashes + scope_hashes + validation_hashes
|
|
77
|
+
else
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
62
80
|
rescue NameError => e
|
|
63
81
|
puts "❌ Could not load model class #{model_name}: #{e.message}"
|
|
64
82
|
[]
|
|
@@ -68,7 +86,7 @@ module Tng
|
|
|
68
86
|
end
|
|
69
87
|
end
|
|
70
88
|
|
|
71
|
-
def self.extract_method_names(node, methods)
|
|
89
|
+
def self.extract_method_names(node, methods, synthetic_methods = [], scopes = [], validations = [])
|
|
72
90
|
return unless node.is_a?(Prism::Node)
|
|
73
91
|
|
|
74
92
|
case node
|
|
@@ -81,18 +99,37 @@ module Tng
|
|
|
81
99
|
first_arg = node.arguments.arguments.first
|
|
82
100
|
if first_arg.is_a?(Prism::SymbolNode)
|
|
83
101
|
scope_name = first_arg.value
|
|
84
|
-
|
|
102
|
+
scopes << scope_name if scope_name
|
|
103
|
+
end
|
|
104
|
+
# Handle validation macros
|
|
105
|
+
elsif node.name.to_s.start_with?("validate") && node.arguments&.arguments&.any?
|
|
106
|
+
if node.name == :validate
|
|
107
|
+
# Custom validation: validate :method_name -> extract actual method
|
|
108
|
+
node.arguments.arguments.each do |arg|
|
|
109
|
+
if arg.is_a?(Prism::SymbolNode)
|
|
110
|
+
validation_method = arg.value
|
|
111
|
+
validations << validation_method if validation_method
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
# Built-in validations: validates :attr, :attr2, ... -> add to validations
|
|
116
|
+
node.arguments.arguments.each do |arg|
|
|
117
|
+
if arg.is_a?(Prism::SymbolNode)
|
|
118
|
+
attr_name = arg.value
|
|
119
|
+
validations << attr_name if attr_name
|
|
120
|
+
end
|
|
121
|
+
end
|
|
85
122
|
end
|
|
86
123
|
end
|
|
87
124
|
when Prism::SingletonClassNode
|
|
88
125
|
# Methods inside class << self blocks
|
|
89
126
|
node.body&.child_nodes&.each do |child|
|
|
90
|
-
extract_method_names(child, methods)
|
|
127
|
+
extract_method_names(child, methods, synthetic_methods, scopes, validations)
|
|
91
128
|
end
|
|
92
129
|
end
|
|
93
130
|
|
|
94
131
|
node.child_nodes.each do |child|
|
|
95
|
-
extract_method_names(child, methods)
|
|
132
|
+
extract_method_names(child, methods, synthetic_methods, scopes, validations)
|
|
96
133
|
end
|
|
97
134
|
end
|
|
98
135
|
end
|
|
@@ -47,7 +47,7 @@ module Tng
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
# Fallback to const_source_location if no method source found
|
|
50
|
-
service_file ||=
|
|
50
|
+
service_file ||= Object.const_source_location(service_class.name)&.first
|
|
51
51
|
|
|
52
52
|
service_methods = if service_file && File.exist?(service_file)
|
|
53
53
|
source_code = File.read(service_file)
|
|
@@ -87,13 +87,13 @@ module Tng
|
|
|
87
87
|
|
|
88
88
|
case type
|
|
89
89
|
when :controller
|
|
90
|
-
Tng.send_request_for_controller(name, file_object[:path], method_info
|
|
90
|
+
Tng.send_request_for_controller(name, file_object[:path], method_info, *config)
|
|
91
91
|
when :model
|
|
92
|
-
Tng.send_request_for_model(name, file_object[:path], method_info
|
|
92
|
+
Tng.send_request_for_model(name, file_object[:path], method_info, *config)
|
|
93
93
|
when :service
|
|
94
|
-
Tng.send_request_for_service(name, file_object[:path], method_info
|
|
94
|
+
Tng.send_request_for_service(name, file_object[:path], method_info, *config)
|
|
95
95
|
when :other
|
|
96
|
-
Tng.send_request_for_other(name, file_object[:path], method_info
|
|
96
|
+
Tng.send_request_for_other(name, file_object[:path], method_info, *config)
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -34,6 +34,18 @@ module Tng
|
|
|
34
34
|
}
|
|
35
35
|
end
|
|
36
36
|
Tng.config[:authentication_entry_points_with_source] = auth_entry_points_with_source
|
|
37
|
+
|
|
38
|
+
# Add source content to test examples for API requests
|
|
39
|
+
if Tng.config[:test_examples]&.any?
|
|
40
|
+
Tng.config[:test_examples] = Tng.config[:test_examples].map do |example|
|
|
41
|
+
next example unless example.is_a?(Hash) && example["path"]
|
|
42
|
+
|
|
43
|
+
example.merge("source" => read_test_file_content(example["path"]))
|
|
44
|
+
rescue StandardError
|
|
45
|
+
example
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
37
49
|
Tng.config
|
|
38
50
|
end
|
|
39
51
|
|
|
@@ -71,6 +83,19 @@ module Tng
|
|
|
71
83
|
rescue StandardError
|
|
72
84
|
nil
|
|
73
85
|
end
|
|
86
|
+
|
|
87
|
+
def self.read_test_file_content(relative_path)
|
|
88
|
+
return nil unless relative_path
|
|
89
|
+
|
|
90
|
+
rails_root = defined?(Rails) && Rails.root ? Rails.root.to_s : Dir.pwd
|
|
91
|
+
full_path = File.join(rails_root, relative_path)
|
|
92
|
+
|
|
93
|
+
return nil unless File.exist?(full_path) && File.readable?(full_path)
|
|
94
|
+
|
|
95
|
+
File.read(full_path)
|
|
96
|
+
rescue StandardError
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
74
99
|
end
|
|
75
100
|
end
|
|
76
101
|
end
|
data/lib/tng/version.rb
CHANGED
data/lib/tng.rb
CHANGED
|
@@ -61,7 +61,8 @@ module Tng
|
|
|
61
61
|
mock_library: "minitest/mock",
|
|
62
62
|
http_mock_library: "webmock",
|
|
63
63
|
factory_library: "active_record",
|
|
64
|
-
test_examples: []
|
|
64
|
+
test_examples: [],
|
|
65
|
+
read_file_source_code: false
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
def self.configure
|
|
@@ -249,6 +250,14 @@ module Tng
|
|
|
249
250
|
@config[:test_examples]
|
|
250
251
|
end
|
|
251
252
|
|
|
253
|
+
def self.read_file_source_code=(value)
|
|
254
|
+
@config[:read_file_source_code] = value
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def self.read_file_source_code
|
|
258
|
+
@config[:read_file_source_code]
|
|
259
|
+
end
|
|
260
|
+
|
|
252
261
|
def self.authentication_configured?
|
|
253
262
|
return false unless authentication_enabled
|
|
254
263
|
return false if authentication_methods.nil? || authentication_methods.empty?
|
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.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ralucab
|
|
@@ -222,6 +222,10 @@ files:
|
|
|
222
222
|
- Rakefile
|
|
223
223
|
- bin/load_dev
|
|
224
224
|
- bin/tng
|
|
225
|
+
- binaries/go-ui-darwin-amd64
|
|
226
|
+
- binaries/go-ui-darwin-arm64
|
|
227
|
+
- binaries/go-ui-linux-amd64
|
|
228
|
+
- binaries/go-ui-linux-arm64
|
|
225
229
|
- binaries/tng.bundle
|
|
226
230
|
- binaries/tng.so
|
|
227
231
|
- lib/generators/tng/install_generator.rb
|
|
@@ -287,7 +291,7 @@ post_install_message: "┌ TNG ────────────────
|
|
|
287
291
|
\ │\n│ • bundle exec
|
|
288
292
|
tng --help - Show help information │\n│ │\n│
|
|
289
293
|
\ \U0001F4A1 Generate tests for individual methods with precision │\n└────────────────────────────────────────────────────────────
|
|
290
|
-
v0.
|
|
294
|
+
v0.3.0 ┘\n"
|
|
291
295
|
rdoc_options: []
|
|
292
296
|
require_paths:
|
|
293
297
|
- lib
|