Skip to content
Open
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
74 changes: 74 additions & 0 deletions IntegrationTests/Assets/Tests/EditMode/CallbackRegistryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using NUnit.Framework;

public class CallbackRegistryTests
{
private CallbackRegistry _registry;

[SetUp]
public void SetUp()
{
_registry = new CallbackRegistry();
}

[Test]
public void TakesCallbacksByRequestIdInAnyOrder()
{
Action first = () => { };
Action second = () => { };

var firstId = _registry.Register(first);
var secondId = _registry.Register(second);

Assert.That(_registry.TryTake(secondId, out Action receivedSecond), Is.True);
Assert.That(receivedSecond, Is.SameAs(second));
Assert.That(_registry.TryTake(firstId, out Action receivedFirst), Is.True);
Assert.That(receivedFirst, Is.SameAs(first));
}

[Test]
public void TakingARequestIdTwiceFailsTheSecondTime()
{
var requestId = _registry.Register<Action>(() => { });

Assert.That(_registry.TryTake(requestId, out Action _), Is.True);
Assert.That(_registry.TryTake(requestId, out Action duplicate), Is.False);
Assert.That(duplicate, Is.Null);
}

[Test]
public void NullCallbackStillCreatesConsumableRequest()
{
Action callback = null;
var requestId = _registry.Register(callback);

Assert.That(requestId, Is.Not.Empty);
Assert.That(_registry.TryTake(requestId, out Action received), Is.True);
Assert.That(received, Is.Null);
Assert.That(_registry.TryTake(requestId, out Action _), Is.False);
}

[Test]
public void TypeMismatchDoesNotConsumeRequest()
{
Action callback = () => { };
var requestId = _registry.Register(callback);

Assert.That(_registry.TryTake(requestId, out Func<int> wrongType), Is.False);
Assert.That(wrongType, Is.Null);
Assert.That(_registry.TryTake(requestId, out Action received), Is.True);
Assert.That(received, Is.SameAs(callback));
}

[Test]
public void ClearRemovesEveryPendingRequest()
{
var firstId = _registry.Register<Action>(() => { });
var secondId = _registry.Register<Action>(() => { });

_registry.Clear();

Assert.That(_registry.TryTake(firstId, out Action _), Is.False);
Assert.That(_registry.TryTake(secondId, out Action _), Is.False);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions RevenueCat/Scripts/CallbackRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;

internal sealed class CallbackRegistry
{
private sealed class CallbackEntry
{
internal readonly Type Type;
internal readonly object Callback;

internal CallbackEntry(Type type, object callback)
{
Type = type;
Callback = callback;
}
}

private readonly object _lock = new object();
private readonly Dictionary<string, CallbackEntry> _callbacks =
new Dictionary<string, CallbackEntry>();

internal string Register<T>(T callback) where T : class
{
var requestId = Guid.NewGuid().ToString("N");
lock (_lock)
{
_callbacks.Add(requestId, new CallbackEntry(typeof(T), callback));
}

return requestId;
}

internal bool TryTake<T>(string requestId, out T callback) where T : class
{
callback = null;
if (string.IsNullOrEmpty(requestId))
{
return false;
}

lock (_lock)
{
if (!_callbacks.TryGetValue(requestId, out var entry) || entry.Type != typeof(T))
{
return false;
}

_callbacks.Remove(requestId);
callback = (T)entry.Callback;
return true;
}
}

internal void Clear()
{
lock (_lock)
{
_callbacks.Clear();
}
}
}
11 changes: 11 additions & 0 deletions RevenueCat/Scripts/CallbackRegistry.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.