using FsCheck; using FsCheck.Xunit; using SolutionCleanupTool.Models; using SolutionCleanupTool.Services; using System; using System.Collections.Generic; using System.IO; using System.Linq; using Xunit; namespace SolutionCleanupTool.Tests { /// /// Tests for the ReportGenerator class /// public class ReportGeneratorTests : PropertyTestBase { private readonly ReportGenerator _reportGenerator; public ReportGeneratorTests() { _reportGenerator = new ReportGenerator(); } /// /// Generator for MissingProject instances /// public static Arbitrary MissingProjectGenerator() { return (from reference in ProjectReferenceGenerator().Generator from expectedPath in Arb.Default.NonEmptyString().Generator from referencingProjects in Arb.Generate>() from errorMessage in Arb.Default.String().Generator select new MissingProject { Reference = reference, ExpectedPath = expectedPath.Get, ReferencingProjects = referencingProjects?.Select(x => x.Get).ToList() ?? new List(), ErrorMessage = errorMessage ?? string.Empty }).ToArbitrary(); } /// /// Generator for CleanupResult instances /// public static Arbitrary CleanupResultGenerator() { return (from removedProjects in Arb.Generate>() from success in Arb.Generate() from backupPath in Arb.Default.String().Generator from warnings in Arb.Generate>() select new CleanupResult { RemovedProjects = removedProjects ?? new List(), TotalProjectsRemoved = removedProjects?.Count ?? 0, Success = success, BackupFilePath = backupPath ?? string.Empty, Warnings = warnings?.Select(x => x.Get).ToList() ?? new List() }).ToArbitrary(); } /// /// Generator for ValidationResult instances /// public static Arbitrary ValidationResultGenerator() { return (from isValid in Arb.Generate() from canLoad in Arb.Generate() from hasCircular in Arb.Generate() from errors in Arb.Generate>() from warnings in Arb.Generate>() select new ValidationResult { IsValid = isValid, CanLoadSolution = canLoad, HasCircularReferences = hasCircular, Errors = errors?.Select(x => x.Get).ToList() ?? new List(), Warnings = warnings?.Select(x => x.Get).ToList() ?? new List() }).ToArbitrary(); } [Property] public Property GenerateReport_ShouldIncludeAllRemovedProjects() { return Prop.ForAll( CleanupResultGenerator(), ValidationResultGenerator(), Arb.Default.NonEmptyString(), (CleanupResult cleanupResult, ValidationResult validationResult, NonEmptyString solutionPath) => { // **Feature: fix-missing-project-references, Property 16: Complete Removal Logging** // **Validates: Requirements 4.1** var report = _reportGenerator.GenerateReport(cleanupResult, validationResult, solutionPath.Get); // For any removed project, the log should contain an entry with the full path and name of the project return cleanupResult.RemovedProjects.All(project => !string.IsNullOrEmpty(project.Reference.Name) && !string.IsNullOrEmpty(project.ExpectedPath) && report.Contains(project.Reference.Name) && report.Contains(project.ExpectedPath)); }); } [Property] public Property GenerateSummary_ShouldIncludeCorrectStatistics() { return Prop.ForAll( CleanupResultGenerator(), (CleanupResult cleanupResult) => { // **Feature: fix-missing-project-references, Property 17: Summary Report Generation** // **Validates: Requirements 4.2** var summary = _reportGenerator.GenerateSummary(cleanupResult); // For any completed cleanup operation, a summary report should be generated containing information about all changes made return summary.Contains(cleanupResult.TotalProjectsRemoved.ToString()) && summary.Contains(cleanupResult.RemovedProjects.Count.ToString()) && summary.Contains(cleanupResult.Warnings.Count.ToString()) && summary.Contains(cleanupResult.Success ? "Completed Successfully" : "Failed"); }); } [Property] public Property GenerateReport_ShouldIncludeErrorMessages() { return Prop.ForAll( CleanupResultGenerator(), ValidationResultGenerator(), Arb.Default.NonEmptyString(), (CleanupResult cleanupResult, ValidationResult validationResult, NonEmptyString solutionPath) => { // **Feature: fix-missing-project-references, Property 18: Error Message Inclusion** // **Validates: Requirements 4.3** var report = _reportGenerator.GenerateReport(cleanupResult, validationResult, solutionPath.Get); // For any removed project, the report should include the original error message that triggered the removal return cleanupResult.RemovedProjects .Where(project => !string.IsNullOrEmpty(project.ErrorMessage)) .All(project => report.Contains(project.ErrorMessage)); }); } [Property] public Property GenerateRestorationRecommendations_ShouldProvideGuidance() { return Prop.ForAll(MissingProjectGenerator(), project => { // **Feature: fix-missing-project-references, Property 19: Restoration Recommendations** // **Validates: Requirements 4.4** var removedProjects = new List { project }; var recommendations = _reportGenerator.GenerateRestorationRecommendations(removedProjects); // For any removed project, the report should provide recommendations for restoring the project if files are found later return recommendations.Contains("RESTORATION RECOMMENDATIONS") && recommendations.Contains("GENERAL RESTORATION STEPS") && recommendations.Contains(project.Reference.Name) && recommendations.Contains(project.ExpectedPath); }); } [Property] public Property GenerateReport_ShouldIncludeBackupLocation() { return Prop.ForAll( CleanupResultGenerator(), ValidationResultGenerator(), Arb.Default.NonEmptyString(), (CleanupResult cleanupResult, ValidationResult validationResult, NonEmptyString solutionPath) => { // **Feature: fix-missing-project-references, Property 20: Backup Location Reporting** // **Validates: Requirements 4.5** var report = _reportGenerator.GenerateReport(cleanupResult, validationResult, solutionPath.Get); // For any generated report, it should include the location of the backup solution file if (string.IsNullOrEmpty(cleanupResult.BackupFilePath)) { return true; // No backup path to include } return report.Contains("BACKUP INFORMATION") && report.Contains(cleanupResult.BackupFilePath); }); } [Fact] public void GenerateReport_WithEmptyCleanupResult_ShouldNotThrow() { // Test with minimal data to ensure robustness var cleanupResult = new CleanupResult(); var validationResult = new ValidationResult(); var solutionPath = "test.sln"; var report = _reportGenerator.GenerateReport(cleanupResult, validationResult, solutionPath); Assert.NotNull(report); Assert.Contains("SOLUTION CLEANUP REPORT", report); Assert.Contains("test.sln", report); } [Fact] public void GenerateSummary_WithEmptyCleanupResult_ShouldNotThrow() { var cleanupResult = new CleanupResult(); var summary = _reportGenerator.GenerateSummary(cleanupResult); Assert.NotNull(summary); Assert.Contains("CLEANUP SUMMARY", summary); Assert.Contains("0", summary); // Should show 0 projects removed } [Fact] public void GenerateRestorationRecommendations_WithEmptyList_ShouldProvideMessage() { var removedProjects = new List(); var recommendations = _reportGenerator.GenerateRestorationRecommendations(removedProjects); Assert.NotNull(recommendations); Assert.Contains("No projects were removed", recommendations); } } }