using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Reflection.Emit; using FluentAssertions; using HarmonyLib; using NitroxModel.Helper; using NitroxPatcher.PatternMatching; namespace NitroxTest.Patcher { public static class PatchTestHelper { public static List GenerateDummyInstructions(int count) { List instructions = new List(); for (int i = 0; i < count; i++) { instructions.Add(new CodeInstruction(OpCodes.Nop)); } return instructions; } public static ReadOnlyCollection GetInstructionsFromMethod(DynamicMethod targetMethod) { Validate.NotNull(targetMethod); return GetInstructionsFromIL(GetILInstructions(targetMethod)); } public static ReadOnlyCollection GetInstructionsFromMethod(MethodInfo targetMethod) { Validate.NotNull(targetMethod); return GetInstructionsFromIL(GetILInstructions(targetMethod)); } public static IEnumerable> GetILInstructions(MethodInfo method) { return PatchProcessor.ReadMethodBody(method, method.GetILGenerator()); } public static IEnumerable> GetILInstructions(DynamicMethod method) { return PatchProcessor.ReadMethodBody(method, method.GetILGenerator()); } public static ILGenerator GetILGenerator(this MethodInfo method) { return new DynamicMethod(method.Name, method.ReturnType, method.GetParameters().Types()).GetILGenerator(); } public static void TestPattern(MethodInfo targetMethod, InstructionsPattern pattern, out IEnumerable originalIl, out IEnumerable transformedIl) { bool shouldHappen = false; originalIl = PatchProcessor.GetCurrentInstructions(targetMethod); transformedIl = originalIl .Transform(pattern, (_, _) => { shouldHappen = true; }) .ToArray(); // Required, otherwise nothing happens. shouldHappen.Should().BeTrue(); } /// /// Clones the instructions so that the returned instructions are not the same reference. /// /// /// Useful for testing code differences before and after a Harmony transpiler. /// public static List Clone(this IEnumerable instructions) { return new List(instructions.Select(il => new CodeInstruction(il))); } private static ReadOnlyCollection GetInstructionsFromIL(IEnumerable> il) { List result = new List(); foreach (KeyValuePair instruction in il) { result.Add(new CodeInstruction(instruction.Key, instruction.Value)); } return result.AsReadOnly(); } } }