Skip to content

Commit da20144

Browse files
committed
simplify meg testing logic
1 parent 65a10e6 commit da20144

19 files changed

Lines changed: 113 additions & 193 deletions

src/PetroglyphTools/PG.StarWarsGame.Engine.Testing/IRepoOriginWriter.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
using System.IO.Abstractions;
1+
using System;
22
using System.Reflection;
33

44
namespace PG.StarWarsGame.Engine.Testing;
55

66
/// <summary>Provides per-origin write operations against the underlying file system.</summary>
77
public interface IRepoOriginWriter
88
{
9-
/// <summary>Gets the file system backing this origin.</summary>
10-
IFileSystem FileSystem { get; }
11-
12-
/// <summary>Gets the absolute path of this origin's root.</summary>
13-
string OriginPath { get; }
14-
159
/// <summary>Writes the text content to a file relative to the origin root.</summary>
1610
void Write(string relativePath, string content);
1711

@@ -30,4 +24,13 @@ public interface IRepoOriginWriter
3024
/// <summary>Writes the XML content to <c>Data/XML/&lt;name&gt;</c> relative to the origin root.</summary>
3125
/// <remarks><paramref name="name"/> may contain subpath separators.</remarks>
3226
void WriteXml(string name, string content);
27+
28+
/// <summary>Writes a MEG archive composed via the configure callback to a file relative to the origin root.</summary>
29+
/// <param name="relativePath">The destination path relative to the origin root.</param>
30+
/// <param name="configure">The callback that populates the archive entries.</param>
31+
void WriteMeg(string relativePath, Action<IMegContentBuilder> configure);
32+
33+
/// <summary>Writes an empty MEG archive to a file relative to the origin root.</summary>
34+
/// <param name="relativePath">The destination path relative to the origin root.</param>
35+
void WriteEmptyMeg(string relativePath);
3336
}
Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Reflection;
43
using System.Text;
5-
using PG.StarWarsGame.Files.MEG.Services.Builder.Normalization;
4+
using PG.StarWarsGame.Files.MEG.Services.Builder;
65

76
namespace PG.StarWarsGame.Engine.Testing;
87

9-
internal sealed class MegContentBuilder : IMegContentBuilder
8+
internal sealed class MegContentBuilder(IMegBuilder inner) : IMegContentBuilder
109
{
11-
private static readonly EmpireAtWarMegDataEntryPathNormalizer Normalizer = new();
12-
13-
private readonly List<PendingEntry> _entries = new();
14-
15-
public IReadOnlyList<PendingEntry> Entries => _entries;
10+
private readonly IMegBuilder _inner = inner ?? throw new ArgumentNullException(nameof(inner));
1611

1712
public IMegContentBuilder Add(string entryName, byte[] content)
1813
{
@@ -21,8 +16,10 @@ public IMegContentBuilder Add(string entryName, byte[] content)
2116
if (content == null)
2217
throw new ArgumentNullException(nameof(content));
2318

24-
_entries.Add(new PendingEntry(Normalize(entryName), content));
25-
return this;
19+
var result = _inner.AddBytes(content, entryName, encrypt: false);
20+
return !result.Added
21+
? throw new InvalidOperationException($"Failed to add MEG entry '{entryName}': {result.Status} ({result.Message ?? "no message"}).")
22+
: this;
2623
}
2724

2825
public IMegContentBuilder Add(string entryName, string content)
@@ -38,15 +35,4 @@ public IMegContentBuilder AddEmbedded(string entryName, string resourceName, Ass
3835
var asm = source ?? Assembly.GetCallingAssembly();
3936
return Add(entryName, EmbeddedFixtures.Load(resourceName, asm));
4037
}
41-
42-
private static string Normalize(string entryName)
43-
{
44-
return Normalizer.Normalize(entryName);
45-
}
46-
47-
internal readonly struct PendingEntry(string normalizedName, byte[] content)
48-
{
49-
public string NormalizedName { get; } = normalizedName;
50-
public byte[] Content { get; } = content;
51-
}
5238
}

src/PetroglyphTools/PG.StarWarsGame.Engine.Testing/MegWriterExtensions.cs

Lines changed: 0 additions & 86 deletions
This file was deleted.
Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
using System;
22
using System.IO.Abstractions;
33
using System.Reflection;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using PG.StarWarsGame.Files.MEG.Files;
6+
using PG.StarWarsGame.Files.MEG.Services.Builder;
47

58
namespace PG.StarWarsGame.Engine.Testing;
69

