Skip to content

Commit e0b9462

Browse files
committed
Added tests for Interpreter and DynamicCompiler.
Implemented missing NegateExpression.
1 parent ee55fdb commit e0b9462

7 files changed

Lines changed: 136 additions & 10 deletions

File tree

ReClass.NET/AddressParser/DynamicCompiler.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,27 @@ public static Func<IProcessReader, IntPtr> CompileAddressFormula(IExpression exp
2929
).Compile();
3030
}
3131

32-
private static Expression GenerateMethodBody(IExpression operation, Expression parameter)
32+
private static Expression GenerateMethodBody(IExpression expression, Expression parameter)
3333
{
34-
Contract.Requires(operation != null);
34+
Contract.Requires(expression != null);
3535
Contract.Requires(parameter != null);
3636

37-
switch (operation)
37+
switch (expression)
3838
{
39+
case ConstantExpression constantExpression:
40+
{
41+
var convertFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.From), new[] { typeof(long) });
42+
43+
return Expression.Call(null, convertFn, Expression.Constant(constantExpression.Value));
44+
}
45+
case NegateExpression negateExpression:
46+
{
47+
var argument = GenerateMethodBody(negateExpression.Expression, parameter);
48+
49+
var negateFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.Negate), new[] { typeof(IntPtr) });
50+
51+
return Expression.Call(null, negateFn, argument);
52+
}
3953
case AddExpression addExpression:
4054
{
4155
var argument1 = GenerateMethodBody(addExpression.Lhs, parameter);
@@ -82,12 +96,6 @@ private static Expression GenerateMethodBody(IExpression operation, Expression p
8296
)
8397
);
8498
}
85-
case ConstantExpression constantExpression:
86-
{
87-
var convertFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.From), new[] { typeof(long) });
88-
89-
return Expression.Call(null, convertFn, Expression.Constant(constantExpression.Value));
90-
}
9199
case ReadMemoryExpression readMemoryExpression:
92100
{
93101
var argument = GenerateMethodBody(readMemoryExpression.Expression, parameter);
@@ -104,7 +112,7 @@ private static Expression GenerateMethodBody(IExpression operation, Expression p
104112
}
105113
}
106114

107-
throw new ArgumentException($"Unsupported operation '{operation.GetType().FullName}'.");
115+
throw new ArgumentException($"Unsupported operation '{expression.GetType().FullName}'.");
108116
}
109117

110118
private static MethodInfo GetIntPtrExtension(string name)

