Skip to content

Commit 58033e5

Browse files
committed
fix tests
1 parent 11a40fa commit 58033e5

6 files changed

Lines changed: 100 additions & 16 deletions

File tree

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

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,36 @@ protected override IFileSystem CreateFileSystem()
2222
protected abstract override void ConfigureStrategy(PetroglyphFileSystem fs);
2323

2424
/// <summary>
25-
/// Constructs a fresh, undisposed instance of the strategy under test, so generic suite
26-
/// tests (<see cref="Dispose_CalledTwice_DoesNotThrow"/>) can exercise it directly without
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
2727
/// fighting the <see cref="PetroglyphFileSystem"/>'s ownership of the active strategy.
2828
/// </summary>
29-
private protected abstract FileExistsStrategy CreateStrategyForDisposeTest();
29+
private protected abstract FileExistsStrategy CreateStrategyForCleanupTest();
3030

3131
[Fact]
32-
public void Dispose_CalledTwice_DoesNotThrow()
32+
public void Cleanup_CalledTwice_DoesNotThrow()
3333
{
34-
var strategy = CreateStrategyForDisposeTest();
35-
strategy.Dispose();
36-
strategy.Dispose();
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()));
3755
}
3856

3957
protected virtual void AssertResolvedPath(string expectedOnDiskPath, string actualResult)

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
using System.Collections.Generic;
2+
using System.Collections.Concurrent;
33
using System.Diagnostics;
44
using System.IO;
55
using System.IO.Abstractions;
@@ -43,7 +43,7 @@ public abstract class LiveVirtualFileExistsStrategyTests : VirtualFileExistsStra
4343
private protected override void ConfigureStrategy(PetroglyphFileSystem fs, FileExistsStrategy underlying)
4444
=> fs.UseLiveVirtualStrategy(underlying);
4545

46-
private protected override FileExistsStrategy CreateStrategyForDisposeTest()
46+
private protected override FileExistsStrategy CreateStrategyForCleanupTest()
4747
=> new LiveVirtualFileExistsStrategy(FileSystem, new WineFileExistsStrategy(FileSystem));
4848

4949
[Fact]
@@ -317,19 +317,46 @@ await AwaitCacheInvalidationAsync(
317317
"gameDir snapshot to invalidate after g.xml deleted (post-Error rebuild)");
318318
}
319319

320+
[Fact]
321+
public async Task Cleanup_RemovesWatchersAndClearsCache_WatchersReinstalledOnNextLookup()
322+
{
323+
var dir = NewTempDir();
324+
var dataDir = FileSystem.Path.Combine(dir, "Data");
325+
FileSystem.Directory.CreateDirectory(dataDir);
326+
var file = FileSystem.Path.Combine(dataDir, "foo.xml");
327+
FileSystem.File.WriteAllText(file, "x");
328+
329+
// Prime: install a watcher and warm the snapshot.
330+
Assert.True(FileExists("Data/foo.xml".AsSpan(), dir.AsSpan()));
331+
332+
var strategyBefore = GetActiveLiveStrategy();
333+
Assert.True(GetWatchers(strategyBefore).ContainsKey(dir));
334+
335+
// Cleanup: teardown watchers and clear the snapshot cache.
336+
strategyBefore.Cleanup();
337+
338+
// Lookups must still work after Cleanup — the strategy re-snapshots lazily.
339+
Assert.True(FileExists("Data/foo.xml".AsSpan(), dir.AsSpan()));
340+
341+
// After the first post-cleanup lookup the watcher must be re-armed: disk changes are tracked again.
342+
await AwaitCacheInvalidationAsync(
343+
() => FileSystem.File.Delete(file),
344+
() => !FileExists("Data/foo.xml".AsSpan(), dir.AsSpan()),
345+
"snapshot to invalidate after Data/foo.xml deleted (post-Cleanup re-arm)");
346+
}
347+
320348
private LiveVirtualFileExistsStrategy GetActiveLiveStrategy()
321349
{
322-
var field = typeof(PetroglyphFileSystem).GetField("_strategy", BindingFlags.NonPublic | BindingFlags.Instance)!;
323-
return (LiveVirtualFileExistsStrategy)field.GetValue(PgFileSystem)!;
350+
return (LiveVirtualFileExistsStrategy)PgFileSystem.Strategy;
324351
}
325352

