SOMS/SolutionCleanupTool.Tests/ReportGeneratorTests.cs
2025-12-31 14:25:09 +08:00

223 lines
10 KiB
C#

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
{
/// <summary>
/// Tests for the ReportGenerator class
/// </summary>
public class ReportGeneratorTests : PropertyTestBase
{
private readonly ReportGenerator _reportGenerator;
public ReportGeneratorTests()
{
_reportGenerator = new ReportGenerator();
}
/// <summary>
/// Generator for MissingProject instances
/// </summary>
public static Arbitrary<MissingProject> MissingProjectGenerator()
{
return (from reference in ProjectReferenceGenerator().Generator
from expectedPath in Arb.Default.NonEmptyString().Generator
from referencingProjects in Arb.Generate<List<NonEmptyString>>()
from errorMessage in Arb.Default.String().Generator
select new MissingProject
{
Reference = reference,
ExpectedPath = expectedPath.Get,
ReferencingProjects = referencingProjects?.Select(x => x.Get).ToList() ?? new List<string>(),
ErrorMessage = errorMessage ?? string.Empty
}).ToArbitrary();
}
/// <summary>
/// Generator for CleanupResult instances
/// </summary>
public static Arbitrary<CleanupResult> CleanupResultGenerator()
{
return (from removedProjects in Arb.Generate<List<MissingProject>>()
from success in Arb.Generate<bool>()
from backupPath in Arb.Default.String().Generator
from warnings in Arb.Generate<List<NonEmptyString>>()
select new CleanupResult
{
RemovedProjects = removedProjects ?? new List<MissingProject>(),
TotalProjectsRemoved = removedProjects?.Count ?? 0,
Success = success,
BackupFilePath = backupPath ?? string.Empty,
Warnings = warnings?.Select(x => x.Get).ToList() ?? new List<string>()
}).ToArbitrary();
}
/// <summary>
/// Generator for ValidationResult instances
/// </summary>
public static Arbitrary<ValidationResult> ValidationResultGenerator()
{
return (from isValid in Arb.Generate<bool>()
from canLoad in Arb.Generate<bool>()
from hasCircular in Arb.Generate<bool>()
from errors in Arb.Generate<List<NonEmptyString>>()
from warnings in Arb.Generate<List<NonEmptyString>>()
select new ValidationResult
{
IsValid = isValid,
CanLoadSolution = canLoad,
HasCircularReferences = hasCircular,
Errors = errors?.Select(x => x.Get).ToList() ?? new List<string>(),
Warnings = warnings?.Select(x => x.Get).ToList() ?? new List<string>()
}).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<MissingProject> { 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<MissingProject>();
var recommendations = _reportGenerator.GenerateRestorationRecommendations(removedProjects);
Assert.NotNull(recommendations);
Assert.Contains("No projects were removed", recommendations);
}
}
}