ReClass.NET/AddressParser/Interpreter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public IntPtr Execute(IExpression expression, IProcessReader processReader)
1616
{
1717
case ConstantExpression constantExpression:
1818
return IntPtrExtension.From(constantExpression.Value);
19+
case NegateExpression negateExpression:
20+
return Execute(negateExpression.Expression, processReader).Negate();
1921
case ModuleExpression moduleExpression:
2022
{
2123
var module = processReader.GetModuleByName(moduleExpression.Name);

ReClass.NET/Extensions/IntPtrExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ public static int Mod(this IntPtr lhs, int mod)
8181
#endif
8282
}
8383

84+
[Pure]
85+
[DebuggerStepThrough]
86+
public static IntPtr Negate(this IntPtr ptr)
87+
{
88+
#if RECLASSNET64
89+
return new IntPtr(-ptr.ToInt64());
90+
#else
91+
return new IntPtr(-ptr.ToInt32());
92+
#endif
93+
}
94+
8495
[Pure]
8596
[DebuggerStepThrough]
8697
public static bool InRange(this IntPtr address, IntPtr start, IntPtr end)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using ReClassNET.AddressParser;
7+
8+
namespace ReClass.NET_Tests.AddressParser
9+
{
10+
public class DynamicCompilerTest : ExecutorTest
11+
{
12+
protected override IExecuter CreateExecutor()
13+
{
14+
return new DynamicCompiler();
15+
}
16+
}
17+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Moq;
7+
using NFluent;
8+
using ReClassNET.AddressParser;
9+
using ReClassNET.Memory;
10+
using Xunit;
11+
12+
namespace ReClass.NET_Tests.AddressParser
13+
{
14+
public abstract class ExecutorTest
15+
{
16+
protected abstract IExecuter CreateExecutor();
17+
18+
public static IEnumerable<object[]> GetSimpleExpressionTestData() => new List<object[]>
19+
{
20+
new object[] { "0", (IntPtr)0x0 },
21+
new object[] { "0 + 0", (IntPtr)0x0 },
22+
new object[] { "+0", (IntPtr)0x0 },
23+
new object[] { "-0", (IntPtr)0x0 },
24+
new object[] { "-1", (IntPtr)(-1) },
25+
new object[] { "+0 + 0", (IntPtr)0x0 },
26+
new object[] { "-0 - 0", (IntPtr)0x0 },
27+
new object[] { "0 + 1", (IntPtr)0x1 },
28+
new object[] { "0 - 1", (IntPtr)(-1) },
29+
new object[] { "1 + 2 * 3", (IntPtr)0x7 },
30+
new object[] { "0x123 + 0x234 * 0x345", (IntPtr)0x73527 }
31+
};
32+
33+
[Theory]
34+
[MemberData(nameof(GetSimpleExpressionTestData))]
35+
public void SimpleExpressionTest(string expression, IntPtr expected)
36+
{
37+
var mock = new Mock<IProcessReader>();
38+
39+
var executor = CreateExecutor();
40+
41+
Check.That(executor.Execute(Parser.Parse(expression), mock.Object)).IsEqualTo(expected);
42+
}
43+
44+
public static IEnumerable<object[]> GetModuleExpressionTestData() => new List<object[]>
45+
{
46+
new object[] { "<test.module>", (IntPtr)0x100 },
47+
new object[] { "<test.module> + 0", (IntPtr)0x100 },
48+
new object[] { "<test.module> + 10", (IntPtr)0x110 },
49+
new object[] { "<test.module> * 2", (IntPtr)0x200 }
50+
};
51+
52+
[Theory]
53+
[MemberData(nameof(GetModuleExpressionTestData))]
54+
public void ModuleExpressionTest(string expression, IntPtr expected)
55+
{
56+
var mock = new Mock<IProcessReader>();
57+
mock.Setup(p => p.GetModuleByName("test.module"))
58+
.Returns(new Module { Start = (IntPtr)0x100 });
59+
60+
var executor = CreateExecutor();
61+
62+
Check.That(executor.Execute(Parser.Parse(expression), mock.Object)).IsEqualTo(expected);
63+
}
64+
}
65+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using ReClassNET.AddressParser;
7+
8+
namespace ReClass.NET_Tests.AddressParser
9+
{
10+
public class InterpreterTest : ExecutorTest
11+
{
12+
protected override IExecuter CreateExecutor()
13+
{
14+
return new Interpreter();
15+
}
16+
}
17+
}

ReClass.NET_Tests/ReClass.NET_Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
<Reference Include="System.Core" />
4040
</ItemGroup>
4141
<ItemGroup>
42+
<Compile Include="AddressParser\DynamicCompilerTest.cs" />
43+
<Compile Include="AddressParser\ExecutorTest.cs" />
44+
<Compile Include="AddressParser\InterpreterTest.cs" />
4245
<Compile Include="AddressParser\ParserTest.cs" />
4346
<Compile Include="AddressParser\TokenizerTest.cs" />
4447
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -50,6 +53,9 @@
5053
</ProjectReference>
5154
</ItemGroup>
5255
<ItemGroup>
56+
<PackageReference Include="Moq">
57+
<Version>4.10.1</Version>
58+
</PackageReference>
5359
<PackageReference Include="NFluent">
5460
<Version>2.5.0</Version>
5561
</PackageReference>

0 commit comments

Comments
 (0)