Skip to content

Commit 6ee55db

Browse files
shargonJim8ycschuchardt88vncoelho
authored
Nep17 UnitTests (#893)
* Draft Nep17 UT * LF * Fix TotalSupply * Some UT still failing, checking bugs * Ensure OnSetOwner is raised during deploy * Fix string * Fix mint test * Test burn * check burn * Test transfer * Remove token reception in Nep17, not required for a template * Fix csproj * Try to execute template compilation * Update src/Neo.SmartContract.Template/templates/neocontractnep17/ProjectName.csproj * Rename project * Use same path as tested project * Fix ut contract=filename * fix comment * Update src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.cs * Need help * Create project with template, and compile, new errors * Generate nef and manifest before compile * Compile works * Only left #895 * forgot files * LF and remove artifact library * format * Update tests/Neo.SmartContract.Template.UnitTests/templates/neocontractnep17/Nep17ContractTests.cs * Remove artifacts * Remove artifacts compilation * Revert "Remove artifacts compilation" This reverts commit 62466f1. * Remove artifacts and use the compiled library * Remove duplicate neo reference in Compiler * Update Neo.Compiler.CSharp.csproj * With source works fine * Reduce changes * Ut pass in local * dotnet format * Prepare for coverage check * Update test with coverage * Fix git notifications * sort coverage dump * remove using * fix bug * Increase transfer coverage using invalid types * Add to workflow * Fix test order * Remove some artifacts * fix comment * ir require artifacts * Remove artifacts and generate them by workflow * Split build * fix path * fix path * fix nccs dll * fix relative * Fix artifacts path * clean project * Update README.md * Sandobx UT * Clean * remove nullable * cleaner * Update console log * Clean table * Update tests/Neo.SmartContract.Template.UnitTests/templates/neocontractnep17/Nep17ContractTests.cs Co-authored-by: Jimmy <jimmy@r3e.network> * Update src/Neo.SmartContract.Testing/Coverage/CoveredContract.cs Co-authored-by: Christopher Schuchardt <cschuchardt88@gmail.com> * cschuchardt88's and Jimmy's feedback & Ownable & Nep17UT * some fixes * Rename test * TestBase * Add Assert * Use same format for auth check * Fix typo * Update src/Neo.SmartContract.Testing/Coverage/CoveredContract.cs Co-authored-by: Christopher Schuchardt <cschuchardt88@gmail.com> * cschuchardt88's feedback * Wait for neo-project/neo#3143 --------- Co-authored-by: Jimmy <jimmy@r3e.network> Co-authored-by: Christopher Schuchardt <cschuchardt88@gmail.com> Co-authored-by: Vitor Nazário Coelho <vncoelho@gmail.com>
1 parent 932aba3 commit 6ee55db

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1600
-372
lines changed

.github/workflows/main.yml

+23-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,18 @@ jobs:
2222
uses: actions/setup-dotnet@v4
2323
with:
2424
dotnet-version: ${{ env.DOTNET_VERSION }}
25-
- name: Build
25+
- name: Build Neo.Compiler.CSharp
26+
run: dotnet build ./src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj
27+
- name: Build Neo.SmartContract.Template and generate artifacts
28+
run: |
29+
dotnet pack ./src/Neo.SmartContract.Template/Neo.SmartContract.Template.csproj
30+
dotnet new install ./src/Neo.SmartContract.Template/bin/Debug/Neo.SmartContract.Template.*.nupkg
31+
dotnet new neocontractnep17 -n Nep17Contract -o ./src/Neo.SmartContract.Template/bin/Debug/ --force
32+
dotnet new uninstall Neo.SmartContract.Template
33+
dotnet remove ./src/Neo.SmartContract.Template/bin/Debug/Nep17Contract.csproj package Neo.SmartContract.Framework
34+
dotnet add ./src/Neo.SmartContract.Template/bin/Debug/Nep17Contract.csproj reference ./src/Neo.SmartContract.Framework/Neo.SmartContract.Framework.csproj
35+
dotnet ./src/Neo.Compiler.CSharp/bin/Debug/net7.0/nccs.dll -d ./src/Neo.SmartContract.Template/bin/Debug/Nep17Contract.csproj -o ./tests/Neo.SmartContract.Template.UnitTests/templates/neocontractnep17/Artifacts/ --generate-artifacts source
36+
- name: Build Solution
2637
run: dotnet build ./neo-devpack-dotnet.sln
2738
- name: Check format
2839
run: |
@@ -39,6 +50,17 @@ jobs:
3950
run: |
4051
dotnet test ./tests/Neo.SmartContract.Framework.UnitTests \
4152
--no-build \
53+
-l "console;verbosity=normal" \
54+
-p:CollectCoverage=true \
55+
-p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov \
56+
-p:MergeWith=${GITHUB_WORKSPACE}/coverage/coverage.json \
57+
-p:Exclude=\"[Neo.Compiler.CSharp.UnitTests]*\" \
58+
-p:CoverletOutputFormat=lcov
59+
- name: Test Neo.SmartContract.Template.UnitTests
60+
run: |
61+
dotnet test ./tests/Neo.SmartContract.Template.UnitTests \
62+
--no-build \
63+
-l "console;verbosity=detailed" \
4264
-p:CollectCoverage=true \
4365
-p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov \
4466
-p:MergeWith=${GITHUB_WORKSPACE}/coverage/coverage.json \

neo-devpack-dotnet.sln

+6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing",
3636
EndProject
3737
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing.UnitTests", "tests\Neo.SmartContract.Testing.UnitTests\Neo.SmartContract.Testing.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}"
3838
EndProject
39+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template.UnitTests", "tests\Neo.SmartContract.Template.UnitTests\Neo.SmartContract.Template.UnitTests.csproj", "{17F45E0B-AB1C-4796-8C99-E5212A5592F8}"
3940
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions", "neo\src\Neo.Extensions\Neo.Extensions.csproj", "{E5EFB018-810D-4297-8921-940FA0B1ED97}"
4041
EndProject
4142
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.IO", "neo\src\Neo.IO\Neo.IO.csproj", "{C2B7927F-AAA5-432A-8E76-B5080BD7EFB9}"
@@ -102,6 +103,10 @@ Global
102103
{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
103104
{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
104105
{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU
106+
{17F45E0B-AB1C-4796-8C99-E5212A5592F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
107+
{17F45E0B-AB1C-4796-8C99-E5212A5592F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
108+
{17F45E0B-AB1C-4796-8C99-E5212A5592F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
109+
{17F45E0B-AB1C-4796-8C99-E5212A5592F8}.Release|Any CPU.Build.0 = Release|Any CPU
105110
{E5EFB018-810D-4297-8921-940FA0B1ED97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
106111
{E5EFB018-810D-4297-8921-940FA0B1ED97}.Debug|Any CPU.Build.0 = Debug|Any CPU
107112
{E5EFB018-810D-4297-8921-940FA0B1ED97}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -129,6 +134,7 @@ Global
129134
{D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091}
130135
{648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA}
131136
{B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8}
137+
{17F45E0B-AB1C-4796-8C99-E5212A5592F8} = {D5266066-0AFD-44D5-A83E-2F73668A63C8}
132138
{E5EFB018-810D-4297-8921-940FA0B1ED97} = {49D5873D-7B38-48A5-B853-85146F032091}
133139
{C2B7927F-AAA5-432A-8E76-B5080BD7EFB9} = {49D5873D-7B38-48A5-B853-85146F032091}
134140
EndGlobalSection

src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<AssemblyTitle>Neo.Compiler.CSharp</AssemblyTitle>
5+
<TargetFramework>net7.0</TargetFramework>
56
<AssemblyName>nccs</AssemblyName>
67
<OutputType>Exe</OutputType>
78
<PackageId>Neo.Compiler.CSharp</PackageId>

src/Neo.Compiler.CSharp/Options.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,21 @@ namespace Neo.Compiler
1616
{
1717
public class Options
1818
{
19+
public enum GenerateArtifactsKind
20+
{
21+
None,
22+
Source,
23+
Library,
24+
SourceAndLibrary
25+
}
26+
1927
public string? Output { get; set; }
2028
public string? BaseName { get; set; }
2129
public NullableContextOptions Nullable { get; set; }
2230
public bool Checked { get; set; }
2331
public bool Debug { get; set; }
2432
public bool Assembly { get; set; }
25-
public bool NoArtifacts { get; set; }
33+
public GenerateArtifactsKind GenerateArtifacts { get; set; } = GenerateArtifactsKind.Source;
2634
public bool NoOptimize { get; set; }
2735
public bool NoInline { get; set; }
2836
public byte AddressVersion { get; set; }

src/Neo.Compiler.CSharp/Program.cs

+55-43
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static int Main(string[] args)
4242
new Option<bool>("--checked", "Indicates whether to check for overflow and underflow."),
4343
new Option<bool>(new[] { "-d", "--debug" }, "Indicates whether to generate debugging information."),
4444
new Option<bool>("--assembly", "Indicates whether to generate assembly."),
45-
new Option<bool>("--no-artifacts", "Instruct the compiler not to generate artifacts."),
45+
new Option<Options.GenerateArtifactsKind>("--generate-artifacts", "Instruct the compiler how to generate artifacts."),
4646
new Option<bool>("--no-optimize", "Instruct the compiler not to optimize the code."),
4747
new Option<bool>("--no-inline", "Instruct the compiler not to insert inline code."),
4848
new Option<byte>("--address-version", () => ProtocolSettings.Default.AddressVersion, "Indicates the address version used by the compiler.")
@@ -188,62 +188,74 @@ private static int ProcessOutputs(Options options, string folder, CompilationCon
188188
return 1;
189189
}
190190
Console.WriteLine($"Created {path}");
191-
if (!options.NoArtifacts)
191+
192+
if (options.GenerateArtifacts != Options.GenerateArtifactsKind.None)
192193
{
193-
var artifact = manifest.Abi.GetArtifactsSource(baseName);
194-
path = Path.Combine(outputFolder, $"{baseName}.artifacts.cs");
195-
File.WriteAllText(path, artifact);
196-
Console.WriteLine($"Created {path}");
194+
var artifact = manifest.GetArtifactsSource(baseName);
197195

198-
try
196+
if (options.GenerateArtifacts == Options.GenerateArtifactsKind.SourceAndLibrary || options.GenerateArtifacts == Options.GenerateArtifactsKind.Source)
199197
{
200-
// Try to compile the artifacts into a dll
201-
202-
string coreDir = Path.GetDirectoryName(typeof(object).Assembly.Location)!;
198+
path = Path.Combine(outputFolder, $"{baseName}.artifacts.cs");
199+
File.WriteAllText(path, artifact);
200+
Console.WriteLine($"Created {path}");
201+
}
203202

204-
var syntaxTree = CSharpSyntaxTree.ParseText(artifact);
205-
var references = new MetadataReference[]
203+
if (options.GenerateArtifacts == Options.GenerateArtifactsKind.SourceAndLibrary || options.GenerateArtifacts == Options.GenerateArtifactsKind.Library)
204+
{
205+
try
206206
{
207-
MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.dll")),
208-
MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.InteropServices.dll")),
209-
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
210-
MetadataReference.CreateFromFile(typeof(DisplayNameAttribute).Assembly.Location),
211-
MetadataReference.CreateFromFile(typeof(System.Numerics.BigInteger).Assembly.Location),
212-
MetadataReference.CreateFromFile(typeof(UInt160).Assembly.Location),
213-
MetadataReference.CreateFromFile(typeof(SmartContract.Testing.SmartContract).Assembly.Location)
214-
};
207+
// Try to compile the artifacts into a dll
208+
209+
var coreDir = Path.GetDirectoryName(typeof(object).Assembly.Location)!;
210+
var references = new MetadataReference[]
211+
{
212+
MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.dll")),
213+
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
214+
MetadataReference.CreateFromFile(typeof(DisplayNameAttribute).Assembly.Location),
215+
MetadataReference.CreateFromFile(typeof(System.Numerics.BigInteger).Assembly.Location),
216+
MetadataReference.CreateFromFile(typeof(NeoSystem).Assembly.Location),
217+
MetadataReference.CreateFromFile(typeof(SmartContract.Testing.TestEngine).Assembly.Location)
218+
};
215219

216-
var compilation = CSharpCompilation.Create(baseName, new[] { syntaxTree }, references,
217-
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
220+
CSharpCompilationOptions csOptions = new(
221+
OutputKind.DynamicallyLinkedLibrary,
222+
optimizationLevel: OptimizationLevel.Debug,
223+
platform: Platform.AnyCpu,
224+
nullableContextOptions: NullableContextOptions.Enable,
225+
deterministic: true);
218226

219-
using var ms = new MemoryStream();
220-
EmitResult result = compilation.Emit(ms);
227+
var syntaxTree = CSharpSyntaxTree.ParseText(artifact, options: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest));
228+
var compilation = CSharpCompilation.Create(baseName, new[] { syntaxTree }, references, csOptions);
221229

222-
if (!result.Success)
223-
{
224-
var failures = result.Diagnostics.Where(diagnostic =>
225-
diagnostic.IsWarningAsError ||
226-
diagnostic.Severity == DiagnosticSeverity.Error);
230+
using var ms = new MemoryStream();
231+
EmitResult result = compilation.Emit(ms);
227232

228-
foreach (var diagnostic in failures)
233+
if (!result.Success)
229234
{
230-
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
235+
var failures = result.Diagnostics.Where(diagnostic =>
236+
diagnostic.IsWarningAsError ||
237+
diagnostic.Severity == DiagnosticSeverity.Error);
238+
239+
foreach (var diagnostic in failures)
240+
{
241+
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
242+
}
231243
}
232-
}
233-
else
234-
{
235-
ms.Seek(0, SeekOrigin.Begin);
244+
else
245+
{
246+
ms.Seek(0, SeekOrigin.Begin);
236247

237-
// Write dll
248+
// Write dll
238249

239-
path = Path.Combine(outputFolder, $"{baseName}.artifacts.dll");
240-
File.WriteAllBytes(path, ms.ToArray());
241-
Console.WriteLine($"Created {path}");
250+
path = Path.Combine(outputFolder, $"{baseName}.artifacts.dll");
251+
File.WriteAllBytes(path, ms.ToArray());
252+
Console.WriteLine($"Created {path}");
253+
}
254+
}
255+
catch
256+
{
257+
Console.Error.WriteLine("Artifacts compilation error.");
242258
}
243-
}
244-
catch
245-
{
246-
Console.Error.WriteLine("Artifacts compilation error.");
247259
}
248260
}
249261
if (options.Debug)

src/Neo.SmartContract.Template/templates/neocontractnep17/.template.config/template.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"language": "C#",
1111
"type": "project"
1212
},
13-
"sourceName": "ProjectName",
13+
"sourceName": "Nep17Contract",
1414
"symbols": {
1515
"NeoVersion": {
1616
"type": "parameter",

src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.cs

+12-45
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010

1111
namespace ProjectName
1212
{
13-
[DisplayName(nameof(Contract1))]
13+
[DisplayName(nameof(Nep17Contract))]
1414
[ManifestExtra("Author", "<Your Name Or Company Here>")]
1515
[ManifestExtra("Description", "<Description Here>")]
1616
[ManifestExtra("Email", "<Your Public Email Here>")]
1717
[ManifestExtra("Version", "<Version String Here>")]
18-
[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/src/Neo.SmartContract.Template")]
18+
[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.cs")]
1919
[ContractPermission("*", "*")]
2020
[SupportedStandards("NEP-17")]
21-
public class Contract1 : Nep17Token
21+
public class Nep17Contract : Nep17Token
2222
{
2323
#region Owner
2424

@@ -33,7 +33,7 @@ public static UInt160 GetOwner()
3333
private static bool IsOwner() =>
3434
Runtime.CheckWitness(GetOwner());
3535

36-
public delegate void OnSetOwnerDelegate(UInt160 newOwner);
36+
public delegate void OnSetOwnerDelegate(UInt160 previousOwner, UInt160 newOwner);
3737

3838
[DisplayName("SetOwner")]
3939
public static event OnSetOwnerDelegate OnSetOwner;
@@ -45,8 +45,9 @@ public static void SetOwner(UInt160 newOwner)
4545

4646
ExecutionEngine.Assert(newOwner.IsValid && !newOwner.IsZero, "owner must be valid");
4747

48+
UInt160 previous = GetOwner();
4849
Storage.Put(new[] { Prefix_Owner }, newOwner);
49-
OnSetOwner(newOwner);
50+
OnSetOwner(previous, newOwner);
5051
}
5152

5253
#endregion
@@ -75,40 +76,6 @@ public static void SetOwner(UInt160 newOwner)
7576

7677
#endregion
7778

78-
#region Payment
79-
80-
public static bool Withdraw(UInt160 token, UInt160 to, BigInteger amount)
81-
{
82-
if (IsOwner() == false)
83-
throw new InvalidOperationException("No Authorization!");
84-
if (amount <= 0)
85-
throw new ArgumentOutOfRangeException(nameof(amount));
86-
if (to == null || to.IsValid == false)
87-
throw new ArgumentException("Invalid Address!");
88-
if (token == null || token.IsValid == false)
89-
throw new ArgumentException("Invalid Token Address!");
90-
if (ContractManagement.GetContract(token) == null)
91-
throw new ArgumentException("Token Not A Contract!");
92-
// TODO: Add logic
93-
return true;
94-
}
95-
96-
// NOTE: Allows ALL NEP-17 tokens to be received for this contract
97-
public static void OnNEP17Payment(UInt160 from, BigInteger amount, object data)
98-
{
99-
// TODO: Add logic for specific NEP-17 contract tokens
100-
if (Runtime.CallingScriptHash == NEO.Hash)
101-
{
102-
// TODO: Add logic (Burn, Mint, Transfer, Etc)
103-
}
104-
if (Runtime.CallingScriptHash == GAS.Hash)
105-
{
106-
// TODO: Add logic (Burn, Mint, Transfer, Etc)
107-
}
108-
}
109-
110-
#endregion
111-
11279
// When this contract address is included in the transaction signature,
11380
// this method will be triggered as a VerificationTrigger to verify that the signature is correct.
11481
// For example, this method needs to be called when withdrawing token from the contract.
@@ -121,6 +88,7 @@ public static string MyMethod()
12188
return Storage.Get(Storage.CurrentContext, "Hello");
12289
}
12390

91+
// This will be executed during deploy
12492
public static void _deploy(object data, bool update)
12593
{
12694
if (update)
@@ -137,16 +105,15 @@ public static void _deploy(object data, bool update)
137105
ExecutionEngine.Assert(initialOwner.IsValid && !initialOwner.IsZero, "owner must exists");
138106

139107
Storage.Put(new[] { Prefix_Owner }, initialOwner);
140-
OnSetOwner(initialOwner);
141-
142-
// This will be executed during deploy
108+
OnSetOwner(null, initialOwner);
143109
Storage.Put(Storage.CurrentContext, "Hello", "World");
144110
}
145111

146-
public static void Update(ByteString nefFile, string manifest)
112+
public static void Update(ByteString nefFile, string manifest, object data)
147113
{
148-
if (!IsOwner()) throw new Exception("No authorization.");
149-
ContractManagement.Update(nefFile, manifest, null);
114+
if (IsOwner() == false)
115+
throw new InvalidOperationException("No authorization.");
116+
ContractManagement.Update(nefFile, manifest, data);
150117
}
151118

152119
// NOTE: NEP-17 contracts "SHOULD NOT" have "Destroy" method

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public float CoveredPercentage
3636
var total = TotalInstructions;
3737
if (total == 0) return 0F;
3838

39-
return (float)CoveredInstructions / total * 100F;
39+
return (float)CoveredInstructions / total;
4040
}
4141
}
4242

0 commit comments

Comments
 (0)