Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TestEngine: Some fixes #969

Merged
merged 12 commits into from
Feb 29, 2024
2 changes: 1 addition & 1 deletion src/Neo.Compiler.CSharp/CompilationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public Compilation GetCompilation(string csproj)
if (!remove.Contains("*.cs"))
{
var obj = Path.Combine(folder, "obj");
var binSc = Path.Combine(Path.Combine(folder, "bin"), "sc");
var binSc = Path.Combine(folder, "bin");
foreach (var entry in Directory.EnumerateFiles(folder, "*.cs", SearchOption.AllDirectories)
.Where(p => !p.StartsWith(obj) && !p.StartsWith(binSc))
.Select(u => u))
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.Compiler.CSharp/CompilationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public enum OptimizationType : byte
public OptimizationType Optimize { get; set; } = OptimizationType.Basic;
public bool Checked { get; set; }
public bool NoInline { get; set; }
public byte AddressVersion { get; set; }
public byte AddressVersion { get; set; } = 0x35;
public string? BaseName { get; set; }

private CSharpParseOptions? parseOptions = null;
Expand Down
10 changes: 5 additions & 5 deletions src/Neo.SmartContract.Testing/Coverage/CoveredCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ public CoveredCollection(params CoverageBase[] entries)
/// <returns>Coverage dump</returns>
public override string Dump(DumpFormat format = DumpFormat.Console)
{
switch (format)
return format switch
{
case DumpFormat.Console: return new ConsoleFormat(GetEntries()).Dump();
case DumpFormat.Html: return new IntructionHtmlFormat(GetEntries()).Dump();
default: throw new NotImplementedException();
}
DumpFormat.Console => new ConsoleFormat(GetEntries()).Dump(),
DumpFormat.Html => new IntructionHtmlFormat(GetEntries()).Dump(),
_ => throw new NotImplementedException(),
};
}

/// <summary>
Expand Down
10 changes: 5 additions & 5 deletions src/Neo.SmartContract.Testing/Coverage/CoveredContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,12 @@ public void Join(CoverageBase? coverage)
/// <returns>Coverage dump</returns>
public override string Dump(DumpFormat format = DumpFormat.Console)
{
switch (format)
return format switch
{
case DumpFormat.Console: return new ConsoleFormat(this).Dump();
case DumpFormat.Html: return new IntructionHtmlFormat(this).Dump();
default: throw new NotImplementedException();
}
DumpFormat.Console => new ConsoleFormat(this).Dump(),
DumpFormat.Html => new IntructionHtmlFormat(this).Dump(),
_ => throw new NotImplementedException(),
};
}

/// <summary>
Expand Down
10 changes: 5 additions & 5 deletions src/Neo.SmartContract.Testing/Coverage/CoveredMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ public CoveredMethod(CoveredContract contract, ContractMethodDescriptor method,
/// <returns>Coverage dump</returns>
public override string Dump(DumpFormat format = DumpFormat.Console)
{
switch (format)
return format switch
{
case DumpFormat.Console: return new ConsoleFormat(Contract, m => ReferenceEquals(m, this)).Dump();
case DumpFormat.Html: return new IntructionHtmlFormat(Contract, m => ReferenceEquals(m, this)).Dump();
default: throw new NotImplementedException();
}
DumpFormat.Console => new ConsoleFormat(Contract, m => ReferenceEquals(m, this)).Dump(),
DumpFormat.Html => new IntructionHtmlFormat(Contract, m => ReferenceEquals(m, this)).Dump(),
_ => throw new NotImplementedException(),
};
}

public override string ToString() => Method.ToString();
Expand Down
10 changes: 5 additions & 5 deletions src/Neo.SmartContract.Testing/Coverage/Formats/ConsoleFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public partial class ConsoleFormat : CoverageFormatBase
/// <param name="filter">Method Filter</param>
public ConsoleFormat(CoveredContract contract, Func<CoveredMethod, bool>? filter = null)
{
Entries = new (CoveredContract, Func<CoveredMethod, bool>?)[] { (contract, filter) };
Entries = new[] { (contract, filter) };
}

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

