Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions Reqnroll/Bindings/Discovery/RuntimeBindingRegistryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Reqnroll.Bindings.Provider;
using Reqnroll.Bindings.Reflection;
using Reqnroll.Configuration;
using Reqnroll.Infrastructure;
using Reqnroll.PlatformCompatibility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Reqnroll.Bindings.Discovery
{
Expand All @@ -15,13 +16,15 @@ public class RuntimeBindingRegistryBuilder : IRuntimeBindingRegistryBuilder
private readonly IReqnrollAttributesFilter _reqnrollAttributesFilter;
private readonly IBindingAssemblyLoader _bindingAssemblyLoader;
private readonly ReqnrollConfiguration _reqnrollConfiguration;
private readonly IBindingProviderService _bindingProviderService;

public RuntimeBindingRegistryBuilder(IRuntimeBindingSourceProcessor bindingSourceProcessor, IReqnrollAttributesFilter reqnrollAttributesFilter, IBindingAssemblyLoader bindingAssemblyLoader, ReqnrollConfiguration reqnrollConfiguration)
public RuntimeBindingRegistryBuilder(IRuntimeBindingSourceProcessor bindingSourceProcessor, IReqnrollAttributesFilter reqnrollAttributesFilter, IBindingAssemblyLoader bindingAssemblyLoader, ReqnrollConfiguration reqnrollConfiguration, IBindingProviderService bindingProviderService)
{
_bindingSourceProcessor = bindingSourceProcessor;
_reqnrollAttributesFilter = reqnrollAttributesFilter;
_bindingAssemblyLoader = bindingAssemblyLoader;
_reqnrollConfiguration = reqnrollConfiguration;
_bindingProviderService = bindingProviderService;
}

public Assembly[] GetBindingAssemblies(Assembly testAssembly)
Expand Down Expand Up @@ -63,6 +66,7 @@ protected virtual Type[] GetAssemblyTypes(Assembly assembly, out string[] typeLo
public void BuildingCompleted()
{
_bindingSourceProcessor.BuildingCompleted();
_bindingProviderService.OnBindingRegistryBuildingCompleted();
}

//internal - for testing
Expand Down
6 changes: 4 additions & 2 deletions Reqnroll/Bindings/Provider/BindingJsonSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
namespace Reqnroll.Bindings.Provider;

[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified, // We specifiy the names explicitly
UseStringEnumConverter = true)] // use strings instead of numbers for enums
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified, // We specify the names explicitly
Comment thread
gasparnagy marked this conversation as resolved.
UseStringEnumConverter = true, // use strings instead of numbers for enums
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull // Ignore null properties
)]
[JsonSerializable(typeof(BindingData))]
internal partial class BindingJsonSourceGenerator : JsonSerializerContext
{
Expand Down
55 changes: 53 additions & 2 deletions Reqnroll/Bindings/Provider/BindingProviderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,76 @@
using Reqnroll.Bindings.Provider.Data;
using Reqnroll.Bindings.Reflection;
using Reqnroll.BoDi;
using Reqnroll.CommonModels;
using Reqnroll.Configuration;
using Reqnroll.EnvironmentAccess;
using Reqnroll.Formatters.Configuration;
using Reqnroll.Infrastructure;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;

namespace Reqnroll.Bindings.Provider;

public class BindingProviderService
public interface IBindingProviderService
{
void OnBindingRegistryBuildingCompleted();
}

public class BindingProviderService(IBindingRegistry bindingRegistry, ITestAssemblyProvider testAssemblyProvider, IEnvironmentWrapper environmentWrapper) : IBindingProviderService
{
/// <summary>
/// Invoked by the Visual Studio extension connectors. Do not remove or change the signature.
/// </summary>
public static string DiscoverBindings(Assembly testAssembly, string jsonConfiguration)
{
if (string.IsNullOrWhiteSpace(jsonConfiguration)) jsonConfiguration = "{}";
var globalContainer = CreateGlobalContainer(testAssembly, jsonConfiguration);
var bindingRegistryBuilder = globalContainer.Resolve<IRuntimeBindingRegistryBuilder>();
BuildBindingRegistry(testAssembly, bindingRegistryBuilder);
var bindingRegistry = globalContainer.Resolve<IBindingRegistry>();
return GetDiscoveredBindingsFromRegistry(bindingRegistry, testAssembly);
}

private const string REQNROLL_BINDING_OUTPUT_ENVIRONMENT_VARIABLE = "REQNROLL_BINDING_OUTPUT";

public void OnBindingRegistryBuildingCompleted()
{
// Experimental feature: This code allows the Visual Studio extension to instruct saving the discovered bindings to a file
// using an environment variable during the test run.
// This might be used as an alternative to invoking the `DiscoverBindings` method, because that needs the test assembly to be
// fully loaded and this is sometimes problematic.

if (environmentWrapper.GetEnvironmentVariable(REQNROLL_BINDING_OUTPUT_ENVIRONMENT_VARIABLE) is ISuccess<string> environmentVariable &&
!string.IsNullOrWhiteSpace(environmentVariable.Result))
{
var outputFilePath = environmentVariable.Result.Equals("true", StringComparison.OrdinalIgnoreCase) ? "reqnroll_bindings.json" :
environmentVariable.Result.Trim();

outputFilePath = Path.GetFullPath(outputFilePath);
TrySaveBindings(outputFilePath);
}
}

private void TrySaveBindings(string outputFilePath)
{
try
{
var bindingsJson = GetDiscoveredBindingsFromRegistry(bindingRegistry, testAssemblyProvider.TestAssembly);
File.WriteAllText(outputFilePath, bindingsJson, Encoding.UTF8);
}
catch (Exception ex)
{
Debug.WriteLine(ex, "Writing bindings failed.");
Comment thread
gasparnagy marked this conversation as resolved.
}
}

private static string GetDiscoveredBindingsFromRegistry(IBindingRegistry bindingRegistry, Assembly testAssembly)
{
var resultData = ParseDiscoveryResult(bindingRegistry, testAssembly);
var jsonString = JsonSerializer.Serialize(resultData, BindingJsonSourceGenerator.Default.BindingData);
return jsonString;
Expand Down Expand Up @@ -145,5 +197,4 @@ private static IObjectContainer CreateGlobalContainer(Assembly testAssembly, str
var configurationProvider = new JsonStringRuntimeConfigurationProvider(jsonConfiguration);
return containerBuilder.CreateGlobalContainer(testAssembly, configurationProvider);
}

}
4 changes: 3 additions & 1 deletion Reqnroll/Infrastructure/DefaultDependencyProvider.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using Gherkin.CucumberMessages;
using Reqnroll.Analytics;
using Reqnroll.Analytics.AppInsights;
using Reqnroll.Analytics.UserId;
using Reqnroll.Bindings;
using Reqnroll.Bindings.CucumberExpressions;
using Reqnroll.Bindings.Discovery;
using Reqnroll.Bindings.Provider;
using Reqnroll.BindingSkeletons;
using Reqnroll.BoDi;
using Reqnroll.Configuration;
Expand All @@ -27,6 +27,7 @@
using Reqnroll.Time;
using Reqnroll.Tracing;
using Reqnroll.Utils;
using System;

namespace Reqnroll.Infrastructure
{
Expand Down Expand Up @@ -62,6 +63,7 @@ public virtual void RegisterGlobalContainerDefaults(ObjectContainer container)
container.RegisterTypeAs<BindingInvoker, IAsyncBindingInvoker>();
container.RegisterTypeAs<BindingDelegateInvoker, IBindingDelegateInvoker>();
container.RegisterTypeAs<TestObjectResolver, ITestObjectResolver>();
container.RegisterTypeAs<BindingProviderService, IBindingProviderService>();

container.RegisterTypeAs<StepDefinitionSkeletonProvider, IStepDefinitionSkeletonProvider>();
container.RegisterTypeAs<DefaultSkeletonTemplateProvider, ISkeletonTemplateProvider>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Xunit;
using Reqnroll.Bindings;
using Reqnroll.Bindings.Discovery;
using Reqnroll.Bindings.Provider;
using Reqnroll.Configuration;
using Reqnroll.Infrastructure;

Expand Down Expand Up @@ -226,7 +227,7 @@ public void GivenAndWhen()

private RuntimeBindingRegistryBuilder CreateSut()
{
return new RuntimeBindingRegistryBuilder(bindingSourceProcessorStub, new ReqnrollAttributesFilter(), new Mock<IBindingAssemblyLoader>().Object, ConfigurationLoader.GetDefault());
return new RuntimeBindingRegistryBuilder(bindingSourceProcessorStub, new ReqnrollAttributesFilter(), new Mock<IBindingAssemblyLoader>().Object, ConfigurationLoader.GetDefault(), new Mock<IBindingProviderService>().Object);
}

[Fact]
Expand Down
Loading