|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.ToolManifest;
using Microsoft.DotNet.Cli.ToolPackage;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.DependencyModel.Tests;
using Microsoft.Extensions.EnvironmentAbstractions;
using NuGet.Versioning;
namespace Microsoft.DotNet.Tests.Commands.Tool
{
public class ToolManifestEditorTests
{
private readonly IFileSystem _fileSystem;
private readonly string _testDirectoryRoot;
private const string _manifestFilename = "dotnet-tools.json";
public ToolManifestEditorTests()
{
_fileSystem = new FileSystemMockBuilder().UseCurrentSystemTemporaryDirectory().Build();
_testDirectoryRoot = _fileSystem.Directory.CreateTemporaryDirectory().DirectoryPath;
}
[Fact]
public void GivenManifestFileItCanAddEntryToIt()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
toolManifestFileEditor.Add(new FilePath(manifestFile),
new PackageId("new-tool"),
NuGetVersion.Parse("3.0.0"),
new[] { new ToolCommandName("newtool") });
_fileSystem.File.ReadAllText(manifestFile).Should().Be(
@"{
""version"": 1,
""isRoot"": true,
""tools"": {
""t-rex"": {
""version"": ""1.0.53"",
""commands"": [
""t-rex""
],
""rollForward"": false
},
""dotnetsay"": {
""version"": ""2.1.4"",
""commands"": [
""dotnetsay""
],
""rollForward"": false
},
""new-tool"": {
""version"": ""3.0.0"",
""commands"": [
""newtool""
],
""rollForward"": false
}
}
}");
}
[Fact]
public void GivenManifestFileWithoutToolsEntryItCanAddEntryToIt()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContentWithoutToolsEntry);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
toolManifestFileEditor.Add(new FilePath(manifestFile),
new PackageId("new-tool"),
NuGetVersion.Parse("3.0.0"),
new[] { new ToolCommandName("newtool") });
_fileSystem.File.ReadAllText(manifestFile).Should().Be(
@"{
""isRoot"": true,
""tools"": {
""new-tool"": {
""version"": ""3.0.0"",
""commands"": [
""newtool""
],
""rollForward"": false
}
}
}");
}
[Fact]
public void GivenManifestFileWhenAddingTheSamePackageIdToolItThrows()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
PackageId packageId = new("dotnetsay");
NuGetVersion nuGetVersion = NuGetVersion.Parse("3.0.0");
Action a = () => toolManifestFileEditor.Add(new FilePath(manifestFile),
packageId,
nuGetVersion,
new[] { new ToolCommandName("dotnetsay") });
var expectedString = string.Format(
CliStrings.ManifestPackageIdCollision,
"2.1.4",
packageId.ToString(),
manifestFile,
nuGetVersion.ToNormalizedString());
a.Should().Throw<ToolManifestException>()
.And.Message.Should().Contain(expectedString);
_fileSystem.File.ReadAllText(manifestFile).Should().Be(_jsonContent);
}
[Fact]
public void GivenManifestFileWhenAddingTheSamePackageIdSameVersionSameCommandsItDoesNothing()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
PackageId packageId = new("dotnetsay");
NuGetVersion nuGetVersion = NuGetVersion.Parse("2.1.4");
Action a = () => toolManifestFileEditor.Add(new FilePath(manifestFile),
packageId,
nuGetVersion,
new[] { new ToolCommandName("dotnetsay") });
a.Should().NotThrow();
_fileSystem.File.ReadAllText(manifestFile).Should().Be(_jsonContent);
}
[Fact]
public void GivenAnInvalidManifestFileWhenAddItThrows()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonWithInvalidField);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
PackageId packageId = new("dotnetsay");
NuGetVersion nuGetVersion = NuGetVersion.Parse("3.0.0");
Action a = () => toolManifestFileEditor.Add(new FilePath(manifestFile),
packageId,
nuGetVersion,
new[] { new ToolCommandName("dotnetsay") });
a.Should().Throw<ToolManifestException>()
.And.Message.Should().Contain(
string.Format(CliStrings.InvalidManifestFilePrefix,
manifestFile,
string.Empty));
_fileSystem.File.ReadAllText(manifestFile).Should().Be(_jsonWithInvalidField);
}
[Fact]
public void GivenAnMissingManifestFileVersionItShouldNotThrow()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContentMissingVersion);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
Action a = () =>
toolManifestFileEditor.Read(new FilePath(manifestFile), new DirectoryPath(_testDirectoryRoot));
a.Should().NotThrow<ToolManifestException>();
}
[Fact]
public void GivenManifestFileItCanRemoveEntryFromIt()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
toolManifestFileEditor.Remove(new FilePath(manifestFile),
new PackageId("dotnetsay"));
_fileSystem.File.ReadAllText(manifestFile).Should().Be(
@"{
""version"": 1,
""isRoot"": true,
""tools"": {
""t-rex"": {
""version"": ""1.0.53"",
""commands"": [
""t-rex""
],
""rollForward"": false
}
}
}");
}
[Fact]
public void GivenManifestFileWhenRemoveNonExistPackageIdToolItThrows()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
Action a = () => toolManifestFileEditor.Remove(
new FilePath(manifestFile),
new PackageId("non-exist"));
a.Should().Throw<ToolManifestException>()
.And.Message.Should().Contain(string.Format(
CliStrings.CannotFindPackageIdInManifest, "non-exist"));
_fileSystem.File.ReadAllText(manifestFile).Should().Be(_jsonContent);
}
[Fact]
public void GivenAnInvalidManifestFileWhenRemoveItThrows()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonWithInvalidField);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
Action a = () => toolManifestFileEditor.Remove(
new FilePath(manifestFile),
new PackageId("dotnetsay"));
a.Should().Throw<ToolManifestException>()
.And.Message.Should().Contain(
string.Format(CliStrings.InvalidManifestFilePrefix,
manifestFile,
string.Empty));
_fileSystem.File.ReadAllText(manifestFile).Should().Be(_jsonWithInvalidField);
}
[Fact]
public void GivenManifestFileWhenEditNonExistPackageIdItThrows()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
Action a = () => toolManifestFileEditor.Edit(new FilePath(manifestFile),
new PackageId("non-exist"),
NuGetVersion.Parse("3.0.0"),
new[] { new ToolCommandName("t-rex3") });
a.Should().Throw<ArgumentException>().And.Message.Should()
.Contain($"Manifest {manifestFile} does not contain package id 'non-exist'.");
}
[Fact]
public void GivenManifestFileItCanEditEntry()
{
string manifestFile = Path.Combine(_testDirectoryRoot, _manifestFilename);
_fileSystem.File.WriteAllText(manifestFile, _jsonContent);
var toolManifestFileEditor = new ToolManifestEditor(_fileSystem, new FakeDangerousFileDetector());
toolManifestFileEditor.Edit(new FilePath(manifestFile),
new PackageId("t-rex"),
NuGetVersion.Parse("3.0.0"),
new[] { new ToolCommandName("t-rex3") });
_fileSystem.File.ReadAllText(manifestFile).Should().Be(
@"{
""version"": 1,
""isRoot"": true,
""tools"": {
""t-rex"": {
""version"": ""3.0.0"",
""commands"": [
""t-rex3""
],
""rollForward"": false
},
""dotnetsay"": {
""version"": ""2.1.4"",
""commands"": [
""dotnetsay""
],
""rollForward"": false
}
}
}", "And original tools entry order is preserved.");
}
private string _jsonContent =
@"{
""version"": 1,
""isRoot"": true,
""tools"": {
""t-rex"": {
""version"": ""1.0.53"",
""commands"": [
""t-rex""
],
""rollForward"": false
},
""dotnetsay"": {
""version"": ""2.1.4"",
""commands"": [
""dotnetsay""
],
""rollForward"": false
}
}
}";
private string _jsonContentWithoutToolsEntry =
@"{
""isRoot"":true
}";
private string _jsonWithInvalidField =
@"{
""version"":1,
""isRoot"":true,
""tools"":{
""t-rex"":{
""version"":""1.*"",
""commands"":[
""t-rex""
]
}
}
}";
private string _jsonContentMissingVersion =
@"{
""isRoot"":true,
""tools"":{
""t-rex"":{
""version"":""1.0.53"",
""commands"":[
""t-rex""
]
}
}
}";
}
}
|