Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaTest/INetSerializableStructImplementationChecks.cs
2022-11-18 18:32:04 +02:00

102 lines
4.1 KiB
C#

using System;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Barotrauma;
using Microsoft.Xna.Framework;
using Xunit;
namespace TestProject;
public class INetSerializableStructImplementationChecks
{
private delegate bool TryFindBehaviorDelegate(Type type, out NetSerializableProperties.IReadWriteBehavior behavior);
[Fact]
public void CheckStructMemberTypes()
{
var interfaceType = typeof(INetSerializableStruct);
var types = interfaceType.Assembly.GetTypes()
.Where(t => !t.IsAbstract && !t.IsInterface && t.IsAssignableTo(interfaceType));
//private static bool TryFindBehavior(Type type, out IReadWriteBehavior behavior)
TryFindBehaviorDelegate tryFindBehavior
= typeof(NetSerializableProperties)
.GetMethod("TryFindBehavior", BindingFlags.NonPublic | BindingFlags.Static,
typeof(TryFindBehaviorDelegate).GetMethod("Invoke")!
.GetParameters().Select(p => p.ParameterType).ToArray())!
.CreateDelegate<TryFindBehaviorDelegate>();
foreach (var type in types)
{
var concreteType = type;
if (type.IsGenericType)
{
// Plug in some known good parameters to evaluate
// a concrete instance of this generic type
var paramsConstraints = type.GetGenericArguments()
.Select(p => p.GetGenericParameterConstraints())
.ToImmutableArray();
var chosenArgs = new Type[paramsConstraints.Length];
for (int i = 0; i < paramsConstraints.Length; i++)
{
var constraints = paramsConstraints[i];
bool refTypeConstraint = constraints.Any(c
=> c.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint));
bool valueTypeConstraint = constraints.Any(c
=> c.GenericParameterAttributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint));
if (refTypeConstraint && valueTypeConstraint)
{
throw new Exception($"Type \"{type.Name}\" has invalid generic constraints");
}
int rngMin = refTypeConstraint ? 3 : 0;
int rngMax = valueTypeConstraint ? 3 : 6;
chosenArgs[i] = Rand.Range(rngMin, rngMax) switch
{
0 => typeof(Vector2),
1 => typeof(Point),
2 => typeof(int),
3 => typeof(string),
4 => typeof(float[]),
5 => typeof(int[]),
var invalid => throw new Exception($"Broken RNG ranges in test, got {invalid}")
};
}
concreteType = type.MakeGenericType(chosenArgs);
}
var members = NetSerializableProperties.GetPropertiesAndFields(concreteType);
foreach (var member in members)
{
void checkType(Type typeBeingChecked)
{
Assert.True(tryFindBehavior(typeBeingChecked, out _), $"{concreteType}.{member.Name} of type {member.Type} is unsupported in {nameof(INetSerializableStruct)}");
Type? nestedType = null;
if (typeBeingChecked.IsGenericType)
{
nestedType = typeBeingChecked.GetGenericArguments()[0];
}
else if (typeBeingChecked.IsArray)
{
nestedType = typeBeingChecked.GetElementType();
}
if (nestedType != null)
{
checkType(nestedType);
}
}
checkType(member.Type);
}
}
}
}