Skip to content

Commit 5590377

Browse files
authored
TestEngine: Some fixes (#969)
* Some fixes * Update TestEngine.cs * Update TestBase.cs * Update TestEngine.cs * Add id to SmartContract storage * Update TestEngine.cs * Update TestEngine.cs * Allow to use pointers * Update * Testing Syscall * Update src/Neo.SmartContract.Testing/TestEngine.cs
1 parent 37c79b8 commit 5590377

File tree

20 files changed

+282
-41
lines changed

20 files changed

+282
-41
lines changed

src/Neo.Compiler.CSharp/CompilationEngine.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ public Compilation GetCompilation(string csproj)
249249
if (!remove.Contains("*.cs"))
250250
{
251251
var obj = Path.Combine(folder, "obj");
252-
var binSc = Path.Combine(Path.Combine(folder, "bin"), "sc");
252+
var binSc = Path.Combine(folder, "bin");
253253
foreach (var entry in Directory.EnumerateFiles(folder, "*.cs", SearchOption.AllDirectories)
254254
.Where(p => !p.StartsWith(obj) && !p.StartsWith(binSc))
255255
.Select(u => u))

src/Neo.Compiler.CSharp/CompilationOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public enum OptimizationType : byte
3232
public OptimizationType Optimize { get; set; } = OptimizationType.Basic;
3333
public bool Checked { get; set; }
3434
public bool NoInline { get; set; }
35-
public byte AddressVersion { get; set; }
35+
public byte AddressVersion { get; set; } = 0x35;
3636
public string? BaseName { get; set; }
3737

3838
private CSharpParseOptions? parseOptions = null;

src/Neo.SmartContract.Testing/Coverage/CoveredCollection.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ public CoveredCollection(params CoverageBase[] entries)
6161
/// <returns>Coverage dump</returns>
6262
public override string Dump(DumpFormat format = DumpFormat.Console)
6363
{
64-
switch (format)
64+
return format switch
6565
{
66-
case DumpFormat.Console: return new ConsoleFormat(GetEntries()).Dump();
67-
case DumpFormat.Html: return new IntructionHtmlFormat(GetEntries()).Dump();
68-
default: throw new NotImplementedException();
69-
}
66+
DumpFormat.Console => new ConsoleFormat(GetEntries()).Dump(),
67+
DumpFormat.Html => new IntructionHtmlFormat(GetEntries()).Dump(),
68+
_ => throw new NotImplementedException(),
69+
};
7070
}
7171

7272
/// <summary>

src/Neo.SmartContract.Testing/Coverage/CoveredContract.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,12 @@ public void Join(CoverageBase? coverage)
292292
/// <returns>Coverage dump</returns>
293293
public override string Dump(DumpFormat format = DumpFormat.Console)
294294
{
295-
switch (format)
295+
return format switch
296296
{
297-
case DumpFormat.Console: return new ConsoleFormat(this).Dump();
298-
case DumpFormat.Html: return new IntructionHtmlFormat(this).Dump();
299-
default: throw new NotImplementedException();
300-
}
297+
DumpFormat.Console => new ConsoleFormat(this).Dump(),
298+
DumpFormat.Html => new IntructionHtmlFormat(this).Dump(),
299+
_ => throw new NotImplementedException(),
300+
};
301301
}
302302

303303
/// <summary>

src/Neo.SmartContract.Testing/Coverage/CoveredMethod.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ public CoveredMethod(CoveredContract contract, ContractMethodDescriptor method,
6161
/// <returns>Coverage dump</returns>
6262
public override string Dump(DumpFormat format = DumpFormat.Console)
6363
{
64-
switch (format)
64+
return format switch
6565
{
66-
case DumpFormat.Console: return new ConsoleFormat(Contract, m => ReferenceEquals(m, this)).Dump();
67-
case DumpFormat.Html: return new IntructionHtmlFormat(Contract, m => ReferenceEquals(m, this)).Dump();
68-
default: throw new NotImplementedException();
69-
}
66+
DumpFormat.Console => new ConsoleFormat(Contract, m => ReferenceEquals(m, this)).Dump(),
67+
DumpFormat.Html => new IntructionHtmlFormat(Contract, m => ReferenceEquals(m, this)).Dump(),
68+
_ => throw new NotImplementedException(),
69+
};
7070
}
7171

