Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

Commit

Permalink
Make sure default avatar factory can be replaced for current call con…
Browse files Browse the repository at this point in the history
…text

Just like the BehaviorPipelineFactory, this will make it easier for scenarios where you want to replace the factory for an entire call chain without affecting other concurrently executing tests, for example.
  • Loading branch information
kzu committed Nov 4, 2020
1 parent 3d1a373 commit 944e35d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
29 changes: 29 additions & 0 deletions src/Avatar.UnitTests/AvatarFactoryTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Avatars.UnitTests
Expand Down Expand Up @@ -27,6 +29,33 @@ public void ReplaceDefaultFactory()
Assert.Same(instance, actual);
}

[Fact]
public async Task ReplaceFactoryLocally()
{
var factory1 = new TestFactory(new object());
var factory2 = new TestFactory(new object());

await Task.WhenAll(
Task.Run(() =>
{
AvatarFactory.LocalDefault = factory1;
Thread.Sleep(50);
Assert.Same(factory1, AvatarFactory.Default);
}),
Task.Run(() =>
{
AvatarFactory.LocalDefault = factory2;
Thread.Sleep(50);
Assert.Same(factory2, AvatarFactory.Default);
})
);

Assert.NotSame(factory1, AvatarFactory.Default);
Assert.NotSame(factory2, AvatarFactory.Default);
}



public class TestFactory : IAvatarFactory
{
object instance;
Expand Down
23 changes: 22 additions & 1 deletion src/Avatar/AvatarFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Reflection;
using System.Threading;

namespace Avatars
{
Expand All @@ -9,13 +10,33 @@ namespace Avatars
/// </summary>
public class AvatarFactory : IAvatarFactory
{
static readonly AsyncLocal<IAvatarFactory?> localFactory = new();
static readonly IAvatarFactory nullFactory = new AvatarFactory();
static IAvatarFactory defaultFactory = nullFactory;

/// <summary>
/// Gets or sets the default <see cref="IAvatarFactory"/> to use
/// to create avatars. Defaults to the <see cref="NotImplemented"/> factory.
/// </summary>
public static IAvatarFactory Default { get; set; } = nullFactory;
/// <remarks>
/// A <see cref="LocalDefault"/> can override the value of this global
/// default, if assigned to a non-null value.
/// </remarks>
public static IAvatarFactory Default
{
get => localFactory.Value ?? defaultFactory;
set => defaultFactory = value;
}

/// <summary>
/// Gets or sets the <see cref="IAvatarFactory"/> to use
/// in the current (async) flow, so it does not affect other threads/flows.
/// </summary>
public static IAvatarFactory? LocalDefault
{
get => localFactory.Value;
set => localFactory.Value = value;
}

/// <summary>
/// A factory that throws <see cref="NotImplementedException"/>.
Expand Down

0 comments on commit 944e35d

Please sign in to comment.