Skip to content

Commit

Permalink
Verify bad argument to select produces error (#85)
Browse files Browse the repository at this point in the history
Also produce a list of valid settings, and lower case the channel names.
  • Loading branch information
agocke authored Jul 7, 2023
1 parent 819e6d0 commit 32d822a
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/dnvm/ListCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static void PrintSdks(Logger logger, Manifest manifest)
string selected = manifest.CurrentSdkDir == channel.SdkDirName ? "*" : " ";
foreach (var version in channel.InstalledSdkVersions)
{
table.AddRow(selected, channel.ChannelName.ToString(), version, channel.SdkDirName.Name);
table.AddRow(selected, channel.ChannelName.GetLowerName(), version, channel.SdkDirName.Name);
}
}
logger.Console.Write(table);
Expand Down
2 changes: 2 additions & 0 deletions src/dnvm/Manifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public static class Channels
Channel.Preview => "The latest preview version",
_ => throw new NotImplementedException(),
};

public static string GetLowerName(this Channel c) => c.ToString().ToLowerInvariant();
}

[GenerateSerde]
Expand Down
2 changes: 1 addition & 1 deletion src/dnvm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static async Task<int> Main(string[] args)
CommandArguments.InstallArguments o => (int)await InstallCommand.Run(globalOptions, logger, o),
CommandArguments.UpdateArguments o => (int)await UpdateCommand.Run(globalOptions, logger, o),
CommandArguments.ListArguments => (int)await ListCommand.Run(logger, dnvmFs),
CommandArguments.SelectArguments o => await SelectCommand.Run(globalOptions, logger, o),
CommandArguments.SelectArguments o => (int)await SelectCommand.Run(globalOptions, logger, o),
CommandArguments.SelfInstallArguments o => (int)await SelfInstallCommand.Run(dnvmFs, globalOptions, logger, o),
_ => throw ExceptionUtilities.Unreachable
};
Expand Down
43 changes: 38 additions & 5 deletions src/dnvm/SelectCommand.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,60 @@

using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Serde.Json;
using Spectre.Console;

namespace Dnvm;