7-
internal sealed class RepoOriginWriter(IFileSystem fileSystem, string originPath) : IRepoOriginWriter
10+
internal sealed class RepoOriginWriter(IServiceProvider services, string originPath) : IRepoOriginWriter
811
{
9-
private readonly IFileSystem _fs = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
10-
11-
public IFileSystem FileSystem => _fs;
12-
13-
public string OriginPath { get; } = originPath ?? throw new ArgumentNullException(nameof(originPath));
12+
private readonly IServiceProvider _services = services ?? throw new ArgumentNullException(nameof(services));
13+
private readonly IFileSystem _fileSystem = services.GetRequiredService<IFileSystem>();
14+
private readonly string _originPath = originPath ?? throw new ArgumentNullException(nameof(originPath));
1415

1516
public void Write(string relativePath, string content)
1617
{
17-
if (content == null)
18+
if (content == null)
1819
throw new ArgumentNullException(nameof(content));
19-
20+
2021
var dst = Resolve(relativePath);
2122
EnsureParent(dst);
22-
_fs.File.WriteAllText(dst, content);
23+
_fileSystem.File.WriteAllText(dst, content);
2324
}
2425

2526
public void Write(string relativePath, byte[] content)
2627
{
2728
if (content == null)
2829
throw new ArgumentNullException(nameof(content));
29-
30+
3031
var dst = Resolve(relativePath);
3132
EnsureParent(dst);
32-
_fs.File.WriteAllBytes(dst, content);
33+
_fileSystem.File.WriteAllBytes(dst, content);
3334
}
3435

3536
public void WriteEmbedded(string relativePath, string resourceName, Assembly? source = null)
@@ -42,34 +43,53 @@ public void WriteEmbedded(string relativePath, string resourceName, Assembly? so
4243
public void Remove(string relativePath)
4344
{
4445
var dst = Resolve(relativePath);
45-
if (_fs.File.Exists(dst))
46-
_fs.File.Delete(dst);
46+
if (_fileSystem.File.Exists(dst))
47+
_fileSystem.File.Delete(dst);
4748
}
4849

4950
public void WriteXml(string name, string content)
5051
{
5152
if (name == null)
5253
throw new ArgumentNullException(nameof(name));
53-
54-
Write(_fs.Path.Combine("Data", "XML", Normalize(name)), content);
54+
55+
Write(_fileSystem.Path.Combine("Data", "XML", Normalize(name)), content);
56+
}
57+
58+
public void WriteMeg(string relativePath, Action<IMegContentBuilder> configure)
59+
{
60+
if (configure == null)
61+
throw new ArgumentNullException(nameof(configure));
62+
63+
var dst = Resolve(relativePath);
64+
EnsureParent(dst);
65+
66+
using var megBuilder = new EmpireAtWarMegBuilder(_fileSystem.Path.GetDirectoryName(dst)!, _services);
67+
configure(new MegContentBuilder(megBuilder));
68+
using var fileInfo = new MegFileInformation(dst, MegFileVersion.V1, encryptionData: null);
69+
megBuilder.Build(fileInfo, overwrite: true);
70+
}
71+
72+
public void WriteEmptyMeg(string relativePath)
73+
{
74+
WriteMeg(relativePath, _ => { });
5575
}
5676

5777
private string Resolve(string relativePath)
5878
{
59-
return relativePath == null
60-
? throw new ArgumentNullException(nameof(relativePath))
61-
: _fs.Path.Combine(OriginPath, Normalize(relativePath));
79+
return relativePath == null
80+
? throw new ArgumentNullException(nameof(relativePath))
81+
: _fileSystem.Path.Combine(_originPath, Normalize(relativePath));
6282
}
6383

6484
private string Normalize(string path)
6585
{
66-
return path.Replace('\\', _fs.Path.DirectorySeparatorChar).Replace('/', _fs.Path.DirectorySeparatorChar);
86+
return path.Replace('\\', _fileSystem.Path.DirectorySeparatorChar).Replace('/', _fileSystem.Path.DirectorySeparatorChar);
6787
}
6888

6989
private void EnsureParent(string fullPath)
7090
{
71-
var dir = _fs.Path.GetDirectoryName(fullPath);
91+
var dir = _fileSystem.Path.GetDirectoryName(fullPath);
7292
if (!string.IsNullOrEmpty(dir))
73-
_fs.Directory.CreateDirectory(dir!);
93+
_fileSystem.Directory.CreateDirectory(dir!);
7494
}
7595
}

src/PetroglyphTools/PG.StarWarsGame.Engine.Testing/VirtualGameRepoBuilder.cs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO.Abstractions;
4+
using Microsoft.Extensions.DependencyInjection;
45

56
namespace PG.StarWarsGame.Engine.Testing;
67

78
/// <summary>Builds a temp-directory-backed <see cref="VirtualGameRepo"/> from raw file content.</summary>
89
public sealed class VirtualGameRepoBuilder
910
{
11+
private readonly IServiceProvider _services;
1012
private readonly IFileSystem _fs;
1113
private readonly string _tempRoot;
1214
private readonly string _gameRoot;
13-
private readonly List<string> _modPaths = new();
14-
private readonly List<string> _fallbackPaths = new();
15+
private readonly List<string> _modPaths = [];
16+
private readonly List<string> _fallbackPaths = [];
1517
private string? _fallbackGamePath;
1618

1719
/// <summary>Initializes a new instance of the <see cref="VirtualGameRepoBuilder"/> class.</summary>
18-
/// <param name="fileSystem">The file system used for all builder I/O.</param>
19-
/// <exception cref="ArgumentNullException"><paramref name="fileSystem"/> is <see langword="null"/>.</exception>
20-
public VirtualGameRepoBuilder(IFileSystem fileSystem)
20+
/// <param name="services">The service provider supplying the file system and file-format services used by the builder.</param>
21+
/// <exception cref="ArgumentNullException"><paramref name="services"/> is <see langword="null"/>.</exception>
22+
public VirtualGameRepoBuilder(IServiceProvider services)
2123
{
22-
_fs = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
24+
_services = services ?? throw new ArgumentNullException(nameof(services));
25+
_fs = services.GetRequiredService<IFileSystem>();
2326
_tempRoot = _fs.Path.Combine(_fs.Path.GetTempPath(),
2427
$"PG.StarWarsGame.Engine.Testing.{Guid.NewGuid():N}");
2528
_gameRoot = _fs.Path.Combine(_tempRoot, "game");
@@ -31,10 +34,10 @@ public VirtualGameRepoBuilder(IFileSystem fileSystem)
3134
/// <exception cref="ArgumentNullException"><paramref name="configure"/> is <see langword="null"/>.</exception>
3235
public VirtualGameRepoBuilder WithGame(Action<IRepoOriginWriter> configure)
3336
{
34-
if (configure == null)
37+
if (configure == null)
3538
throw new ArgumentNullException(nameof(configure));
36-
37-
configure(new RepoOriginWriter(_fs, _gameRoot));
39+
40+
configure(new RepoOriginWriter(_services, _gameRoot));
3841
return this;
3942
}
4043

@@ -45,13 +48,13 @@ public VirtualGameRepoBuilder WithFallbackGame(Action<IRepoOriginWriter> configu
4548
{
4649
if (configure == null)
4750
throw new ArgumentNullException(nameof(configure));
48-
51+
4952
if (_fallbackGamePath == null)
5053
{
5154
_fallbackGamePath = _fs.Path.Combine(_tempRoot, "fallback", "_primary");
5255
_fs.Directory.CreateDirectory(_fallbackGamePath);
5356
}
54-
configure(new RepoOriginWriter(_fs, _fallbackGamePath));
57+
configure(new RepoOriginWriter(_services, _fallbackGamePath));
5558
return this;
5659
}
5760

@@ -62,18 +65,18 @@ public VirtualGameRepoBuilder WithFallbackGame(Action<IRepoOriginWriter> configu
6265
/// <exception cref="ArgumentNullException"><paramref name="configure"/> is <see langword="null"/>.</exception>
6366
public VirtualGameRepoBuilder WithFallback(string name, Action<IRepoOriginWriter> configure)
6467
{
65-
if (string.IsNullOrEmpty(name))
68+
if (string.IsNullOrEmpty(name))
6669
throw new ArgumentException("Fallback name must be non-empty.", nameof(name));
67-
if (configure == null)
70+
if (configure == null)
6871
throw new ArgumentNullException(nameof(configure));
69-
72+
7073
var dir = _fs.Path.Combine(_tempRoot, "fallback", name);
7174
if (!_fallbackPaths.Contains(dir))
7275
{
7376
_fs.Directory.CreateDirectory(dir);
7477
_fallbackPaths.Add(dir);
7578
}
76-
configure(new RepoOriginWriter(_fs, dir));
79+
configure(new RepoOriginWriter(_services, dir));
7780
return this;
7881
}
7982

@@ -89,14 +92,14 @@ public VirtualGameRepoBuilder WithMod(string name, Action<IRepoOriginWriter> con
8992
throw new ArgumentException("Mod name must be non-empty.", nameof(name));
9093
if (configure == null)
9194
throw new ArgumentNullException(nameof(configure));
92-
95+
9396
var dir = _fs.Path.Combine(_tempRoot, "mods", name);
9497
if (!_modPaths.Contains(dir))
9598
{
9699
_fs.Directory.CreateDirectory(dir);
97100
_modPaths.Add(dir);
98101
}
99-
configure(new RepoOriginWriter(_fs, dir));
102+
configure(new RepoOriginWriter(_services, dir));
100103
return this;
101104
}
102105

0 commit comments

Comments
 (0)