writer.WriteLine($"┌-{"─".PadLeft(max[0], '─')}-┬-{"─".PadLeft(max[1], '─')}-┬-{"─".PadLeft(max[1], '─')}-┐");
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])} │");
writer.WriteLine($"├-{"─".PadLeft(max[0], '─')}-┼-{"─".PadLeft(max[1], '─')}-┼-{"─".PadLeft(max[1], '─')}-┤");
writer.WriteLine($"┌-{"─".PadLeft(max[0], '─')}-┬-{"─".PadLeft(max[1], '─')}-┬-{"─".PadLeft(max[2], '─')}-┐");
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])} │");
writer.WriteLine($"├-{"─".PadLeft(max[0], '─')}-┼-{"─".PadLeft(max[1], '─')}-┼-{"─".PadLeft(max[2], '─')}-┤");

foreach (var print in rows)
{
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])} │");
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])} │");
}

writer.WriteLine($"└-{"─".PadLeft(max[0], '─')}-┴-{"─".PadLeft(max[1], '─')}-┴-{"─".PadLeft(max[2], '─')}-┘");
Expand Down
18 changes: 15 additions & 3 deletions src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using Neo.IO;
using Neo.Json;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Testing.Coverage;
using Neo.SmartContract.Testing.TestingStandards;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -58,6 +56,7 @@ public static string GetArtifactsSource(this ContractManifest manifest, string?
if (manifest.IsVerificable()) inheritance.Add(typeof(IVerificable));

sourceCode.WriteLine("using Neo.Cryptography.ECC;");
sourceCode.WriteLine("using System;");
sourceCode.WriteLine("using System.Collections.Generic;");
sourceCode.WriteLine("using System.ComponentModel;");
sourceCode.WriteLine("using System.Numerics;");
Expand Down Expand Up @@ -180,6 +179,7 @@ public static string GetArtifactsSource(this ContractManifest manifest, string?
private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor getter, ContractMethodDescriptor? setter)[] properties)
ProcessAbiMethods(ContractMethodDescriptor[] methods)
{
HashSet<string> propertyNames = new();
List<ContractMethodDescriptor> methodList = new(methods);
List<(ContractMethodDescriptor, ContractMethodDescriptor?)> properties = new();

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

// Avoid property repetition

var propertyName = GetPropertyName(getter);
if (!propertyNames.Add(propertyName)) continue;

// Add property and remove method

properties.Add((getter, setter));
methodList.Remove(getter);

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

private static string GetPropertyName(ContractMethodDescriptor getter)
{
return TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name));
}

/// <summary>
/// Create source code from event
/// </summary>
Expand Down Expand Up @@ -296,7 +308,7 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev,
/// <returns>Source</returns>
private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor getter, ContractMethodDescriptor? setter)
{
var propertyName = TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name));
var propertyName = GetPropertyName(getter);
var getset = setter is not null ? $"{{ [DisplayName(\"{getter.Name}\")] get; [DisplayName(\"{setter.Name}\")] set; }}" : $"{{ [DisplayName(\"{getter.Name}\")] get; }}";

var builder = new StringBuilder();
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Akka.Util;
using Neo.Cryptography.ECC;
using Neo.SmartContract.Testing.Attributes;
using Neo.VM.Types;
Expand Down Expand Up @@ -50,6 +49,7 @@ public static class TestExtensions