public static class SelectCommand
{
public static async Task<int> Run(GlobalOptions options, Logger logger, CommandArguments.SelectArguments args)
public enum Result
{
Success,
BadDirName,
}

public static async Task<Result> Run(GlobalOptions options, Logger logger, CommandArguments.SelectArguments args)
{
var newDir = new SdkDirName(args.SdkDirName);
var manifest = ManifestUtils.ReadOrCreateManifest(options.ManifestPath);
manifest = await SelectNewDir(options.DnvmHome, newDir, manifest);
File.WriteAllText(options.ManifestPath, JsonSerializer.Serialize(manifest));
return 0;
switch (await RunWithManifest(options.DnvmHome, newDir, manifest, logger))
{
case Result<Manifest, Result>.Ok(var newManifest):
File.WriteAllText(options.ManifestPath, JsonSerializer.Serialize(newManifest));
return Result.Success;
case Result<Manifest, Result>.Err(var error):
return error;
default:
throw ExceptionUtilities.Unreachable;
};
}

public static async ValueTask<Result<Manifest, Result>> RunWithManifest(string dnvmHome, SdkDirName newDir, Manifest manifest, Logger logger)
{
var validDirs = manifest.TrackedChannels.Select(c => c.SdkDirName).ToList();

if (!validDirs.Contains(newDir))
{
logger.Log($"Invalid SDK directory name: {newDir.Name}");
logger.Log("Valid SDK directory names:");
foreach (var dir in validDirs)
{
logger.Log($" {dir.Name}");
}
return Result.BadDirName;
}

return await SelectNewDir(dnvmHome, newDir, manifest);
}

/// <summary>
/// Replaces the dotnet symlink with one pointing to the new SDK and
/// updates the manifest to reflect the new SDK dir.
/// </summary>
public static Task<Manifest> SelectNewDir(string dnvmHome, SdkDirName newDir, Manifest manifest)
private static Task<Manifest> SelectNewDir(string dnvmHome, SdkDirName newDir, Manifest manifest)
{
InstallCommand.RetargetSymlink(dnvmHome, newDir);
return Task.FromResult(manifest with { CurrentSdkDir = newDir });
Expand Down
21 changes: 21 additions & 0 deletions src/dnvm/Utilities/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

using System;

namespace Dnvm;

public abstract record Result<TOk, TErr>
{
private Result() { }

public sealed record Ok(TOk Value) : Result<TOk, TErr>;
public sealed record Err(TErr Value) : Result<TOk, TErr>;

public static implicit operator Result<TOk, TErr>(TOk success) => new Ok(success);
public static implicit operator Result<TOk, TErr>(TErr error) => new Err(error);

public TOk Unwrap() => this switch
{
Ok(var ok) => ok,
_ => throw new InvalidOperationException(),
};
}
15 changes: 13 additions & 2 deletions test/Shared/MockServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public sealed class MockServer : IAsyncDisposable

public DnvmReleases DnvmReleases { get; set; }

public static async Task WithScope(Func<MockServer, ValueTask> test)
=> await TaskScope.With(async taskScope =>
{
await using var mockServer = new MockServer(taskScope);
await test(mockServer);
});

public MockServer(TaskScope scope)
{
_scope = scope;
Expand Down Expand Up @@ -162,8 +169,12 @@ private void GetReleasesJson(HttpListenerResponse response)

public ValueTask DisposeAsync()
{
_listener.Stop();
_listener.Close();
try
{
_listener.Stop();
_listener.Close();
}
catch (HttpListenerException) { }
return ValueTask.CompletedTask;
}
}
2 changes: 0 additions & 2 deletions test/Shared/TaskScope.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@

using System.Diagnostics;

public sealed class TaskScope
{
private readonly CancellationTokenSource _cts = new();
Expand Down
6 changes: 3 additions & 3 deletions test/UnitTests/ListTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public void BasicList()
┌───┬─────────┬────────────────┬──────────┐
│ │ Channel │ Version │ Location │
├───┼─────────┼────────────────┼──────────┤
│ * │ Latest │ 1.0.0 │ dn │
│ │ Preview │ 4.0.0-preview1 │ preview │
│ * │ latest │ 1.0.0 │ dn │
│ │ preview │ 4.0.0-preview1 │ preview │
└───┴─────────┴────────────────┴──────────┘
""";

Expand All @@ -55,7 +55,7 @@ public async Task ListFromFile()
┌───┬─────────┬──────────┬──────────┐
│ │ Channel │ Version │ Location │
├───┼─────────┼──────────┼──────────┤
│ * │ Latest │ 42.42.42 │ dn │
│ * │ latest │ 42.42.42 │ dn │
└───┴─────────┴──────────┴──────────┘
""";

Expand Down
30 changes: 28 additions & 2 deletions test/UnitTests/SelectTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using Dnvm.Test;
using Spectre.Console.Testing;
Expand All @@ -9,6 +10,7 @@ namespace Dnvm;

public sealed class SelectTests : IDisposable
{
private readonly TestConsole _console = new();
private readonly Logger _logger;
private readonly TempDirectory _userHome = TestUtils.CreateTempDirectory();
private readonly TempDirectory _dnvmHome = TestUtils.CreateTempDirectory();
Expand All @@ -18,7 +20,7 @@ public sealed class SelectTests : IDisposable
public SelectTests(ITestOutputHelper output)
{
var wrapper = new OutputWrapper(output);
_logger = new Logger(new TestConsole());
_logger = new Logger(_console);
_globalOptions = new GlobalOptions {
DnvmHome = _dnvmHome.Path,
UserHome = _userHome.Path,
Expand Down Expand Up @@ -66,13 +68,37 @@ await TaskScope.With(async scope =>
Assert.Equal(GlobalOptions.DefaultSdkDirName, manifest.CurrentSdkDir);

var previewSdkDir = new SdkDirName("preview");
manifest = await SelectCommand.SelectNewDir(_globalOptions.DnvmHome, previewSdkDir, manifest);
manifest = (await SelectCommand.RunWithManifest(_globalOptions.DnvmHome, previewSdkDir, manifest, _logger)).Unwrap();

Assert.Equal(previewSdkDir, manifest.CurrentSdkDir);
AssertSymlinkTarget(dotnetSymlink, previewSdkDir);
});
}

[Fact]
public Task BadDirName() => MockServer.WithScope(async server =>
{
var dn = new SdkDirName("dn");
var manifest = new Manifest()
{
CurrentSdkDir = dn,
TrackedChannels = ImmutableArray.Create<TrackedChannel>(new TrackedChannel
{
ChannelName = Channel.Latest,
SdkDirName = dn
})
};
var result = await SelectCommand.RunWithManifest(_globalOptions.DnvmHome, new SdkDirName("bad"), manifest, _logger);
Assert.Equal(SelectCommand.Result.BadDirName, result);

Assert.Equal("""
Invalid SDK directory name: bad
Valid SDK directory names:
dn
""".Replace(Environment.NewLine, "\n"), _console.Output);
});

private static void AssertSymlinkTarget(string dotnetSymlink, SdkDirName dirName)
{
if (OperatingSystem.IsWindows())
Expand Down

0 comments on commit 32d822a

Please sign in to comment.