147 lines
5.0 KiB
C#
147 lines
5.0 KiB
C#
using Xunit;
|
|
|
|
namespace MrGameEng.Mods.Tests;
|
|
|
|
public sealed class DefDatabaseTests : IDisposable
|
|
{
|
|
private sealed class AnimalDef : Def
|
|
{
|
|
public float Speed { get; init; }
|
|
|
|
public int Legs { get; init; } = 4;
|
|
|
|
public List<string> Tags { get; init; } = [];
|
|
}
|
|
|
|
private readonly string _root = Directory.CreateTempSubdirectory("mrge-defs-tests-").FullName;
|
|
private int _modCounter;
|
|
|
|
public void Dispose() => Directory.Delete(_root, recursive: true);
|
|
|
|
/// <summary>Создаёт мод с одним файлом дефов и возвращает его (порядок загрузки = порядок создания).</summary>
|
|
private Mod WriteDefsMod(string defsJson)
|
|
{
|
|
var id = $"mod{_modCounter++:D2}";
|
|
var modDir = Path.Combine(_root, id);
|
|
Directory.CreateDirectory(Path.Combine(modDir, "Defs"));
|
|
File.WriteAllText(Path.Combine(modDir, "Defs", "animals.json"), defsJson);
|
|
return new Mod(new ModInfo { Id = id }, modDir);
|
|
}
|
|
|
|
private DefDatabase LoadAnimals(params Mod[] mods)
|
|
{
|
|
var database = new DefDatabase();
|
|
database.RegisterType<AnimalDef>("Animal");
|
|
database.Load(mods);
|
|
return database;
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_ParsesDefs_AndAllIsSortedByName()
|
|
{
|
|
var mod = WriteDefsMod(
|
|
"""
|
|
{ "type": "Animal", "defs": [
|
|
{ "defName": "Wolf", "label": "волк", "speed": 9 },
|
|
{ "defName": "Bear", "speed": 6 }
|
|
]}
|
|
"""
|
|
);
|
|
|
|
var database = LoadAnimals(mod);
|
|
|
|
Assert.Equal(["Bear", "Wolf"], database.All<AnimalDef>().Select(d => d.DefName));
|
|
Assert.Equal(9f, database.Get<AnimalDef>("Wolf").Speed);
|
|
Assert.Equal("волк", database.Get<AnimalDef>("Wolf").Label);
|
|
Assert.Equal(4, database.Get<AnimalDef>("Bear").Legs); // значение по умолчанию
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_ParentChain_MergesFields_ChildWins()
|
|
{
|
|
var mod = WriteDefsMod(
|
|
"""
|
|
{ "type": "Animal", "defs": [
|
|
{ "defName": "BaseAnimal", "abstract": true, "speed": 5, "tags": ["wild"] },
|
|
{ "defName": "Hare", "parent": "BaseAnimal", "speed": 12 },
|
|
{ "defName": "Snail", "parent": "BaseAnimal", "legs": 0, "tags": ["slow", "slimy"] }
|
|
]}
|
|
"""
|
|
);
|
|
|
|
var database = LoadAnimals(mod);
|
|
|
|
var hare = database.Get<AnimalDef>("Hare");
|
|
Assert.Equal(12f, hare.Speed); // своё поле победило
|
|
Assert.Equal(["wild"], hare.Tags); // унаследовано
|
|
var snail = database.Get<AnimalDef>("Snail");
|
|
Assert.Equal(5f, snail.Speed); // унаследовано
|
|
Assert.Equal(0, snail.Legs);
|
|
Assert.Equal(["slow", "slimy"], snail.Tags); // массив заменён целиком
|
|
Assert.False(database.TryGet<AnimalDef>("BaseAnimal", out _)); // абстрактный не эмитится
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_LaterMod_ReplacesSameDefName()
|
|
{
|
|
var core = WriteDefsMod(
|
|
"""{ "type": "Animal", "defs": [ { "defName": "Wolf", "speed": 9, "tags": ["wild"] } ] }"""
|
|
);
|
|
var patch = WriteDefsMod(
|
|
"""{ "type": "Animal", "defs": [ { "defName": "Wolf", "speed": 20 } ] }"""
|
|
);
|
|
|
|
var database = LoadAnimals(core, patch);
|
|
|
|
var wolf = database.Get<AnimalDef>("Wolf");
|
|
Assert.Equal(20f, wolf.Speed);
|
|
Assert.Empty(wolf.Tags); // полная замена, не слияние с дефом раннего мода
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_CyclicParents_Throws()
|
|
{
|
|
var mod = WriteDefsMod(
|
|
"""
|
|
{ "type": "Animal", "defs": [
|
|
{ "defName": "A", "parent": "B" },
|
|
{ "defName": "B", "parent": "A" }
|
|
]}
|
|
"""
|
|
);
|
|
|
|
var exception = Assert.Throws<InvalidDataException>(() => LoadAnimals(mod));
|
|
Assert.Contains("Cyclic", exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_UnknownParent_Throws()
|
|
{
|
|
var mod = WriteDefsMod(
|
|
"""{ "type": "Animal", "defs": [ { "defName": "X", "parent": "Ghost" } ] }"""
|
|
);
|
|
|
|
var exception = Assert.Throws<InvalidDataException>(() => LoadAnimals(mod));
|
|
Assert.Contains("Ghost", exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_UnknownDefType_ThrowsWithFileAndMod()
|
|
{
|
|
var mod = WriteDefsMod("""{ "type": "Vehicle", "defs": [] }""");
|
|
|
|
var exception = Assert.Throws<InvalidDataException>(() => LoadAnimals(mod));
|
|
Assert.Contains("Vehicle", exception.Message);
|
|
Assert.Contains(mod.Id, exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Get_UnknownDef_Throws_TryGetReturnsFalse()
|
|
{
|
|
var database = LoadAnimals(WriteDefsMod("""{ "type": "Animal", "defs": [] }"""));
|
|
|
|
Assert.Throws<KeyNotFoundException>(() => database.Get<AnimalDef>("Dodo"));
|
|
Assert.False(database.TryGet<AnimalDef>("Dodo", out _));
|
|
}
|
|
}
|