Skip to content

Commit a3cb110

Browse files
authored
Virtual File Exist Strategy with FileSystemWatcher (#45)
* implement livevirtual strategy * fix documentation make make project prod ready * strategies are not dispoable anymore but can be cleaned. Make LiveVirtualStrategy is faster. * move to auto-property * fix tests * make gameenge disposable and cleanup FS handler * use different FS strategies on verify and create baseline * fix tests
1 parent d3e2c36 commit a3cb110

28 files changed

Lines changed: 1237 additions & 339 deletions

src/ModVerify.CliApp/Settings/SettingsBuilder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@ private AppVerifySettings BuildFromVerifyVerb(VerifyVerbOption verifyOptions)
3636
ParallelVerifiers = verifyOptions.Parallel ? 4 : 1,
3737
VerifiersProvider = new DefaultGameVerifiersProvider(),
3838
FailFastSettings = failFastSetting,
39+
UseLiveVirtualFileSystem = true,
3940
GameVerifySettings = new GameVerifySettings
4041
{
4142
IgnoreAsserts = verifyOptions.IgnoreAsserts,
42-
ThrowsOnMinimumSeverity = failFastSetting.IsFailFast
43+
ThrowsOnMinimumSeverity = failFastSetting.IsFailFast
4344
? failFastSetting.MinumumSeverity
4445
// The app shall not make a specific verifier throw, but it should always run to completion.
45-
: null
46+
: null
4647
}
4748
},
4849
AppFailsOnMinimumSeverity = verifyOptions.MinimumFailureSeverity,

src/ModVerify/GameVerifyPipeline.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Microsoft.Extensions.DependencyInjection;
1919
using Microsoft.Extensions.Logging;
2020
using PG.StarWarsGame.Engine;
21+
using PG.StarWarsGame.Engine.IO;
2122

2223
namespace AET.ModVerify;
2324

@@ -35,6 +36,8 @@ internal sealed class GameVerifyPipeline : StepRunnerPipelineBase<AsyncStepRunne
3536
private readonly SuppressionList _suppressions;
3637
private VerificationErrors _errors = VerificationErrors.Empty;
3738

39+
private IStarWarsGameEngineHandle? _gameEngine;
40+
3841
internal VerificationErrors Errors => _errors;
3942

4043
internal IReadOnlyCollection<IGameVerifierInfo> Verifiers => [.. _verifiers];
@@ -78,17 +81,20 @@ protected override async Task PrepareCoreAsync(CancellationToken token)
7881
_verifiers.Clear();
7982
_errors = VerificationErrors.Empty;
8083

81-
IStarWarsGameEngine gameEngine;
82-
8384
try
8485
{
8586
var engineService = ServiceProvider.GetRequiredService<IPetroglyphStarWarsGameEngineService>();
86-
gameEngine = await engineService.InitializeAsync(
87+
Action<PetroglyphFileSystem>? configureFs = _serviceSettings.UseLiveVirtualFileSystem
88+
? static fs => fs.UseLiveVirtualStrategy()
89+
: null;
90+
91+
_gameEngine = await engineService.InitializeAsync(
8792
_verificationTarget.Engine,
8893
_verificationTarget.Location,
8994
_engineErrorReporter,
9095
_engineInitializationReporter,
9196
false,
97+
configureFs,
9298
CancellationToken.None).ConfigureAwait(false);
9399
}
94100
catch (Exception e)
@@ -97,9 +103,9 @@ protected override async Task PrepareCoreAsync(CancellationToken token)
97103
throw;
98104
}
99105

100-
AddStep(new GameEngineErrorCollector(_engineErrorReporter, gameEngine, _serviceSettings.GameVerifySettings, ServiceProvider));
106+
AddStep(new GameEngineErrorCollector(_engineErrorReporter, _gameEngine, _serviceSettings.GameVerifySettings, ServiceProvider));
101107

102-
foreach (var gameVerificationStep in CreateVerifiers(gameEngine))
108+
foreach (var gameVerificationStep in CreateVerifiers(_gameEngine))
103109
AddStep(gameVerificationStep);
104110
}
105111

@@ -153,6 +159,8 @@ protected override void DisposeResources()
153159
_engineErrorReporter.Clear();
154160
_aggregatedVerifyProgressReporter?.Dispose();
155161
_aggregatedVerifyProgressReporter = null;
162+
_gameEngine?.Dispose();
163+
_gameEngine = null;
156164
}
157165

158166
private void AddStep(GameVerifier verifier)

src/ModVerify/Settings/VerifierServiceSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ public sealed class VerifierServiceSettings
99
public FailFastSetting FailFastSettings { get; init; } = FailFastSetting.NoFailFast;
1010

1111
public int ParallelVerifiers { get; init; } = 4;
12+
13+
public bool UseLiveVirtualFileSystem { get; init; } = false;
1214
}

src/PetroglyphTools/PG.StarWarsGame.Engine.FileSystem.Test/IO/FileExistStrategies/FileExistsStrategyTestBase.cs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO.Abstractions;
44
using System.Runtime.InteropServices;
55
using PG.StarWarsGame.Engine.IO;
6+
using PG.StarWarsGame.Engine.IO.FileExistStrategies;
67
using PG.StarWarsGame.Engine.Utilities;
78
using Testably.Abstractions;
89
using Xunit;
@@ -20,6 +21,39 @@ protected override IFileSystem CreateFileSystem()
2021

2122
protected abstract override void ConfigureStrategy(PetroglyphFileSystem fs);
2223

24+
/// <summary>
25+
/// Constructs a fresh instance of the strategy under test, so generic suite
26+
/// tests (<see cref="Cleanup_CalledTwice_DoesNotThrow"/>) can exercise it directly without
27+
/// fighting the <see cref="PetroglyphFileSystem"/>'s ownership of the active strategy.
28+
/// </summary>
29+
private protected abstract FileExistsStrategy CreateStrategyForCleanupTest();
30+
31+
[Fact]
32+
public void Cleanup_CalledTwice_DoesNotThrow()
33+
{
34+
var strategy = CreateStrategyForCleanupTest();
35+
strategy.Cleanup();
36+
strategy.Cleanup();
37+
}
38+
39+
[Fact]
40+
public void FileExists_AfterCleanup_RemainsUsable()
41+
{
42+
var dir = NewTempDir();
43+
var file = FileSystem.Path.Combine(dir, "test.txt");
44+
FileSystem.File.WriteAllText(file, "x");
45+
46+
// Warm up the strategy.
47+
Assert.True(FileExists("test.txt".AsSpan(), dir.AsSpan()));
48+
49+
// Cleanup must not permanently break the strategy.
50+
PgFileSystem.Strategy.Cleanup();
51+
52+
// Must still serve correct lookups after Cleanup.
53+
Assert.True(FileExists("test.txt".AsSpan(), dir.AsSpan()));
54+
Assert.False(FileExists("missing.txt".AsSpan(), dir.AsSpan()));
55+
}
56+
2357
protected virtual void AssertResolvedPath(string expectedOnDiskPath, string actualResult)
2458
{
2559
var expected = expectedOnDiskPath.Replace('\\', FileSystem.Path.DirectorySeparatorChar).Replace('/', FileSystem.Path.DirectorySeparatorChar);
@@ -53,10 +87,6 @@ protected string NewTempDir()
5387
return dir;
5488
}
5589

56-
// ---------------------------------------------------------------------------------------------
57-
// Shared tests — every strategy must satisfy.
58-
// ---------------------------------------------------------------------------------------------
59-
6090
[Theory]
6191
[InlineData("/gameDir")]
6292
[InlineData(null)]

0 commit comments

Comments
 (0)