Files
AIC-Project/Server/PublishTool.Tests/PublishLayoutTests.cs
T
2026-07-10 10:24:29 +08:00

96 lines
4.8 KiB
C#

using System.IO;
using System.Security.Cryptography;
using Xunit;
using XWorld.PublishTool;
namespace XWorld.PublishTool.Tests
{
public class PublishLayoutTests
{
private static GameSpec MakeSpec() => new GameSpec
{
GameId = "rps", Version = 1, MinFrameworkVersion = 1, PlayerCount = 2, TickRateHz = 10,
ServerAssembly = "RPS.Server.dll", ServerEntryType = "RPS.Server.RpsServerRoom",
CoreDll = "RPS.Core.dll", ClientDll = "RPS.Client.dll", ClientEntryType = "RPS.Client.RpsGameClient",
CodeAb = "code.unity3d",
Assets = new System.Collections.Generic.List<string> { "res.unity3d" },
};
private static string TempDir() =>
Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "pub_" + System.Guid.NewGuid().ToString("N"))).FullName;
[Fact]
public void PublishServer_ProducesDlls_GameJson_Manifest_Signature()
{
string src = TempDir(); string outDir = Path.Combine(TempDir(), "s");
File.WriteAllBytes(Path.Combine(src, "RPS.Core.dll"), new byte[] { 1, 2, 3 });
File.WriteAllBytes(Path.Combine(src, "RPS.Server.dll"), new byte[] { 4, 5 });
using var rsa = RSA.Create(2048);
new PublishLayout().PublishServer(src, outDir, MakeSpec(), rsa.ExportRSAPrivateKeyPem());
Assert.True(File.Exists(Path.Combine(outDir, "RPS.Server.dll")));
Assert.True(File.Exists(Path.Combine(outDir, "RPS.Core.dll")));
Assert.True(File.Exists(Path.Combine(outDir, "game.json")));
var fm = FilesManifest.Parse(File.ReadAllText(Path.Combine(outDir, "files.txt")));
Assert.True(fm.Entries.ContainsKey("RPS.Server.dll"));
Assert.True(fm.Entries.ContainsKey("RPS.Core.dll"));
Assert.True(fm.Entries.ContainsKey("game.json"));
byte[] sig = File.ReadAllBytes(Path.Combine(outDir, "files.txt.sig"));
Assert.True(ManifestSigner.Verify(fm.Digest(), sig, rsa.ExportRSAPublicKeyPem()));
}
[Fact]
public void PublishClient_Md5NamedAbs_CodeAbInManifest_NoLooseBytes()
{
string src = TempDir(); string outDir = Path.Combine(TempDir(), "c");
File.WriteAllBytes(Path.Combine(src, "code.unity3d"), new byte[] { 6, 7, 8 });
File.WriteAllBytes(Path.Combine(src, "res.unity3d"), new byte[] { 9 });
using var rsa = RSA.Create(2048);
new PublishLayout().PublishClient(src, outDir, MakeSpec(), rsa.ExportRSAPrivateKeyPem());
var fm = FilesManifest.Parse(File.ReadAllText(Path.Combine(outDir, "files.txt")));
// files.txt 登记逻辑名;落盘 md5 命名(与 MiniGameDownloader.Md5Name 一致)
Assert.True(fm.Entries.ContainsKey("code.unity3d"));
Assert.True(fm.Entries.ContainsKey("res.unity3d"));
string codeMd5 = Md5Util.OfFile(Path.Combine(src, "code.unity3d"));
string resMd5 = Md5Util.OfFile(Path.Combine(src, "res.unity3d"));
Assert.True(File.Exists(Path.Combine(outDir, $"code_{codeMd5}.unity3d")));
Assert.True(File.Exists(Path.Combine(outDir, $"res_{resMd5}.unity3d")));
// 统一 AB:不再有散 .bytes 文件
Assert.Empty(Directory.GetFiles(outDir, "*.bytes"));
// game.json 带 codeAb
Assert.Contains("\"codeAb\": \"code.unity3d\"", File.ReadAllText(Path.Combine(outDir, "game.json")));
byte[] sig = File.ReadAllBytes(Path.Combine(outDir, "files.txt.sig"));
Assert.True(ManifestSigner.Verify(fm.Digest(), sig, rsa.ExportRSAPublicKeyPem()));
}
[Fact]
public void NullKey_WritesEmptySig_BothTrees()
{
string src = TempDir();
string outS = Path.Combine(TempDir(), "s"); string outC = Path.Combine(TempDir(), "c");
File.WriteAllBytes(Path.Combine(src, "RPS.Core.dll"), new byte[] { 1 });
File.WriteAllBytes(Path.Combine(src, "RPS.Server.dll"), new byte[] { 2 });
File.WriteAllBytes(Path.Combine(src, "code.unity3d"), new byte[] { 3 });
File.WriteAllBytes(Path.Combine(src, "res.unity3d"), new byte[] { 4 });
var layout = new PublishLayout();
layout.PublishServer(src, outS, MakeSpec(), null);
layout.PublishClient(src, outC, MakeSpec(), null);
Assert.Equal(0, new FileInfo(Path.Combine(outS, "files.txt.sig")).Length);
Assert.Equal(0, new FileInfo(Path.Combine(outC, "files.txt.sig")).Length);
}
[Fact]
public void PublishClient_EmptyCodeAb_Throws()
{
var spec = MakeSpec(); spec.CodeAb = null;
Assert.Throws<System.InvalidOperationException>(
() => new PublishLayout().PublishClient(TempDir(), Path.Combine(TempDir(), "c"), spec, null));
}
}
}