using System.CommandLine; using NatsNet.PortTracker.Data; namespace NatsNet.PortTracker.Commands; public static class TestCommands { public static Command Create(Option dbOption, Option schemaOption) { var testCommand = new Command("test", "Manage unit tests"); // list var listModule = new Option("--module") { Description = "Filter by module ID" }; var listStatus = new Option("--status") { Description = "Filter by status" }; var listCmd = new Command("list", "List unit tests"); listCmd.Add(listModule); listCmd.Add(listStatus); listCmd.SetAction(parseResult => { var dbPath = parseResult.GetValue(dbOption)!; var moduleId = parseResult.GetValue(listModule); var status = parseResult.GetValue(listStatus); using var db = new Database(dbPath); var sql = "SELECT t.id, t.name, t.status, t.module_id, m.name as module_name, t.go_method, t.dotnet_method FROM unit_tests t LEFT JOIN modules m ON t.module_id = m.id"; var parameters = new List<(string, object?)>(); var clauses = new List(); if (moduleId is not null) { clauses.Add("t.module_id = @module"); parameters.Add(("@module", moduleId)); } if (status is not null) { clauses.Add("t.status = @status"); parameters.Add(("@status", status)); } if (clauses.Count > 0) sql += " WHERE " + string.Join(" AND ", clauses); sql += " ORDER BY m.name, t.name"; var rows = db.Query(sql, parameters.ToArray()); Console.WriteLine($"{"ID",-5} {"Name",-30} {"Status",-15} {"Module",-20} {"Go Method",-25} {"DotNet Method",-25}"); Console.WriteLine(new string('-', 120)); foreach (var row in rows) { Console.WriteLine($"{row["id"],-5} {Truncate(row["name"]?.ToString(), 29),-30} {row["status"],-15} {Truncate(row["module_name"]?.ToString(), 19),-20} {Truncate(row["go_method"]?.ToString(), 24),-25} {Truncate(row["dotnet_method"]?.ToString(), 24),-25}"); } Console.WriteLine($"\nTotal: {rows.Count} tests"); }); // show var showId = new Argument("id") { Description = "Test ID" }; var showCmd = new Command("show", "Show test details"); showCmd.Add(showId); showCmd.SetAction(parseResult => { var dbPath = parseResult.GetValue(dbOption)!; var id = parseResult.GetValue(showId); using var db = new Database(dbPath); var tests = db.Query( "SELECT t.*, m.name as module_name FROM unit_tests t LEFT JOIN modules m ON t.module_id = m.id WHERE t.id = @id", ("@id", id)); if (tests.Count == 0) { Console.WriteLine($"Test {id} not found."); return; } var t = tests[0]; Console.WriteLine($"Test #{t["id"]}: {t["name"]}"); Console.WriteLine($" Module: #{t["module_id"]} ({t["module_name"]})"); Console.WriteLine($" Feature: {(t["feature_id"] is not null ? $"#{t["feature_id"]}" : "(none)")}"); Console.WriteLine($" Status: {t["status"]}"); Console.WriteLine($" Go File: {t["go_file"]}"); Console.WriteLine($" Go Class: {t["go_class"]}"); Console.WriteLine($" Go Method: {t["go_method"]}"); Console.WriteLine($" Go Line: {t["go_line_number"]}"); Console.WriteLine($" Go LOC: {t["go_line_count"]}"); Console.WriteLine($" .NET: {t["dotnet_project"]} / {t["dotnet_class"]} / {t["dotnet_method"]}"); Console.WriteLine($" Notes: {t["notes"]}"); var deps = db.Query( "SELECT d.target_type, d.target_id, d.dependency_kind FROM dependencies d WHERE d.source_type = 'unit_test' AND d.source_id = @id", ("@id", id)); Console.WriteLine($"\n Dependencies ({deps.Count}):"); foreach (var d in deps) Console.WriteLine($" -> {d["target_type"]} #{d["target_id"]} [{d["dependency_kind"]}]"); }); // update var updateId = new Argument("id") { Description = "Test ID" }; var updateStatus = new Option("--status") { Description = "New status", Required = true }; var updateCmd = new Command("update", "Update test status"); updateCmd.Add(updateId); updateCmd.Add(updateStatus); updateCmd.SetAction(parseResult => { var dbPath = parseResult.GetValue(dbOption)!; var id = parseResult.GetValue(updateId); var status = parseResult.GetValue(updateStatus)!; using var db = new Database(dbPath); var affected = db.Execute("UPDATE unit_tests SET status = @status WHERE id = @id", ("@status", status), ("@id", id)); Console.WriteLine(affected > 0 ? $"Test {id} updated to '{status}'." : $"Test {id} not found."); }); // map var mapId = new Argument("id") { Description = "Test ID" }; var mapProject = new Option("--project") { Description = "Target .NET project" }; var mapClass = new Option("--class") { Description = "Target .NET test class" }; var mapMethod = new Option("--method") { Description = "Target .NET test method" }; var mapCmd = new Command("map", "Map test to .NET test method"); mapCmd.Add(mapId); mapCmd.Add(mapProject); mapCmd.Add(mapClass); mapCmd.Add(mapMethod); mapCmd.SetAction(parseResult => { var dbPath = parseResult.GetValue(dbOption)!; var id = parseResult.GetValue(mapId); var project = parseResult.GetValue(mapProject); var cls = parseResult.GetValue(mapClass); var method = parseResult.GetValue(mapMethod); using var db = new Database(dbPath); var affected = db.Execute( "UPDATE unit_tests SET dotnet_project = COALESCE(@project, dotnet_project), dotnet_class = COALESCE(@cls, dotnet_class), dotnet_method = COALESCE(@method, dotnet_method) WHERE id = @id", ("@project", project), ("@cls", cls), ("@method", method), ("@id", id)); Console.WriteLine(affected > 0 ? $"Test {id} mapped." : $"Test {id} not found."); }); testCommand.Add(listCmd); testCommand.Add(showCmd); testCommand.Add(updateCmd); testCommand.Add(mapCmd); return testCommand; } private static string Truncate(string? s, int maxLen) { if (s is null) return ""; return s.Length <= maxLen ? s : s[..(maxLen - 2)] + ".."; } }