7272
public override string ToString() => Method.ToString();

src/Neo.SmartContract.Testing/Coverage/Formats/ConsoleFormat.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public partial class ConsoleFormat : CoverageFormatBase
1919
/// <param name="filter">Method Filter</param>
2020
public ConsoleFormat(CoveredContract contract, Func<CoveredMethod, bool>? filter = null)
2121
{
22-
Entries = new (CoveredContract, Func<CoveredMethod, bool>?)[] { (contract, filter) };
22+
Entries = new[] { (contract, filter) };
2323
}
2424

2525
/// <summary>
@@ -69,13 +69,13 @@ private void WriteReport(StreamWriter writer)
6969
max[2] = Math.Max(coverLines.Length, max[2]);
7070
}
7171

72-
writer.WriteLine($"┌-{"─".PadLeft(max[0], '─')}-┬-{"─".PadLeft(max[1], '─')}-┬-{"─".PadLeft(max[1], '─')}-┐");
73-
writer.WriteLine($"│ {string.Format($"{{0,-{max[0]}}}", "Method", max[0])}{string.Format($"{{0,{max[1]}}}", "Line ", max[1])}{string.Format($"{{0,{max[2]}}}", "Branch", max[1])} │");
74-
writer.WriteLine($"├-{"─".PadLeft(max[0], '─')}-┼-{"─".PadLeft(max[1], '─')}-┼-{"─".PadLeft(max[1], '─')}-┤");
72+
writer.WriteLine($"┌-{"─".PadLeft(max[0], '─')}-┬-{"─".PadLeft(max[1], '─')}-┬-{"─".PadLeft(max[2], '─')}-┐");
73+
writer.WriteLine($"│ {string.Format($"{{0,-{max[0]}}}", "Method", max[0])}{string.Format($"{{0,{max[1]}}}", "Line ", max[1])}{string.Format($"{{0,{max[2]}}}", "Branch", max[2])} │");
74+
writer.WriteLine($"├-{"─".PadLeft(max[0], '─')}-┼-{"─".PadLeft(max[1], '─')}-┼-{"─".PadLeft(max[2], '─')}-┤");
7575

7676
foreach (var print in rows)
7777
{
78-
writer.WriteLine($"│ {string.Format($"{{0,-{max[0]}}}", print[0], max[0])}{string.Format($"{{0,{max[1]}}}", print[1], max[1])}{string.Format($"{{0,{max[1]}}}", print[2], max[2])} │");
78+
writer.WriteLine($"│ {string.Format($"{{0,-{max[0]}}}", print[0], max[0])}{string.Format($"{{0,{max[1]}}}", print[1], max[1])}{string.Format($"{{0,{max[2]}}}", print[2], max[2])} │");
7979
}
8080

8181
writer.WriteLine($"└-{"─".PadLeft(max[0], '─')}-┴-{"─".PadLeft(max[1], '─')}-┴-{"─".PadLeft(max[2], '─')}-┘");

