Skip to content

Commit

Permalink
asyncapi#196 add unitTests for tofile
Browse files Browse the repository at this point in the history
  • Loading branch information
Senn Geerts authored and Senn Geerts committed Jul 11, 2024
1 parent 240c9ed commit e181850
Show file tree
Hide file tree
Showing 20 changed files with 754 additions and 101 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ PublishScripts/
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
dotnet-tools.json

# Microsoft Azure Build Output
csx/
Expand Down
9 changes: 9 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>
<ItemGroup>
<!-- Make it possible for NSubstitube to make substitues of internal classes -->
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />

<!-- Make project internals visible to their respective .Tests project -->
<InternalsVisibleTo Include="$(AssemblyName).Tests" />
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion Saunter.sln
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{E0D34C77-9
.editorconfig = .editorconfig
.gitattributes = .gitattributes
CHANGELOG.md = CHANGELOG.md
Directory.Build.props = Directory.Build.props
README.md = README.md
EndProjectSection
EndProject
Expand All @@ -45,7 +46,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "npm", "npm", "{E8FACA22-CFE
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Cli", "src\AsyncAPI.Saunter.Generator.Cli\AsyncAPI.Saunter.Generator.Cli.csproj", "{6C102D4D-3DA4-4763-B75E-C15E33E7E94A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncAPI.Saunter.Generator.Cli.Tests", "test\AsyncAPI.Saunter.Generator.Cli.Tests\AsyncAPI.Saunter.Generator.Cli.Tests.csproj", "{18AD0249-0436-4A26-9972-B97BA6905A54}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncAPI.Saunter.Generator.Cli.Tests", "test\AsyncAPI.Saunter.Generator.Cli.Tests\AsyncAPI.Saunter.Generator.Cli.Tests.csproj", "{18AD0249-0436-4A26-9972-B97BA6905A54}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Saunter.Serialization;
using Saunter;
using Saunter.Serialization;

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal class AsyncApiDocumentExtractor(ILogger<AsyncApiDocumentExtractor> logger)
internal interface IAsyncApiDocumentExtractor
{
IEnumerable<(string name, AsyncApiDocument document)> GetAsyncApiDocument(IServiceProvider serviceProvider, string[] requestedDocuments);
}

internal class AsyncApiDocumentExtractor(ILogger<AsyncApiDocumentExtractor> logger) : IAsyncApiDocumentExtractor
{
private IEnumerable<string> GetDocumentNames(string[] requestedDocuments, AsyncApiOptions asyncApiOptions)
{
Expand Down
21 changes: 11 additions & 10 deletions src/AsyncAPI.Saunter.Generator.Cli/ToFile/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal class EnvironmentBuilder(ILogger<EnvironmentBuilder> logger)
internal interface IEnvironmentBuilder
{
void SetEnvironmentVariables(string env);
}

internal class EnvironmentBuilder(ILogger<EnvironmentBuilder> logger) : IEnvironmentBuilder
{
public void SetEnvironmentVariables(string env)
{
var envVars = !string.IsNullOrWhiteSpace(env) ? env.Split(',').Select(x => x.Trim()) : Array.Empty<string>();
foreach (var envVar in envVars.Select(x => x.Split('=').Select(x => x.Trim()).ToList()))
var keyValues = envVars.Select(x => x.Split('=').Select(x => x.Trim()).ToList());
foreach (var envVar in keyValues)
{
if (envVar.Count is 1)
{
Environment.SetEnvironmentVariable(envVar[0], null, EnvironmentVariableTarget.Process);
logger.LogDebug($"Set environment flag: {envVar[0]}");
}
if (envVar.Count is 2)
if (envVar.Count == 2 && !string.IsNullOrWhiteSpace(envVar[0]))
{
Environment.SetEnvironmentVariable(envVar[0], envVar.ElementAtOrDefault(1), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(envVar[0], envVar[1], EnvironmentVariableTarget.Process);
logger.LogDebug($"Set environment variable: {envVar[0]} = {envVar[1]}");
}
else
{
logger.LogCritical("Environment variables should be in the format: env1=value1,env2=value2,env3");
logger.LogCritical("Environment variables should be in the format: env1=value1,env2=value2");
}
}
}
Expand Down
11 changes: 8 additions & 3 deletions src/AsyncAPI.Saunter.Generator.Cli/ToFile/FileWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal class FileWriter(ILogger<FileWriter> logger)
internal interface IFileWriter
{
void Write(string outputPath, string fileTemplate, string documentName, string format, Action<Stream> streamWriter);
}

internal class FileWriter(IStreamProvider streamProvider, ILogger<FileWriter> logger) : IFileWriter
{
public void Write(string outputPath, string fileTemplate, string documentName, string format, Action<Stream> streamWriter)
{
Expand All @@ -12,12 +17,12 @@ public void Write(string outputPath, string fileTemplate, string documentName, s

private void WriteFile(string outputPath, Action<Stream> writeAction)
{
using var stream = outputPath != null ? File.Create(outputPath) : Console.OpenStandardOutput();
using var stream = streamProvider.GetStreamFor(outputPath);
writeAction(stream);

if (outputPath != null)
{
logger.LogInformation($"AsyncAPI {Path.GetExtension(outputPath)[1..]} successfully written to {outputPath}");
logger.LogInformation($"AsyncAPI {Path.GetExtension(outputPath).TrimStart('.')} successfully written to {outputPath}");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ internal static class ServiceExtensions
{
public static IServiceCollection AddToFileCommand(this IServiceCollection services)
{
services.AddTransient<EnvironmentBuilder>();
services.AddTransient<ServiceProviderBuilder>();
services.AddTransient<AsyncApiDocumentExtractor>();
services.AddTransient<FileWriter>();
services.AddTransient<IEnvironmentBuilder, EnvironmentBuilder>();
services.AddTransient<IServiceProviderBuilder, ServiceProviderBuilder>();
services.AddTransient<IAsyncApiDocumentExtractor, AsyncApiDocumentExtractor>();
services.AddTransient<IStreamProvider, StreamProvider>();
services.AddTransient<IFileWriter, FileWriter>();
return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal class ServiceProviderBuilder(ILogger<ServiceProviderBuilder> logger)
internal interface IServiceProviderBuilder
{
IServiceProvider BuildServiceProvider(string startupAssembly);
}

internal class ServiceProviderBuilder(ILogger<ServiceProviderBuilder> logger) : IServiceProviderBuilder
{
public IServiceProvider BuildServiceProvider(string startupAssembly)
{
Expand All @@ -17,4 +22,3 @@ public IServiceProvider BuildServiceProvider(string startupAssembly)
return serviceProvider;
}
}

19 changes: 19 additions & 0 deletions src/AsyncAPI.Saunter.Generator.Cli/ToFile/StreamProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal interface IStreamProvider
{
Stream GetStreamFor(string path);
}

internal class StreamProvider : IStreamProvider
{
public Stream GetStreamFor(string path)
{
if (!string.IsNullOrEmpty(path))
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
}

return path != null ? File.Create(path) : Console.OpenStandardOutput();
}
}
8 changes: 2 additions & 6 deletions src/AsyncAPI.Saunter.Generator.Cli/ToFile/ToFileCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal class ToFileCommand(ILogger<ToFileCommand> logger, EnvironmentBuilder environment, ServiceProviderBuilder builder, AsyncApiDocumentExtractor docExtractor, FileWriter fileWriter)
internal class ToFileCommand(ILogger<ToFileCommand> logger, IEnvironmentBuilder environment, IServiceProviderBuilder builder, IAsyncApiDocumentExtractor docExtractor, IFileWriter fileWriter)
{
private const string DEFAULT_FILENAME = "{document}_asyncapi.{extension}";

Expand Down Expand Up @@ -37,11 +37,7 @@ public int ToFile([Argument] string startupassembly, string output = "./", strin
foreach (var (documentName, asyncApiDocument) in documents)
{
// Serialize to specified output location or stdout
var outputPath = !string.IsNullOrWhiteSpace(output) ? Path.Combine(Directory.GetCurrentDirectory(), output) : null;
if (!string.IsNullOrEmpty(outputPath))
{
Directory.CreateDirectory(outputPath);
}
var outputPath = !string.IsNullOrWhiteSpace(output) ? Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), output)) : null;

var exportJson = true;
var exportYml = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -9,11 +9,17 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AsyncAPI.NET" Version="5.2.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
<PackageReference Include="NSubstitute.Community.Logging" Version="0.0.1" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
59 changes: 59 additions & 0 deletions test/AsyncAPI.Saunter.Generator.Cli.Tests/E2ETests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Diagnostics;
using Shouldly;
using Xunit.Abstractions;

namespace AsyncAPI.Saunter.Generator.Cli.Tests;

public class E2ETests(ITestOutputHelper output)
{
private string Run(string file, string args, string workingDirectory, int expectedExitCode = 0)
{
var process = Process.Start(new ProcessStartInfo(file)
{
Arguments = args,
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
});
process.WaitForExit(TimeSpan.FromSeconds(20));
var stdOut = process.StandardOutput.ReadToEnd().Trim();
var stdError = process.StandardError.ReadToEnd().Trim();
output.WriteLine($"### Output of \"{file} {args}\"");
output.WriteLine(stdOut);
output.WriteLine(stdError);

process.ExitCode.ShouldBe(expectedExitCode);
return stdOut;
}

[Fact(Skip = "Manual verification only")]
public void Pack_Install_Run_Uninstall_Test()
{
var workingDirectory = "../../../../../src/AsyncAPI.Saunter.Generator.Cli";
var stdOut = this.Run("dotnet", "pack", workingDirectory);
stdOut.ShouldContain("Successfully created package");

// use --force flag to ensure the test starts clean every run
stdOut = this.Run("dotnet", "new tool-manifest --force", workingDirectory);
stdOut.ShouldContain("The template \"Dotnet local tool manifest file\" was created successfully");

stdOut = this.Run("dotnet", "tool install --local --add-source ./bin/Release AsyncAPI.Saunter.Generator.Cli", workingDirectory);
stdOut = stdOut.Replace("Skipping NuGet package signature verification.", "").Trim();
stdOut.ShouldContain("You can invoke the tool from this directory using the following commands: 'dotnet tool run dotnet-asyncapi");
stdOut.ShouldContain("was successfully installed.");

stdOut = this.Run("dotnet", "tool list --local asyncapi.saunter.generator.cli", workingDirectory);
stdOut.ShouldContain("dotnet-asyncapi");

stdOut = this.Run("dotnet", "tool run dotnet-asyncapi", workingDirectory, 1);
stdOut.ShouldContain("tofile: retrieves AsyncAPI from a startup assembly, and writes to file");

stdOut = this.Run("dotnet", "tool uninstall --local asyncapi.saunter.generator.cli", workingDirectory);
stdOut.ShouldContain(" was successfully uninstalled");
stdOut.ShouldContain("removed from manifest file");

stdOut = this.Run("dotnet", "tool list --local asyncapi.saunter.generator.cli", workingDirectory, 1);
stdOut.ShouldNotContain("dotnet-asyncapi");
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
using System.Diagnostics;
using Shouldly;
using Shouldly;
using Xunit.Abstractions;

namespace AsyncAPI.Saunter.Generator.Cli.Tests;

public class DotnetCliToolTests(ITestOutputHelper output)
public class IntegrationTests(ITestOutputHelper output)
{
private string RunTool(string args, int expectedExitCode = 1)
{
var process = Process.Start(new ProcessStartInfo("dotnet")
{
Arguments = $"../../../../../src/AsyncAPI.Saunter.Generator.Cli/bin/Debug/net8.0/AsyncAPI.Saunter.Generator.Cli.dll tofile {args}",
RedirectStandardOutput = true,
RedirectStandardError = true,
});
process.WaitForExit();
var stdOut = process.StandardOutput.ReadToEnd().Trim();
var stdError = process.StandardError.ReadToEnd().Trim();
using var outWriter = new StringWriter();
using var errorWriter = new StringWriter();
Console.SetOut(outWriter);
Console.SetError(errorWriter);

var entryPoint = typeof(Program).Assembly.EntryPoint!;
entryPoint.Invoke(null, new object[] { args.Split(' ') });

var stdOut = outWriter.ToString();
var stdError = errorWriter.ToString();
output.WriteLine($"RUN: {args}");
output.WriteLine("### STD OUT");
output.WriteLine(stdOut);
output.WriteLine("### STD ERROR");
output.WriteLine(stdError);

process.ExitCode.ShouldBe(expectedExitCode);
Environment.ExitCode.ShouldBe(expectedExitCode);
//stdError.ShouldBeEmpty(); LEGO lib doesn't like id: "id is not a valid property at #/components/schemas/lightMeasuredEvent""
return stdOut;
}

[Fact]
public void DefaultCallPrintsCommandInfo()
{
var stdOut = RunTool("", 0).Trim();
var stdOut = RunTool("tofile", 0).Trim();

stdOut.ShouldBe("""
Usage: tofile [arguments...] [options...] [-h|--help] [--version]
Expand All @@ -52,7 +55,7 @@ public void StreetlightsAPIExportSpecTest()
{
var path = Directory.GetCurrentDirectory();
output.WriteLine($"Output path: {path}");
var stdOut = RunTool($"../../../../../examples/StreetlightsAPI/bin/Debug/net8.0/StreetlightsAPI.dll --output {path} --format json,yml,yaml");
var stdOut = RunTool($"tofile ../../../../../examples/StreetlightsAPI/bin/Debug/net8.0/StreetlightsAPI.dll --output {path} --format json,yml,yaml");

stdOut.ShouldNotBeEmpty();
stdOut.ShouldContain($"AsyncAPI yaml successfully written to {Path.Combine(path, "asyncapi.yaml")}");
Expand Down

This file was deleted.

Loading

0 comments on commit e181850

Please sign in to comment.