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
12 changes: 7 additions & 5 deletions src/Packages/Audience/Runtime/ConsentLevel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ namespace Immutable.Audience
// How much data the Audience SDK is allowed to collect.
public enum ConsentLevel
{
// No tracking.
// No tracking
None,
// Anonymous tracking only.
// Anonymous tracking only
Anonymous,
// Full tracking, including identity.
// Full tracking
Full
}

internal static class ConsentLevelExtensions
{
// Throws on unknown casts rather than emitting null: a null value
// would poison the backend consent log.
internal static string ToLowercaseString(this ConsentLevel level) => level switch
{
ConsentLevel.None => "none",
Expand All @@ -25,5 +23,9 @@ internal static class ConsentLevelExtensions
_ => throw new System.ArgumentOutOfRangeException(
nameof(level), level, "Unhandled ConsentLevel"),
};

internal static bool CanTrack(this ConsentLevel level) => level != ConsentLevel.None;

internal static bool CanIdentify(this ConsentLevel level) => level == ConsentLevel.Full;
}
}
2 changes: 1 addition & 1 deletion src/Packages/Audience/Runtime/Core/Identity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ internal static void ClearCache()
internal static string? GetOrCreate(string persistentDataPath, ConsentLevel consent)
{
// No ID until the player grants at least anonymous consent.
if (consent == ConsentLevel.None)
if (!consent.CanTrack())
return null;

// Fast path — already loaded this session, no lock needed.
Expand Down
10 changes: 5 additions & 5 deletions src/Packages/Audience/Runtime/ImmutableAudience.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ public static void Identify(string userId, string identityType, Dictionary<strin
Log.Warn("Identify called with null or empty userId — dropping.");
return;
}
if (_consent != ConsentLevel.Full)
if (!_consent.CanIdentify())
{
Log.Warn($"Identify discarded — requires Full consent, current is {_consent}");
return;
Expand Down Expand Up @@ -227,7 +227,7 @@ public static void Alias(string fromId, string fromType, string toId, string toT
Log.Warn("Alias called with null or empty fromId/toId — dropping.");
return;
}
if (_consent != ConsentLevel.Full)
if (!_consent.CanIdentify())
{
Log.Warn($"Alias discarded — requires Full consent, current is {_consent}");
return;
Expand Down Expand Up @@ -556,7 +556,7 @@ internal static void ResetState()

private static bool CanTrack()
{
return _initialized && _consent != ConsentLevel.None;
return _initialized && _consent.CanTrack();
}

// Shallow-copy the caller's dict so a post-call mutation cannot race the drain-thread serialiser.
Expand All @@ -570,7 +570,7 @@ private static void Enqueue(Dictionary<string, object>? msg)

// Re-check consent inside the drain lock so a SetConsent(None) racing
// the caller's CanTrack cannot leak this event past the purge.
queue.EnqueueChecked(msg, () => _consent != ConsentLevel.None);
queue.EnqueueChecked(msg, () => _consent.CanTrack());
}

private static void SendBatch()
Expand Down Expand Up @@ -632,7 +632,7 @@ private static void RescheduleSendTimer(HttpTransport transport)
// landing between Init returning and here still drops the event.
private static void FireGameLaunch(AudienceConfig config, ConsentLevel consentAtInit)
{
if (consentAtInit == ConsentLevel.None) return;
if (!consentAtInit.CanTrack()) return;

var properties = new Dictionary<string, object>();

Expand Down
57 changes: 57 additions & 0 deletions src/Packages/Audience/Tests/Runtime/ConsentLevelTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using NUnit.Framework;

namespace Immutable.Audience.Tests
{
[TestFixture]
internal class ConsentLevelTests
{
[TestCase(ConsentLevel.None, "none")]
[TestCase(ConsentLevel.Anonymous, "anonymous")]
[TestCase(ConsentLevel.Full, "full")]
public void ToLowercaseString_MapsEachEnumValueToLowercaseBackendString(ConsentLevel level, string expected)
{
Assert.AreEqual(expected, level.ToLowercaseString());
}

[Test]
public void ToLowercaseString_UnknownValue_Throws()
{
var invalid = (ConsentLevel)999;

Assert.Throws<ArgumentOutOfRangeException>(() => invalid.ToLowercaseString());
}

[TestCase(ConsentLevel.None, false)]
[TestCase(ConsentLevel.Anonymous, true)]
[TestCase(ConsentLevel.Full, true)]
public void CanTrack_TrueForAnonymousAndFull(ConsentLevel level, bool expected)
{
Assert.AreEqual(expected, level.CanTrack());
}

[Test]
public void CanTrack_UnknownValue_ReturnsTrue()
{
var invalid = (ConsentLevel)999;

Assert.IsTrue(invalid.CanTrack());
}

[TestCase(ConsentLevel.None, false)]
[TestCase(ConsentLevel.Anonymous, false)]
[TestCase(ConsentLevel.Full, true)]
public void CanIdentify_TrueOnlyForFull(ConsentLevel level, bool expected)
{
Assert.AreEqual(expected, level.CanIdentify());
}

[Test]
public void CanIdentify_UnknownValue_ReturnsFalse()
{
var invalid = (ConsentLevel)999;

Assert.IsFalse(invalid.CanIdentify());
}
}
}
Loading