Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions PCL.Core.Test/Minecraft/Modpack/CurseForgeManifestTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PCL.Core.Minecraft.Modpack;
using PCL.Core.Utils;

namespace PCL.Core.Test.Minecraft.Modpack;

[TestClass]
public class CurseForgeManifestTest
{
[TestMethod]
public void ParsesCompleteManifest()
{
const string json = """
{
"manifestType": "minecraftModpack",
"manifestVersion": 1,
"name": "示例整合包",
"version": "1.0.0",
"recommendedRam": 8192,
"author": "作者名",
"minecraft": {
"version": "1.20.1",
"modLoaders": [ { "id": "forge-47.2.0", "primary": true } ]
},
"files": [
{ "projectID": 238222, "fileID": 5246076, "required": true },
{ "projectID": 123456, "fileID": 789012, "required": false }
],
"overrides": "overrides"
}
""";
var manifest = CurseForgeManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.AreEqual("minecraftModpack", manifest.ManifestType);
Assert.AreEqual(1, manifest.ManifestVersion);
Assert.AreEqual("示例整合包", manifest.Name);
Assert.AreEqual("1.0.0", manifest.Version);
Assert.AreEqual(8192, manifest.RecommendedRam);
Assert.AreEqual("作者名", manifest.Author);
Assert.AreEqual("1.20.1", manifest.Minecraft?.Version);
Assert.IsNotNull(manifest.Minecraft?.ModLoaders);
Assert.AreEqual(1, manifest.Minecraft.ModLoaders.Count);
Assert.AreEqual("forge-47.2.0", manifest.Minecraft.ModLoaders[0].Id);
Assert.IsTrue(manifest.Minecraft.ModLoaders[0].Primary);
Assert.IsNotNull(manifest.Files);
Assert.AreEqual(2, manifest.Files.Count);
Assert.AreEqual(238222, manifest.Files[0].ProjectId);
Assert.AreEqual(5246076, manifest.Files[0].FileId);
Assert.IsFalse(manifest.Files[0].IsOptional);
Assert.IsTrue(manifest.Files[1].IsOptional);
Assert.AreEqual("overrides", manifest.Overrides);
}

[TestMethod]
public void RecommendedRamPrefersRootOverMinecraft()
{
const string json = """
{
"recommendedRam": 4096,
"minecraft": {
"version": "1.20.1",
"recommendedRam": 8192
}
}
""";
var manifest = CurseForgeManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.AreEqual(4096, manifest.RecommendedRam);
Assert.AreEqual(8192, manifest.Minecraft?.RecommendedRam);
Assert.AreEqual(4096, manifest.RecommendedRamEffective);
}

[TestMethod]
public void RecommendedRamFromMinecraftWhenRootMissing()
{
const string json = """{"minecraft": { "version": "1.20.1", "recommendedRam": 8192 }}""";
var manifest = CurseForgeManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.IsNull(manifest.RecommendedRam);
Assert.AreEqual(8192, manifest.Minecraft?.RecommendedRam);
Assert.AreEqual(8192, manifest.RecommendedRamEffective);
}

[TestMethod]
public void MissingRequiredDefaultsToRequired()
{
const string json = """{"files":[{"projectID":1,"fileID":2}]}""";
var manifest = CurseForgeManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.IsNotNull(manifest.Files);
Assert.IsFalse(manifest.Files[0].IsOptional);
}

[TestMethod]
public void MissingOptionalFieldsStayNull()
{
const string json = """{"name":"Test"}""";
var manifest = CurseForgeManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.AreEqual("Test", manifest.Name);
Assert.IsNull(manifest.Minecraft);
Assert.IsNull(manifest.Files);
Assert.IsNull(manifest.Overrides);
Assert.IsNull(manifest.Version);
Assert.IsNull(manifest.RecommendedRam);
Assert.IsNull(manifest.RecommendedRamEffective);
}

[TestMethod]
public void ParseNullReturnsNull()
{
Assert.IsNull(CurseForgeManifest.Parse(null));
}
}
44 changes: 44 additions & 0 deletions PCL.Core.Test/Minecraft/Modpack/FakeModpackArchive.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PCL.Core.Minecraft.Modpack;

