171 lines
7.1 KiB
C#
171 lines
7.1 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using System.Reflection;
|
|
using Pcg;
|
|
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Static;
|
|
using PkmnLib.Static.Species;
|
|
using PkmnLib.Static.Utils;
|
|
using PkmnLib.Tests.Integration;
|
|
|
|
namespace PkmnLib.Tests.Static;
|
|
|
|
public class DeepCloneTests
|
|
{
|
|
[SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "ValueParameterNotUsed")]
|
|
private class TestClass : IDeepCloneable
|
|
{
|
|
public int Value { get; set; }
|
|
public int Field;
|
|
private int PrivateValue { get; set; }
|
|
#pragma warning disable CS0169 // Field is never used
|
|
private int _privateField;
|
|
#pragma warning restore CS0169 // Field is never used
|
|
private int OnlyGetter => 0;
|
|
|
|
private int OnlySetter
|
|
{
|
|
set { }
|
|
}
|
|
|
|
public TestClass? Self { get; set; }
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepCloneTestProperty()
|
|
{
|
|
var obj = new TestClass { Value = 1 };
|
|
var clone = obj.DeepClone();
|
|
await Assert.That(clone).IsNotEqualTo(obj);
|
|
await Assert.That(clone.Value).IsEqualTo(1);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepCloneTestField()
|
|
{
|
|
var obj = new TestClass { Field = 1 };
|
|
var clone = obj.DeepClone();
|
|
await Assert.That(clone).IsNotEqualTo(obj);
|
|
await Assert.That(clone.Field).IsEqualTo(1);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepCloneTestPrivateProperty()
|
|
{
|
|
var obj = new TestClass();
|
|
obj.GetType().GetProperty("PrivateValue", BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(obj, 1);
|
|
var clone = obj.DeepClone();
|
|
await Assert.That(clone).IsNotEqualTo(obj);
|
|
var clonePrivateValue =
|
|
clone.GetType().GetProperty("PrivateValue", BindingFlags.NonPublic | BindingFlags.Instance)!
|
|
.GetValue(clone);
|
|
await Assert.That(clonePrivateValue).IsEqualTo(1);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepCloneTestPrivateField()
|
|
{
|
|
var obj = new TestClass();
|
|
obj.GetType().GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(obj, 1);
|
|
var clone = obj.DeepClone();
|
|
await Assert.That(clone).IsNotEqualTo(obj);
|
|
var clonePrivateField =
|
|
clone.GetType().GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(clone);
|
|
await Assert.That(clonePrivateField).IsEqualTo(1);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepCloneTestRecursion()
|
|
{
|
|
var obj = new TestClass();
|
|
obj.Self = obj;
|
|
var clone = obj.DeepClone();
|
|
await Assert.That(clone).IsNotEqualTo(obj);
|
|
await Assert.That(clone.Self).IsNotEqualTo(obj);
|
|
await Assert.That(clone.Self).IsEqualTo(clone);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepCloneIntegrationTestsBattle()
|
|
{
|
|
var library = LibraryHelpers.LoadLibrary();
|
|
await Assert.That(library.StaticLibrary.Species.TryGet("bulbasaur", out var bulbasaur)).IsTrue();
|
|
await Assert.That(library.StaticLibrary.Species.TryGet("charmander", out var charmander)).IsTrue();
|
|
var party1 = new PokemonParty(6);
|
|
party1.SwapInto(new PokemonImpl(library, bulbasaur!, bulbasaur!.GetDefaultForm(), new AbilityIndex
|
|
{
|
|
IsHidden = false,
|
|
Index = 0,
|
|
}, 50, 0, Gender.Male, 0, "hardy"), 0);
|
|
var party2 = new PokemonParty(6);
|
|
party2.SwapInto(new PokemonImpl(library, charmander!, charmander!.GetDefaultForm(), new AbilityIndex
|
|
{
|
|
IsHidden = false,
|
|
Index = 0,
|
|
}, 50, 0, Gender.Male, 0, "hardy"), 0);
|
|
|
|
var parties = new[]
|
|
{
|
|
new BattlePartyImpl(party1, [new ResponsibleIndex(0, 0)]),
|
|
new BattlePartyImpl(party2, [new ResponsibleIndex(1, 0)]),
|
|
};
|
|
var battle = new BattleImpl(library, parties, false, 2, 3, 0);
|
|
battle.Sides[0].SwapPokemon(0, party1[0]);
|
|
battle.Sides[1].SwapPokemon(0, party2[0]);
|
|
party1[0]!.ChangeStatBoost(Statistic.Defense, 2, true);
|
|
await Assert.That(party1[0]!.StatBoost.Defense).IsEqualTo((sbyte)2);
|
|
|
|
var clone = battle.DeepClone();
|
|
await Assert.That(clone).IsNotEqualTo(battle);
|
|
await Assert.That(clone.Sides[0].Pokemon[0]).IsNotEqualTo(battle.Sides[0].Pokemon[0]);
|
|
await Assert.That(clone.Sides[1].Pokemon[0]).IsNotEqualTo(battle.Sides[1].Pokemon[0]);
|
|
|
|
await Assert.That(clone.Sides[0].Pokemon[0]!.Species).IsEqualTo(battle.Sides[0].Pokemon[0]!.Species);
|
|
await Assert.That(clone.Sides[1].Pokemon[0]!.Species).IsEqualTo(battle.Sides[1].Pokemon[0]!.Species);
|
|
|
|
await Assert.That(clone.Library).IsEqualTo(battle.Library);
|
|
|
|
var pokemon = clone.Sides[0].Pokemon[0]!;
|
|
await Assert.That(pokemon.BattleData).IsNotNull();
|
|
await Assert.That(pokemon.BattleData).IsNotEqualTo(battle.Sides[0].Pokemon[0]!.BattleData);
|
|
await Assert.That(pokemon.BattleData!.Battle).IsEqualTo(clone);
|
|
await Assert.That(pokemon.BattleData!.SeenOpponents).Contains(clone.Sides[1].Pokemon[0]!);
|
|
await Assert.That(pokemon.BattleData!.SeenOpponents).DoesNotContain(battle.Sides[1].Pokemon[0]!);
|
|
await Assert.That(pokemon.StatBoost.Defense).IsEqualTo((sbyte)2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// We have custom handling for the random number generator within the deep cloning handling. We need to ensure that
|
|
/// the random number generator is cloned correctly, so that the state of the random number generator is the same
|
|
/// in the clone as it is in the original, while still being a different instance.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task DeepCloneIntegrationTestsBattleRandom()
|
|
{
|
|
var battleRandom = new BattleRandomImpl(0);
|
|
battleRandom.GetInt();
|
|
var clone = battleRandom.DeepClone();
|
|
|
|
await Assert.That(clone).IsNotEqualTo(battleRandom);
|
|
// We hack out way into the private fields of the random number generator to ensure that the state is the same
|
|
// in the clone as it is in the original. None of this is part of the public API, so we use reflection to
|
|
// access the private fields.
|
|
var pcgRandomField = typeof(RandomImpl).GetField("_random", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
var pcgRandom = (PcgRandom)pcgRandomField.GetValue(battleRandom)!;
|
|
var clonePcgRandom = (PcgRandom)pcgRandomField.GetValue(clone)!;
|
|
await Assert.That(clonePcgRandom).IsNotEqualTo(pcgRandom);
|
|
|
|
var pcgRngField = typeof(PcgRandom).GetField("_rng", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
var pcgRng = pcgRngField.GetValue(pcgRandom)!;
|
|
var clonePcgRng = pcgRngField.GetValue(clonePcgRandom)!;
|
|
|
|
var pcgStateField = pcgRng.GetType().GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
var pcgState = pcgStateField.GetValue(pcgRng);
|
|
var clonePcgState = pcgStateField.GetValue(clonePcgRng);
|
|
|
|
await Assert.That(clonePcgState).IsEqualTo(pcgState);
|
|
|
|
var randomNumber = battleRandom.GetInt();
|
|
var cloneRandomNumber = clone.GetInt();
|
|
await Assert.That(cloneRandomNumber).IsEqualTo(randomNumber);
|
|
}
|
|
} |