Skip to content

Commit

Permalink
asyncapi#196 add unitTests for tofile classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Senn Geerts authored and Senn Geerts committed Jul 10, 2024
1 parent 240c9ed commit 715a62d
Show file tree
Hide file tree
Showing 14 changed files with 430 additions and 17 deletions.
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,8 +3,8 @@
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;

Expand Down
14 changes: 5 additions & 9 deletions src/AsyncAPI.Saunter.Generator.Cli/ToFile/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ internal class EnvironmentBuilder(ILogger<EnvironmentBuilder> logger)
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)
if (envVar.Count == 2 && !string.IsNullOrWhiteSpace(envVar[0]))
{
Environment.SetEnvironmentVariable(envVar[0], null, EnvironmentVariableTarget.Process);
logger.LogDebug($"Set environment flag: {envVar[0]}");
}
if (envVar.Count is 2)
{
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
6 changes: 3 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,7 @@

namespace AsyncAPI.Saunter.Generator.Cli.ToFile;

internal class FileWriter(ILogger<FileWriter> logger)
internal class FileWriter(IStreamProvider streamProvider, ILogger<FileWriter> logger)
{
public void Write(string outputPath, string fileTemplate, string documentName, string format, Action<Stream> streamWriter)
{
Expand All @@ -12,12 +12,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 @@ -9,6 +9,7 @@ public static IServiceCollection AddToFileCommand(this IServiceCollection servic
services.AddTransient<EnvironmentBuilder>();
services.AddTransient<ServiceProviderBuilder>();
services.AddTransient<AsyncApiDocumentExtractor>();
services.AddTransient<IStreamProvider, StreamProvider>();
services.AddTransient<FileWriter>();
return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ public IServiceProvider BuildServiceProvider(string startupAssembly)
return serviceProvider;
}
}

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

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

internal class StreamProvider : IStreamProvider
{
public Stream GetStreamFor(string path) => path != null ? File.Create(path) : Console.OpenStandardOutput();
}
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,14 @@
</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="NSubstitute.Community.Logging" Version="0.0.1" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using AsyncAPI.Saunter.Generator.Cli.ToFile;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NSubstitute;
using NSubstitute.Community.Logging;
using Saunter;
using Saunter.AsyncApiSchema.v2;
using Saunter.Serialization;
using Shouldly;
using Xunit.Abstractions;

namespace AsyncAPI.Saunter.Generator.Cli.Tests.ToFile;

public class AsyncApiDocumentExtractorTests
{
private readonly AsyncApiDocumentExtractor _extractor;
private readonly ILogger<AsyncApiDocumentExtractor> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly IAsyncApiDocumentProvider _documentProvider;
private readonly IOptions<AsyncApiOptions> _asyncApiOptions;
private readonly IAsyncApiDocumentSerializer _documentSerializer;

public AsyncApiDocumentExtractorTests(ITestOutputHelper output)
{
var services = new ServiceCollection();
this._documentProvider = Substitute.For<IAsyncApiDocumentProvider>();
this._asyncApiOptions = Substitute.For<IOptions<AsyncApiOptions>>();
var options = new AsyncApiOptions();
this._asyncApiOptions.Value.Returns(options);
this._documentSerializer = Substitute.For<IAsyncApiDocumentSerializer>();
services.AddSingleton(this._documentProvider);
services.AddSingleton(this._asyncApiOptions);
services.AddSingleton(this._documentSerializer);
this._serviceProvider = services.BuildServiceProvider();

this._logger = Substitute.For<ILogger<AsyncApiDocumentExtractor>>();
this._extractor = new AsyncApiDocumentExtractor(this._logger);
}

[Fact]
public void GetAsyncApiDocument_Null_NoMarkerAssemblies()
{
var documents = this._extractor.GetAsyncApiDocument(this._serviceProvider, null).ToList();

this._logger.Received(1).CallToLog(LogLevel.Critical);
}

[Fact]
public void GetAsyncApiDocument_Default_WithMarkerAssembly()
{
this._asyncApiOptions.Value.AssemblyMarkerTypes = [typeof(AsyncApiDocumentExtractorTests)];
var doc = new AsyncApiDocument();
this._documentProvider.GetDocument(default, default).ReturnsForAnyArgs(doc);
this._documentSerializer.Serialize(doc).ReturnsForAnyArgs("""
asyncapi: 2.6.0
info:
title: Streetlights API
""");

var documents = this._extractor.GetAsyncApiDocument(this._serviceProvider, null).ToList();

this._logger.Received(0).CallToLog(LogLevel.Critical);
documents.Count.ShouldBe(1);
documents[0].name.ShouldBeNull();
documents[0].document.Info.Title.ShouldBe("Streetlights API");
}

[Fact]
public void GetAsyncApiDocument_1NamedDocument()
{
this._asyncApiOptions.Value.AssemblyMarkerTypes = [typeof(AsyncApiDocumentExtractorTests)];
var doc = new AsyncApiDocument();
this._asyncApiOptions.Value.NamedApis["service 1"] = doc;
this._documentProvider.GetDocument(default, default).ReturnsForAnyArgs(doc);
this._documentSerializer.Serialize(doc).ReturnsForAnyArgs("""
asyncapi: 2.6.0
info:
title: Streetlights API
""");

var documents = this._extractor.GetAsyncApiDocument(this._serviceProvider, null).ToList();

this._logger.Received(0).CallToLog(LogLevel.Critical);
documents.Count.ShouldBe(1);
documents[0].name.ShouldBe("service 1");
documents[0].document.Info.Title.ShouldBe("Streetlights API");
}

[Fact]
public void GetAsyncApiDocument_2NamedDocument()
{
this._asyncApiOptions.Value.AssemblyMarkerTypes = [typeof(AsyncApiDocumentExtractorTests)];
var doc1 = new AsyncApiDocument { Id = "1" };
var doc2 = new AsyncApiDocument { Id = "2" };
this._asyncApiOptions.Value.NamedApis["service 1"] = doc1;
this._asyncApiOptions.Value.NamedApis["service 2"] = doc2;
this._documentProvider.GetDocument(Arg.Any<AsyncApiOptions>(), Arg.Is(doc1)).Returns(doc1);
this._documentProvider.GetDocument(Arg.Any<AsyncApiOptions>(), Arg.Is(doc2)).Returns(doc2);
this._documentSerializer.Serialize(doc1).Returns("""
asyncapi: 2.6.0
info:
title: Streetlights API 1
""");
this._documentSerializer.Serialize(doc2).Returns("""
asyncapi: 2.6.0
info:
title: Streetlights API 2
""");

var documents = this._extractor.GetAsyncApiDocument(this._serviceProvider, null).OrderBy(x => x.name).ToList();

this._logger.Received(0).CallToLog(LogLevel.Critical);
documents.Count.ShouldBe(2);
documents[0].name.ShouldBe("service 1");
documents[0].document.Info.Title.ShouldBe("Streetlights API 1");
documents[1].name.ShouldBe("service 2");
documents[1].document.Info.Title.ShouldBe("Streetlights API 2");
}

[Fact]
public void GetAsyncApiDocument_LogErrors()
{
this._asyncApiOptions.Value.AssemblyMarkerTypes = [typeof(AsyncApiDocumentExtractorTests)];
var doc = new AsyncApiDocument();
this._documentProvider.GetDocument(default, default).ReturnsForAnyArgs(doc);
this._documentSerializer.Serialize(doc).ReturnsForAnyArgs("""
asyncapi: 2.6.0
info:
title: Streetlights API
channels:
publish/light/measured:
servers:
- webapi
publish:
operationId: MeasureLight
summary: Inform about environmental lighting conditions for a particular streetlight.
tags:
- name: Light
message:
$ref: '#/components/messages/lightMeasuredEvent'
""");

var documents = this._extractor.GetAsyncApiDocument(this._serviceProvider, null).ToList();

this._logger.Received(0).CallToLog(LogLevel.Critical);
this._logger.Received(3).CallToLog(LogLevel.Error);
this._logger.Received(0).CallToLog(LogLevel.Warning);
documents.Count.ShouldBe(1);
documents[0].name.ShouldBeNull();
documents[0].document.Info.Title.ShouldBe("Streetlights API");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System.Collections;
using AsyncAPI.Saunter.Generator.Cli.ToFile;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NSubstitute.Community.Logging;
using Shouldly;
using Xunit.Abstractions;

namespace AsyncAPI.Saunter.Generator.Cli.Tests.ToFile;

public class EnvironmentBuilderTests : IDisposable
{
private readonly IDictionary _variablesBefore = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process);
private readonly EnvironmentBuilder _environment;
private readonly ILogger<EnvironmentBuilder> _logger;

public EnvironmentBuilderTests()
{
this._logger = Substitute.For<ILogger<EnvironmentBuilder>>();
this._environment = new EnvironmentBuilder(this._logger);
}

private Dictionary<string, string> GetAddedEnvironmentVariables()
{
var after = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process);
return after.Cast<DictionaryEntry>().ExceptBy(this._variablesBefore.Keys.Cast<string>(), x => x.Key).ToDictionary(x => x.Key.ToString(), x => x.Value?.ToString());
}

public void Dispose()
{
foreach (var variable in this.GetAddedEnvironmentVariables())
{
Environment.SetEnvironmentVariable(variable.Key, null, EnvironmentVariableTarget.Process);
}
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void EmptyEnvStringProvided(string env)
{
this._environment.SetEnvironmentVariables(env);

this._logger.ReceivedCalls().Count().ShouldBe(0);
this.GetAddedEnvironmentVariables().ShouldBeEmpty();
}

[Theory]
[InlineData("env1=val1", 1)]
[InlineData("a=b,b=c", 2)]
public void ValidEnvStringProvided(string env, int expectedSets)
{
this._environment.SetEnvironmentVariables(env);

this._logger.Received(expectedSets).CallToLog(LogLevel.Debug);
this.GetAddedEnvironmentVariables().ShouldNotBeEmpty();
}

[Theory]
[InlineData(",", 2)]
[InlineData(",,,,", 5)]
[InlineData("=a", 1)]
[InlineData("b", 1)]
[InlineData("=", 1)]
[InlineData("====", 1)]
public void InvalidEnvStringProvided(string env, int expectedSets)
{
this._environment.SetEnvironmentVariables(env);

this._logger.Received(expectedSets).CallToLog(LogLevel.Critical);
this.GetAddedEnvironmentVariables().ShouldBeEmpty();
}

[Fact]
public void ValidateEnvValues()
{
this._environment.SetEnvironmentVariables("ENV=1,,Test=two");

Environment.GetEnvironmentVariable("ENV").ShouldBe("1");
Environment.GetEnvironmentVariable("Test").ShouldBe("two");
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData(" ")]
public void EmptyValueDeletesEnvValue(string value)
{
this._environment.SetEnvironmentVariables($"ENV=1,,ENV={value}");

Environment.GetEnvironmentVariable("ENV").ShouldBe(null);
}
}
Loading

0 comments on commit 715a62d

Please sign in to comment.