src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using Neo.IO;
2-
using Neo.Json;
32
using Neo.SmartContract.Manifest;
4-
using Neo.SmartContract.Testing.Coverage;
53
using Neo.SmartContract.Testing.TestingStandards;
64
using System;
75
using System.Collections.Generic;
@@ -58,6 +56,7 @@ public static string GetArtifactsSource(this ContractManifest manifest, string?
5856
if (manifest.IsVerificable()) inheritance.Add(typeof(IVerificable));
5957

6058
sourceCode.WriteLine("using Neo.Cryptography.ECC;");
59+
sourceCode.WriteLine("using System;");
6160
sourceCode.WriteLine("using System.Collections.Generic;");
6261
sourceCode.WriteLine("using System.ComponentModel;");
6362
sourceCode.WriteLine("using System.Numerics;");
@@ -180,6 +179,7 @@ public static string GetArtifactsSource(this ContractManifest manifest, string?
180179
private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor getter, ContractMethodDescriptor? setter)[] properties)
181180
ProcessAbiMethods(ContractMethodDescriptor[] methods)
182181
{
182+
HashSet<string> propertyNames = new();
183183
List<ContractMethodDescriptor> methodList = new(methods);
184184
List<(ContractMethodDescriptor, ContractMethodDescriptor?)> properties = new();
185185

@@ -199,6 +199,13 @@ private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor ge
199199
u.ReturnType == ContractParameterType.Void
200200
) : null;
201201

202+
// Avoid property repetition
203+
204+
var propertyName = GetPropertyName(getter);
205+
if (!propertyNames.Add(propertyName)) continue;
206+
207+
// Add property and remove method
208+
202209
properties.Add((getter, setter));
203210
methodList.Remove(getter);
204211

@@ -211,6 +218,11 @@ private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor ge
211218
return (methodList.ToArray(), properties.ToArray());
212219
}
213220

221+
private static string GetPropertyName(ContractMethodDescriptor getter)
222+
{
223+
return TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name));
224+
}
225+
214226
/// <summary>
215227
/// Create source code from event
216228
/// </summary>
@@ -296,7 +308,7 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev,
296308
/// <returns>Source</returns>
297309
private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor getter, ContractMethodDescriptor? setter)
298310
{
299-
var propertyName = TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name));
311+
var propertyName = GetPropertyName(getter);
300312
var getset = setter is not null ? $"{{ [DisplayName(\"{getter.Name}\")] get; [DisplayName(\"{setter.Name}\")] set; }}" : $"{{ [DisplayName(\"{getter.Name}\")] get; }}";
301313

302314
var builder = new StringBuilder();

src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using Akka.Util;
21
using Neo.Cryptography.ECC;
32
using Neo.SmartContract.Testing.Attributes;
43
using Neo.VM.Types;
@@ -50,6 +49,7 @@ public static class TestExtensions
5049