326353
// GetWatchers / InvokeOnWatcherError exist only to *synthesize* an Error event (no portable
327354
// way to make a real FSW fire one). The Error tests themselves assert observable behavior,
328355
// not the watcher dictionary's contents.
329-
private static Dictionary<string, IFileSystemWatcher> GetWatchers(LiveVirtualFileExistsStrategy strategy)
356+
private static ConcurrentDictionary<string, IFileSystemWatcher> GetWatchers(LiveVirtualFileExistsStrategy strategy)
330357
{
331358
var field = typeof(LiveVirtualFileExistsStrategy).GetField("_watchers", BindingFlags.NonPublic | BindingFlags.Instance)!;
332-
return (Dictionary<string, IFileSystemWatcher>)field.GetValue(strategy)!;
359+
return (ConcurrentDictionary<string, IFileSystemWatcher>)field.GetValue(strategy)!;
333360
}
334361

335362
private static void InvokeOnWatcherError(LiveVirtualFileExistsStrategy strategy, IFileSystemWatcher sender, ErrorEventArgs args)

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Concurrent;
3+
using System.Reflection;
24
using PG.StarWarsGame.Engine.IO;
35
using PG.StarWarsGame.Engine.IO.FileExistStrategies;
46
using PG.StarWarsGame.Engine.Utilities;
@@ -119,4 +121,41 @@ public void FileExists_MissingSubdirectoryUnderGameRoot_DoesNotDelegate()
119121

120122
Assert.Equal(0, tracking.CallCount);
121123
}
124+
125+
[Fact]
126+
public void Cleanup_ClearsSnapshotCache_FreshSnapshotOnNextLookup()
127+
{
128+
var dir = NewTempDir();
129+
var dataDir = FileSystem.Path.Combine(dir, "Data");
130+
FileSystem.Directory.CreateDirectory(dataDir);
131+
FileSystem.File.WriteAllText(FileSystem.Path.Combine(dataDir, "foo.xml"), "x");
132+
133+
// Prime the snapshot — foo.xml is in cache.
134+
Assert.True(FileExists("Data/foo.xml".AsSpan(), dir.AsSpan()));
135+
Assert.NotEmpty(GetSnapshotStore());
136+
137+
// Cleanup evicts the snapshot cache.
138+
GetActiveVirtualStrategy().Cleanup();
139+
Assert.Empty(GetSnapshotStore());
140+
141+
// Add a file to disk after cleanup; the post-cleanup re-snapshot must pick it up.
142+
FileSystem.File.WriteAllText(FileSystem.Path.Combine(dataDir, "bar.xml"), "y");
143+
144+
// Post-cleanup: fresh snapshot taken on next lookup — both files visible.
145+
Assert.True(FileExists("Data/foo.xml".AsSpan(), dir.AsSpan()));
146+
Assert.True(FileExists("Data/bar.xml".AsSpan(), dir.AsSpan()));
147+
}
148+
149+
private VirtualFileExistsStrategyBase GetActiveVirtualStrategy()
150+
{
151+
var field = typeof(PetroglyphFileSystem).GetField("_strategy", BindingFlags.NonPublic | BindingFlags.Instance)!;
152+
return (VirtualFileExistsStrategyBase)field.GetValue(PgFileSystem)!;
153+
}
154+
155+
private ConcurrentDictionary<string, VirtualDirectory?> GetSnapshotStore()
156+
{
157+
var strategy = GetActiveVirtualStrategy();
158+
var field = typeof(VirtualFileExistsStrategyBase).GetField("Store", BindingFlags.NonPublic | BindingFlags.Instance)!;
159+
return (ConcurrentDictionary<string, VirtualDirectory?>)field.GetValue(strategy)!;
160+
}
122161
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public abstract class VirtualFileExistsStrategyTests : VirtualFileExistsStrategy
2626
private protected override void ConfigureStrategy(PetroglyphFileSystem fs, FileExistsStrategy underlying)
2727
=> fs.UseVirtualStrategy(underlying);
2828

29-
private protected override FileExistsStrategy CreateStrategyForDisposeTest()
29+
private protected override FileExistsStrategy CreateStrategyForCleanupTest()
3030
=> new VirtualFileExistsStrategy(FileSystem, new WineFileExistsStrategy(FileSystem));
3131

3232
[Fact]

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ protected override void ConfigureStrategy(PetroglyphFileSystem fs)
1919
fs.UseWindowsStrategy();
2020
}
2121

22-
private protected override FileExistsStrategy CreateStrategyForDisposeTest()
22+
private protected override FileExistsStrategy CreateStrategyForCleanupTest()
2323
{
2424
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
2525
Assert.Skip("Windows strategy requires a Windows host.");

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ public sealed class WineFileExistsStrategyTests : FileExistsStrategyTestBase
88
protected override void ConfigureStrategy(PetroglyphFileSystem fs)
99
=> fs.UseWineStrategy();
1010

11-
private protected override FileExistsStrategy CreateStrategyForDisposeTest()
11+
private protected override FileExistsStrategy CreateStrategyForCleanupTest()
1212
=> new WineFileExistsStrategy(FileSystem);
1313
}

0 commit comments

Comments
 (0)