MarketAlly.AIPlugin.Extensions/Test.Readme/Program.cs

875 lines
24 KiB
C#
Executable File

using MarketAlly.AIPlugin;
using MarketAlly.AIPlugin.Refactoring.Plugins;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
namespace MarketAlly.AIPlugin.Refactoring.TestConsole;
/// <summary>
/// Test console for the ReadmeGeneratorPlugin
/// </summary>
class ReadmeTestProgram
{
static async Task<int> Main(string[] args)
{
var host = CreateHost();
var testService = host.Services.GetRequiredService<ReadmeTestService>();
try
{
ShowWelcome();
// If command line arguments provided, execute them first
if (args.Length > 0)
{
await ExecuteCommand(args, testService);
Console.WriteLine();
}
// Start interactive loop
while (true)
{
try
{
Console.Write("ReadmeTest> ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
continue;
if (input.Trim() == "/exit" || input.Trim() == "exit")
{
Console.WriteLine("[INFO] Goodbye!");
break;
}
if (input.Trim() == "/help" || input.Trim() == "help")
{
ShowHelp();
continue;
}
var commandArgs = ParseInput(input);
if (commandArgs.Length == 0)
continue;
await ExecuteCommand(commandArgs, testService);
Console.WriteLine();
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Command error: {ex.Message}");
Console.WriteLine();
}
}
return 0;
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Application error: {ex.Message}");
var logger = host.Services.GetRequiredService<ILogger<ReadmeTestProgram>>();
logger.LogError(ex, "Application failed");
return 1;
}
}
private static async Task ExecuteCommand(string[] args, ReadmeTestService service)
{
if (args.Length == 0)
{
ShowHelp();
return;
}
var command = args[0].ToLower();
switch (command)
{
case "generate":
case "readme":
await HandleGenerateCommand(args, service);
break;
case "preview":
await HandlePreviewCommand(args, service);
break;
case "test-self":
await service.TestOnSelfAsync();
break;
case "test-types":
await service.TestProjectTypesAsync();
break;
case "create-samples":
await service.CreateSampleProjectsAsync();
break;
case "help":
ShowHelp();
break;
default:
Console.WriteLine($"[ERROR] Unknown command: {command}");
ShowHelp();
break;
}
}
private static async Task HandleGenerateCommand(string[] args, ReadmeTestService service)
{
string projectPath = GetPathFromArgs(args, "Enter project path: ");
if (string.IsNullOrEmpty(projectPath)) return;
string projectType = GetValueFromArgs(args, "--type", "auto");
bool apply = args.Contains("--apply");
bool includeApi = !args.Contains("--no-api");
bool includeArch = !args.Contains("--no-arch");
bool includeSetup = !args.Contains("--no-setup");
bool includeExamples = !args.Contains("--no-examples");
await service.GenerateReadmeAsync(projectPath, projectType, apply, includeApi, includeArch, includeSetup, includeExamples);
}
private static async Task HandlePreviewCommand(string[] args, ReadmeTestService service)
{
string projectPath = GetPathFromArgs(args, "Enter project path: ");
if (string.IsNullOrEmpty(projectPath)) return;
string projectType = GetValueFromArgs(args, "--type", "auto");
await service.PreviewReadmeAsync(projectPath, projectType);
}
private static string GetPathFromArgs(string[] args, string prompt)
{
var pathIndex = Array.IndexOf(args, "--path");
if (pathIndex >= 0 && pathIndex + 1 < args.Length)
{
return args[pathIndex + 1];
}
Console.Write(prompt);
var path = Console.ReadLine()?.Trim();
return string.IsNullOrEmpty(path) ? null : path;
}
private static string GetValueFromArgs(string[] args, string flag, string defaultValue = "")
{
var index = Array.IndexOf(args, flag);
if (index >= 0 && index + 1 < args.Length)
{
return args[index + 1];
}
return defaultValue;
}
private static string[] ParseInput(string input)
{
var parts = new List<string>();
var current = new System.Text.StringBuilder();
bool inQuotes = false;
foreach (char c in input)
{
if (c == '"')
{
inQuotes = !inQuotes;
continue;
}
if (char.IsWhiteSpace(c) && !inQuotes)
{
if (current.Length > 0)
{
parts.Add(current.ToString());
current.Clear();
}
}
else
{
current.Append(c);
}
}
if (current.Length > 0)
{
parts.Add(current.ToString());
}
return parts.ToArray();
}
private static void ShowWelcome()
{
Console.WriteLine("MarketAlly AI Plugin README Generator Test Console");
Console.WriteLine("=" + new string('=', 54));
Console.WriteLine();
Console.WriteLine("Test suite for the ReadmeGeneratorPlugin");
Console.WriteLine("Type 'help' for commands or 'exit' to quit");
Console.WriteLine();
}
private static void ShowHelp()
{
Console.WriteLine();
Console.WriteLine("Available commands:");
Console.WriteLine(" generate [--path <path>] [--type <type>] [--apply] Generate README for project");
Console.WriteLine(" preview [--path <path>] [--type <type>] Preview README content");
Console.WriteLine(" test-self Test on this project");
Console.WriteLine(" test-types Test different project types");
Console.WriteLine(" create-samples Create sample projects");
Console.WriteLine(" help Show this help");
Console.WriteLine(" exit Exit application");
Console.WriteLine();
Console.WriteLine("Project types: auto, library, application, tool, maui");
Console.WriteLine();
Console.WriteLine("Flags:");
Console.WriteLine(" --apply Apply changes and create README.md");
Console.WriteLine(" --no-api Skip API documentation");
Console.WriteLine(" --no-arch Skip architecture section");
Console.WriteLine(" --no-setup Skip setup instructions");
Console.WriteLine(" --no-examples Skip usage examples");
Console.WriteLine();
Console.WriteLine("Examples:");
Console.WriteLine(" generate --path \"C:\\MyProject\" --type library --apply");
Console.WriteLine(" preview --path \"C:\\MyMauiApp\" --type maui");
Console.WriteLine(" test-self");
Console.WriteLine();
}
private static IHost CreateHost()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddLogging(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
services.AddSingleton<AIPluginRegistry>();
services.AddTransient<ReadmeTestService>();
})
.Build();
}
}
/// <summary>
/// Service for testing the ReadmeGeneratorPlugin
/// </summary>
public class ReadmeTestService
{
private readonly AIPluginRegistry _pluginRegistry;
private readonly ILogger<ReadmeTestService> _logger;
public ReadmeTestService(AIPluginRegistry pluginRegistry, ILogger<ReadmeTestService> logger)
{
_pluginRegistry = pluginRegistry;
_logger = logger;
SetupPlugins();
}
private void SetupPlugins()
{
_pluginRegistry.RegisterPlugin(new ReadmeGeneratorPlugin());
_logger.LogInformation("Registered ReadmeGeneratorPlugin");
}
public async Task GenerateReadmeAsync(string projectPath, string projectType, bool apply,
bool includeApi, bool includeArch, bool includeSetup, bool includeExamples)
{
Console.WriteLine($"[INFO] Generating README for: {projectPath}");
Console.WriteLine($"[INFO] Project type: {projectType}");
Console.WriteLine($"[INFO] Apply changes: {apply}");
Console.WriteLine(new string('=', 60));
try
{
var parameters = new Dictionary<string, object>
{
["projectPath"] = projectPath,
["projectType"] = projectType,
["includeApiDocs"] = includeApi,
["includeArchitecture"] = includeArch,
["includeSetup"] = includeSetup,
["includeExamples"] = includeExamples,
["applyChanges"] = apply
};
var result = await _pluginRegistry.CallFunctionAsync("ReadmeGenerator", parameters);
if (result.Success)
{
Console.WriteLine("[SUCCESS] README generation completed!");
DisplayReadmeResults(result.Data);
}
else
{
Console.WriteLine($"[ERROR] Generation failed: {result.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Test failed: {ex.Message}");
}
}
public async Task PreviewReadmeAsync(string projectPath, string projectType)
{
Console.WriteLine($"[PREVIEW] README for: {projectPath}");
Console.WriteLine($"[INFO] Project type: {projectType}");
Console.WriteLine(new string('=', 60));
try
{
var parameters = new Dictionary<string, object>
{
["projectPath"] = projectPath,
["projectType"] = projectType,
["applyChanges"] = false
};
var result = await _pluginRegistry.CallFunctionAsync("ReadmeGenerator", parameters);
if (result.Success)
{
Console.WriteLine("[SUCCESS] README preview generated!");
DisplayReadmeResults(result.Data);
// Show preview content
var resultJson = JsonSerializer.Serialize(result.Data, new JsonSerializerOptions { WriteIndented = true });
var resultElement = JsonSerializer.Deserialize<JsonElement>(resultJson);
if (resultElement.TryGetProperty("PreviewContent", out var previewContent))
{
Console.WriteLine("\n[PREVIEW CONTENT]");
Console.WriteLine(new string('-', 40));
Console.WriteLine(previewContent.GetString());
}
}
else
{
Console.WriteLine($"[ERROR] Preview failed: {result.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Preview failed: {ex.Message}");
}
}
public async Task TestOnSelfAsync()
{
Console.WriteLine("[TEST] Testing README generation on this project");
Console.WriteLine(new string('=', 60));
// Get the current project directory
var currentDir = Directory.GetCurrentDirectory();
// Look for project file in current or parent directories
var projectPath = FindProjectDirectory(currentDir);
if (projectPath == null)
{
Console.WriteLine("[ERROR] Could not find project file in current directory or parents");
return;
}
Console.WriteLine($"[INFO] Found project at: {projectPath}");
await GenerateReadmeAsync(projectPath, "auto", false, true, true, true, true);
}
public async Task TestProjectTypesAsync()
{
Console.WriteLine("[TEST] Testing different project types");
Console.WriteLine(new string('=', 60));
await CreateSampleProjectsAsync();
var sampleDir = Path.Combine(Directory.GetCurrentDirectory(), "ReadmeSamples");
if (!Directory.Exists(sampleDir))
{
Console.WriteLine("[ERROR] Sample directory not found");
return;
}
var testCases = new[]
{
("LibrarySample", "library"),
("ApplicationSample", "application"),
("ToolSample", "tool"),
("MauiSample", "maui")
};
foreach (var (projectName, projectType) in testCases)
{
var projectPath = Path.Combine(sampleDir, projectName);
if (Directory.Exists(projectPath))
{
Console.WriteLine($"\n[TESTING] {projectType.ToUpper()} project type");
Console.WriteLine(new string('-', 30));
await PreviewReadmeAsync(projectPath, projectType);
}
}
}
public async Task CreateSampleProjectsAsync()
{
Console.WriteLine("[INFO] Creating sample projects for testing...");
var sampleDir = Path.Combine(Directory.GetCurrentDirectory(), "ReadmeSamples");
if (Directory.Exists(sampleDir))
{
Directory.Delete(sampleDir, true);
}
Directory.CreateDirectory(sampleDir);
// Create Library Sample
await CreateLibrarySample(Path.Combine(sampleDir, "LibrarySample"));
// Create Application Sample
await CreateApplicationSample(Path.Combine(sampleDir, "ApplicationSample"));
// Create Tool Sample
await CreateToolSample(Path.Combine(sampleDir, "ToolSample"));
// Create MAUI Sample
await CreateMauiSample(Path.Combine(sampleDir, "MauiSample"));
Console.WriteLine($"[SUCCESS] Created sample projects in: {sampleDir}");
}
private async Task CreateLibrarySample(string projectPath)
{
Directory.CreateDirectory(projectPath);
var projectContent = @"<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Library</OutputType>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=""Microsoft.Extensions.DependencyInjection"" Version=""8.0.0"" />
<PackageReference Include=""Microsoft.Extensions.Logging"" Version=""8.0.0"" />
</ItemGroup>
</Project>";
await File.WriteAllTextAsync(Path.Combine(projectPath, "LibrarySample.csproj"), projectContent);
var serviceContent = @"using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace LibrarySample
{
/// <summary>
/// Main service for library operations
/// </summary>
public class LibraryService : ILibraryService
{
private readonly ILogger<LibraryService> _logger;
public LibraryService(ILogger<LibraryService> logger)
{
_logger = logger;
}
/// <summary>
/// Processes data asynchronously
/// </summary>
public async Task<string> ProcessDataAsync(string input, int count)
{
_logger.LogInformation(""Processing data: {Input}"", input);
await Task.Delay(100);
return $""Processed: {input} x {count}"";
}
/// <summary>
/// Validates input data
/// </summary>
public bool ValidateInput(string input)
{
return !string.IsNullOrWhiteSpace(input);
}
}
/// <summary>
/// Interface for library service
/// </summary>
public interface ILibraryService
{
Task<string> ProcessDataAsync(string input, int count);
bool ValidateInput(string input);
}
}";
await File.WriteAllTextAsync(Path.Combine(projectPath, "LibraryService.cs"), serviceContent);
}
private async Task CreateApplicationSample(string projectPath)
{
Directory.CreateDirectory(projectPath);
var projectContent = @"<Project Sdk=""Microsoft.NET.Sdk.Web"">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=""Microsoft.AspNetCore.OpenApi"" Version=""8.0.0"" />
<PackageReference Include=""Swashbuckle.AspNetCore"" Version=""6.4.0"" />
</ItemGroup>
</Project>";
await File.WriteAllTextAsync(Path.Combine(projectPath, "ApplicationSample.csproj"), projectContent);
var programContent = @"using ApplicationSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IDataService, DataService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
namespace ApplicationSample.Services
{
public interface IDataService
{
Task<object> GetDataAsync();
}
public class DataService : IDataService
{
public async Task<object> GetDataAsync()
{
await Task.Delay(10);
return new { Message = ""Hello from ApplicationSample"", Timestamp = DateTime.UtcNow };
}
}
}";
await File.WriteAllTextAsync(Path.Combine(projectPath, "Program.cs"), programContent);
}
private async Task CreateToolSample(string projectPath)
{
Directory.CreateDirectory(projectPath);
var projectContent = @"<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>toolsample</ToolCommandName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=""System.CommandLine"" Version=""2.0.0-beta4.22272.1"" />
</ItemGroup>
</Project>";
await File.WriteAllTextAsync(Path.Combine(projectPath, "ToolSample.csproj"), projectContent);
var programContent = @"using System;
using System.CommandLine;
using System.IO;
using System.Threading.Tasks;
namespace ToolSample
{
class Program
{
/// <summary>
/// Main entry point for the tool
/// </summary>
static async Task<int> Main(string[] args)
{
var rootCommand = new RootCommand(""A sample command-line tool"");
var processCommand = new Command(""process"", ""Process a file"");
var inputOption = new Option<FileInfo>(""--input"", ""Input file to process"");
var outputOption = new Option<FileInfo>(""--output"", ""Output file"");
processCommand.AddOption(inputOption);
processCommand.AddOption(outputOption);
processCommand.SetHandler(ProcessFileAsync, inputOption, outputOption);
rootCommand.AddCommand(processCommand);
return await rootCommand.InvokeAsync(args);
}
/// <summary>
/// Processes a file asynchronously
/// </summary>
static async Task ProcessFileAsync(FileInfo input, FileInfo output)
{
Console.WriteLine($""Processing {input.Name} -> {output.Name}"");
if (!input.Exists)
{
Console.WriteLine(""Input file does not exist"");
return;
}
var content = await File.ReadAllTextAsync(input.FullName);
var processedContent = content.ToUpperInvariant();
await File.WriteAllTextAsync(output.FullName, processedContent);
Console.WriteLine(""File processed successfully"");
}
}
}";
await File.WriteAllTextAsync(Path.Combine(projectPath, "Program.cs"), programContent);
}
private async Task CreateMauiSample(string projectPath)
{
Directory.CreateDirectory(projectPath);
var projectContent = @"<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst;net8.0-windows10.0.19041.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>MauiSample</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=""Microsoft.Maui.Controls"" Version=""8.0.0"" />
<PackageReference Include=""Microsoft.Maui.Controls.Compatibility"" Version=""8.0.0"" />
</ItemGroup>
</Project>";
await File.WriteAllTextAsync(Path.Combine(projectPath, "MauiSample.csproj"), projectContent);
var appContent = @"using Microsoft.Extensions.Logging;
namespace MauiSample;
/// <summary>
/// Main MAUI application class
/// </summary>
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
}";
await File.WriteAllTextAsync(Path.Combine(projectPath, "App.xaml.cs"), appContent);
var mainPageContent = @"using Microsoft.Extensions.Logging;
namespace MauiSample;
/// <summary>
/// Main page for the MAUI application
/// </summary>
public partial class MainPage : ContentPage
{
private readonly ILogger<MainPage> _logger;
private int _clickCount = 0;
public MainPage(ILogger<MainPage> logger)
{
_logger = logger;
InitializeComponent();
}
/// <summary>
/// Handles the counter button click event
/// </summary>
private void OnCounterClicked(object sender, EventArgs e)
{
_clickCount++;
if (_clickCount == 1)
CounterBtn.Text = $""Clicked {_clickCount} time"";
else
CounterBtn.Text = $""Clicked {_clickCount} times"";
_logger.LogInformation(""Button clicked {ClickCount} times"", _clickCount);
SemanticScreenReader.Announce(CounterBtn.Text);
}
/// <summary>
/// Resets the counter to zero
/// </summary>
public void ResetCounter()
{
_clickCount = 0;
CounterBtn.Text = ""Click me"";
_logger.LogInformation(""Counter reset"");
}
}";
await File.WriteAllTextAsync(Path.Combine(projectPath, "MainPage.xaml.cs"), mainPageContent);
var mauiProgramContent = @"using Microsoft.Extensions.Logging;
namespace MauiSample;
/// <summary>
/// MAUI program configuration
/// </summary>
public static class MauiProgram
{
/// <summary>
/// Creates and configures the MAUI app
/// </summary>
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont(""OpenSans-Regular.ttf"", ""OpenSansRegular"");
});
builder.Services.AddMauiBlazorWebView();
#if DEBUG
builder.Services.AddLogging(logging => logging.AddDebug());
#endif
builder.Services.AddSingleton<MainPage>();
builder.Services.AddTransient<IDataService, DataService>();
return builder.Build();
}
}
/// <summary>
/// Service interface for data operations
/// </summary>
public interface IDataService
{
Task<string> GetDataAsync();
Task SaveDataAsync(string data);
}
/// <summary>
/// Implementation of data service
/// </summary>
public class DataService : IDataService
{
private readonly ILogger<DataService> _logger;
public DataService(ILogger<DataService> logger)
{
_logger = logger;
}
/// <summary>
/// Retrieves data asynchronously
/// </summary>
public async Task<string> GetDataAsync()
{
_logger.LogInformation(""Getting data..."");
await Task.Delay(100);
return ""Sample data from MAUI app"";
}
/// <summary>
/// Saves data asynchronously
/// </summary>
public async Task SaveDataAsync(string data)
{
_logger.LogInformation(""Saving data: {Data}"", data);
await Task.Delay(50);
}
}";
await File.WriteAllTextAsync(Path.Combine(projectPath, "MauiProgram.cs"), mauiProgramContent);
}
private string FindProjectDirectory(string startPath)
{
var currentDir = new DirectoryInfo(startPath);
while (currentDir != null)
{
// Look for .csproj files
var projectFiles = currentDir.GetFiles("*.csproj");
if (projectFiles.Any())
{
return currentDir.FullName;
}
// Look for .sln files
var solutionFiles = currentDir.GetFiles("*.sln");
if (solutionFiles.Any())
{
return currentDir.FullName;
}
currentDir = currentDir.Parent;
}
return null;
}
private void DisplayReadmeResults(object data)
{
var json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
var resultElement = JsonSerializer.Deserialize<JsonElement>(json);
Console.WriteLine("\n[RESULTS]");
DisplayJsonProperty(resultElement, "Message");
DisplayJsonProperty(resultElement, "ProjectType");
DisplayJsonProperty(resultElement, "FilesAnalyzed");
DisplayJsonProperty(resultElement, "ContentLength");
DisplayJsonProperty(resultElement, "ChangesApplied");
if (resultElement.TryGetProperty("ReadmePath", out var readmePath))
{
Console.WriteLine($" README saved to: {readmePath.GetString()}");
}
if (resultElement.TryGetProperty("Sections", out var sections) && sections.ValueKind == JsonValueKind.Array)
{
Console.WriteLine(" Sections included:");
foreach (var section in sections.EnumerateArray())
{
Console.WriteLine($" - {section.GetString()}");
}
}
}
private void DisplayJsonProperty(JsonElement element, string propertyName)
{
if (element.TryGetProperty(propertyName, out var property))
{
var value = property.ValueKind switch
{
JsonValueKind.String => property.GetString(),
JsonValueKind.Number => property.GetDouble().ToString("F0"),
JsonValueKind.True => "True",
JsonValueKind.False => "False",
_ => property.ToString()
};
Console.WriteLine($" {propertyName}: {value}");
}
}
}