5150
return type switch
5251
{
52+
_ when type == stackItem.GetType() => stackItem,
5353
_ when type == typeof(object) => stackItem,
5454
_ when type == typeof(string) => Utility.StrictUTF8.GetString(stackItem.GetSpan()),
5555
_ when type == typeof(byte[]) => stackItem.GetSpan().ToArray(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Neo.Cryptography.ECC;
2+
3+
namespace Neo.SmartContract.Testing.InvalidTypes
4+
{
5+
public class InvalidECPoint
6+
{
7+
/// <summary>
8+
/// Null ECPoint
9+
/// </summary>
10+
public static readonly ECPoint? Null = null;
11+
12+
/// <summary>
13+
/// This will be an invalid ECPoint (ByteString)
14+
/// </summary>
15+
public static readonly ECPoint InvalidLength = new();
16+
17+
/// <summary>
18+
/// This will be an invalid ECPoint (Integer)
19+
/// </summary>
20+
public static readonly ECPoint InvalidType = new();
21+
}
22+
}

src/Neo.SmartContract.Testing/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ And for read and write, we have:
8484
- **Gas**: Sets the gas execution limit for contract calls. Sets the `NetworkFee` of the `Transaction` object.
8585
- **EnableCoverageCapture**: Enables or disables the coverage capture.
8686
- **Trigger**: The trigger of the execution.
87+
- **CallFlags**: Define the `CallFlags` for the mocked function, `All` by default.
8788
- **OnGetEntryScriptHash**: This feature makes it easy to change the EntryScriptHash.
8889
- **OnGetCallingScriptHash**: This feature makes it easy to change the CallingScriptHash.
8990

src/Neo.SmartContract.Testing/SmartContract.cs

+54-11
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,30 @@ internal StackItem Invoke(string methodName, params object[] args)
5353
{
5454
// Compose script
5555

56+
TestingSyscall? dynArgument = null;
5657
using ScriptBuilder script = new();
5758

59+
ConvertArgs(script, args, ref dynArgument);
60+
61+
script.EmitPush(Engine.CallFlags);
62+
script.EmitPush(methodName);
63+
script.EmitPush(Hash);
64+
script.EmitSysCall(ApplicationEngine.System_Contract_Call);
65+
66+
// Execute
67+
68+
return Engine.Execute(script.ToArray(), 0, dynArgument is null ? null : engine => ConfigureEngine(engine, dynArgument));
69+
}
70+
71+
private void ConfigureEngine(ApplicationEngine engine, TestingSyscall testingSyscall)
72+
{
73+
if (engine is not TestingApplicationEngine testEngine) throw new InvalidOperationException();
74+
75+
testEngine.TestingSyscall = testingSyscall;
76+
}
77+
78+
private void ConvertArgs(ScriptBuilder script, object[] args, ref TestingSyscall? testingSyscall)
79+
{
5880
if (args is null || args.Length == 0)
5981
script.Emit(OpCode.NEWARRAY0);
6082
else
@@ -63,31 +85,52 @@ internal StackItem Invoke(string methodName, params object[] args)
6385
{
6486
var arg = args[i];
6587

88+
if (arg is object[] arg2)
89+
{
90+
ConvertArgs(script, arg2, ref testingSyscall);
91+
continue;
92+
}
93+
else if (arg is IEnumerable<object> argEnumerable)
94+
{
95+
ConvertArgs(script, argEnumerable.ToArray(), ref testingSyscall);
96+
continue;
97+
}
98+
6699
if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.InvalidLength) ||
67-
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidLength))
100+
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidLength) ||
101+
ReferenceEquals(arg, InvalidTypes.InvalidECPoint.InvalidLength))
68102
{
69103
arg = System.Array.Empty<byte>();
70104
}
71105
else if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.InvalidType) ||
72-
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidType))
106+
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidType) ||
107+
ReferenceEquals(arg, InvalidTypes.InvalidECPoint.InvalidType))
73108
{
74109
arg = BigInteger.Zero;
75110
}
111+
else if (arg is InteropInterface interop)
112+
{
113+
// We can't send the interopInterface by an script
114+
// We create a syscall in order to detect it and push the item
115+
116+
testingSyscall ??= new TestingSyscall();
117+
script.EmitSysCall(TestingSyscall.Hash, testingSyscall.Add((e) => e.Push(interop)));
118+
continue;
119+
}
120+
else if (arg is Action<ApplicationEngine> onItem)
121+
{
122+
// We create a syscall in order to detect it and push the item
123+
124+
testingSyscall ??= new TestingSyscall();
125+
script.EmitSysCall(TestingSyscall.Hash, testingSyscall.Add((e) => onItem(e)));
126+
continue;
127+
}
76128

77129
script.EmitPush(arg);
78130
}
79131
script.EmitPush(args.Length);
80132
script.Emit(OpCode.PACK);
81133
}
82-
83-
script.EmitPush(CallFlags.All);
84-
script.EmitPush(methodName);
85-
script.EmitPush(Hash);
86-
script.EmitSysCall(ApplicationEngine.System_Contract_Call);
87-
88-
// Execute
89-
90-
return Engine.Execute(script.ToArray());
91134
}
92135

93136
/// <summary>

src/Neo.SmartContract.Testing/Storage/SmartContractStorage.cs

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ public class SmartContractStorage
1010
private readonly SmartContract _smartContract;
1111
private int? _contractId;
1212

13+
/// <summary>
14+
/// Storage Id
15+
/// </summary>
16+
public int Id => GetContractId();
17+
1318
/// <summary>
1419
/// Constructor
1520
/// </summary>

0 commit comments

Comments
 (0)