tng 0.5.2 → 0.5.3
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 +4 -4
- data/bin/tng +137 -36
- 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-darwin-arm64.bundle +0 -0
- data/binaries/tng-darwin-x86_64.bundle +0 -0
- data/binaries/tng-linux-arm64.so +0 -0
- data/binaries/tng-linux-x86_64.so +0 -0
- data/binaries/tng.bundle +0 -0
- data/lib/tng/services/direct_generation.rb +3 -0
- data/lib/tng/ui/go_ui_session.rb +4 -4
- data/lib/tng/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e58f1737f7ea5758205fa1f6b41985b468d090cb9c770a7af7ed3e78f3cff989
|
|
4
|
+
data.tar.gz: 5b8f8c374574ca0dd254a6c3549418cdaf508842740911203f12f86c581690d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc2064efd17db8711d02eb8a3e75197fb3fb2ea016a23e75bafc7094875779d092c1cfeb2773f4f918aafa66bb4d93aa7d589233fbe8d1e466e2f439e3e2da42
|
|
7
|
+
data.tar.gz: f635125b141d218d832f08da04143bbc41f24faf18ee5d056d0b1aee0c57829bb22530b486b8c615c201a2339de05c2ce70b6087bb7eec1c6d4187a1d16c3dbd
|
data/README.md
CHANGED
|
@@ -144,12 +144,12 @@ bundle exec tng -f order.rb -m calculate_total -t
|
|
|
144
144
|
- Method call chains
|
|
145
145
|
- Mermaid diagram generation
|
|
146
146
|
|
|
147
|
-
####
|
|
147
|
+
#### Regression Check
|
|
148
148
|
|
|
149
149
|
Compare a method against its committed (`HEAD`) version and surface blast radius:
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
|
-
# Run
|
|
152
|
+
# Run regression check for a method
|
|
153
153
|
bundle exec tng --file app/services/payment_service.rb --method process_payment --impact
|
|
154
154
|
|
|
155
155
|
# JSON output for automation/CI
|
|
@@ -318,7 +318,7 @@ Path 3: !discount_code.present? → calculate_tax → total
|
|
|
318
318
|
| `--method` | `-m` | Method name to analyze |
|
|
319
319
|
| `--audit` | `-a` | Run audit mode |
|
|
320
320
|
| `--trace` | `-t` | Run symbolic trace mode |
|
|
321
|
-
| `--impact` | | Run
|
|
321
|
+
| `--impact` | | Run regression check mode |
|
|
322
322
|
| `--clones` | `-c` | Run clone detection |
|
|
323
323
|
| `--deadcode` | `-d` | Run dead code detection |
|
|
324
324
|
| `--level` | `-l` | Clone detection level (1, 2, 3, or all) |
|
|
@@ -337,7 +337,7 @@ bundle exec tng -f payment_service.rb -m process -a
|
|
|
337
337
|
# Symbolic trace
|
|
338
338
|
bundle exec tng -f order.rb -m calculate_total -t
|
|
339
339
|
|
|
340
|
-
#
|
|
340
|
+
# Regression check
|
|
341
341
|
bundle exec tng -f payment_service.rb -m process --impact
|
|
342
342
|
|
|
343
343
|
# Clone detection (all levels)
|
data/bin/tng
CHANGED
|
@@ -32,6 +32,17 @@ class CLI
|
|
|
32
32
|
include TTY::Option
|
|
33
33
|
include Tng::Utils
|
|
34
34
|
|
|
35
|
+
def method_label(class_name, method_name)
|
|
36
|
+
return method_name if class_name.nil? || class_name.empty?
|
|
37
|
+
"#{class_name}##{method_name}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def parse_method_label(label)
|
|
41
|
+
return [nil, label] if label.nil? || !label.include?("#")
|
|
42
|
+
class_name, method_name = label.split("#", 2)
|
|
43
|
+
[class_name, method_name]
|
|
44
|
+
end
|
|
45
|
+
|
|
35
46
|
usage do
|
|
36
47
|
program "tng"
|
|
37
48
|
desc "LLM-Powered Rails Test Generator"
|
|
@@ -57,8 +68,11 @@ class CLI
|
|
|
57
68
|
example " bundle exec tng app/services/payment_processor.rb process_payment --xray", ""
|
|
58
69
|
example " bundle exec tng --file=users_controller.rb --method=create --xray --json", ""
|
|
59
70
|
example ""
|
|
60
|
-
example "
|
|
71
|
+
example "Regression Check:", ""
|
|
61
72
|
example " bundle exec tng --file=app/services/payment_service.rb --method=process --impact", ""
|
|
73
|
+
example ""
|
|
74
|
+
example "Call Sites:", ""
|
|
75
|
+
example " bundle exec tng --file=app/services/payment_service.rb --method=process --callsites", ""
|
|
62
76
|
end
|
|
63
77
|
|
|
64
78
|
option :file do
|
|
@@ -73,6 +87,11 @@ class CLI
|
|
|
73
87
|
desc "Method name (for per-method tests)"
|
|
74
88
|
end
|
|
75
89
|
|
|
90
|
+
option :class_name do
|
|
91
|
+
long "--class=CLASS"
|
|
92
|
+
desc "Class/module name to disambiguate methods when multiple classes define the same method in a file"
|
|
93
|
+
end
|
|
94
|
+
|
|
76
95
|
flag :clones do
|
|
77
96
|
short "-c"
|
|
78
97
|
long "--clones"
|
|
@@ -107,9 +126,14 @@ class CLI
|
|
|
107
126
|
desc "Generate and visualize a symbolic trace"
|
|
108
127
|
end
|
|
109
128
|
|
|
129
|
+
flag :callsites do
|
|
130
|
+
long "--callsites"
|
|
131
|
+
desc "Find in-repo call sites for a method"
|
|
132
|
+
end
|
|
133
|
+
|
|
110
134
|
flag :impact do
|
|
111
135
|
long "--impact"
|
|
112
|
-
desc "Run
|
|
136
|
+
desc "Run regression check (compare against Git HEAD)"
|
|
113
137
|
end
|
|
114
138
|
|
|
115
139
|
flag :xray do
|
|
@@ -172,6 +196,8 @@ class CLI
|
|
|
172
196
|
handle_fix_command
|
|
173
197
|
elsif params[:impact] && params[:file]
|
|
174
198
|
run_direct_impact
|
|
199
|
+
elsif params[:callsites] && params[:file]
|
|
200
|
+
run_direct_call_sites
|
|
175
201
|
elsif params[:trace] && params[:file]
|
|
176
202
|
run_direct_trace
|
|
177
203
|
elsif params[:deadcode]
|
|
@@ -220,6 +246,8 @@ class CLI
|
|
|
220
246
|
normalized << "--impact"
|
|
221
247
|
when /^(?:--)?(xray)$/
|
|
222
248
|
normalized << "--xray"
|
|
249
|
+
when /^(?:--)?(callsites)$/
|
|
250
|
+
normalized << "--callsites"
|
|
223
251
|
when /^(?:--)?(json|j)$/
|
|
224
252
|
normalized << "--json"
|
|
225
253
|
when /^(?:--)?(fix|x)$/
|
|
@@ -518,12 +546,14 @@ class CLI
|
|
|
518
546
|
return
|
|
519
547
|
end
|
|
520
548
|
|
|
521
|
-
items = methods.map { |m| { name: m[:name], path: controller[:name] } }
|
|
549
|
+
items = methods.map { |m| { name: method_label(controller[:name], m[:name]), path: controller[:name] } }
|
|
522
550
|
selected_name = @go_ui.show_list_view("Select Method to Audit", items)
|
|
523
551
|
return if selected_name == "back"
|
|
524
552
|
|
|
525
|
-
|
|
553
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
554
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
526
555
|
return unless method_choice
|
|
556
|
+
method_choice = method_choice.merge(class_name: selected_class || controller[:name])
|
|
527
557
|
|
|
528
558
|
run_audit_for_controller_method(controller, method_choice)
|
|
529
559
|
end
|
|
@@ -737,12 +767,14 @@ class CLI
|
|
|
737
767
|
return
|
|
738
768
|
end
|
|
739
769
|
|
|
740
|
-
items = methods.map { |m| { name: m[:name], path: model[:name] } }
|
|
770
|
+
items = methods.map { |m| { name: method_label(model[:name], m[:name]), path: model[:name] } }
|
|
741
771
|
selected_name = @go_ui.show_list_view("Select Method to Audit", items)
|
|
742
772
|
return if selected_name == "back"
|
|
743
773
|
|
|
744
|
-
|
|
774
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
775
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
745
776
|
return unless method_choice
|
|
777
|
+
method_choice = method_choice.merge(class_name: selected_class || model[:name])
|
|
746
778
|
|
|
747
779
|
run_audit_for_model_method(model, method_choice)
|
|
748
780
|
end
|
|
@@ -812,12 +844,14 @@ class CLI
|
|
|
812
844
|
return
|
|
813
845
|
end
|
|
814
846
|
|
|
815
|
-
items = methods.map { |m| { name: m[:name], path: service[:name] } }
|
|
847
|
+
items = methods.map { |m| { name: method_label(service[:name], m[:name]), path: service[:name] } }
|
|
816
848
|
selected_name = @go_ui.show_list_view("Select Method to Audit", items)
|
|
817
849
|
return if selected_name == "back"
|
|
818
850
|
|
|
819
|
-
|
|
851
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
852
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
820
853
|
return unless method_choice
|
|
854
|
+
method_choice = method_choice.merge(class_name: selected_class || service[:name])
|
|
821
855
|
|
|
822
856
|
run_audit_for_service_method(service, method_choice)
|
|
823
857
|
end
|
|
@@ -885,12 +919,14 @@ class CLI
|
|
|
885
919
|
return
|
|
886
920
|
end
|
|
887
921
|
|
|
888
|
-
items = methods.map { |m| { name: m[:name], path: other_file[:name] } }
|
|
922
|
+
items = methods.map { |m| { name: method_label(other_file[:name], m[:name]), path: other_file[:name] } }
|
|
889
923
|
selected_name = @go_ui.show_list_view("Audit Method in #{other_file[:name]}", items)
|
|
890
924
|
return if selected_name == "back"
|
|
891
925
|
|
|
892
|
-
|
|
926
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
927
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
893
928
|
return unless method_choice
|
|
929
|
+
method_choice = method_choice.merge(class_name: selected_class || other_file[:name])
|
|
894
930
|
|
|
895
931
|
run_audit_for_other_method(other_file, method_choice)
|
|
896
932
|
end
|
|
@@ -1051,12 +1087,14 @@ class CLI
|
|
|
1051
1087
|
return
|
|
1052
1088
|
end
|
|
1053
1089
|
|
|
1054
|
-
items = methods.map { |m| { name: m[:name], path: controller[:name] } }
|
|
1090
|
+
items = methods.map { |m| { name: method_label(controller[:name], m[:name]), path: controller[:name] } }
|
|
1055
1091
|
selected_name = @go_ui.show_list_view("Select Method in #{controller[:name]}", items)
|
|
1056
1092
|
return if selected_name == "back"
|
|
1057
1093
|
|
|
1058
|
-
|
|
1094
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
1095
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
1059
1096
|
return unless method_choice
|
|
1097
|
+
method_choice = method_choice.merge(class_name: selected_class || controller[:name])
|
|
1060
1098
|
|
|
1061
1099
|
generate_test_for_controller_method(controller, method_choice)
|
|
1062
1100
|
end
|
|
@@ -1109,12 +1147,14 @@ class CLI
|
|
|
1109
1147
|
return
|
|
1110
1148
|
end
|
|
1111
1149
|
|
|
1112
|
-
items = methods.map { |m| { name: m[:name], path: model[:name] } }
|
|
1150
|
+
items = methods.map { |m| { name: method_label(model[:name], m[:name]), path: model[:name] } }
|
|
1113
1151
|
selected_name = @go_ui.show_list_view("Select Method in #{model[:name]}", items)
|
|
1114
1152
|
return if selected_name == "back"
|
|
1115
1153
|
|
|
1116
|
-
|
|
1154
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
1155
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
1117
1156
|
return unless method_choice
|
|
1157
|
+
method_choice = method_choice.merge(class_name: selected_class || model[:name])
|
|
1118
1158
|
|
|
1119
1159
|
generate_test_for_model_method(model, method_choice)
|
|
1120
1160
|
end
|
|
@@ -1169,12 +1209,14 @@ class CLI
|
|
|
1169
1209
|
return
|
|
1170
1210
|
end
|
|
1171
1211
|
|
|
1172
|
-
items = methods.map { |m| { name: m[:name], path: service[:name] } }
|
|
1212
|
+
items = methods.map { |m| { name: method_label(service[:name], m[:name]), path: service[:name] } }
|
|
1173
1213
|
selected_name = @go_ui.show_list_view("Select Method in #{service[:name]}", items)
|
|
1174
1214
|
return if selected_name == "back"
|
|
1175
1215
|
|
|
1176
|
-
|
|
1216
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
1217
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
1177
1218
|
return unless method_choice
|
|
1219
|
+
method_choice = method_choice.merge(class_name: selected_class || service[:name])
|
|
1178
1220
|
|
|
1179
1221
|
generate_test_for_service_method(service, method_choice)
|
|
1180
1222
|
end
|
|
@@ -1193,12 +1235,14 @@ class CLI
|
|
|
1193
1235
|
return
|
|
1194
1236
|
end
|
|
1195
1237
|
|
|
1196
|
-
items = methods.map { |m| { name: m[:name], path: other_file[:name] } }
|
|
1238
|
+
items = methods.map { |m| { name: method_label(other_file[:name], m[:name]), path: other_file[:name] } }
|
|
1197
1239
|
selected_name = @go_ui.show_list_view("Select Method in #{other_file[:name]}", items)
|
|
1198
1240
|
return if selected_name == "back"
|
|
1199
1241
|
|
|
1200
|
-
|
|
1242
|
+
selected_class, selected_method = parse_method_label(selected_name)
|
|
1243
|
+
method_choice = methods.find { |m| m[:name] == selected_method }
|
|
1201
1244
|
return unless method_choice
|
|
1245
|
+
method_choice = method_choice.merge(class_name: selected_class || other_file[:name])
|
|
1202
1246
|
|
|
1203
1247
|
generate_test_for_other_method(other_file, method_choice)
|
|
1204
1248
|
end
|
|
@@ -1507,25 +1551,25 @@ class CLI
|
|
|
1507
1551
|
end
|
|
1508
1552
|
|
|
1509
1553
|
def impact_controller_method
|
|
1510
|
-
select_controller_and_method("
|
|
1554
|
+
select_controller_and_method("Regression Check") do |controller, method_info|
|
|
1511
1555
|
run_impact_for_method(controller, method_info)
|
|
1512
1556
|
end
|
|
1513
1557
|
end
|
|
1514
1558
|
|
|
1515
1559
|
def impact_model_method
|
|
1516
|
-
select_model_and_method("
|
|
1560
|
+
select_model_and_method("Regression Check") do |model, method_info|
|
|
1517
1561
|
run_impact_for_method(model, method_info)
|
|
1518
1562
|
end
|
|
1519
1563
|
end
|
|
1520
1564
|
|
|
1521
1565
|
def impact_service_method
|
|
1522
|
-
select_service_and_method("
|
|
1566
|
+
select_service_and_method("Regression Check") do |service, method_info|
|
|
1523
1567
|
run_impact_for_method(service, method_info)
|
|
1524
1568
|
end
|
|
1525
1569
|
end
|
|
1526
1570
|
|
|
1527
1571
|
def impact_other_method
|
|
1528
|
-
select_other_and_method("
|
|
1572
|
+
select_other_and_method("Regression Check") do |file, method_info|
|
|
1529
1573
|
run_impact_for_method(file, method_info)
|
|
1530
1574
|
end
|
|
1531
1575
|
end
|
|
@@ -1562,11 +1606,12 @@ class CLI
|
|
|
1562
1606
|
project_root = Dir.pwd
|
|
1563
1607
|
path = File.expand_path(file_info[:path])
|
|
1564
1608
|
|
|
1609
|
+
class_name = method_info[:class_name] || file_info[:name]
|
|
1565
1610
|
trace_json = Tng::Analyzer::Context.analyze_symbolic_trace(
|
|
1566
1611
|
project_root,
|
|
1567
1612
|
path,
|
|
1568
1613
|
method_info[:name],
|
|
1569
|
-
|
|
1614
|
+
class_name
|
|
1570
1615
|
)
|
|
1571
1616
|
|
|
1572
1617
|
f = Tempfile.new(['trace', '.json'])
|
|
@@ -1589,12 +1634,12 @@ class CLI
|
|
|
1589
1634
|
def run_impact_for_method(file_info, method_info)
|
|
1590
1635
|
result_path = nil
|
|
1591
1636
|
|
|
1592
|
-
@go_ui.show_spinner("Running
|
|
1637
|
+
@go_ui.show_spinner("Running regression check for #{method_info[:name]}...") do
|
|
1593
1638
|
begin
|
|
1594
1639
|
project_root = Dir.pwd
|
|
1595
1640
|
path = File.expand_path(file_info[:path])
|
|
1596
1641
|
|
|
1597
|
-
class_name = file_info[:name]
|
|
1642
|
+
class_name = method_info[:class_name] || file_info[:name]
|
|
1598
1643
|
impact_json = Tng::Analyzer::Context.analyze_impact(
|
|
1599
1644
|
project_root,
|
|
1600
1645
|
path,
|
|
@@ -1607,7 +1652,7 @@ class CLI
|
|
|
1607
1652
|
f.close
|
|
1608
1653
|
result_path = f.path
|
|
1609
1654
|
|
|
1610
|
-
{ success: true, message: "
|
|
1655
|
+
{ success: true, message: "Regression check completed" }
|
|
1611
1656
|
rescue => e
|
|
1612
1657
|
{ success: false, message: e.message }
|
|
1613
1658
|
end
|
|
@@ -1637,14 +1682,62 @@ class CLI
|
|
|
1637
1682
|
relative_path = full_path.gsub("#{Dir.pwd}/", "")
|
|
1638
1683
|
namespaced_name = relative_path.sub(/\.rb\z/, "").split("/").map(&:camelize).join("::")
|
|
1639
1684
|
file_info = { path: full_path, name: namespaced_name }
|
|
1640
|
-
method_info = { name: method_name }
|
|
1685
|
+
method_info = { name: method_name, class_name: params[:class_name] }
|
|
1641
1686
|
|
|
1642
1687
|
run_trace_for_method(file_info, method_info)
|
|
1643
1688
|
end
|
|
1644
1689
|
|
|
1690
|
+
def run_direct_call_sites
|
|
1691
|
+
file_path = params[:file]
|
|
1692
|
+
method_name = params[:method]
|
|
1693
|
+
class_name = params[:class_name]
|
|
1694
|
+
|
|
1695
|
+
unless method_name
|
|
1696
|
+
puts @pastel.decorate("Please specify a method name with --method or -m", Tng::UI::Theme.color(:error))
|
|
1697
|
+
return
|
|
1698
|
+
end
|
|
1699
|
+
|
|
1700
|
+
full_path = File.expand_path(file_path)
|
|
1701
|
+
unless File.exist?(full_path)
|
|
1702
|
+
puts @pastel.decorate("File not found: #{full_path}", Tng::UI::Theme.color(:error))
|
|
1703
|
+
return
|
|
1704
|
+
end
|
|
1705
|
+
|
|
1706
|
+
relative_path = full_path.gsub("#{Dir.pwd}/", "")
|
|
1707
|
+
namespaced_name = relative_path.sub(/\.rb\z/, "").split("/").map(&:camelize).join("::")
|
|
1708
|
+
effective_class = class_name || namespaced_name
|
|
1709
|
+
|
|
1710
|
+
sites = Tng::Analyzer::Context.analyze_call_sites(
|
|
1711
|
+
Dir.pwd,
|
|
1712
|
+
full_path,
|
|
1713
|
+
method_name,
|
|
1714
|
+
effective_class
|
|
1715
|
+
)
|
|
1716
|
+
|
|
1717
|
+
if params[:json]
|
|
1718
|
+
puts JSON.generate(sites)
|
|
1719
|
+
return
|
|
1720
|
+
end
|
|
1721
|
+
|
|
1722
|
+
if sites.nil? || sites.empty?
|
|
1723
|
+
puts @pastel.decorate("No call sites found.", Tng::UI::Theme.color(:success))
|
|
1724
|
+
return
|
|
1725
|
+
end
|
|
1726
|
+
|
|
1727
|
+
puts @pastel.decorate("Found #{sites.length} call sites:", Tng::UI::Theme.color(:info))
|
|
1728
|
+
sites.take(200).each do |site|
|
|
1729
|
+
file = site["file"] || site[:file] || "unknown"
|
|
1730
|
+
line = site["line"] || site[:line] || 0
|
|
1731
|
+
content = site["content"] || site[:content] || ""
|
|
1732
|
+
puts "#{file}:#{line} #{content}"
|
|
1733
|
+
end
|
|
1734
|
+
puts @pastel.dim("... #{sites.length - 200} more") if sites.length > 200
|
|
1735
|
+
end
|
|
1736
|
+
|
|
1645
1737
|
def run_direct_impact
|
|
1646
1738
|
file_path = params[:file]
|
|
1647
1739
|
method_name = params[:method]
|
|
1740
|
+
class_name = params[:class_name]
|
|
1648
1741
|
|
|
1649
1742
|
unless method_name
|
|
1650
1743
|
puts @pastel.decorate("Please specify a method name with --method or -m", Tng::UI::Theme.color(:error))
|
|
@@ -1660,7 +1753,7 @@ class CLI
|
|
|
1660
1753
|
relative_path = full_path.gsub("#{Dir.pwd}/", "")
|
|
1661
1754
|
namespaced_name = relative_path.sub(/\.rb\z/, "").split("/").map(&:camelize).join("::")
|
|
1662
1755
|
file_info = { path: full_path, name: namespaced_name }
|
|
1663
|
-
method_info = { name: method_name }
|
|
1756
|
+
method_info = { name: method_name, class_name: class_name }
|
|
1664
1757
|
|
|
1665
1758
|
run_impact_for_method(file_info, method_info)
|
|
1666
1759
|
end
|
|
@@ -1760,12 +1853,14 @@ class CLI
|
|
|
1760
1853
|
next
|
|
1761
1854
|
end
|
|
1762
1855
|
|
|
1763
|
-
m_items = methods.map { |m| { name: m[:name], path: choice[:name] } }
|
|
1856
|
+
m_items = methods.map { |m| { name: method_label(choice[:name], m[:name]), path: choice[:name] } }
|
|
1764
1857
|
m_selected = @go_ui.show_list_view("Select Method to #{action_name}", m_items)
|
|
1765
1858
|
next if m_selected == "back"
|
|
1766
1859
|
|
|
1767
|
-
|
|
1860
|
+
selected_class, selected_method = parse_method_label(m_selected)
|
|
1861
|
+
m_choice = methods.find { |m| m[:name] == selected_method }
|
|
1768
1862
|
next unless m_choice
|
|
1863
|
+
m_choice = m_choice.merge(class_name: selected_class || choice[:name])
|
|
1769
1864
|
|
|
1770
1865
|
yield(choice, m_choice)
|
|
1771
1866
|
end
|
|
@@ -1799,11 +1894,13 @@ class CLI
|
|
|
1799
1894
|
next
|
|
1800
1895
|
end
|
|
1801
1896
|
|
|
1802
|
-
m_items = methods.map { |m| { name: m[:name], path: choice[:name] } }
|
|
1897
|
+
m_items = methods.map { |m| { name: method_label(choice[:name], m[:name]), path: choice[:name] } }
|
|
1803
1898
|
m_selected = @go_ui.show_list_view("Select Method to #{action_name}", m_items)
|
|
1804
1899
|
next if m_selected == "back"
|
|
1805
1900
|
|
|
1806
|
-
|
|
1901
|
+
selected_class, selected_method = parse_method_label(m_selected)
|
|
1902
|
+
m_choice = methods.find { |m| m[:name] == selected_method }
|
|
1903
|
+
m_choice = m_choice.merge(class_name: selected_class || choice[:name]) if m_choice
|
|
1807
1904
|
yield(choice, m_choice)
|
|
1808
1905
|
end
|
|
1809
1906
|
end
|
|
@@ -1836,11 +1933,13 @@ class CLI
|
|
|
1836
1933
|
next
|
|
1837
1934
|
end
|
|
1838
1935
|
|
|
1839
|
-
m_items = methods.map { |m| { name: m[:name], path: choice[:name] } }
|
|
1936
|
+
m_items = methods.map { |m| { name: method_label(choice[:name], m[:name]), path: choice[:name] } }
|
|
1840
1937
|
m_selected = @go_ui.show_list_view("Select Method to #{action_name}", m_items)
|
|
1841
1938
|
next if m_selected == "back"
|
|
1842
1939
|
|
|
1843
|
-
|
|
1940
|
+
selected_class, selected_method = parse_method_label(m_selected)
|
|
1941
|
+
m_choice = methods.find { |m| m[:name] == selected_method }
|
|
1942
|
+
m_choice = m_choice.merge(class_name: selected_class || choice[:name]) if m_choice
|
|
1844
1943
|
yield(choice, m_choice)
|
|
1845
1944
|
end
|
|
1846
1945
|
end
|
|
@@ -1873,12 +1972,14 @@ class CLI
|
|
|
1873
1972
|
next
|
|
1874
1973
|
end
|
|
1875
1974
|
|
|
1876
|
-
m_items = methods.map { |m| { name: m[:name], path: choice[:name] } }
|
|
1975
|
+
m_items = methods.map { |m| { name: method_label(choice[:name], m[:name]), path: choice[:name] } }
|
|
1877
1976
|
m_selected = @go_ui.show_list_view("Select Method to #{action_name}", m_items)
|
|
1878
1977
|
next if m_selected == "back"
|
|
1879
1978
|
|
|
1880
|
-
|
|
1979
|
+
selected_class, selected_method = parse_method_label(m_selected)
|
|
1980
|
+
m_choice = methods.find { |m| m[:name] == selected_method }
|
|
1881
1981
|
next unless m_choice
|
|
1982
|
+
m_choice = m_choice.merge(class_name: selected_class || choice[:name])
|
|
1882
1983
|
|
|
1883
1984
|
yield(choice, m_choice)
|
|
1884
1985
|
end
|
data/binaries/go-ui-darwin-amd64
CHANGED
|
Binary file
|
data/binaries/go-ui-darwin-arm64
CHANGED
|
Binary file
|
data/binaries/go-ui-linux-amd64
CHANGED
|
Binary file
|
data/binaries/go-ui-linux-arm64
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/binaries/tng-linux-arm64.so
CHANGED
|
Binary file
|
|
Binary file
|
data/binaries/tng.bundle
CHANGED
|
Binary file
|
|
@@ -89,6 +89,9 @@ module Tng
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
method_info = methods.find { |m| m[:name].downcase == method_name.downcase }
|
|
92
|
+
if method_info && @params[:class_name]
|
|
93
|
+
method_info = method_info.merge(class_name: @params[:class_name])
|
|
94
|
+
end
|
|
92
95
|
|
|
93
96
|
unless method_info
|
|
94
97
|
@go_ui.display_error(@pastel.red("❌ Method '#{method_name}' not found in #{file_object[:name]}"))
|
data/lib/tng/ui/go_ui_session.rb
CHANGED
|
@@ -256,7 +256,7 @@ module Tng
|
|
|
256
256
|
puts "Trace results error: #{e.message}"
|
|
257
257
|
end
|
|
258
258
|
|
|
259
|
-
# Show
|
|
259
|
+
# Show regression check results
|
|
260
260
|
# @param impact_file_path [String] Path to JSON impact file
|
|
261
261
|
def show_impact_results(impact_file_path)
|
|
262
262
|
system(@binary_path, "ruby-impact-results", "--file", impact_file_path)
|
|
@@ -415,7 +415,7 @@ module Tng
|
|
|
415
415
|
{ cmd: "bundle exec tng --file=FILE --method=METHOD", desc: "Direct test generation" },
|
|
416
416
|
{ cmd: "bundle exec tng --file=FILE --method=METHOD --audit", desc: "Direct audit mode" },
|
|
417
417
|
{ cmd: "bundle exec tng --file=FILE --method=METHOD --trace", desc: "Symbolic trace mode" },
|
|
418
|
-
{ cmd: "bundle exec tng --file=FILE --method=METHOD --impact", desc: "
|
|
418
|
+
{ cmd: "bundle exec tng --file=FILE --method=METHOD --impact", desc: "Regression check mode" },
|
|
419
419
|
{ cmd: "bundle exec tng --file=FILE --clones", desc: "Check for code duplicates" },
|
|
420
420
|
{ cmd: "bundle exec tng --file=FILE --deadcode", desc: "Run dead code detection" },
|
|
421
421
|
{ cmd: "bundle exec tng --file=FILE --method=METHOD --xray", desc: "X-Ray visualization" }
|
|
@@ -426,7 +426,7 @@ module Tng
|
|
|
426
426
|
"Per-method test generation",
|
|
427
427
|
"Code audit for issues & behaviors",
|
|
428
428
|
"Symbolic execution traces",
|
|
429
|
-
"
|
|
429
|
+
"Regression check against Git HEAD",
|
|
430
430
|
"Duplicate code detection (Clones)",
|
|
431
431
|
"Dead code detection (Rust-powered)",
|
|
432
432
|
"X-Ray Logic Flow Visualization",
|
|
@@ -438,7 +438,7 @@ module Tng
|
|
|
438
438
|
{ flag: "--method=NAME", desc: "Method name to generate test for" },
|
|
439
439
|
{ flag: "--audit", desc: "Run audit mode instead of test generation" },
|
|
440
440
|
{ flag: "--trace", desc: "Run symbolic trace mode" },
|
|
441
|
-
{ flag: "--impact", desc: "Run
|
|
441
|
+
{ flag: "--impact", desc: "Run regression check mode" },
|
|
442
442
|
{ flag: "--clones", desc: "Run clone detection mode" },
|
|
443
443
|
{ flag: "--level=1|2|3|all", desc: "Set clone detection level (default: all)" },
|
|
444
444
|
{ flag: "--deadcode", desc: "Run dead code detection" },
|
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.5.
|
|
4
|
+
version: 0.5.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ralucab
|
|
@@ -222,7 +222,7 @@ post_install_message: "┌ TNG ────────────────
|
|
|
222
222
|
\ │\n│ • bundle exec
|
|
223
223
|
tng --help - Show help information │\n│ │\n│
|
|
224
224
|
\ \U0001F4A1 Generate tests for individual methods with precision │\n└────────────────────────────────────────────────────────────
|
|
225
|
-
v0.5.
|
|
225
|
+
v0.5.3 ┘\n"
|
|
226
226
|
rdoc_options: []
|
|
227
227
|
require_paths:
|
|
228
228
|
- lib
|