diff --git a/Directory.Build.props b/Directory.Build.props
index 5110cdb..723456e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -33,20 +33,17 @@
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
+
all
3.9.50
-
+
\ No newline at end of file
diff --git a/aet.png b/aet.png
new file mode 100644
index 0000000..ac47943
Binary files /dev/null and b/aet.png differ
diff --git a/modules/ModdingToolBase b/modules/ModdingToolBase
index 5103bad..e12f6ce 160000
--- a/modules/ModdingToolBase
+++ b/modules/ModdingToolBase
@@ -1 +1 @@
-Subproject commit 5103bad6f09ba88061ccbc36ee285ee9300744cc
+Subproject commit e12f6ceedb83fe9e3372dd89c68d508f8479cf92
diff --git a/src/ModVerify.CliApp/App/CreateBaselineAction.cs b/src/ModVerify.CliApp/App/CreateBaselineAction.cs
index b0eb880..b776e09 100644
--- a/src/ModVerify.CliApp/App/CreateBaselineAction.cs
+++ b/src/ModVerify.CliApp/App/CreateBaselineAction.cs
@@ -2,10 +2,10 @@
using AET.ModVerify.App.Settings;
using AET.ModVerify.App.Utilities;
using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
-using System.Collections.Generic;
using System.IO.Abstractions;
using System.Threading.Tasks;
@@ -26,16 +26,14 @@ protected override void PrintAction(VerificationTarget target)
Console.WriteLine();
}
- protected override async Task ProcessVerifyFindings(
- VerificationTarget verificationTarget,
- IReadOnlyCollection allErrors)
+ protected override async Task ProcessResult(VerificationResult result)
{
var baselineFactory = ServiceProvider.GetRequiredService();
- var baseline = baselineFactory.CreateBaseline(verificationTarget, Settings, allErrors);
+ var baseline = baselineFactory.CreateBaseline(result.Target, Settings, result.Errors);
var fullPath = _fileSystem.Path.GetFullPath(Settings.NewBaselinePath);
Logger?.LogInformation(ModVerifyConstants.ConsoleEventId,
- "Writing Baseline to '{FullPath}' with {Number} findings", fullPath, allErrors.Count);
+ "Writing Baseline to '{FullPath}' with {Number} findings", fullPath, result.Errors.Count);
await baselineFactory.WriteBaselineAsync(baseline, Settings.NewBaselinePath);
@@ -43,7 +41,7 @@ protected override async Task ProcessVerifyFindings(
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGreen;
- Console.WriteLine($"Baseline for {verificationTarget.Name} created.");
+ Console.WriteLine($"Baseline for {result.Target.Name} created.");
Console.ResetColor();
return ModVerifyConstants.Success;
diff --git a/src/ModVerify.CliApp/App/ModVerifyApplicationAction.cs b/src/ModVerify.CliApp/App/ModVerifyApplicationAction.cs
index b3f12f7..113e633 100644
--- a/src/ModVerify.CliApp/App/ModVerifyApplicationAction.cs
+++ b/src/ModVerify.CliApp/App/ModVerifyApplicationAction.cs
@@ -1,13 +1,13 @@
using System;
-using System.Collections.Generic;
using System.IO.Abstractions;
using System.Threading.Tasks;
using AET.ModVerify.App.GameFinder;
using AET.ModVerify.App.Reporting;
using AET.ModVerify.App.Settings;
using AET.ModVerify.App.TargetSelectors;
-using AET.ModVerify.Pipeline;
using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
+using AET.ModVerify.Reporting.Suppressions;
using AnakinRaW.ApplicationBase;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -71,43 +71,55 @@ public async Task ExecuteAsync()
PrintAction(verificationTarget);
- var allErrors = await VerifyTargetAsync(verificationTarget)
+ var verificationResult = await VerifyTargetAsync(verificationTarget)
.ConfigureAwait(false);
- return await ProcessVerifyFindings(verificationTarget, allErrors);
+ return await ProcessResult(verificationResult);
}
- protected abstract Task ProcessVerifyFindings(
- VerificationTarget verificationTarget,
- IReadOnlyCollection allErrors);
+ protected abstract Task ProcessResult(VerificationResult result);
protected abstract VerificationBaseline GetBaseline(VerificationTarget verificationTarget);
- private async Task> VerifyTargetAsync(VerificationTarget verificationTarget)
+ private async Task VerifyTargetAsync(VerificationTarget verificationTarget)
{
var progressReporter = new VerifyConsoleProgressReporter(verificationTarget.Name, Settings.ReportSettings);
var baseline = GetBaseline(verificationTarget);
var suppressions = GetSuppressions();
- using var verifyPipeline = new GameVerifyPipeline(
- verificationTarget,
- Settings.VerifyPipelineSettings,
- progressReporter,
- new EngineInitializeProgressReporter(verificationTarget.Engine),
- baseline,
- suppressions,
- ServiceProvider);
-
try
{
+ var verifierService = ServiceProvider.GetRequiredService();
+
Logger?.LogInformation(ModVerifyConstants.ConsoleEventId, "Verifying '{Target}'...", verificationTarget.Name);
- await verifyPipeline.RunAsync().ConfigureAwait(false);
+
+ var verificationResult = await verifierService.VerifyAsync(
+ verificationTarget,
+ Settings.VerifierServiceSettings,
+ baseline,
+ suppressions,
+ progressReporter,
+ new EngineInitializeProgressReporter(verificationTarget.Engine));
+
progressReporter.Report(string.Empty, 1.0);
- }
- catch (OperationCanceledException)
- {
- Logger?.LogWarning(ModVerifyConstants.ConsoleEventId, "Verification stopped due to enabled failFast setting.");
+
+ switch (verificationResult.Status)
+ {
+ case VerificationCompletionStatus.CompletedFailFast:
+ Logger?.LogWarning(ModVerifyConstants.ConsoleEventId, "Verification stopped due to enabled failFast setting.");
+ break;
+ case VerificationCompletionStatus.Cancelled:
+ Logger?.LogWarning(ModVerifyConstants.ConsoleEventId, "Verification was cancelled.");
+ break;
+ case VerificationCompletionStatus.Completed:
+ default:
+ Logger?.LogInformation(ModVerifyConstants.ConsoleEventId, "Verification completed successfully.");
+ break;
+ }
+
+ return verificationResult;
+
}
catch (Exception e)
{
@@ -119,9 +131,6 @@ private async Task> VerifyTargetAsync(Ver
{
progressReporter.Dispose();
}
-
- Logger?.LogInformation(ModVerifyConstants.ConsoleEventId, "Finished verification");
- return verifyPipeline.FilteredErrors;
}
private SuppressionList GetSuppressions()
diff --git a/src/ModVerify.CliApp/App/VerifyAction.cs b/src/ModVerify.CliApp/App/VerifyAction.cs
index 0cfea0e..f30305c 100644
--- a/src/ModVerify.CliApp/App/VerifyAction.cs
+++ b/src/ModVerify.CliApp/App/VerifyAction.cs
@@ -1,12 +1,14 @@
using AET.ModVerify.App.Reporting;
using AET.ModVerify.App.Settings;
+using AET.ModVerify.App.Utilities;
using AET.ModVerify.Reporting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using AET.ModVerify.App.Utilities;
+using AET.ModVerify.Reporting.Reporters;
+using AET.ModVerify.Reporting.Baseline;
namespace AET.ModVerify.App;
@@ -23,20 +25,27 @@ protected override void PrintAction(VerificationTarget target)
Console.WriteLine();
}
- protected override async Task ProcessVerifyFindings(
- VerificationTarget verificationTarget,
- IReadOnlyCollection allErrors)
+ protected override async Task ProcessResult(VerificationResult result)
{
Logger?.LogInformation(ModVerifyConstants.ConsoleEventId, "Reporting Errors...");
- var reportBroker = new VerificationReportBroker(ServiceProvider);
- await reportBroker.ReportAsync(allErrors);
+ var reportBroker = new VerificationReportBroker(CreateReporters(), ServiceProvider);
+
+ result = result with
+ {
+ Target = result.Target with
+ {
+ Location = result.Target.Location.MaskUsername()
+ }
+ };
+
+ await reportBroker.ReportAsync(result);
if (Settings.AppFailsOnMinimumSeverity.HasValue &&
- allErrors.Any(x => x.Severity >= Settings.AppFailsOnMinimumSeverity))
+ result.Errors.Any(x => x.Severity >= Settings.AppFailsOnMinimumSeverity))
{
Logger?.LogInformation(ModVerifyConstants.ConsoleEventId,
"The verification of {Target} completed with findings of the specified failure severity {Severity}",
- verificationTarget.Name, Settings.AppFailsOnMinimumSeverity);
+ result.Target.Name, Settings.AppFailsOnMinimumSeverity);
return ModVerifyConstants.CompletedWithFindings;
}
@@ -57,4 +66,32 @@ protected override VerificationBaseline GetBaseline(VerificationTarget verificat
}
return baseline;
}
+
+ private IReadOnlyCollection CreateReporters()
+ {
+ var reporters = new List();
+
+ reporters.Add(IVerificationReporter.CreateConsole(new ConsoleReporterSettings
+ {
+ MinimumReportSeverity = Settings.VerifierServiceSettings.FailFastSettings.IsFailFast
+ ? VerificationSeverity.Information
+ : VerificationSeverity.Error
+ }, ServiceProvider));
+
+ var outputDirectory = Settings.ReportDirectory;
+ reporters.Add(IVerificationReporter.CreateJson(new JsonReporterSettings
+ {
+ OutputDirectory = outputDirectory,
+ MinimumReportSeverity = Settings.ReportSettings.MinimumReportSeverity,
+ AggregateResults = true
+ }, ServiceProvider));
+
+ reporters.Add(IVerificationReporter.CreateText(new TextFileReporterSettings
+ {
+ OutputDirectory = outputDirectory!,
+ MinimumReportSeverity = Settings.ReportSettings.MinimumReportSeverity
+ }, ServiceProvider));
+
+ return reporters;
+ }
}
\ No newline at end of file
diff --git a/src/ModVerify.CliApp/ModVerify.CliApp.csproj b/src/ModVerify.CliApp/ModVerify.CliApp.csproj
index ec2fd46..7dcf361 100644
--- a/src/ModVerify.CliApp/ModVerify.CliApp.csproj
+++ b/src/ModVerify.CliApp/ModVerify.CliApp.csproj
@@ -5,14 +5,14 @@
Exe
AET.ModVerify.App
ModVerify
- $(RepoRootPath)aet.ico
+ Resources/aet.ico
AlamoEngineTools.ModVerify.CliApp
ModVerify Console Application
AET.ModVerify
- Console application that analyzes game modifications for Empire at War / Forces of Corruption for common errors.
+ An application that analyzes game modifications for Empire at War / Forces of Corruption for common errors.
alamo,petroglyph,glyphx
@@ -25,10 +25,6 @@
true
-
-
-
-
@@ -70,7 +66,7 @@
compile
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
compile
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -86,10 +82,6 @@
-
-
-
-
diff --git a/src/ModVerify.CliApp/Program.cs b/src/ModVerify.CliApp/Program.cs
index 2d23b3b..68056a4 100644
--- a/src/ModVerify.CliApp/Program.cs
+++ b/src/ModVerify.CliApp/Program.cs
@@ -2,11 +2,6 @@
using AET.ModVerify.App.Settings.CommandLine;
using AET.ModVerify.App.Updates;
using AET.ModVerify.App.Utilities;
-using AET.ModVerify.Reporting;
-using AET.ModVerify.Reporting.Reporters;
-using AET.ModVerify.Reporting.Reporters.JSON;
-using AET.ModVerify.Reporting.Reporters.Text;
-using AET.ModVerify.Reporting.Settings;
using AET.SteamAbstraction;
using AnakinRaW.ApplicationBase;
using AnakinRaW.ApplicationBase.Environment;
@@ -36,7 +31,6 @@
using Serilog.Sinks.SystemConsole.Themes;
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO.Abstractions;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -157,11 +151,10 @@ protected override void CreateAppServices(IServiceCollection services, IReadOnly
PetroglyphCommons.ContributeServices(services);
PetroglyphEngineServiceContribution.ContributeServices(services);
+ services.AddModVerify();
services.RegisterVerifierCache();
services.AddSingleton(sp => new BaselineFactory(sp));
-
- SetupVerifyReporting(services);
if (_offlineMode)
{
@@ -200,37 +193,6 @@ protected override async Task RunAppAsync(string[] args, IServiceProvider a
return await new ModVerifyApplication(_modVerifyAppSettings, appServiceProvider).RunAsync().ConfigureAwait(false);
}
- private void SetupVerifyReporting(IServiceCollection serviceCollection)
- {
- Debug.Assert(_modVerifyAppSettings is not null);
-
- var verifySettings = _modVerifyAppSettings as AppVerifySettings;
-
- // Console should be in minimal summary mode if we are in a different mode than verify.
- serviceCollection.RegisterConsoleReporter(new ReporterSettings
- {
- MinimumReportSeverity = verifySettings?.VerifyPipelineSettings.FailFastSettings.IsFailFast is true
- ? VerificationSeverity.Information
- : VerificationSeverity.Error
- }, summaryOnly: verifySettings is null);
-
- if (verifySettings == null)
- return;
-
- var outputDirectory = verifySettings.ReportDirectory;
- serviceCollection.RegisterJsonReporter(new JsonReporterSettings
- {
- OutputDirectory = outputDirectory!,
- MinimumReportSeverity = _modVerifyAppSettings.ReportSettings.MinimumReportSeverity
- });
-
- serviceCollection.RegisterTextFileReporter(new TextFileReporterSettings
- {
- OutputDirectory = outputDirectory!,
- MinimumReportSeverity = _modVerifyAppSettings.ReportSettings.MinimumReportSeverity
- });
- }
-
private void ConfigureLogging(ILoggingBuilder loggingBuilder)
{
loggingBuilder.ClearProviders();
diff --git a/src/ModVerify.CliApp/Reporting/BaselineFactory.cs b/src/ModVerify.CliApp/Reporting/BaselineFactory.cs
index a83cea9..b621343 100644
--- a/src/ModVerify.CliApp/Reporting/BaselineFactory.cs
+++ b/src/ModVerify.CliApp/Reporting/BaselineFactory.cs
@@ -7,10 +7,9 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.Abstractions;
-using System.Linq;
using System.Threading.Tasks;
-using PG.StarWarsGame.Engine;
using AET.ModVerify.App.Utilities;
+using AET.ModVerify.Reporting.Baseline;
namespace AET.ModVerify.App.Reporting;
@@ -89,21 +88,13 @@ public VerificationBaseline CreateBaseline(
Engine = target.Engine,
Name = target.Name,
Version = target.Version,
- Location = settings.WriteLocations ? MaskUsername(target.Location) : null,
+ Location = settings.WriteLocations ? target.Location.MaskUsername() : null,
IsGame = target.IsGame,
};
return new VerificationBaseline(settings.ReportSettings.MinimumReportSeverity, errors, baselineTarget);
}
- private static GameLocations MaskUsername(GameLocations targetLocation)
- {
- return new GameLocations(
- targetLocation.ModPaths.Select(PathUtilities.MaskUsername).ToList(),
- PathUtilities.MaskUsername(targetLocation.GamePath),
- targetLocation.FallbackPaths.Select(PathUtilities.MaskUsername).ToList());
- }
-
public async Task WriteBaselineAsync(VerificationBaseline baseline, string filePath)
{
#if NET
diff --git a/src/ModVerify.CliApp/Reporting/BaselineSelector.cs b/src/ModVerify.CliApp/Reporting/BaselineSelector.cs
index 791eaae..efcaae5 100644
--- a/src/ModVerify.CliApp/Reporting/BaselineSelector.cs
+++ b/src/ModVerify.CliApp/Reporting/BaselineSelector.cs
@@ -1,6 +1,6 @@
using AET.ModVerify.App.Resources.Baselines;
using AET.ModVerify.App.Settings;
-using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
using AnakinRaW.ApplicationBase;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
diff --git a/src/ModVerify.CliApp/Reporting/IBaselineFactory.cs b/src/ModVerify.CliApp/Reporting/IBaselineFactory.cs
index 721a7ce..a534cdb 100644
--- a/src/ModVerify.CliApp/Reporting/IBaselineFactory.cs
+++ b/src/ModVerify.CliApp/Reporting/IBaselineFactory.cs
@@ -1,5 +1,6 @@
using AET.ModVerify.App.Settings;
using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/ModVerify.CliApp/Reporting/VerifyConsoleProgressReporter.cs b/src/ModVerify.CliApp/Reporting/VerifyConsoleProgressReporter.cs
index b2ce170..66587ae 100644
--- a/src/ModVerify.CliApp/Reporting/VerifyConsoleProgressReporter.cs
+++ b/src/ModVerify.CliApp/Reporting/VerifyConsoleProgressReporter.cs
@@ -1,7 +1,7 @@
using System;
using System.Threading;
using AET.ModVerify.App.Settings;
-using AET.ModVerify.Pipeline.Progress;
+using AET.ModVerify.Progress;
using AnakinRaW.CommonUtilities;
using AnakinRaW.CommonUtilities.SimplePipeline.Progress;
using ShellProgressBar;
diff --git a/aet.ico b/src/ModVerify.CliApp/Resources/aet.ico
similarity index 100%
rename from aet.ico
rename to src/ModVerify.CliApp/Resources/aet.ico
diff --git a/src/ModVerify.CliApp/Settings/ModVerifyAppSettings.cs b/src/ModVerify.CliApp/Settings/ModVerifyAppSettings.cs
index e4488a0..add39a5 100644
--- a/src/ModVerify.CliApp/Settings/ModVerifyAppSettings.cs
+++ b/src/ModVerify.CliApp/Settings/ModVerifyAppSettings.cs
@@ -29,7 +29,7 @@ public required VerificationTargetSettings VerificationTargetSettings
init => field = value ?? throw new ArgumentNullException(nameof(value));
}
- public required VerifyPipelineSettings VerifyPipelineSettings
+ public required VerifierServiceSettings VerifierServiceSettings
{
get;
init => field = value ?? throw new ArgumentNullException(nameof(value));
diff --git a/src/ModVerify.CliApp/Settings/SettingsBuilder.cs b/src/ModVerify.CliApp/Settings/SettingsBuilder.cs
index 23a89ff..62bca7a 100644
--- a/src/ModVerify.CliApp/Settings/SettingsBuilder.cs
+++ b/src/ModVerify.CliApp/Settings/SettingsBuilder.cs
@@ -1,5 +1,4 @@
using AET.ModVerify.App.Settings.CommandLine;
-using AET.ModVerify.Pipeline;
using AET.ModVerify.Settings;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -31,7 +30,7 @@ private AppVerifySettings BuildFromVerifyVerb(VerifyVerbOption verifyOptions)
return new AppVerifySettings(BuildReportSettings())
{
ReportDirectory = GetReportDirectory(),
- VerifyPipelineSettings = new VerifyPipelineSettings
+ VerifierServiceSettings = new VerifierServiceSettings
{
ParallelVerifiers = verifyOptions.Parallel ? 4 : 1,
VerifiersProvider = new DefaultGameVerifiersProvider(),
@@ -97,7 +96,7 @@ private AppBaselineSettings BuildFromCreateBaselineVerb(CreateBaselineVerbOption
{
return new AppBaselineSettings(BuildReportSettings())
{
- VerifyPipelineSettings = new VerifyPipelineSettings
+ VerifierServiceSettings = new VerifierServiceSettings
{
ParallelVerifiers = baselineVerb.Parallel ? 4 : 1,
VerifiersProvider = new DefaultGameVerifiersProvider(),
diff --git a/src/ModVerify.CliApp/TargetSelectors/VerificationTargetSelectorBase.cs b/src/ModVerify.CliApp/TargetSelectors/VerificationTargetSelectorBase.cs
index 68f0f39..0c45986 100644
--- a/src/ModVerify.CliApp/TargetSelectors/VerificationTargetSelectorBase.cs
+++ b/src/ModVerify.CliApp/TargetSelectors/VerificationTargetSelectorBase.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Linq;
-using System.Runtime.InteropServices;
using AET.ModVerify.App.GameFinder;
using AET.ModVerify.App.Settings;
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/ModVerify.CliApp/Utilities/ExtensionMethods.cs b/src/ModVerify.CliApp/Utilities/ExtensionMethods.cs
index fc07469..5871311 100644
--- a/src/ModVerify.CliApp/Utilities/ExtensionMethods.cs
+++ b/src/ModVerify.CliApp/Utilities/ExtensionMethods.cs
@@ -1,8 +1,9 @@
-using System.Diagnostics.CodeAnalysis;
-using AET.ModVerify.App.Settings.CommandLine;
+using AET.ModVerify.App.Settings.CommandLine;
using AnakinRaW.ApplicationBase.Environment;
using PG.StarWarsGame.Engine;
using PG.StarWarsGame.Infrastructure.Games;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
namespace AET.ModVerify.App.Utilities;
@@ -21,10 +22,6 @@ public GameEngineType Opposite()
}
}
- public static GameEngineType ToEngineType(this GameType type)
- {
- return (GameEngineType)(int)type;
- }
extension(ApplicationEnvironment modVerifyEnvironment)
{
public bool IsUpdatable()
@@ -39,6 +36,19 @@ public bool IsUpdatable([NotNullWhen(true)] out UpdatableApplicationEnvironment?
}
}
+ public static GameEngineType ToEngineType(this GameType type)
+ {
+ return (GameEngineType)(int)type;
+ }
+
+ public static GameLocations MaskUsername(this GameLocations targetLocation)
+ {
+ return new GameLocations(
+ targetLocation.ModPaths.Select(PathUtilities.MaskUsername).ToList(),
+ PathUtilities.MaskUsername(targetLocation.GamePath),
+ targetLocation.FallbackPaths.Select(PathUtilities.MaskUsername).ToList());
+ }
+
public static bool LaunchedWithoutArguments(this BaseModVerifyOptions options)
{
if (options is VerifyVerbOption verifyOptions)
diff --git a/src/ModVerify.CliApp/Utilities/ModVerifyConsoleUtilities.cs b/src/ModVerify.CliApp/Utilities/ModVerifyConsoleUtilities.cs
index b9ebff0..9f9962b 100644
--- a/src/ModVerify.CliApp/Utilities/ModVerifyConsoleUtilities.cs
+++ b/src/ModVerify.CliApp/Utilities/ModVerifyConsoleUtilities.cs
@@ -2,7 +2,7 @@
using Figgle;
using System;
using System.Collections.Generic;
-using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
namespace AET.ModVerify.App.Utilities;
diff --git a/src/ModVerify/Pipeline/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs
similarity index 96%
rename from src/ModVerify/Pipeline/DefaultGameVerifiersProvider.cs
rename to src/ModVerify/DefaultGameVerifiersProvider.cs
index 26b3893..c9982b7 100644
--- a/src/ModVerify/Pipeline/DefaultGameVerifiersProvider.cs
+++ b/src/ModVerify/DefaultGameVerifiersProvider.cs
@@ -5,7 +5,7 @@
using AET.ModVerify.Verifiers.GuiDialogs;
using PG.StarWarsGame.Engine;
-namespace AET.ModVerify.Pipeline;
+namespace AET.ModVerify;
public sealed class DefaultGameVerifiersProvider : IGameVerifiersProvider
{
diff --git a/src/ModVerify/GameVerificationException.cs b/src/ModVerify/GameVerificationException.cs
index dba312b..a6ada92 100644
--- a/src/ModVerify/GameVerificationException.cs
+++ b/src/ModVerify/GameVerificationException.cs
@@ -7,8 +7,11 @@ namespace AET.ModVerify;
public sealed class GameVerificationException : Exception
{
+ ///
+ public override string Message => ErrorMessage;
+
public IReadOnlyCollection Errors { get; }
-
+
private string ErrorMessage
{
get
@@ -23,14 +26,11 @@ private string ErrorMessage
}
} = null;
- ///
- public override string Message => ErrorMessage;
-
- public GameVerificationException(VerificationError error) : this([error])
+ internal GameVerificationException(VerificationError error) : this([error])
{
}
- public GameVerificationException(IEnumerable errors)
+ internal GameVerificationException(IEnumerable errors)
{
if (errors is null)
throw new ArgumentNullException(nameof(errors));
diff --git a/src/ModVerify/Pipeline/GameVerifierPipelineStep.cs b/src/ModVerify/GameVerifierPipelineStep.cs
similarity index 91%
rename from src/ModVerify/Pipeline/GameVerifierPipelineStep.cs
rename to src/ModVerify/GameVerifierPipelineStep.cs
index e83cb25..b1f45b8 100644
--- a/src/ModVerify/Pipeline/GameVerifierPipelineStep.cs
+++ b/src/ModVerify/GameVerifierPipelineStep.cs
@@ -1,16 +1,16 @@
-using AET.ModVerify.Verifiers;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using AET.ModVerify.Progress;
+using AET.ModVerify.Verifiers;
using AnakinRaW.CommonUtilities.SimplePipeline;
using AnakinRaW.CommonUtilities.SimplePipeline.Progress;
using AnakinRaW.CommonUtilities.SimplePipeline.Steps;
using Microsoft.Extensions.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using AET.ModVerify.Pipeline.Progress;
-namespace AET.ModVerify.Pipeline;
+namespace AET.ModVerify;
-public sealed class GameVerifierPipelineStep(
+internal sealed class GameVerifierPipelineStep(
GameVerifier verifier,
IServiceProvider serviceProvider)
: PipelineStep(serviceProvider), IProgressStep
diff --git a/src/ModVerify/GameVerifierService.cs b/src/ModVerify/GameVerifierService.cs
new file mode 100644
index 0000000..f6d8f07
--- /dev/null
+++ b/src/ModVerify/GameVerifierService.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using AET.ModVerify.Progress;
+using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
+using AET.ModVerify.Reporting.Suppressions;
+using AET.ModVerify.Settings;
+using PG.StarWarsGame.Engine;
+
+namespace AET.ModVerify;
+
+internal sealed class GameVerifierService(IServiceProvider serviceProvider) : IGameVerifierService
+{
+ public async Task VerifyAsync(
+ VerificationTarget verificationTarget,
+ VerifierServiceSettings settings,
+ VerificationBaseline baseline,
+ SuppressionList suppressions,
+ IVerifyProgressReporter? progressReporter,
+ IGameEngineInitializationReporter? engineInitializationReporter,
+ CancellationToken token = default)
+ {
+ if (verificationTarget == null)
+ throw new ArgumentNullException(nameof(verificationTarget));
+ if (settings == null)
+ throw new ArgumentNullException(nameof(settings));
+
+ using var pipeline = new GameVerifyPipeline(
+ verificationTarget,
+ settings,
+ serviceProvider,
+ baseline,
+ suppressions,
+ progressReporter,
+ engineInitializationReporter);
+
+ VerificationCompletionStatus completionStatus;
+ var start = DateTime.UtcNow;
+
+ try
+ {
+ await pipeline.RunAsync(token).ConfigureAwait(false);
+ completionStatus = VerificationCompletionStatus.Completed;
+ }
+ catch (OperationCanceledException)
+ {
+ completionStatus = settings.FailFastSettings.IsFailFast
+ ? VerificationCompletionStatus.CompletedFailFast
+ : VerificationCompletionStatus.Cancelled;
+ }
+
+ var duration = DateTime.UtcNow - start;
+
+ return new VerificationResult
+ {
+ Duration = duration,
+ Errors = pipeline.Errors,
+ Status = completionStatus,
+ Target = verificationTarget,
+ UsedBaseline = baseline,
+ UsedSuppressions = suppressions,
+ Verifiers = pipeline.Verifiers
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Pipeline/GameVerifyPipeline.cs b/src/ModVerify/GameVerifyPipeline.cs
similarity index 56%
rename from src/ModVerify/Pipeline/GameVerifyPipeline.cs
rename to src/ModVerify/GameVerifyPipeline.cs
index 493aa8c..4ed351e 100644
--- a/src/ModVerify/Pipeline/GameVerifyPipeline.cs
+++ b/src/ModVerify/GameVerifyPipeline.cs
@@ -1,63 +1,67 @@
-using AET.ModVerify.Pipeline.Progress;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using AET.ModVerify.Progress;
using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
+using AET.ModVerify.Reporting.Engine;
+using AET.ModVerify.Reporting.Suppressions;
using AET.ModVerify.Settings;
+using AET.ModVerify.Utilities;
using AET.ModVerify.Verifiers;
using AnakinRaW.CommonUtilities.SimplePipeline;
using AnakinRaW.CommonUtilities.SimplePipeline.Runners;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PG.StarWarsGame.Engine;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using AET.ModVerify.Utilities;
-using Microsoft.Extensions.DependencyInjection;
-namespace AET.ModVerify.Pipeline;
+namespace AET.ModVerify;
-public sealed class GameVerifyPipeline : StepRunnerPipelineBase
+internal sealed class GameVerifyPipeline : StepRunnerPipelineBase
{
private readonly List _verifiers = [];
+ private readonly List _errors = [];
private readonly List _verificationSteps = [];
- private readonly ConcurrentGameEngineErrorReporter _engineErrorReporter = new();
-
+
+ private readonly GameEngineErrorCollection _engineErrorReporter = new();
private readonly VerificationTarget _verificationTarget;
- private readonly VerifyPipelineSettings _pipelineSettings;
- private readonly IVerifyProgressReporter _progressReporter;
+ private readonly VerifierServiceSettings _serviceSettings;
+ private readonly IVerifyProgressReporter? _progressReporter;
private readonly IGameEngineInitializationReporter? _engineInitializationReporter;
- private readonly IPetroglyphStarWarsGameEngineService _gameEngineService;
- private readonly ILogger? _logger;
- private AggregatedVerifyProgressReporter? _aggregatedVerifyProgressReporter;
+ private readonly VerificationBaseline _baseline;
+ private readonly SuppressionList _suppressions;
+
+ internal IReadOnlyCollection Errors => [.._errors];
+
+ internal IReadOnlyCollection Verifiers => [.. _verifiers];
- public IReadOnlyCollection FilteredErrors { get; private set; } = [];
- public VerificationBaseline Baseline { get; }
- public SuppressionList Suppressions { get; }
+ private AggregatedVerifyProgressReporter? _aggregatedVerifyProgressReporter;
public GameVerifyPipeline(
VerificationTarget verificationTarget,
- VerifyPipelineSettings pipelineSettings,
- IVerifyProgressReporter progressReporter,
- IGameEngineInitializationReporter? engineInitializationReporter,
+ VerifierServiceSettings serviceSettings,
+ IServiceProvider serviceProvider,
VerificationBaseline baseline,
SuppressionList suppressions,
- IServiceProvider serviceProvider) : base(serviceProvider)
+ IVerifyProgressReporter? progressReporter = null,
+ IGameEngineInitializationReporter? engineInitializationReporter = null)
+ : base(serviceProvider)
{
- Baseline = baseline ?? throw new ArgumentNullException(nameof(baseline));
- Suppressions = suppressions ?? throw new ArgumentNullException(nameof(suppressions));
_verificationTarget = verificationTarget ?? throw new ArgumentNullException(nameof(verificationTarget));
- _pipelineSettings = pipelineSettings ?? throw new ArgumentNullException(nameof(pipelineSettings));
- _progressReporter = progressReporter ?? throw new ArgumentNullException(nameof(progressReporter));
+ _serviceSettings = serviceSettings ?? throw new ArgumentNullException(nameof(serviceSettings));
+ _baseline = baseline ?? throw new ArgumentNullException(nameof(baseline));
+ _suppressions = suppressions ?? throw new ArgumentNullException(nameof(suppressions));
+ _progressReporter = progressReporter;
_engineInitializationReporter = engineInitializationReporter;
- _gameEngineService = serviceProvider.GetRequiredService();
- _logger = serviceProvider.GetService()?.CreateLogger(GetType());
- FailFast = pipelineSettings.FailFastSettings.IsFailFast;
+ FailFast = serviceSettings.FailFastSettings.IsFailFast;
}
-
+
protected override AsyncStepRunner CreateRunner()
{
- var requestedRunnerCount = _pipelineSettings.ParallelVerifiers;
+ var requestedRunnerCount = _serviceSettings.ParallelVerifiers;
return requestedRunnerCount switch
{
< 0 or > 64 => throw new InvalidOperationException(
@@ -70,12 +74,14 @@ protected override AsyncStepRunner CreateRunner()
protected override async Task PrepareCoreAsync(CancellationToken token)
{
_verifiers.Clear();
+ _errors.Clear();
IStarWarsGameEngine gameEngine;
try
{
- gameEngine = await _gameEngineService.InitializeAsync(
+ var engineService = ServiceProvider.GetRequiredService();
+ gameEngine = await engineService.InitializeAsync(
_verificationTarget.Engine,
_verificationTarget.Location,
_engineErrorReporter,
@@ -85,38 +91,43 @@ protected override async Task PrepareCoreAsync(CancellationToken token)
}
catch (Exception e)
{
- _logger?.LogError(e, "Creating game engine failed: {Message}", e.Message);
+ Logger?.LogError(e, "Creating game engine failed: {Message}", e.Message);
throw;
}
- AddStep(new GameEngineErrorCollector(_engineErrorReporter, gameEngine, _pipelineSettings.GameVerifySettings, ServiceProvider));
+ AddStep(new GameEngineErrorCollector(_engineErrorReporter, gameEngine, _serviceSettings.GameVerifySettings, ServiceProvider));
- foreach (var gameVerificationStep in CreateVerificationSteps(gameEngine))
+ foreach (var gameVerificationStep in CreateVerifiers(gameEngine))
AddStep(gameVerificationStep);
}
protected override void OnExecuteStarted()
{
Logger?.LogInformation("Running game verifiers...");
- _aggregatedVerifyProgressReporter = new AggregatedVerifyProgressReporter(_progressReporter, _verificationSteps);
- _progressReporter.Report(0.0, $"Verifying {_verificationTarget.Name}...", VerifyProgress.ProgressType, default);
+ if (_progressReporter is not null)
+ {
+ _aggregatedVerifyProgressReporter = new AggregatedVerifyProgressReporter(_progressReporter, _verificationSteps);
+ _progressReporter.Report(0.0, $"Verifying {_verificationTarget.Name}...",
+ VerifyProgress.ProgressType, default);
+ }
}
protected override void OnExecuteCompleted()
{
Logger?.LogInformation("Game verifiers finished.");
- FilteredErrors = GetReportableErrors(_verifiers.SelectMany(s => s.VerifyErrors)).ToList();
- _progressReporter.Report(1.0, $"Finished Verifying {_verificationTarget.Name}", VerifyProgress.ProgressType, default);
+ _errors.AddRange(GetReportableErrors(_verifiers.SelectMany(s => s.VerifyErrors)));
+ _progressReporter?.Report(1.0, $"Finished Verifying {_verificationTarget.Name}",
+ VerifyProgress.ProgressType, default);
}
protected override void OnRunnerExecutionError(object sender, StepRunnerErrorEventArgs e)
{
if (FailFast && e.Exception is GameVerificationException verificationException)
{
- var minSeverity = _pipelineSettings.FailFastSettings.MinumumSeverity;
+ var minSeverity = _serviceSettings.FailFastSettings.MinumumSeverity;
var ignoreError = verificationException.Errors
.Where(error => error.Severity >= minSeverity)
- .All(error => Baseline.Contains(error) || Suppressions.Suppresses(error));
+ .All(error => _baseline.Contains(error) || _suppressions.Suppresses(error));
if (ignoreError)
return;
}
@@ -128,6 +139,14 @@ protected override IEnumerable GetFailedSteps(IEnumerable steps)
return base.GetFailedSteps(steps).Where(s => s.Error is not GameVerificationException);
}
+ protected override void DisposeResources()
+ {
+ base.DisposeResources();
+ _engineErrorReporter.Clear();
+ _aggregatedVerifyProgressReporter?.Dispose();
+ _aggregatedVerifyProgressReporter = null;
+ }
+
private void AddStep(GameVerifier verifier)
{
var verificationStep = new GameVerifierPipelineStep(verifier, ServiceProvider);
@@ -141,18 +160,13 @@ private IEnumerable GetReportableErrors(IEnumerable CreateVerificationSteps(IStarWarsGameEngine engine)
- {
- return _pipelineSettings.VerifiersProvider
- .GetVerifiers(engine, _pipelineSettings.GameVerifySettings, ServiceProvider);
+ return errors.ApplyBaseline(_baseline).ApplySuppressions(_suppressions);
}
- protected override void DisposeResources()
+ private IEnumerable CreateVerifiers(IStarWarsGameEngine engine)
{
- base.DisposeResources();
- _aggregatedVerifyProgressReporter?.Dispose();
+ return _serviceSettings.VerifiersProvider
+ .GetVerifiers(engine, _serviceSettings.GameVerifySettings, ServiceProvider)
+ .Distinct(NameBasedEqualityComparer.Instance);
}
}
\ No newline at end of file
diff --git a/src/ModVerify/IGameVerifierService.cs b/src/ModVerify/IGameVerifierService.cs
new file mode 100644
index 0000000..c814779
--- /dev/null
+++ b/src/ModVerify/IGameVerifierService.cs
@@ -0,0 +1,22 @@
+using System.Threading;
+using System.Threading.Tasks;
+using AET.ModVerify.Progress;
+using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
+using AET.ModVerify.Reporting.Suppressions;
+using AET.ModVerify.Settings;
+using PG.StarWarsGame.Engine;
+
+namespace AET.ModVerify;
+
+public interface IGameVerifierService
+{
+ Task VerifyAsync(
+ VerificationTarget verificationTarget,
+ VerifierServiceSettings settings,
+ VerificationBaseline baseline,
+ SuppressionList suppressions,
+ IVerifyProgressReporter? progressReporter,
+ IGameEngineInitializationReporter? engineInitializationReporter,
+ CancellationToken token = default);
+}
\ No newline at end of file
diff --git a/src/ModVerify/Pipeline/IGameVerifiersProvider.cs b/src/ModVerify/IGameVerifiersProvider.cs
similarity index 91%
rename from src/ModVerify/Pipeline/IGameVerifiersProvider.cs
rename to src/ModVerify/IGameVerifiersProvider.cs
index 930afa6..8cde9dc 100644
--- a/src/ModVerify/Pipeline/IGameVerifiersProvider.cs
+++ b/src/ModVerify/IGameVerifiersProvider.cs
@@ -4,7 +4,7 @@
using AET.ModVerify.Verifiers;
using PG.StarWarsGame.Engine;
-namespace AET.ModVerify.Pipeline;
+namespace AET.ModVerify;
public interface IGameVerifiersProvider
{
diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj
index f1415bc..aecf306 100644
--- a/src/ModVerify/ModVerify.csproj
+++ b/src/ModVerify/ModVerify.csproj
@@ -10,33 +10,25 @@
ModVerify Core
AET.ModVerify
- Provides interfaces and classes to verify Empire at War / Forces of Corruption game modifications.
+ A library that contains classes and methods to verify Empire at War / Forces of Corruption game modifications.
alamo,petroglyph,glyphx
true
true
-
-
-
true
snupkg
-
-
-
-
-
-
+
@@ -50,9 +42,4 @@
-
-
-
-
-
diff --git a/src/ModVerify/ModVerify.csproj.DotSettings b/src/ModVerify/ModVerify.csproj.DotSettings
index fcd6f14..3859842 100644
--- a/src/ModVerify/ModVerify.csproj.DotSettings
+++ b/src/ModVerify/ModVerify.csproj.DotSettings
@@ -1,4 +1,9 @@
+ True
+ True
+ True
+ True
+ False
True
True
True
\ No newline at end of file
diff --git a/src/ModVerify/ModVerifyServiceExtensions.cs b/src/ModVerify/ModVerifyServiceExtensions.cs
index 8b46960..41fbeaa 100644
--- a/src/ModVerify/ModVerifyServiceExtensions.cs
+++ b/src/ModVerify/ModVerifyServiceExtensions.cs
@@ -5,8 +5,16 @@ namespace AET.ModVerify;
public static class ModVerifyServiceExtensions
{
- public static IServiceCollection RegisterVerifierCache(this IServiceCollection serviceCollection)
+ extension(IServiceCollection serviceCollection)
{
- return serviceCollection.AddSingleton(sp => new AlreadyVerifiedCache(sp));
+ public IServiceCollection AddModVerify()
+ {
+ return serviceCollection.AddSingleton(sp => new GameVerifierService(sp));
+ }
+
+ public IServiceCollection RegisterVerifierCache()
+ {
+ return serviceCollection.AddSingleton(sp => new AlreadyVerifiedCache(sp));
+ }
}
}
\ No newline at end of file
diff --git a/src/ModVerify/Pipeline/Progress/AggregatedVerifyProgressReporter.cs b/src/ModVerify/Progress/AggregatedVerifyProgressReporter.cs
similarity index 95%
rename from src/ModVerify/Pipeline/Progress/AggregatedVerifyProgressReporter.cs
rename to src/ModVerify/Progress/AggregatedVerifyProgressReporter.cs
index cfdae25..1dbf538 100644
--- a/src/ModVerify/Pipeline/Progress/AggregatedVerifyProgressReporter.cs
+++ b/src/ModVerify/Progress/AggregatedVerifyProgressReporter.cs
@@ -1,8 +1,8 @@
-using AnakinRaW.CommonUtilities.SimplePipeline.Progress;
-using System;
+using System;
using System.Collections.Generic;
+using AnakinRaW.CommonUtilities.SimplePipeline.Progress;
-namespace AET.ModVerify.Pipeline.Progress;
+namespace AET.ModVerify.Progress;
internal class AggregatedVerifyProgressReporter(
IVerifyProgressReporter progressReporter,
diff --git a/src/ModVerify/Pipeline/Progress/IVerifyProgressReporter.cs b/src/ModVerify/Progress/IVerifyProgressReporter.cs
similarity index 76%
rename from src/ModVerify/Pipeline/Progress/IVerifyProgressReporter.cs
rename to src/ModVerify/Progress/IVerifyProgressReporter.cs
index e63e0f9..99c2141 100644
--- a/src/ModVerify/Pipeline/Progress/IVerifyProgressReporter.cs
+++ b/src/ModVerify/Progress/IVerifyProgressReporter.cs
@@ -1,5 +1,5 @@
using AnakinRaW.CommonUtilities.SimplePipeline.Progress;
-namespace AET.ModVerify.Pipeline.Progress;
+namespace AET.ModVerify.Progress;
public interface IVerifyProgressReporter : IProgressReporter;
\ No newline at end of file
diff --git a/src/ModVerify/Pipeline/Progress/VerifyProgress.cs b/src/ModVerify/Progress/VerifyProgress.cs
similarity index 84%
rename from src/ModVerify/Pipeline/Progress/VerifyProgress.cs
rename to src/ModVerify/Progress/VerifyProgress.cs
index a18f3d3..aa5f2f2 100644
--- a/src/ModVerify/Pipeline/Progress/VerifyProgress.cs
+++ b/src/ModVerify/Progress/VerifyProgress.cs
@@ -1,6 +1,6 @@
using AnakinRaW.CommonUtilities.SimplePipeline.Progress;
-namespace AET.ModVerify.Pipeline.Progress;
+namespace AET.ModVerify.Progress;
public static class VerifyProgress
{
diff --git a/src/ModVerify/Pipeline/Progress/VerifyProgressInfo.cs b/src/ModVerify/Progress/VerifyProgressInfo.cs
similarity index 74%
rename from src/ModVerify/Pipeline/Progress/VerifyProgressInfo.cs
rename to src/ModVerify/Progress/VerifyProgressInfo.cs
index cadeb0d..b7c8b3d 100644
--- a/src/ModVerify/Pipeline/Progress/VerifyProgressInfo.cs
+++ b/src/ModVerify/Progress/VerifyProgressInfo.cs
@@ -1,4 +1,4 @@
-namespace AET.ModVerify.Pipeline.Progress;
+namespace AET.ModVerify.Progress;
public struct VerifyProgressInfo
{
diff --git a/src/ModVerify/Reporting/Baseline/BaselineVerificationTarget.cs b/src/ModVerify/Reporting/Baseline/BaselineVerificationTarget.cs
new file mode 100644
index 0000000..ca77fa8
--- /dev/null
+++ b/src/ModVerify/Reporting/Baseline/BaselineVerificationTarget.cs
@@ -0,0 +1,12 @@
+using PG.StarWarsGame.Engine;
+
+namespace AET.ModVerify.Reporting.Baseline;
+
+public sealed record BaselineVerificationTarget
+{
+ public required GameEngineType Engine { get; init; }
+ public required string Name { get; init; }
+ public GameLocations? Location { get; init; } // Optional compared to Verification Target
+ public string? Version { get; init; }
+ public bool IsGame { get; init; }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Baseline/InvalidBaselineException.cs b/src/ModVerify/Reporting/Baseline/InvalidBaselineException.cs
new file mode 100644
index 0000000..58e180e
--- /dev/null
+++ b/src/ModVerify/Reporting/Baseline/InvalidBaselineException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace AET.ModVerify.Reporting.Baseline;
+
+public sealed class InvalidBaselineException : Exception
+{
+ internal InvalidBaselineException(string message) : base(message)
+ {
+ }
+
+ internal InvalidBaselineException(string? message, Exception? inner) : base(message, inner)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonBaselineParser.cs b/src/ModVerify/Reporting/Baseline/Json/JsonBaselineParser.cs
similarity index 95%
rename from src/ModVerify/Reporting/Json/JsonBaselineParser.cs
rename to src/ModVerify/Reporting/Baseline/Json/JsonBaselineParser.cs
index 669ef53..a8ba53c 100644
--- a/src/ModVerify/Reporting/Json/JsonBaselineParser.cs
+++ b/src/ModVerify/Reporting/Baseline/Json/JsonBaselineParser.cs
@@ -2,7 +2,7 @@
using System.IO;
using System.Text.Json;
-namespace AET.ModVerify.Reporting.Json;
+namespace AET.ModVerify.Reporting.Baseline.Json;
internal static class JsonBaselineParser
{
diff --git a/src/ModVerify/Reporting/Json/JsonBaselineSchema.cs b/src/ModVerify/Reporting/Baseline/Json/JsonBaselineSchema.cs
similarity index 97%
rename from src/ModVerify/Reporting/Json/JsonBaselineSchema.cs
rename to src/ModVerify/Reporting/Baseline/Json/JsonBaselineSchema.cs
index 12e3705..cf4513a 100644
--- a/src/ModVerify/Reporting/Json/JsonBaselineSchema.cs
+++ b/src/ModVerify/Reporting/Baseline/Json/JsonBaselineSchema.cs
@@ -7,9 +7,9 @@
using Json.Schema;
using Json.Schema.Keywords;
-namespace AET.ModVerify.Reporting.Json;
+namespace AET.ModVerify.Reporting.Baseline.Json;
-public static class JsonBaselineSchema
+internal static class JsonBaselineSchema
{
private static readonly JsonSchema Schema;
private static readonly EvaluationOptions EvaluationOptions;
diff --git a/src/ModVerify/Reporting/Json/JsonVerificationBaseline.cs b/src/ModVerify/Reporting/Baseline/Json/JsonVerificationBaseline.cs
similarity index 92%
rename from src/ModVerify/Reporting/Json/JsonVerificationBaseline.cs
rename to src/ModVerify/Reporting/Baseline/Json/JsonVerificationBaseline.cs
index 0d9a1b7..3e25aed 100644
--- a/src/ModVerify/Reporting/Json/JsonVerificationBaseline.cs
+++ b/src/ModVerify/Reporting/Baseline/Json/JsonVerificationBaseline.cs
@@ -1,9 +1,10 @@
-using System;
+using AET.ModVerify.Reporting.Json;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
-namespace AET.ModVerify.Reporting.Json;
+namespace AET.ModVerify.Reporting.Baseline.Json;
internal class JsonVerificationBaseline
{
diff --git a/src/ModVerify/Reporting/VerificationBaseline.cs b/src/ModVerify/Reporting/Baseline/VerificationBaseline.cs
similarity index 96%
rename from src/ModVerify/Reporting/VerificationBaseline.cs
rename to src/ModVerify/Reporting/Baseline/VerificationBaseline.cs
index 3f9c274..d734e6e 100644
--- a/src/ModVerify/Reporting/VerificationBaseline.cs
+++ b/src/ModVerify/Reporting/Baseline/VerificationBaseline.cs
@@ -6,9 +6,10 @@
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
+using AET.ModVerify.Reporting.Baseline.Json;
using AET.ModVerify.Reporting.Json;
-namespace AET.ModVerify.Reporting;
+namespace AET.ModVerify.Reporting.Baseline;
public sealed class VerificationBaseline : IReadOnlyCollection
{
diff --git a/src/ModVerify/Reporting/BaselineVerificationTarget.cs b/src/ModVerify/Reporting/BaselineVerificationTarget.cs
deleted file mode 100644
index 6e21ddd..0000000
--- a/src/ModVerify/Reporting/BaselineVerificationTarget.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Text;
-using PG.StarWarsGame.Engine;
-
-namespace AET.ModVerify.Reporting;
-
-public sealed class BaselineVerificationTarget
-{
- public required GameEngineType Engine { get; init; }
- public required string Name { get; init; }
- public GameLocations? Location { get; init; } // Optional compared to Verification Target
- public string? Version { get; init; }
- public bool IsGame { get; init; }
-
- public override string ToString()
- {
- var sb = new StringBuilder($"[Name={Name};EngineType={Engine};IsGame={IsGame};");
- if (!string.IsNullOrEmpty(Version)) sb.Append($"Version={Version};");
- if (Location is not null)
- sb.Append($"Location={Location};");
- sb.Append(']');
- return sb.ToString();
- }
-}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/Engine/EngineErrorReporterBase.cs b/src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs
similarity index 83%
rename from src/ModVerify/Reporting/Reporters/Engine/EngineErrorReporterBase.cs
rename to src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs
index 455212d..7200f23 100644
--- a/src/ModVerify/Reporting/Reporters/Engine/EngineErrorReporterBase.cs
+++ b/src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs
@@ -1,16 +1,22 @@
using System;
using System.Collections.Generic;
+using AET.ModVerify.Verifiers;
using AnakinRaW.CommonUtilities;
using PG.StarWarsGame.Engine.IO;
-namespace AET.ModVerify.Reporting.Reporters.Engine;
+namespace AET.ModVerify.Reporting.Engine;
-internal abstract class EngineErrorReporterBase(IGameRepository gameRepository, IServiceProvider serviceProvider)
+internal abstract class EngineErrorReporterBase(IGameRepository gameRepository, IServiceProvider serviceProvider)
+ : IGameVerifierInfo
{
protected readonly IGameRepository GameRepository = gameRepository ?? throw new ArgumentNullException(nameof(gameRepository));
protected readonly IServiceProvider ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
- public abstract string Name { get; }
+ public IGameVerifierInfo? Parent => null;
+
+ public string Name => GetType().FullName;
+
+ public abstract string FriendlyName { get; }
public IEnumerable GetErrors(IEnumerable errors)
{
@@ -18,7 +24,7 @@ public IEnumerable GetErrors(IEnumerable errors)
{
var errorData = CreateError(error);
yield return new VerificationError(
- errorData.Identifier, errorData.Message, [Name], errorData.Context, errorData.Asset, errorData.Severity);
+ errorData.Identifier, errorData.Message, [this], errorData.Context, errorData.Asset, errorData.Severity);
}
}
diff --git a/src/ModVerify/Reporting/Reporters/Engine/GameAssertErrorReporter.cs b/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs
similarity index 93%
rename from src/ModVerify/Reporting/Reporters/Engine/GameAssertErrorReporter.cs
rename to src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs
index 6c5fb17..f75334c 100644
--- a/src/ModVerify/Reporting/Reporters/Engine/GameAssertErrorReporter.cs
+++ b/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs
@@ -5,12 +5,12 @@
using PG.StarWarsGame.Engine.ErrorReporting;
using PG.StarWarsGame.Engine.IO;
-namespace AET.ModVerify.Reporting.Reporters.Engine;
+namespace AET.ModVerify.Reporting.Engine;
internal sealed class GameAssertErrorReporter(IGameRepository gameRepository, IServiceProvider serviceProvider)
: EngineErrorReporterBase(gameRepository, serviceProvider)
{
- public override string Name => "GameAsserts";
+ public override string FriendlyName => "Game Engine Asserts";
protected override ErrorData CreateError(EngineAssert assert)
{
diff --git a/src/ModVerify/Reporting/ConcurrentGameEngineErrorReporter.cs b/src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs
similarity index 50%
rename from src/ModVerify/Reporting/ConcurrentGameEngineErrorReporter.cs
rename to src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs
index 3130547..ba0abf5 100644
--- a/src/ModVerify/Reporting/ConcurrentGameEngineErrorReporter.cs
+++ b/src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs
@@ -3,9 +3,9 @@
using System.Linq;
using PG.StarWarsGame.Engine.ErrorReporting;
-namespace AET.ModVerify.Reporting;
+namespace AET.ModVerify.Reporting.Engine;
-public sealed class ConcurrentGameEngineErrorReporter : GameEngineErrorReporter, IGameEngineErrorCollection
+public sealed class GameEngineErrorCollection : IGameEngineErrorCollection, IGameEngineErrorReporter
{
private readonly ConcurrentBag _xmlErrors = new();
private readonly ConcurrentBag _initializationErrors = new();
@@ -17,18 +17,36 @@ public sealed class ConcurrentGameEngineErrorReporter : GameEngineErrorReporter,
public IEnumerable Asserts => _asserts.ToList();
- public override void Report(XmlError error)
+ void IGameEngineErrorReporter.Report(XmlError error)
{
_xmlErrors.Add(error);
}
- public override void Report(InitializationError error)
+ void IGameEngineErrorReporter.Report(InitializationError error)
{
_initializationErrors.Add(error);
}
- public override void Assert(EngineAssert assert)
+ void IGameEngineErrorReporter.Assert(EngineAssert assert)
{
_asserts.Add(assert);
}
+
+ internal void Clear()
+ {
+#if !NETFRAMEWORK && !NETSTANDARD2_0
+ _xmlErrors.Clear();
+ _initializationErrors.Clear();
+ _asserts.Clear();
+#else
+ ClearUnsafe(_xmlErrors);
+ ClearUnsafe(_initializationErrors);
+ ClearUnsafe(_asserts);
+
+ static void ClearUnsafe(ConcurrentBag bag)
+ {
+ while (bag.TryTake(out _)) ;
+ }
+#endif
+ }
}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/IGameEngineErrorCollection.cs b/src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs
similarity index 87%
rename from src/ModVerify/Reporting/IGameEngineErrorCollection.cs
rename to src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs
index 14d59d9..adf734d 100644
--- a/src/ModVerify/Reporting/IGameEngineErrorCollection.cs
+++ b/src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using PG.StarWarsGame.Engine.ErrorReporting;
-namespace AET.ModVerify.Reporting;
+namespace AET.ModVerify.Reporting.Engine;
public interface IGameEngineErrorCollection
{
diff --git a/src/ModVerify/Reporting/Reporters/Engine/InitializationErrorReporter.cs b/src/ModVerify/Reporting/Engine/InitializationErrorReporter.cs
similarity index 84%
rename from src/ModVerify/Reporting/Reporters/Engine/InitializationErrorReporter.cs
rename to src/ModVerify/Reporting/Engine/InitializationErrorReporter.cs
index fc44c66..e46db1a 100644
--- a/src/ModVerify/Reporting/Reporters/Engine/InitializationErrorReporter.cs
+++ b/src/ModVerify/Reporting/Engine/InitializationErrorReporter.cs
@@ -3,12 +3,12 @@
using PG.StarWarsGame.Engine.ErrorReporting;
using PG.StarWarsGame.Engine.IO;
-namespace AET.ModVerify.Reporting.Reporters.Engine;
+namespace AET.ModVerify.Reporting.Engine;
internal sealed class InitializationErrorReporter(IGameRepository gameRepository, IServiceProvider serviceProvider)
: EngineErrorReporterBase(gameRepository, serviceProvider)
{
- public override string Name => "InitializationErrors";
+ public override string FriendlyName => "Initialization Errors";
protected override ErrorData CreateError(InitializationError error)
{
diff --git a/src/ModVerify/Reporting/Reporters/Engine/XmlParseErrorReporter.cs b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs
similarity index 97%
rename from src/ModVerify/Reporting/Reporters/Engine/XmlParseErrorReporter.cs
rename to src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs
index 094a701..2629f26 100644
--- a/src/ModVerify/Reporting/Reporters/Engine/XmlParseErrorReporter.cs
+++ b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs
@@ -8,14 +8,14 @@
using PG.StarWarsGame.Engine.IO;
using PG.StarWarsGame.Files.XML.ErrorHandling;
-namespace AET.ModVerify.Reporting.Reporters.Engine;
+namespace AET.ModVerify.Reporting.Engine;
internal sealed class XmlParseErrorReporter(IGameRepository gameRepository, IServiceProvider serviceProvider) :
EngineErrorReporterBase(gameRepository, serviceProvider)
{
private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService();
- public override string Name => "XMLError";
+ public override string FriendlyName => "XML Errors";
protected override ErrorData CreateError(XmlError error)
{
diff --git a/src/ModVerify/Reporting/IVerificationReporter.cs b/src/ModVerify/Reporting/IVerificationReporter.cs
deleted file mode 100644
index 8b8664e..0000000
--- a/src/ModVerify/Reporting/IVerificationReporter.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System.Collections.Generic;
-using System.Threading.Tasks;
-
-namespace AET.ModVerify.Reporting;
-
-public interface IVerificationReporter
-{
- public Task ReportAsync(IReadOnlyCollection errors);
-}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/InvalidBaselineException.cs b/src/ModVerify/Reporting/InvalidBaselineException.cs
deleted file mode 100644
index 37ab9c8..0000000
--- a/src/ModVerify/Reporting/InvalidBaselineException.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace AET.ModVerify.Reporting;
-
-public sealed class InvalidBaselineException : Exception
-{
- public InvalidBaselineException(string message) : base(message)
- {
- }
-
- public InvalidBaselineException(string? message, Exception? inner) : base(message, inner)
- {
- }
-}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs b/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs
new file mode 100644
index 0000000..5a9cbb3
--- /dev/null
+++ b/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace AET.ModVerify.Reporting.Json;
+
+internal class JsonAggregatedVerificationError : JsonVerificationErrorBase
+{
+ [JsonPropertyName("contexts")]
+ [JsonPropertyOrder(99)]
+ public IEnumerable> Contexts { get; }
+
+ [JsonConstructor]
+ public JsonAggregatedVerificationError(
+ string id,
+ IReadOnlyList? verifierChain,
+ string message,
+ VerificationSeverity severity,
+ IEnumerable>? contexts,
+ string? asset) : base(id, verifierChain, message, severity, asset)
+ {
+ Contexts = contexts ?? [];
+ }
+
+ public JsonAggregatedVerificationError(
+ VerificationError error,
+ IEnumerable> contexts) : base(error)
+ {
+ Contexts = contexts;
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonVerificationError.cs b/src/ModVerify/Reporting/Json/JsonVerificationError.cs
index 55f7b92..0e23283 100644
--- a/src/ModVerify/Reporting/Json/JsonVerificationError.cs
+++ b/src/ModVerify/Reporting/Json/JsonVerificationError.cs
@@ -1,53 +1,29 @@
using System.Collections.Generic;
+using System.Linq;
using System.Text.Json.Serialization;
namespace AET.ModVerify.Reporting.Json;
-internal class JsonVerificationError
+internal class JsonVerificationError : JsonVerificationErrorBase
{
- [JsonPropertyName("id")]
- public string Id { get; }
-
- [JsonPropertyName("verifiers")]
- public IReadOnlyList VerifierChain { get; }
-
- [JsonPropertyName("message")]
- public string Message { get; }
-
- [JsonPropertyName("severity")]
- [JsonConverter(typeof(JsonStringEnumConverter))]
- public VerificationSeverity Severity { get; }
-
[JsonPropertyName("context")]
- public IEnumerable ContextEntries { get; }
-
- [JsonPropertyName("asset")]
- public string Asset { get; }
+ [JsonPropertyOrder(99)]
+ public IEnumerable? ContextEntries { get; }
[JsonConstructor]
- private JsonVerificationError(
+ public JsonVerificationError(
string id,
IReadOnlyList? verifierChain,
string message,
VerificationSeverity severity,
IEnumerable? contextEntries,
- string? asset)
+ string? asset) : base(id, verifierChain, message, severity, asset)
{
- Id = id;
- VerifierChain = verifierChain ?? [];
- Message = message;
- Severity = severity;
- ContextEntries = contextEntries ?? [];
- Asset = asset ?? string.Empty;
+ ContextEntries = contextEntries;
}
- public JsonVerificationError(VerificationError error)
+ public JsonVerificationError(VerificationError error) : base(error)
{
- Id = error.Id;
- VerifierChain = error.VerifierChain;
- Message = error.Message;
- Severity = error.Severity;
- ContextEntries = error.ContextEntries;
- Asset = error.Asset;
+ ContextEntries = error.ContextEntries.Any() ? error.ContextEntries : null;
}
}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs b/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs
new file mode 100644
index 0000000..06af012
--- /dev/null
+++ b/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json.Serialization;
+
+namespace AET.ModVerify.Reporting.Json;
+
+[JsonDerivedType(typeof(JsonVerificationError))]
+[JsonDerivedType(typeof(JsonAggregatedVerificationError))]
+internal abstract class JsonVerificationErrorBase
+{
+ [JsonPropertyName("id")]
+ public string Id { get; }
+
+ [JsonPropertyName("verifiers")]
+ public IReadOnlyList VerifierChain { get; }
+
+ [JsonPropertyName("message")]
+ public string Message { get; }
+
+ [JsonPropertyName("severity")]
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public VerificationSeverity Severity { get; }
+
+ [JsonPropertyName("asset")]
+ public string Asset { get; }
+
+ protected JsonVerificationErrorBase(
+ string id,
+ IReadOnlyList? verifierChain,
+ string message,
+ VerificationSeverity severity,
+ string? asset)
+ {
+ Id = id;
+ VerifierChain = verifierChain ?? [];
+ Message = message;
+ Severity = severity;
+ Asset = asset ?? string.Empty;
+ }
+
+ protected JsonVerificationErrorBase(VerificationError error)
+ {
+ Id = error.Id;
+ VerifierChain = error.VerifierChain.Select(x => x.Name).ToList();
+ Message = error.Message;
+ Severity = error.Severity;
+ Asset = error.Asset;
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonVerificationReport.cs b/src/ModVerify/Reporting/Json/JsonVerificationReport.cs
index 6ebb926..d10d18f 100644
--- a/src/ModVerify/Reporting/Json/JsonVerificationReport.cs
+++ b/src/ModVerify/Reporting/Json/JsonVerificationReport.cs
@@ -3,8 +3,11 @@
namespace AET.ModVerify.Reporting.Json;
-internal class JsonVerificationReport(IEnumerable errors)
+internal class JsonVerificationReport
{
+ [JsonPropertyName("metadata")]
+ public required JsonVerificationReportMetadata Metadata { get; init; }
+
[JsonPropertyName("errors")]
- public IEnumerable Errors { get; } = errors;
+ public required IEnumerable Errors { get; init; }
}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonVerificationReportMetadata.cs b/src/ModVerify/Reporting/Json/JsonVerificationReportMetadata.cs
new file mode 100644
index 0000000..7e3b90e
--- /dev/null
+++ b/src/ModVerify/Reporting/Json/JsonVerificationReportMetadata.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace AET.ModVerify.Reporting.Json;
+
+internal class JsonVerificationReportMetadata
+{
+ [JsonPropertyName("status")]
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public VerificationCompletionStatus Status { get; init; }
+
+ [JsonPropertyName("target")]
+ public JsonVerificationTarget Target { get; init; }
+
+ [JsonPropertyName("time")]
+ public string Date { get; } = DateTime.Now.ToString("s");
+
+ [JsonPropertyName("duration")]
+ public string Duration { get; init; }
+
+ [JsonPropertyName("verifiers")]
+ public IReadOnlyCollection Verifiers { get; init; }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonVerificationTarget.cs b/src/ModVerify/Reporting/Json/JsonVerificationTarget.cs
index 9495456..fe7e33d 100644
--- a/src/ModVerify/Reporting/Json/JsonVerificationTarget.cs
+++ b/src/ModVerify/Reporting/Json/JsonVerificationTarget.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
+using AET.ModVerify.Reporting.Baseline;
using PG.StarWarsGame.Engine;
namespace AET.ModVerify.Reporting.Json;
@@ -38,6 +39,15 @@ private JsonVerificationTarget(
IsGame = isGame;
}
+ public JsonVerificationTarget(VerificationTarget target)
+ {
+ Name = target.Name;
+ Version = target.Version;
+ Engine = target.Engine;
+ Location = new JsonGameLocation(target.Location);
+ IsGame = target.IsGame;
+ }
+
public JsonVerificationTarget(BaselineVerificationTarget target)
{
Name = target.Name;
diff --git a/src/ModVerify/Reporting/Reporters/ConsoleReporter.cs b/src/ModVerify/Reporting/Reporters/Console/ConsoleReporter.cs
similarity index 62%
rename from src/ModVerify/Reporting/Reporters/ConsoleReporter.cs
rename to src/ModVerify/Reporting/Reporters/Console/ConsoleReporter.cs
index dbee50d..5266550 100644
--- a/src/ModVerify/Reporting/Reporters/ConsoleReporter.cs
+++ b/src/ModVerify/Reporting/Reporters/Console/ConsoleReporter.cs
@@ -2,25 +2,21 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using AET.ModVerify.Reporting.Settings;
namespace AET.ModVerify.Reporting.Reporters;
-internal class ConsoleReporter(
- ReporterSettings settings,
- bool summaryOnly,
- IServiceProvider serviceProvider) :
- ReporterBase(settings, serviceProvider)
+internal class ConsoleReporter(ConsoleReporterSettings settings, IServiceProvider serviceProvider) :
+ ReporterBase(settings, serviceProvider)
{
- public override Task ReportAsync(IReadOnlyCollection errors)
+ public override Task ReportAsync(VerificationResult verificationResult)
{
- var filteredErrors = FilteredErrors(errors).OrderByDescending(x => x.Severity).ToList();
- PrintErrorStats(errors, filteredErrors);
+ var filteredErrors = FilteredErrors(verificationResult.Errors).OrderByDescending(x => x.Severity).ToList();
+ PrintErrorStats(verificationResult, filteredErrors);
Console.WriteLine();
return Task.CompletedTask;
}
- private void PrintErrorStats(IReadOnlyCollection errors, List filteredErrors)
+ private void PrintErrorStats(VerificationResult verificationResult, List filteredErrors)
{
Console.WriteLine();
Console.WriteLine();
@@ -28,9 +24,9 @@ private void PrintErrorStats(IReadOnlyCollection errors, List
Console.WriteLine(" Error Report ");
Console.WriteLine("***********************");
Console.WriteLine();
- if (errors.Count == 0)
+ if (verificationResult.Errors.Count == 0)
{
- if (summaryOnly)
+ if (Settings.SummaryOnly)
{
Console.WriteLine("No errors found.");
}
@@ -44,21 +40,21 @@ private void PrintErrorStats(IReadOnlyCollection errors, List
return;
}
- Console.WriteLine($"TOTAL Verification Errors: {errors.Count}");
+ Console.WriteLine($"TOTAL Verification Errors: {verificationResult.Errors.Count}");
- var groupedBySeverity = errors.GroupBy(x => x.Severity);
+ var groupedBySeverity = verificationResult.Errors.GroupBy(x => x.Severity);
foreach (var group in groupedBySeverity)
Console.WriteLine($" Severity {group.Key}: {group.Count()}");
Console.WriteLine();
if (filteredErrors.Count == 0)
{
- if (errors.Count != 0)
+ if (verificationResult.Errors.Count != 0)
Console.WriteLine("Some errors are not displayed to the console. Please check the created output files.");
return;
}
- if (summaryOnly)
+ if (Settings.SummaryOnly)
return;
Console.WriteLine($"Below the list of errors with severity '{Settings.MinimumReportSeverity}' or higher:");
diff --git a/src/ModVerify/Reporting/Reporters/Console/ConsoleReporterSettings.cs b/src/ModVerify/Reporting/Reporters/Console/ConsoleReporterSettings.cs
new file mode 100644
index 0000000..4dc2a77
--- /dev/null
+++ b/src/ModVerify/Reporting/Reporters/Console/ConsoleReporterSettings.cs
@@ -0,0 +1,6 @@
+namespace AET.ModVerify.Reporting.Reporters;
+
+public sealed record ConsoleReporterSettings : ReporterSettings
+{
+ public bool SummaryOnly { get; init; }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/ExtensionMethods.cs b/src/ModVerify/Reporting/Reporters/ExtensionMethods.cs
new file mode 100644
index 0000000..480e956
--- /dev/null
+++ b/src/ModVerify/Reporting/Reporters/ExtensionMethods.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace AET.ModVerify.Reporting.Reporters;
+
+public static class ExtensionMethods
+{
+ extension(IVerificationReporter)
+ {
+ public static IVerificationReporter CreateJson(IServiceProvider serviceProvider)
+ {
+ return IVerificationReporter.CreateJson(new JsonReporterSettings(), serviceProvider);
+ }
+
+ public static IVerificationReporter CreateJson(JsonReporterSettings settings, IServiceProvider serviceProvider)
+ {
+ return new JsonReporter(settings, serviceProvider);
+ }
+
+ public static IVerificationReporter CreateText(IServiceProvider serviceProvider)
+ {
+ return IVerificationReporter.CreateText(new TextFileReporterSettings(), serviceProvider);
+ }
+
+ public static IVerificationReporter CreateText(TextFileReporterSettings settings, IServiceProvider serviceProvider)
+ {
+ return new TextFileReporter(settings, serviceProvider);
+ }
+
+ public static IVerificationReporter CreateConsole(IServiceProvider serviceProvider, bool summaryOnly = false)
+ {
+ var settings = new ConsoleReporterSettings
+ {
+ MinimumReportSeverity = VerificationSeverity.Error,
+ SummaryOnly = summaryOnly
+ };
+ return IVerificationReporter.CreateConsole(settings, serviceProvider);
+ }
+
+ public static IVerificationReporter CreateConsole(ConsoleReporterSettings settings, IServiceProvider serviceProvider)
+ {
+ return new ConsoleReporter(settings, serviceProvider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/FileBasedReporter.cs b/src/ModVerify/Reporting/Reporters/FileBasedReporter.cs
index 1057bfa..4c60121 100644
--- a/src/ModVerify/Reporting/Reporters/FileBasedReporter.cs
+++ b/src/ModVerify/Reporting/Reporters/FileBasedReporter.cs
@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.IO.Abstractions;
-using AET.ModVerify.Reporting.Settings;
using Microsoft.Extensions.DependencyInjection;
namespace AET.ModVerify.Reporting.Reporters;
diff --git a/src/ModVerify/Reporting/Settings/FileBasedReporterSettings.cs b/src/ModVerify/Reporting/Reporters/FileBasedReporterSettings.cs
similarity index 85%
rename from src/ModVerify/Reporting/Settings/FileBasedReporterSettings.cs
rename to src/ModVerify/Reporting/Reporters/FileBasedReporterSettings.cs
index 759a6ab..aa468fc 100644
--- a/src/ModVerify/Reporting/Settings/FileBasedReporterSettings.cs
+++ b/src/ModVerify/Reporting/Reporters/FileBasedReporterSettings.cs
@@ -1,6 +1,6 @@
using System;
-namespace AET.ModVerify.Reporting.Settings;
+namespace AET.ModVerify.Reporting.Reporters;
public record FileBasedReporterSettings : ReporterSettings
{
diff --git a/src/ModVerify/Reporting/Reporters/IVerificationReporter.cs b/src/ModVerify/Reporting/Reporters/IVerificationReporter.cs
new file mode 100644
index 0000000..5ce7a65
--- /dev/null
+++ b/src/ModVerify/Reporting/Reporters/IVerificationReporter.cs
@@ -0,0 +1,8 @@
+using System.Threading.Tasks;
+
+namespace AET.ModVerify.Reporting.Reporters;
+
+public interface IVerificationReporter
+{
+ public Task ReportAsync(VerificationResult verificationResult);
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs
index 348fbb1..1feb655 100644
--- a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs
+++ b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs
@@ -4,21 +4,88 @@
using System.Text.Json;
using System.Threading.Tasks;
using AET.ModVerify.Reporting.Json;
+using AET.ModVerify.Verifiers;
+using AnakinRaW.CommonUtilities.FileSystem.Validation;
-namespace AET.ModVerify.Reporting.Reporters.JSON;
+namespace AET.ModVerify.Reporting.Reporters;
internal class JsonReporter(JsonReporterSettings settings, IServiceProvider serviceProvider)
: FileBasedReporter(settings, serviceProvider)
{
- public const string FileName = "VerificationResult.json";
-
- public override async Task ReportAsync(IReadOnlyCollection errors)
+ public override async Task ReportAsync(VerificationResult verificationResult)
{
- var report = new JsonVerificationReport(errors.Select(x => new JsonVerificationError(x)));
+ var report = CreateJsonReport(verificationResult);
+ var fileName = CreateFileName(verificationResult);
+
#if NET || NETSTANDARD2_1
await
#endif
- using var fs = CreateFile(FileName);
+ using var fs = CreateFile(fileName);
await JsonSerializer.SerializeAsync(fs, report, ModVerifyJsonSettings.JsonSettings);
}
+
+ private JsonVerificationReport CreateJsonReport(VerificationResult result)
+ {
+ IEnumerable errors;
+ if (Settings.AggregateResults)
+ {
+ errors = result.Errors
+ .GroupBy(x => new GroupKey(x.Asset, x.Id, x.VerifierChain))
+ .Select, JsonVerificationErrorBase>(g =>
+ {
+ var first = g.First();
+ var contexts = g.Select(x => x.ContextEntries).ToList();
+
+ if (contexts.Count == 1)
+ return new JsonVerificationError(first);
+ return new JsonAggregatedVerificationError(first, contexts);
+ });
+ }
+ else
+ {
+ errors = result.Errors.Select(x => new JsonVerificationError(x));
+ }
+
+ return new JsonVerificationReport
+ {
+ Metadata = new JsonVerificationReportMetadata
+ {
+ Target = new JsonVerificationTarget(result.Target),
+ Duration = result.Duration.ToString("g"),
+ Status = result.Status,
+ Verifiers = result.Verifiers.Select(x => x.Name).ToList()
+ },
+ Errors = errors
+ };
+ }
+
+ private static string CreateFileName(VerificationResult result)
+ {
+ var fileName = $"VerificationResult_{result.Target.Name}.json";
+ if (CurrentSystemFileNameValidator.Instance.IsValidFileName(fileName) is FileNameValidationResult.Valid)
+ return fileName;
+ // I don't think there is a safe/secure way to re-encode the file name, if it's not valid using the plain target name.
+ // Thus, we simply use the current date and accept the fact that files may get overwritten for different targets.
+ return $"VerificationResult_{DateTime.Now:yyyy_mm_dd}.json";
+
+ }
+
+ private readonly record struct GroupKey(string Asset, string Id, IReadOnlyList VerifierChain)
+ {
+ public bool Equals(GroupKey other)
+ {
+ return Asset == other.Asset
+ && Id == other.Id
+ && VerifierChainEqualityComparer.Instance.Equals(VerifierChain, other.VerifierChain);
+ }
+
+ public override int GetHashCode()
+ {
+ var hashCode = new HashCode();
+ hashCode.Add(Asset);
+ hashCode.Add(Id);
+ hashCode.Add(VerifierChain, VerifierChainEqualityComparer.Instance);
+ return hashCode.ToHashCode();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs b/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs
index 4207b36..7ccbba9 100644
--- a/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs
+++ b/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs
@@ -1,5 +1,6 @@
-using AET.ModVerify.Reporting.Settings;
+namespace AET.ModVerify.Reporting.Reporters;
-namespace AET.ModVerify.Reporting.Reporters.JSON;
-
-public record JsonReporterSettings : FileBasedReporterSettings;
\ No newline at end of file
+public record JsonReporterSettings : FileBasedReporterSettings
+{
+ public bool AggregateResults { get; init; }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/ReporterBase.cs b/src/ModVerify/Reporting/Reporters/ReporterBase.cs
index df444e3..47cafc5 100644
--- a/src/ModVerify/Reporting/Reporters/ReporterBase.cs
+++ b/src/ModVerify/Reporting/Reporters/ReporterBase.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using AET.ModVerify.Reporting.Settings;
namespace AET.ModVerify.Reporting.Reporters;
@@ -12,7 +11,7 @@ public abstract class ReporterBase(T settings, IServiceProvider serviceProvid
protected T Settings { get; } = settings ?? throw new ArgumentNullException(nameof(settings));
- public abstract Task ReportAsync(IReadOnlyCollection errors);
+ public abstract Task ReportAsync(VerificationResult verificationResult);
protected IEnumerable FilteredErrors(IReadOnlyCollection errors)
{
diff --git a/src/ModVerify/Reporting/Settings/ReporterSettings.cs b/src/ModVerify/Reporting/Reporters/ReporterSettings.cs
similarity index 74%
rename from src/ModVerify/Reporting/Settings/ReporterSettings.cs
rename to src/ModVerify/Reporting/Reporters/ReporterSettings.cs
index ef33857..73332eb 100644
--- a/src/ModVerify/Reporting/Settings/ReporterSettings.cs
+++ b/src/ModVerify/Reporting/Reporters/ReporterSettings.cs
@@ -1,4 +1,4 @@
-namespace AET.ModVerify.Reporting.Settings;
+namespace AET.ModVerify.Reporting.Reporters;
public record ReporterSettings
{
diff --git a/src/ModVerify/Reporting/Reporters/Text/TextFileReporter.cs b/src/ModVerify/Reporting/Reporters/Text/TextFileReporter.cs
index cfc5c91..f3e8126 100644
--- a/src/ModVerify/Reporting/Reporters/Text/TextFileReporter.cs
+++ b/src/ModVerify/Reporting/Reporters/Text/TextFileReporter.cs
@@ -1,49 +1,56 @@
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text;
using System.Threading.Tasks;
-namespace AET.ModVerify.Reporting.Reporters.Text;
+namespace AET.ModVerify.Reporting.Reporters;
-internal class TextFileReporter(TextFileReporterSettings settings, IServiceProvider serviceProvider) : FileBasedReporter(settings, serviceProvider)
+internal sealed class TextFileReporter(TextFileReporterSettings settings, IServiceProvider serviceProvider)
+ : FileBasedReporter(settings, serviceProvider)
{
internal const string SingleReportFileName = "VerificationResult.txt";
- public override async Task ReportAsync(IReadOnlyCollection errors)
+ public override async Task ReportAsync(VerificationResult verificationResult)
{
if (Settings.SplitIntoFiles)
- await ReportByVerifier(errors);
+ await ReportByVerifier(verificationResult);
else
- await ReportWhole(errors);
+ await ReportWhole(verificationResult);
}
- private async Task ReportWhole(IReadOnlyCollection errors)
+ private async Task ReportWhole(VerificationResult result)
{
#if NET || NETSTANDARD2_1
await
#endif
using var streamWriter = new StreamWriter(CreateFile(SingleReportFileName));
- foreach (var error in errors.OrderBy(x => x.Id))
+ await WriteHeader(result.Target, DateTime.Now, null, streamWriter);
+
+ foreach (var error in result.Errors.OrderBy(x => x.Id))
await WriteError(error, streamWriter);
}
- private async Task ReportByVerifier(IReadOnlyCollection errors)
+ private async Task ReportByVerifier(VerificationResult result)
{
- var grouped = errors.GroupBy(x => x.VerifierChain.Last());
+ var time = DateTime.Now;
+ var grouped = result.Errors.GroupBy(x => x.VerifierChain.Last().Name);
foreach (var group in grouped)
- await ReportToSingleFile(group);
+ await ReportToSingleFile(group, result.Target, time);
}
- private async Task ReportToSingleFile(IGrouping group)
+ private async Task ReportToSingleFile(IGrouping group, VerificationTarget target, DateTime time)
{
- var fileName = $"{GetVerifierName(group.Key)}Results.txt";
+ var fileName = $"{GetVerifierName(group.Key)}_Results.txt";
#if NET || NETSTANDARD2_1
await
#endif
using var streamWriter = new StreamWriter(CreateFile(fileName));
+
+ await WriteHeader(target, time, group.Key, streamWriter);
+
foreach (var error in group.OrderBy(x => x.Id))
await WriteError(error, streamWriter);
}
@@ -52,23 +59,41 @@ private static string GetVerifierName(string verifierTypeName)
{
var typeNameSpan = verifierTypeName.AsSpan();
var nameIndex = typeNameSpan.LastIndexOf('.');
+ var isSupType = typeNameSpan.IndexOf('/') > -1;
- if (nameIndex == -1)
+ if (nameIndex == -1 && !isSupType)
return verifierTypeName;
- // They type name must not be empty
- if (typeNameSpan.Length == nameIndex)
- throw new InvalidOperationException();
-
var name = typeNameSpan.Slice(nameIndex + 1);
// Normalize subtypes (such as C/M) to avoid creating directories
- if (name.IndexOf('/') != -1)
+ if (isSupType)
return name.ToString().Replace('/', '.');
return name.ToString();
}
+ private static async Task WriteHeader(
+ VerificationTarget target,
+ DateTime time,
+ string? verifier,
+ StreamWriter writer)
+ {
+ var header = CreateHeader(target, time, verifier);
+ await writer.WriteLineAsync(header);
+ await writer.WriteLineAsync();
+ }
+
+ private static string CreateHeader(VerificationTarget target, DateTime time, string? verifier)
+ {
+ var sb = new StringBuilder();
+ sb.Append($"# Target '{target.Name}'");
+ if (!string.IsNullOrEmpty(verifier))
+ sb.Append($"; Verifier: {verifier}");
+ sb.Append($"; Time: {time:s}");
+ return sb.ToString();
+ }
+
private static async Task WriteError(VerificationError error, StreamWriter writer)
{
await writer.WriteLineAsync($"[{error.Id}] {error.Message}");
diff --git a/src/ModVerify/Reporting/Reporters/Text/TextFileReporterSettings.cs b/src/ModVerify/Reporting/Reporters/Text/TextFileReporterSettings.cs
index 8fb833b..2d0e348 100644
--- a/src/ModVerify/Reporting/Reporters/Text/TextFileReporterSettings.cs
+++ b/src/ModVerify/Reporting/Reporters/Text/TextFileReporterSettings.cs
@@ -1,8 +1,6 @@
-using AET.ModVerify.Reporting.Settings;
+namespace AET.ModVerify.Reporting.Reporters;
-namespace AET.ModVerify.Reporting.Reporters.Text;
-
-public record TextFileReporterSettings : FileBasedReporterSettings
+public sealed record TextFileReporterSettings : FileBasedReporterSettings
{
public bool SplitIntoFiles { get; init; } = true;
}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/VerificationReportBroker.cs b/src/ModVerify/Reporting/Reporters/VerificationReportBroker.cs
new file mode 100644
index 0000000..0ea6630
--- /dev/null
+++ b/src/ModVerify/Reporting/Reporters/VerificationReportBroker.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace AET.ModVerify.Reporting.Reporters;
+
+public sealed class VerificationReportBroker : IVerificationReporter
+{
+ private readonly ILogger? _logger;
+ private readonly IReadOnlyCollection _reporters;
+
+ public VerificationReportBroker(
+ IReadOnlyCollection reporters,
+ IServiceProvider serviceProvider)
+ {
+ _reporters = reporters ?? throw new ArgumentNullException(nameof(reporters));
+ _logger = serviceProvider.GetService()?.CreateLogger(typeof(VerificationReportBroker));
+ }
+
+ public async Task ReportAsync(VerificationResult result)
+ {
+ foreach (var reporter in _reporters)
+ {
+ try
+ {
+ await reporter.ReportAsync(result);
+ }
+ catch (Exception e)
+ {
+ _logger?.LogError(e, "Exception while reporting verification error");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Reporters/VerificationReportersExtensions.cs b/src/ModVerify/Reporting/Reporters/VerificationReportersExtensions.cs
deleted file mode 100644
index b8906ac..0000000
--- a/src/ModVerify/Reporting/Reporters/VerificationReportersExtensions.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using AET.ModVerify.Reporting.Reporters.JSON;
-using AET.ModVerify.Reporting.Reporters.Text;
-using AET.ModVerify.Reporting.Settings;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace AET.ModVerify.Reporting.Reporters;
-
-public static class VerificationReportersExtensions
-{
- extension(IServiceCollection serviceCollection)
- {
- public IServiceCollection RegisterJsonReporter()
- {
- return serviceCollection.RegisterJsonReporter(new JsonReporterSettings
- {
- OutputDirectory = "."
- });
- }
-
- public IServiceCollection RegisterTextFileReporter()
- {
- return serviceCollection.RegisterTextFileReporter(new TextFileReporterSettings
- {
- OutputDirectory = "."
- });
- }
-
- public IServiceCollection RegisterConsoleReporter(bool summaryOnly = false)
- {
- return serviceCollection.RegisterConsoleReporter(new ReporterSettings
- {
- MinimumReportSeverity = VerificationSeverity.Error
- }, summaryOnly);
- }
-
- public IServiceCollection RegisterJsonReporter(JsonReporterSettings settings)
- {
- return serviceCollection.AddSingleton(sp => new JsonReporter(settings, sp));
- }
-
- public IServiceCollection RegisterTextFileReporter(TextFileReporterSettings settings)
- {
- return serviceCollection.AddSingleton(sp => new TextFileReporter(settings, sp));
- }
-
- public IServiceCollection RegisterConsoleReporter(ReporterSettings settings,
- bool summaryOnly = false)
- {
- return serviceCollection.AddSingleton(sp => new ConsoleReporter(settings, summaryOnly, sp));
- }
- }
-}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/RestoredVerifierInfo.cs b/src/ModVerify/Reporting/RestoredVerifierInfo.cs
new file mode 100644
index 0000000..0c29488
--- /dev/null
+++ b/src/ModVerify/Reporting/RestoredVerifierInfo.cs
@@ -0,0 +1,10 @@
+using AET.ModVerify.Verifiers;
+
+namespace AET.ModVerify.Reporting;
+
+internal sealed class RestoredVerifierInfo : IGameVerifierInfo
+{
+ public IGameVerifierInfo? Parent { get; init; }
+ public required string Name { get; init; }
+ public string FriendlyName => Name;
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Settings/GlobalVerifyReportSettings.cs b/src/ModVerify/Reporting/Settings/GlobalVerifyReportSettings.cs
deleted file mode 100644
index 5a51436..0000000
--- a/src/ModVerify/Reporting/Settings/GlobalVerifyReportSettings.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace AET.ModVerify.Reporting.Settings;
-
-//public record GlobalVerifyReportSettings
-//{
-// //public VerificationSeverity MinimumReportSeverity { get; init; } = VerificationSeverity.Information;
-
-// public VerificationBaseline Baseline { get; init; } = VerificationBaseline.Empty;
-
-// public SuppressionList Suppressions { get; init; } = SuppressionList.Empty;
-//}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/Json/JsonSuppressionFilter.cs b/src/ModVerify/Reporting/Suppressions/Json/JsonSuppressionFilter.cs
similarity index 91%
rename from src/ModVerify/Reporting/Json/JsonSuppressionFilter.cs
rename to src/ModVerify/Reporting/Suppressions/Json/JsonSuppressionFilter.cs
index 6d232c7..13f8335 100644
--- a/src/ModVerify/Reporting/Json/JsonSuppressionFilter.cs
+++ b/src/ModVerify/Reporting/Suppressions/Json/JsonSuppressionFilter.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace AET.ModVerify.Reporting.Json;
+namespace AET.ModVerify.Reporting.Suppressions.Json;
internal class JsonSuppressionFilter(SuppressionFilter filter)
{
diff --git a/src/ModVerify/Reporting/Json/JsonSuppressionList.cs b/src/ModVerify/Reporting/Suppressions/Json/JsonSuppressionList.cs
similarity index 88%
rename from src/ModVerify/Reporting/Json/JsonSuppressionList.cs
rename to src/ModVerify/Reporting/Suppressions/Json/JsonSuppressionList.cs
index 1a8cb4a..54569eb 100644
--- a/src/ModVerify/Reporting/Json/JsonSuppressionList.cs
+++ b/src/ModVerify/Reporting/Suppressions/Json/JsonSuppressionList.cs
@@ -2,7 +2,7 @@
using System.Linq;
using System.Text.Json.Serialization;
-namespace AET.ModVerify.Reporting.Json;
+namespace AET.ModVerify.Reporting.Suppressions.Json;
internal class JsonSuppressionList
{
diff --git a/src/ModVerify/Reporting/SuppressionFilter.cs b/src/ModVerify/Reporting/Suppressions/SuppressionFilter.cs
similarity index 93%
rename from src/ModVerify/Reporting/SuppressionFilter.cs
rename to src/ModVerify/Reporting/Suppressions/SuppressionFilter.cs
index efac588..35a21d7 100644
--- a/src/ModVerify/Reporting/SuppressionFilter.cs
+++ b/src/ModVerify/Reporting/Suppressions/SuppressionFilter.cs
@@ -1,8 +1,8 @@
using System;
using System.Linq;
-using AET.ModVerify.Reporting.Json;
+using AET.ModVerify.Reporting.Suppressions.Json;
-namespace AET.ModVerify.Reporting;
+namespace AET.ModVerify.Reporting.Suppressions;
public sealed class SuppressionFilter : IEquatable
{
@@ -42,7 +42,7 @@ public bool Suppresses(VerificationError error)
if (Verifier is not null)
{
- if (error.VerifierChain.Contains(Verifier))
+ if (error.VerifierChain.Any(x => x.Name.Equals(Verifier)))
suppresses = true;
else
return false;
diff --git a/src/ModVerify/Reporting/SuppressionList.cs b/src/ModVerify/Reporting/Suppressions/SuppressionList.cs
similarity index 96%
rename from src/ModVerify/Reporting/SuppressionList.cs
rename to src/ModVerify/Reporting/Suppressions/SuppressionList.cs
index 12ebab4..a5fc8f9 100644
--- a/src/ModVerify/Reporting/SuppressionList.cs
+++ b/src/ModVerify/Reporting/Suppressions/SuppressionList.cs
@@ -5,8 +5,9 @@
using System.IO;
using System.Linq;
using System.Text.Json;
+using AET.ModVerify.Reporting.Suppressions.Json;
-namespace AET.ModVerify.Reporting;
+namespace AET.ModVerify.Reporting.Suppressions;
public sealed class SuppressionList : IReadOnlyCollection
{
diff --git a/src/ModVerify/Reporting/VerificationCompletionStatus.cs b/src/ModVerify/Reporting/VerificationCompletionStatus.cs
new file mode 100644
index 0000000..94fde18
--- /dev/null
+++ b/src/ModVerify/Reporting/VerificationCompletionStatus.cs
@@ -0,0 +1,8 @@
+namespace AET.ModVerify.Reporting;
+
+public enum VerificationCompletionStatus
+{
+ Completed,
+ CompletedFailFast,
+ Cancelled,
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/VerificationError.cs b/src/ModVerify/Reporting/VerificationError.cs
index 538a8fd..d55f71b 100644
--- a/src/ModVerify/Reporting/VerificationError.cs
+++ b/src/ModVerify/Reporting/VerificationError.cs
@@ -17,7 +17,7 @@ public sealed class VerificationError : IEquatable
public string Message { get; }
- public IReadOnlyList VerifierChain { get; }
+ public IReadOnlyList VerifierChain { get; }
public IReadOnlyCollection ContextEntries { get; }
@@ -28,7 +28,7 @@ public sealed class VerificationError : IEquatable
public VerificationError(
string id,
string message,
- IReadOnlyList verifiers,
+ IReadOnlyList verifiers,
IEnumerable contextEntries,
string asset,
VerificationSeverity severity)
@@ -41,10 +41,9 @@ public VerificationError(
Id = id;
Message = message ?? throw new ArgumentNullException(nameof(message));
- VerifierChain = verifiers;
+ VerifierChain = [.. verifiers];
Severity = severity;
- _contextEntries = [.. contextEntries];
- ContextEntries = _contextEntries.ToList();
+ ContextEntries = _contextEntries = [.. contextEntries];
Asset = asset;
}
@@ -52,7 +51,7 @@ internal VerificationError(JsonVerificationError error)
{
Id = error.Id;
Message = error.Message;
- VerifierChain = error.VerifierChain;
+ VerifierChain = RestoreVerifierChain(error.VerifierChain);
_contextEntries = [..error.ContextEntries];
ContextEntries = _contextEntries.ToList();
Asset = error.Asset;
@@ -66,7 +65,7 @@ public static VerificationError Create(
IEnumerable context,
string asset)
{
- return new VerificationError(id, message, verifiers.Select(x => x.Name).ToList(), context, asset, severity);
+ return new VerificationError(id, message, verifiers, context, asset, severity);
}
public static VerificationError Create(
@@ -79,7 +78,7 @@ public static VerificationError Create(
return new VerificationError(
id,
message,
- verifiers.Select(x => x.Name).ToList(),
+ verifiers,
[],
asset,
severity);
@@ -120,4 +119,23 @@ public override string ToString()
return $"[{Severity}] [{string.Join(" --> ", VerifierChain)}] " +
$"{Id}: Message={Message}; Asset='{Asset}'; Context=[{string.Join(",", ContextEntries)}];";
}
+
+ private static IReadOnlyList RestoreVerifierChain(IReadOnlyList errorVerifierChain)
+ {
+ var verifierChain = new List();
+ IGameVerifierInfo? previousVerifier = null;
+
+ foreach (var name in errorVerifierChain)
+ {
+ var verifier = new RestoredVerifierInfo
+ {
+ Name = name,
+ Parent = previousVerifier
+ };
+ verifierChain.Add(verifier);
+ previousVerifier = verifier;
+ }
+
+ return verifierChain;
+ }
}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/VerificationReportBroker.cs b/src/ModVerify/Reporting/VerificationReportBroker.cs
deleted file mode 100644
index 5c1e8a3..0000000
--- a/src/ModVerify/Reporting/VerificationReportBroker.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-
-namespace AET.ModVerify.Reporting;
-
-public sealed class VerificationReportBroker(IServiceProvider serviceProvider)
-{
- private readonly ILogger? _logger = serviceProvider.GetService()?.CreateLogger(typeof(VerificationReportBroker));
-
- public async Task ReportAsync(IReadOnlyCollection errors)
- {
- var reporters = serviceProvider.GetServices();
-
- foreach (var reporter in reporters)
- {
- try
- {
- await reporter.ReportAsync(errors);
- }
- catch (Exception e)
- {
- _logger?.LogError(e, "Exception while reporting verification error");
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/VerificationResult.cs b/src/ModVerify/Reporting/VerificationResult.cs
new file mode 100644
index 0000000..a4dbe1c
--- /dev/null
+++ b/src/ModVerify/Reporting/VerificationResult.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using AET.ModVerify.Reporting.Baseline;
+using AET.ModVerify.Reporting.Suppressions;
+using AET.ModVerify.Verifiers;
+
+namespace AET.ModVerify.Reporting;
+
+public sealed record VerificationResult
+{
+ public required VerificationCompletionStatus Status { get; init; }
+
+ public required IReadOnlyCollection Errors
+ {
+ get;
+ init => field = value ?? throw new ArgumentNullException(nameof(value));
+ }
+
+ public required VerificationBaseline UsedBaseline
+ {
+ get;
+ init => field = value ?? throw new ArgumentNullException(nameof(value));
+ }
+
+ public required SuppressionList UsedSuppressions
+ {
+ get;
+ init => field = value ?? throw new ArgumentNullException(nameof(value));
+ }
+
+ public required IReadOnlyCollection Verifiers
+ {
+ get;
+ init => field = value ?? throw new ArgumentNullException(nameof(value));
+ }
+
+ public required VerificationTarget Target
+ {
+ get;
+ init => field = value ?? throw new ArgumentNullException(nameof(value));
+ }
+
+ public required TimeSpan Duration { get; init; }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs b/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs
new file mode 100644
index 0000000..abb01ef
--- /dev/null
+++ b/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using AET.ModVerify.Verifiers;
+
+namespace AET.ModVerify.Reporting;
+
+internal sealed class VerifierChainEqualityComparer : IEqualityComparer>
+{
+ public static readonly VerifierChainEqualityComparer Instance = new();
+
+ private VerifierChainEqualityComparer()
+ {
+ }
+
+ public bool Equals(IReadOnlyList? x, IReadOnlyList? y)
+ {
+ if (ReferenceEquals(x, y))
+ return true;
+ if (x is null || y is null)
+ return false;
+ if (x.Count != y.Count)
+ return false;
+ for (var i = 0; i < x.Count; i++)
+ {
+ if (!NameBasedEqualityComparer.Instance.Equals(x[i], y[i]))
+ return false;
+ }
+ return true;
+ }
+
+ public int GetHashCode(IReadOnlyList? obj)
+ {
+ if (obj == null)
+ return 0;
+ var hashCode = new HashCode();
+ foreach (var verifier in obj)
+ hashCode.Add(verifier.Name);
+ return hashCode.ToHashCode();
+ }
+}
diff --git a/src/ModVerify/Settings/VerifyPipelineSettings.cs b/src/ModVerify/Settings/VerifierServiceSettings.cs
similarity index 72%
rename from src/ModVerify/Settings/VerifyPipelineSettings.cs
rename to src/ModVerify/Settings/VerifierServiceSettings.cs
index 46fc997..762806d 100644
--- a/src/ModVerify/Settings/VerifyPipelineSettings.cs
+++ b/src/ModVerify/Settings/VerifierServiceSettings.cs
@@ -1,8 +1,6 @@
-using AET.ModVerify.Pipeline;
+namespace AET.ModVerify.Settings;
-namespace AET.ModVerify.Settings;
-
-public sealed class VerifyPipelineSettings
+public sealed class VerifierServiceSettings
{
public required GameVerifySettings GameVerifySettings { get; init; }
diff --git a/src/ModVerify/Utilities/VerificationErrorExtensions.cs b/src/ModVerify/Utilities/VerificationErrorExtensions.cs
index e5aa9fe..f7eefbc 100644
--- a/src/ModVerify/Utilities/VerificationErrorExtensions.cs
+++ b/src/ModVerify/Utilities/VerificationErrorExtensions.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using AET.ModVerify.Reporting;
+using AET.ModVerify.Reporting.Baseline;
+using AET.ModVerify.Reporting.Suppressions;
namespace AET.ModVerify.Utilities;
diff --git a/src/ModVerify/VerificationTarget.cs b/src/ModVerify/VerificationTarget.cs
index c0d5b97..f12bc4d 100644
--- a/src/ModVerify/VerificationTarget.cs
+++ b/src/ModVerify/VerificationTarget.cs
@@ -1,10 +1,9 @@
using System;
-using System.Text;
using PG.StarWarsGame.Engine;
namespace AET.ModVerify;
-public sealed class VerificationTarget
+public sealed record VerificationTarget
{
public required GameEngineType Engine { get; init; }
@@ -28,14 +27,4 @@ public required GameLocations Location
public string? Version { get; init; }
public bool IsGame => Location.ModPaths.Count == 0;
-
- public override string ToString()
- {
- var sb = new StringBuilder($"[Name={Name};EngineType={Engine};");
- if (!string.IsNullOrEmpty(Version))
- sb.Append($"Version={Version};");
- sb.Append($"Location={Location};");
- sb.Append(']');
- return sb.ToString();
- }
}
\ No newline at end of file
diff --git a/src/ModVerify/Verifiers/GameEngineErrorCollector.cs b/src/ModVerify/Verifiers/GameEngineErrorCollector.cs
index 6475ea7..975e360 100644
--- a/src/ModVerify/Verifiers/GameEngineErrorCollector.cs
+++ b/src/ModVerify/Verifiers/GameEngineErrorCollector.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading;
using AET.ModVerify.Reporting;
-using AET.ModVerify.Reporting.Reporters.Engine;
+using AET.ModVerify.Reporting.Engine;
using AET.ModVerify.Settings;
using PG.StarWarsGame.Engine;
@@ -12,7 +12,8 @@ public sealed class GameEngineErrorCollector(
IGameEngineErrorCollection errorCollection,
IStarWarsGameEngine gameEngine,
GameVerifySettings settings,
- IServiceProvider serviceProvider) : GameVerifier(null, gameEngine, settings, serviceProvider)
+ IServiceProvider serviceProvider)
+ : GameVerifier(null, gameEngine, settings, serviceProvider)
{
public override string FriendlyName => "Game Engine Initialization";
diff --git a/src/ModVerify/Verifiers/GameVerifierBase.cs b/src/ModVerify/Verifiers/GameVerifierBase.cs
index 02bacc4..22b2789 100644
--- a/src/ModVerify/Verifiers/GameVerifierBase.cs
+++ b/src/ModVerify/Verifiers/GameVerifierBase.cs
@@ -7,7 +7,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Abstractions;
-using AET.ModVerify.Pipeline.Progress;
+using AET.ModVerify.Progress;
using PG.StarWarsGame.Engine;
namespace AET.ModVerify.Verifiers;
diff --git a/src/ModVerify/Verifiers/NameBasedEqualityComparer.cs b/src/ModVerify/Verifiers/NameBasedEqualityComparer.cs
new file mode 100644
index 0000000..01f396f
--- /dev/null
+++ b/src/ModVerify/Verifiers/NameBasedEqualityComparer.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace AET.ModVerify.Verifiers;
+
+internal sealed class NameBasedEqualityComparer : IEqualityComparer, IEqualityComparer
+{
+ public static readonly NameBasedEqualityComparer Instance = new();
+
+ public bool Equals(GameVerifier? x, GameVerifier? y)
+ {
+ return Equals(x as IGameVerifierInfo, y);
+ }
+
+ public int GetHashCode(GameVerifier? obj)
+ {
+ return GetHashCode(obj as IGameVerifierInfo);
+ }
+
+ public bool Equals(IGameVerifierInfo? x, IGameVerifierInfo? y)
+ {
+ if (ReferenceEquals(x, y))
+ return true;
+ if (x is null)
+ return false;
+ if (y is null)
+ return false;
+ return x.Name == y.Name;
+ }
+
+ public int GetHashCode(IGameVerifierInfo? obj)
+ {
+ return obj?.Name.GetHashCode() ?? 0;
+ }
+}
\ No newline at end of file
diff --git a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs
index a36648b..4a5feb6 100644
--- a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs
+++ b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs
@@ -17,24 +17,37 @@ public sealed class ReferencedModelsVerifier(
public override void Verify(CancellationToken token)
{
- var models = GameEngine.GameObjectTypeManager.Entries
- .SelectMany(x => x.Models)
- .Concat(FocHardcodedConstants.HardcodedModels).ToList();
+ var gameObjectEntries = GameEngine.GameObjectTypeManager.Entries.ToList();
+ var hardcodedModels = FocHardcodedConstants.HardcodedModels.ToList();
- if (models.Count == 0)
+ var totalModelsCount = gameObjectEntries.Sum(x => x.Models.Count()) + hardcodedModels.Count;
+
+ if (totalModelsCount == 0)
return;
- var numModels = models.Count;
var counter = 0;
var inner = new SingleModelVerifier(this, GameEngine, Settings, Services);
try
{
inner.Error += OnModelError;
- foreach (var model in models)
+
+ var context = new string[1];
+ foreach (var gameObject in gameObjectEntries)
+ {
+ context[0] = $"GameObject: {gameObject.Name}";
+ foreach (var model in gameObject.Models)
+ {
+ OnProgress((double)++counter / totalModelsCount, $"Model - '{model}'");
+ inner.Verify(model, context, token);
+ }
+ }
+
+ context[0] = "Hardcoded Model";
+ foreach (var hardcodedModel in hardcodedModels)
{
- OnProgress((double)++counter / numModels, $"Model - '{model}'");
- inner.Verify(model, [], token);
+ OnProgress((double)++counter / totalModelsCount, $"Model - '{hardcodedModel}'");
+ inner.Verify(hardcodedModel, context, token);
}
}
finally
@@ -47,4 +60,4 @@ private void OnModelError(object sender, VerificationErrorEventArgs e)
{
AddError(e.Error);
}
-}
+}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporter.cs
deleted file mode 100644
index 0030344..0000000
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporter.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace PG.StarWarsGame.Engine.ErrorReporting;
-
-public abstract class GameEngineErrorReporter : IGameEngineErrorReporter
-{
- public virtual void Report(XmlError error)
- {
- }
-
- public virtual void Report(InitializationError error)
- {
- }
-
- public virtual void Assert(EngineAssert assert)
- {
- }
-}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj
index 326fd1d..47b3a7f 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj
@@ -39,7 +39,4 @@
-
-
-
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj
index 0d071ca..052190c 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj
+++ b/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj
@@ -24,7 +24,4 @@
-
-
-
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj
index 5df0123..5328887 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj
+++ b/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj
@@ -19,7 +19,4 @@
-
-
-
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj
index be85ee8..5feadba 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj
+++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj
@@ -26,7 +26,4 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
\ No newline at end of file
diff --git a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj
index ef3c9ef..58914c1 100644
--- a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj
+++ b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj
@@ -35,10 +35,6 @@
-
-
-
-
true
true
diff --git a/test/ModVerify.CliApp.Test/TestData/NoVerifierProvider.cs b/test/ModVerify.CliApp.Test/TestData/NoVerifierProvider.cs
index ef7ad74..649aeb7 100644
--- a/test/ModVerify.CliApp.Test/TestData/NoVerifierProvider.cs
+++ b/test/ModVerify.CliApp.Test/TestData/NoVerifierProvider.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
-using AET.ModVerify.Pipeline;
+using AET.ModVerify;
using AET.ModVerify.Settings;
using AET.ModVerify.Verifiers;
using PG.StarWarsGame.Engine;