return type switch
{
_ when type == stackItem.GetType() => stackItem,
_ when type == typeof(object) => stackItem,
_ when type == typeof(string) => Utility.StrictUTF8.GetString(stackItem.GetSpan()),
_ when type == typeof(byte[]) => stackItem.GetSpan().ToArray(),
Expand Down
22 changes: 22 additions & 0 deletions src/Neo.SmartContract.Testing/InvalidTypes/InvalidECPoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Neo.Cryptography.ECC;

namespace Neo.SmartContract.Testing.InvalidTypes
{
public class InvalidECPoint
{
/// <summary>
/// Null ECPoint
/// </summary>
public static readonly ECPoint? Null = null;

/// <summary>
/// This will be an invalid ECPoint (ByteString)
/// </summary>
public static readonly ECPoint InvalidLength = new();

/// <summary>
/// This will be an invalid ECPoint (Integer)
/// </summary>
public static readonly ECPoint InvalidType = new();
}
}
1 change: 1 addition & 0 deletions src/Neo.SmartContract.Testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ And for read and write, we have:
- **Gas**: Sets the gas execution limit for contract calls. Sets the `NetworkFee` of the `Transaction` object.
- **EnableCoverageCapture**: Enables or disables the coverage capture.
- **Trigger**: The trigger of the execution.
- **CallFlags**: Define the `CallFlags` for the mocked function, `All` by default.
- **OnGetEntryScriptHash**: This feature makes it easy to change the EntryScriptHash.
- **OnGetCallingScriptHash**: This feature makes it easy to change the CallingScriptHash.

Expand Down
65 changes: 54 additions & 11 deletions src/Neo.SmartContract.Testing/SmartContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,30 @@ internal StackItem Invoke(string methodName, params object[] args)
{
// Compose script

TestingSyscall? dynArgument = null;
using ScriptBuilder script = new();

ConvertArgs(script, args, ref dynArgument);

script.EmitPush(Engine.CallFlags);
script.EmitPush(methodName);
script.EmitPush(Hash);
script.EmitSysCall(ApplicationEngine.System_Contract_Call);

// Execute

return Engine.Execute(script.ToArray(), 0, dynArgument is null ? null : engine => ConfigureEngine(engine, dynArgument));
}

private void ConfigureEngine(ApplicationEngine engine, TestingSyscall testingSyscall)
{
if (engine is not TestingApplicationEngine testEngine) throw new InvalidOperationException();

testEngine.TestingSyscall = testingSyscall;
}

private void ConvertArgs(ScriptBuilder script, object[] args, ref TestingSyscall? testingSyscall)
{
if (args is null || args.Length == 0)
script.Emit(OpCode.NEWARRAY0);
else
Expand All @@ -63,31 +85,52 @@ internal StackItem Invoke(string methodName, params object[] args)
{
var arg = args[i];

if (arg is object[] arg2)
{
ConvertArgs(script, arg2, ref testingSyscall);
continue;
}
else if (arg is IEnumerable<object> argEnumerable)
{
ConvertArgs(script, argEnumerable.ToArray(), ref testingSyscall);
continue;
}

if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.InvalidLength) ||
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidLength))
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidLength) ||
ReferenceEquals(arg, InvalidTypes.InvalidECPoint.InvalidLength))
{
arg = System.Array.Empty<byte>();
}
else if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.InvalidType) ||
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidType))
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidType) ||
ReferenceEquals(arg, InvalidTypes.InvalidECPoint.InvalidType))
{
arg = BigInteger.Zero;
}
else if (arg is InteropInterface interop)
{
// We can't send the interopInterface by an script
// We create a syscall in order to detect it and push the item

testingSyscall ??= new TestingSyscall();
script.EmitSysCall(TestingSyscall.Hash, testingSyscall.Add((e) => e.Push(interop)));
continue;
}
else if (arg is Action<ApplicationEngine> onItem)
{
// We create a syscall in order to detect it and push the item

testingSyscall ??= new TestingSyscall();
script.EmitSysCall(TestingSyscall.Hash, testingSyscall.Add((e) => onItem(e)));
continue;
}

script.EmitPush(arg);
}
script.EmitPush(args.Length);
script.Emit(OpCode.PACK);
}

script.EmitPush(CallFlags.All);
script.EmitPush(methodName);
script.EmitPush(Hash);
script.EmitSysCall(ApplicationEngine.System_Contract_Call);

// Execute

return Engine.Execute(script.ToArray());
}

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Neo.SmartContract.Testing/Storage/SmartContractStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public class SmartContractStorage
private readonly SmartContract _smartContract;
private int? _contractId;

/// <summary>
/// Storage Id
/// </summary>
public int Id => GetContractId();

/// <summary>
/// Constructor
/// </summary>
Expand Down
Loading
Loading