namespace PCL.Core.Test.Minecraft.Modpack;

/// <summary>
/// 内存中的 <see cref="IModpackArchiveReader"/> 实现,用于格式识别与清单解析的单元测试。
/// </summary>
internal sealed class FakeModpackArchive : IModpackArchiveReader
{
private readonly Dictionary<string, string> _entries;

public FakeModpackArchive(params KeyValuePair<string, string>[] entries)
{
_entries = entries.ToDictionary(entry => entry.Key, entry => entry.Value);
}

public FakeModpackArchive(params string[] entryNames)
{
_entries = entryNames.ToDictionary(name => name, _ => "");
}

public IEnumerable<string> EntryNames => _entries.Keys;

public bool EntryExists(string entryName)
{
return _entries.ContainsKey(entryName);
}

public string ReadEntryText(string entryName)
{
return _entries[entryName];
}

public void ExtractEntryToFile(string entryName, string destinationPath)
{
if (!_entries.TryGetValue(entryName, out var content))
return;
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath) ?? "");
File.WriteAllText(destinationPath, content);
}
}
72 changes: 72 additions & 0 deletions PCL.Core.Test/Minecraft/Modpack/McbbsManifestTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PCL.Core.Minecraft.Modpack;
using PCL.Core.Utils;

namespace PCL.Core.Test.Minecraft.Modpack;

[TestClass]
public class McbbsManifestTest
{
[TestMethod]
public void ParsesCompleteManifest()
{
const string json = """
{
"manifestType": "minecraftModpack",
"name": "示例整合包",
"version": "1.0.0",
"addons": [
{ "id": "game", "version": "1.20.1" },
{ "id": "forge", "version": "47.2.0" }
],
"launchInfo": {
"javaArgument": ["-Xmx2G", "-XX:+UseG1GC"],
"launchArgument": ["--username", "Player"]
}
}
""";
var manifest = McbbsManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.AreEqual("示例整合包", manifest.Name);
Assert.AreEqual("1.0.0", manifest.Version);
Assert.IsNotNull(manifest.Addons);
Assert.AreEqual(2, manifest.Addons.Count);
Assert.AreEqual("game", manifest.Addons[0].Id);
Assert.AreEqual("1.20.1", manifest.Addons[0].Version);
Assert.AreEqual("forge", manifest.Addons[1].Id);
Assert.AreEqual("47.2.0", manifest.Addons[1].Version);
Assert.IsNotNull(manifest.LaunchInfo);
Assert.AreEqual("-Xmx2G", manifest.LaunchInfo.JavaArgument?[0]?.ToString());
Assert.AreEqual("-XX:+UseG1GC", manifest.LaunchInfo.JavaArgument?[1]?.ToString());
Assert.AreEqual("--username", manifest.LaunchInfo.LaunchArgument?[0]?.ToString());
}

[TestMethod]
public void MissingOptionalFieldsStayNull()
{
const string json = """{"name":"Test"}""";
var manifest = McbbsManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.AreEqual("Test", manifest.Name);
Assert.IsNull(manifest.Addons);
Assert.IsNull(manifest.LaunchInfo);
Assert.IsNull(manifest.Version);
}

[TestMethod]
public void SingleStringLaunchArgumentIsPreserved()
{
// 兼容个别包把 launchInfo 写成单个字符串而不是数组
const string json = """{"launchInfo":{"javaArgument":"-Xmx2G"}}""";
var manifest = McbbsManifest.Parse(JsonCompat.ParseNode(json));
Assert.IsNotNull(manifest);
Assert.IsNotNull(manifest.LaunchInfo);
Assert.AreEqual("-Xmx2G", manifest.LaunchInfo.JavaArgument?.ToString());
}

[TestMethod]
public void ParseNullReturnsNull()
{
Assert.IsNull(McbbsManifest.Parse(null));
}
}
Loading