geometry-tower-defense/Assets/Tests/EditMode/PlayerInventoryTowerAssembl...

420 lines
16 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using GameFramework.DataTable;
using GeometryTD.CustomComponent;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using NUnit.Framework;
using UnityEngine;
namespace GeometryTD.Tests.EditMode
{
public sealed class PlayerInventoryTowerAssemblyServiceTests
{
private GameObject _inventoryObject;
private PlayerInventoryComponent _originalPlayerInventory;
[TearDown]
public void TearDown()
{
SetStaticPlayerInventory(_originalPlayerInventory);
if (_inventoryObject != null)
{
UnityEngine.Object.DestroyImmediate(_inventoryObject);
_inventoryObject = null;
}
}
[Test]
public void TryAssembleTower_Builds_Expected_Rarity_Stats_And_Tags()
{
PlayerInventoryComponent inventoryComponent = CreateBoundPlayerInventory(new BackpackInventoryData
{
MuzzleComponents =
{
new MuzzleCompItemData
{
InstanceId = 10001,
ConfigId = 1,
Name = "测试枪口",
Rarity = RarityType.Green,
AttackDamage = new[] { 10, 20, 30, 40, 50 },
DamageRandomRate = 0.15f,
AttackMethodType = AttackMethodType.NormalBullet,
Tags = new[] { TagType.Fire }
}
},
BearingComponents =
{
new BearingCompItemData
{
InstanceId = 20001,
ConfigId = 1,
Name = "测试轴承",
Rarity = RarityType.Blue,
RotateSpeed = new[] { 1f, 2f, 3f, 4f, 5f },
AttackRange = new[] { 10f, 20f, 30f, 40f, 50f },
Tags = new[] { TagType.Ice }
}
},
BaseComponents =
{
new BaseCompItemData
{
InstanceId = 30001,
ConfigId = 1,
Name = "测试底座",
Rarity = RarityType.Purple,
AttackSpeed = new[] { 2f, 4f, 6f, 8f, 10f },
AttackPropertyType = AttackPropertyType.Fire,
Tags = new[] { TagType.Fire }
}
}
});
InjectAssemblyTables(
inventoryComponent,
new FakeDataTable<DRMuzzleComp>(CreateMuzzleRow()),
new FakeDataTable<DRBearingComp>(CreateBearingRow()),
new FakeDataTable<DRBaseComp>(CreateBaseRow()));
bool assembled = inventoryComponent.TryAssembleTower(10001, 20001, 30001, out TowerItemData tower);
BackpackInventoryData committedInventory = inventoryComponent.GetInventorySnapshot();
Assert.That(assembled, Is.True);
Assert.That(tower, Is.Not.Null);
Assert.That(tower.Rarity, Is.EqualTo(RarityType.Blue));
Assert.That(tower.Stats.AttackDamage, Is.EqualTo(new[] { 20, 23, 26, 29, 32 }));
Assert.That(tower.Stats.RotateSpeed, Is.EqualTo(new[] { 3f, 3.5f, 4f, 4.5f, 5f }));
Assert.That(tower.Stats.AttackRange, Is.EqualTo(new[] { 30f, 31f, 32f, 33f, 34f }));
Assert.That(tower.Stats.AttackSpeed, Is.EqualTo(new[] { 8f, 7.75f, 7.5f, 7.25f, 7f }));
Assert.That(tower.Stats.DamageRandomRate, Is.EqualTo(0.15f));
Assert.That(tower.Stats.AttackMethodType, Is.EqualTo(AttackMethodType.NormalBullet));
Assert.That(tower.Stats.AttackPropertyType, Is.EqualTo(AttackPropertyType.Fire));
Assert.That(tower.Stats.Tags, Is.EqualTo(new[] { TagType.Fire, TagType.Ice }));
Assert.That(tower.Stats.TagRuntimes, Has.Length.EqualTo(2));
Assert.That(tower.Stats.TagRuntimes[0].TagType, Is.EqualTo(TagType.Fire));
Assert.That(tower.Stats.TagRuntimes[0].TotalStack, Is.EqualTo(2));
Assert.That(tower.Stats.TagRuntimes[1].TagType, Is.EqualTo(TagType.Ice));
Assert.That(tower.Stats.TagRuntimes[1].TotalStack, Is.EqualTo(1));
Assert.That(committedInventory.Towers, Has.Count.EqualTo(1));
Assert.That(committedInventory.MuzzleComponents[0].IsAssembledIntoTower, Is.True);
Assert.That(committedInventory.BearingComponents[0].IsAssembledIntoTower, Is.True);
Assert.That(committedInventory.BaseComponents[0].IsAssembledIntoTower, Is.True);
}
[Test]
public void TryAssembleTower_Returns_False_When_Required_Config_Row_Is_Missing()
{
PlayerInventoryComponent inventoryComponent = CreateBoundPlayerInventory(new BackpackInventoryData
{
MuzzleComponents =
{
new MuzzleCompItemData
{
InstanceId = 10001,
ConfigId = 1,
Rarity = RarityType.White,
AttackDamage = new[] { 10, 20, 30, 40, 50 },
AttackMethodType = AttackMethodType.NormalBullet
}
},
BearingComponents =
{
new BearingCompItemData
{
InstanceId = 20001,
ConfigId = 1,
Rarity = RarityType.White,
RotateSpeed = new[] { 1f, 2f, 3f, 4f, 5f },
AttackRange = new[] { 1f, 2f, 3f, 4f, 5f }
}
},
BaseComponents =
{
new BaseCompItemData
{
InstanceId = 30001,
ConfigId = 999,
Rarity = RarityType.White,
AttackSpeed = new[] { 1f, 2f, 3f, 4f, 5f },
AttackPropertyType = AttackPropertyType.Physics
}
}
});
InjectAssemblyTables(
inventoryComponent,
new FakeDataTable<DRMuzzleComp>(CreateMuzzleRow()),
new FakeDataTable<DRBearingComp>(CreateBearingRow()),
new FakeDataTable<DRBaseComp>(CreateBaseRow()));
bool assembled = inventoryComponent.TryAssembleTower(10001, 20001, 30001, out TowerItemData tower);
BackpackInventoryData committedInventory = inventoryComponent.GetInventorySnapshot();
Assert.That(assembled, Is.False);
Assert.That(tower, Is.Null);
Assert.That(committedInventory.Towers, Has.Count.EqualTo(0));
Assert.That(committedInventory.MuzzleComponents[0].IsAssembledIntoTower, Is.False);
Assert.That(committedInventory.BearingComponents[0].IsAssembledIntoTower, Is.False);
Assert.That(committedInventory.BaseComponents[0].IsAssembledIntoTower, Is.False);
}
private PlayerInventoryComponent CreateBoundPlayerInventory(BackpackInventoryData inventory)
{
_originalPlayerInventory = GameEntry.PlayerInventory;
_inventoryObject = new GameObject("TestPlayerInventory");
PlayerInventoryComponent inventoryComponent = _inventoryObject.AddComponent<PlayerInventoryComponent>();
SetStaticPlayerInventory(inventoryComponent);
inventoryComponent.ReplaceInventorySnapshot(inventory);
return inventoryComponent;
}
private static void SetStaticPlayerInventory(PlayerInventoryComponent inventoryComponent)
{
FieldInfo backingField = typeof(GameEntry).GetField(
"<PlayerInventory>k__BackingField",
BindingFlags.Static | BindingFlags.NonPublic);
Assert.That(backingField, Is.Not.Null);
backingField.SetValue(null, inventoryComponent);
}
private static void InjectAssemblyTables(
PlayerInventoryComponent inventoryComponent,
IDataTable<DRMuzzleComp> muzzleTable,
IDataTable<DRBearingComp> bearingTable,
IDataTable<DRBaseComp> baseTable)
{
FieldInfo serviceField = typeof(PlayerInventoryComponent).GetField(
"_towerAssemblyService",
BindingFlags.Instance | BindingFlags.NonPublic);
Assert.That(serviceField, Is.Not.Null);
object assemblyService = serviceField.GetValue(inventoryComponent);
Assert.That(assemblyService, Is.Not.Null);
SetPrivateField(assemblyService, "_drMuzzleComp", muzzleTable);
SetPrivateField(assemblyService, "_drBearingComp", bearingTable);
SetPrivateField(assemblyService, "_drBaseComp", baseTable);
}
private static void SetPrivateField(object instance, string fieldName, object value)
{
FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
Assert.That(field, Is.Not.Null);
field.SetValue(instance, value);
}
private static DRMuzzleComp CreateMuzzleRow()
{
DRMuzzleComp row = new DRMuzzleComp();
Assert.That(row.ParseDataRow("\t1\t\t测试枪口\t[10,20,30,40,50]\t3\t0.15\tNormalBullet\t\t[Fire]", null), Is.True);
return row;
}
private static DRBearingComp CreateBearingRow()
{
DRBearingComp row = new DRBearingComp();
Assert.That(row.ParseDataRow("\t1\t\t测试轴承\t[1,2,3,4,5]\t0.5\t[10,20,30,40,50]\t1\t\t[Ice]", null), Is.True);
return row;
}
private static DRBaseComp CreateBaseRow()
{
DRBaseComp row = new DRBaseComp();
Assert.That(row.ParseDataRow("\t1\t\t测试底座\t[2,4,6,8,10]\t-0.25\tFire\t\t[Fire]", null), Is.True);
return row;
}
private sealed class FakeDataTable<TRow> : IDataTable<TRow> where TRow : class, IDataRow
{
private readonly Dictionary<int, TRow> _rowsById = new();
public FakeDataTable(params TRow[] rows)
{
if (rows != null)
{
for (int i = 0; i < rows.Length; i++)
{
TRow row = rows[i];
if (row != null)
{
_rowsById[row.Id] = row;
}
}
}
}
public string Name => typeof(TRow).Name;
public string FullName => typeof(TRow).FullName;
public Type Type => typeof(TRow);
public int Count => _rowsById.Count;
public TRow this[int id] => GetDataRow(id);
public TRow MinIdDataRow => _rowsById.Count <= 0 ? null : GetDataRow(GetOrderedIds()[0]);
public TRow MaxIdDataRow => _rowsById.Count <= 0 ? null : GetDataRow(GetOrderedIds()[^1]);
public bool HasDataRow(int id)
{
return _rowsById.ContainsKey(id);
}
public bool HasDataRow(Predicate<TRow> condition)
{
return GetDataRow(condition) != null;
}
public TRow GetDataRow(int id)
{
return _rowsById.TryGetValue(id, out TRow row) ? row : null;
}
public TRow GetDataRow(Predicate<TRow> condition)
{
if (condition == null)
{
return null;
}
foreach (TRow row in _rowsById.Values)
{
if (row != null && condition(row))
{
return row;
}
}
return null;
}
public TRow[] GetDataRows(Predicate<TRow> condition)
{
List<TRow> results = new();
GetDataRows(condition, results);
return results.ToArray();
}
public void GetDataRows(Predicate<TRow> condition, List<TRow> results)
{
results?.Clear();
if (condition == null || results == null)
{
return;
}
foreach (TRow row in _rowsById.Values)
{
if (row != null && condition(row))
{
results.Add(row);
}
}
}
public TRow[] GetDataRows(Comparison<TRow> comparison)
{
List<TRow> results = new();
GetDataRows(comparison, results);
return results.ToArray();
}
public void GetDataRows(Comparison<TRow> comparison, List<TRow> results)
{
results?.Clear();
if (results == null)
{
return;
}
results.AddRange(_rowsById.Values);
if (comparison != null)
{
results.Sort(comparison);
}
}
public TRow[] GetDataRows(Predicate<TRow> condition, Comparison<TRow> comparison)
{
List<TRow> results = new();
GetDataRows(condition, comparison, results);
return results.ToArray();
}
public void GetDataRows(Predicate<TRow> condition, Comparison<TRow> comparison, List<TRow> results)
{
GetDataRows(condition, results);
if (results != null && comparison != null)
{
results.Sort(comparison);
}
}
public TRow[] GetAllDataRows()
{
List<TRow> results = new();
GetAllDataRows(results);
return results.ToArray();
}
public void GetAllDataRows(List<TRow> results)
{
results?.Clear();
if (results == null)
{
return;
}
foreach (int id in GetOrderedIds())
{
results.Add(_rowsById[id]);
}
}
public bool AddDataRow(string dataRowString, object userData)
{
throw new NotSupportedException();
}
public bool AddDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
{
throw new NotSupportedException();
}
public bool RemoveDataRow(int id)
{
return _rowsById.Remove(id);
}
public void RemoveAllDataRows()
{
_rowsById.Clear();
}
public IEnumerator<TRow> GetEnumerator()
{
foreach (int id in GetOrderedIds())
{
yield return _rowsById[id];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private int[] GetOrderedIds()
{
int[] ids = new int[_rowsById.Count];
_rowsById.Keys.CopyTo(ids, 0);
Array.Sort(ids);
return ids;
}
}
}
}