diff --git a/src/Neo.SmartContract.Template/README.md b/src/Neo.SmartContract.Template/README.md index deafa501f..31f6bdf91 100644 --- a/src/Neo.SmartContract.Template/README.md +++ b/src/Neo.SmartContract.Template/README.md @@ -84,6 +84,7 @@ Project templates generate: ``` MyContract/ +├── .config/dotnet-tools.json ├── MyContract.cs # Main contract file ├── MyContract.csproj # Project file with proper references └── README.md # Template-specific documentation diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep11/.config/dotnet-tools.json b/src/Neo.SmartContract.Template/templates/neocontractnep11/.config/dotnet-tools.json new file mode 100644 index 000000000..33d1b0eb0 --- /dev/null +++ b/src/Neo.SmartContract.Template/templates/neocontractnep11/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "neo.compiler.csharp": { + "version": "TemplateNeoVersion", + "commands": [ + "nccs" + ] + } + } +} diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj b/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj index 8dbd3226d..c8572980a 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj +++ b/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj @@ -25,7 +25,8 @@ - + + diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj b/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj index 8dbd3226d..c8572980a 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj @@ -25,7 +25,8 @@ - + + diff --git a/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj b/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj index 8dbd3226d..c8572980a 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj +++ b/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj @@ -25,7 +25,8 @@ - + + diff --git a/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj b/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj index 8dbd3226d..c8572980a 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj +++ b/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj @@ -25,7 +25,8 @@ - + + diff --git a/tests/Neo.SmartContract.Template.UnitTests/templates/ContractTemplateToolManifestTests.cs b/tests/Neo.SmartContract.Template.UnitTests/templates/ContractTemplateToolManifestTests.cs new file mode 100644 index 000000000..87b2d7bbd --- /dev/null +++ b/tests/Neo.SmartContract.Template.UnitTests/templates/ContractTemplateToolManifestTests.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2026 The Neo Project. +// +// ContractTemplateToolManifestTests.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Xml.Linq; + +namespace Neo.SmartContract.Template.UnitTests.templates; + +[TestClass] +public class ContractTemplateToolManifestTests +{ + private static readonly string TemplateRoot = Path.GetFullPath( + "../../../../../src/Neo.SmartContract.Template/templates"); + + [DataTestMethod] + [DataRow("neocontractnep11")] + [DataRow("neocontractnep17")] + [DataRow("neocontractoracle")] + [DataRow("neocontractowner")] + [DataRow("neocontractsolution")] + public void ContractTemplate_IncludesCompilerToolManifest(string templateName) + { + var manifestPath = Path.Combine(TemplateRoot, templateName, ".config", "dotnet-tools.json"); + Assert.IsTrue(File.Exists(manifestPath), $"{templateName} is missing .config/dotnet-tools.json."); + + using var document = JsonDocument.Parse(File.ReadAllText(manifestPath)); + var root = document.RootElement; + var compiler = root.GetProperty("tools").GetProperty("neo.compiler.csharp"); + + Assert.AreEqual(1, root.GetProperty("version").GetInt32()); + Assert.IsTrue(root.GetProperty("isRoot").GetBoolean()); + Assert.AreEqual("TemplateNeoVersion", compiler.GetProperty("version").GetString()); + + var commands = compiler.GetProperty("commands"); + Assert.AreEqual(1, commands.GetArrayLength()); + Assert.AreEqual("nccs", commands[0].GetString()); + } + + [DataTestMethod] + [DataRow("neocontractnep11", "Nep11Contract.csproj")] + [DataRow("neocontractnep17", "Nep17Contract.csproj")] + [DataRow("neocontractoracle", "OracleRequest.csproj")] + [DataRow("neocontractowner", "Ownable.csproj")] + public void StandaloneContractTemplate_UsesLocalCompilerTool( + string templateName, + string projectName) + { + var project = XDocument.Load(Path.Combine(TemplateRoot, templateName, projectName)); + var commands = project.Descendants("Exec") + .Select(element => (string?)element.Attribute("Command")) + .Where(command => command is not null) + .ToArray(); + + CollectionAssert.Contains(commands, "dotnet tool restore"); + Assert.IsTrue( + commands.Any(command => command!.StartsWith("dotnet tool run nccs ", StringComparison.Ordinal)), + $"{projectName} must invoke nccs through the local tool manifest."); + } +}