Add serialization tests and refactor serialization classes

Implemented new integration tests for serialization of programmatic workflows. Additionally, major refactoring was performed on the serialization classes. This involved moving the classes to new namespaces and enhancing their functionalities to correctly handle null inputs and to support the serialization of activities and expressions. Also, updated Elsa.sln.DotSettings and JsonActivitySerializer to handle new serializers.
This commit is contained in:
Sipke Schoorstra 2024-02-05 22:19:51 +01:00
parent f71b8c3b1c
commit fa44259cd1
13 changed files with 82 additions and 10 deletions

View file

@ -4,6 +4,7 @@
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/MAX_INITIALIZER_ELEMENTS_ON_LINE/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>

View file

@ -10,7 +10,7 @@ using Elsa.Workflows.Models;
using Humanizer;
using Microsoft.Extensions.Logging;
namespace Elsa.Workflows.Management.Serialization.Converters;
namespace Elsa.Workflows.Serialization.Converters;
/// <summary>
/// (De)serializes objects of type <see cref="IActivity"/>.

View file

@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
using Elsa.Workflows.Contracts;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.Management.Serialization.Converters;
namespace Elsa.Workflows.Serialization.Converters;
/// <summary>
/// Creates instances of <see cref="ActivityJsonConverter"/>.

View file

@ -5,7 +5,7 @@ using Elsa.Expressions.Helpers;
using Elsa.Expressions.Models;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Management.Serialization.Converters;
namespace Elsa.Workflows.Serialization.Converters;
/// <summary>
/// Serializes <see cref="Input"/> objects.

View file

@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
using Elsa.Workflows.Models;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.Management.Serialization.Converters;
namespace Elsa.Workflows.Serialization.Converters;
/// <summary>
/// A JSON converter factory that creates <see cref="InputJsonConverter{T}"/> instances.

View file

@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
@ -18,6 +19,7 @@ public class JsonIgnoreCompositeRootConverter : JsonConverter<IActivity>
}
/// <inheritdoc />
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
public override void Write(Utf8JsonWriter writer, IActivity? value, JsonSerializerOptions options)
{
writer.WriteStartObject();
@ -35,7 +37,15 @@ public class JsonIgnoreCompositeRootConverter : JsonConverter<IActivity>
var propName = options.PropertyNamingPolicy?.ConvertName(property.Name) ?? property.Name;
writer.WritePropertyName(propName);
JsonSerializer.Serialize(writer, property.GetValue(value), newOptions);
var input = property.GetValue(value);
if (input == null)
{
writer.WriteNullValue();
continue;
}
JsonSerializer.Serialize(writer, input, newOptions);
}
writer.WriteEndObject();

View file

@ -5,7 +5,7 @@ using Elsa.Expressions.Extensions;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Management.Serialization.Converters;
namespace Elsa.Workflows.Serialization.Converters;
/// <summary>
/// Serializes <see cref="Input"/> objects.

View file

@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
using Elsa.Workflows.Models;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.Management.Serialization.Converters;
namespace Elsa.Workflows.Serialization.Converters;
/// <summary>
/// A JSON converter factory that creates <see cref="OutputJsonConverter{T}"/> instances.

View file

@ -44,5 +44,6 @@ public class JsonActivitySerializer : ConfigurableSerializer, IActivitySerialize
protected override void AddConverters(JsonSerializerOptions options)
{
options.Converters.Add(CreateInstance<TypeJsonConverter>());
options.Converters.Add(CreateInstance<InputJsonConverterFactory>());
}
}

View file

@ -1,8 +1,8 @@
using System.Text.Json;
using Elsa.Workflows.Management.Serialization.Converters;
using Elsa.Workflows.Serialization.Converters;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.Management.Serialization;
namespace Elsa.Workflows.Serialization.Serializers;
/// <summary>
/// Configures the JSON serialization options with support for serializing and deserializing activities and expressions.

View file

@ -20,8 +20,8 @@ using Elsa.Workflows.Management.Materializers;
using Elsa.Workflows.Management.Models;
using Elsa.Workflows.Management.Options;
using Elsa.Workflows.Management.Providers;
using Elsa.Workflows.Management.Serialization;
using Elsa.Workflows.Management.Services;
using Elsa.Workflows.Serialization.Serializers;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;

View file

@ -0,0 +1,40 @@
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows.Contracts;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Xunit.Abstractions;
namespace Elsa.IntegrationTests.Serialization.ProgrammaticWorkflowsAndDelegates;
/// <summary>
/// Contains tests for variable expressions serialization.
/// </summary>
public class Tests
{
private readonly IActivitySerializer _activitySerializer;
private readonly IWorkflowBuilder _workflowBuilder;
/// <summary>
/// Initializes a new instance of the <see cref="Tests"/> class.
/// </summary>
public Tests(ITestOutputHelper testOutputHelper)
{
var serviceProvider = new TestApplicationBuilder(testOutputHelper).Build();
_activitySerializer = serviceProvider.GetRequiredService<IActivitySerializer>();
var workflowBuilderFactory = serviceProvider.GetRequiredService<IWorkflowBuilderFactory>();
_workflowBuilder = workflowBuilderFactory.CreateBuilder();
}
/// <summary>
/// Tests that programmatic workflows with inputs using delegates do not throw exceptions when serialized.
/// </summary>
[Fact(DisplayName = "Programmatic workflows with inputs using delegates do not throw exceptions when serialized")]
public async Task Test1()
{
var workflow = await _workflowBuilder.BuildWorkflowAsync<GreeterWorkflow>();
var serializedWorkflow = _activitySerializer.Serialize(workflow);
// If it reached here, the test passed
}
}

View file

@ -0,0 +1,20 @@
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
namespace Elsa.IntegrationTests.Serialization.ProgrammaticWorkflowsAndDelegates;
/// <inheritdoc />
public class GreeterWorkflow : WorkflowBase
{
/// <inheritdoc />
protected override void Build(IWorkflowBuilder builder)
{
var messageInput = builder.WithInput<string>("Message", "The message to write to the console.");
builder.Name = "Greeter Workflow";
builder.Inputs.Add(messageInput);
builder.Root = new WriteLine(context => context.GetInput<string>(messageInput));
}
}