diff --git a/docs/recording.md b/docs/recording.md
index d0b953faaf..5c6f0c90ad 100644
--- a/docs/recording.md
+++ b/docs/recording.md
@@ -117,7 +117,7 @@ public Task SameKey()
return Verify("TheValue");
}
```
-snippet source | anchor
+snippet source | anchor
Results in:
@@ -186,7 +186,7 @@ public Task Case()
return Verify("TheValue");
}
```
-snippet source | anchor
+snippet source | anchor
Results in:
@@ -305,7 +305,7 @@ public Task Clear()
return Verify();
}
```
-snippet source | anchor
+snippet source | anchor
Results in:
@@ -341,7 +341,7 @@ public Task PauseResume()
return Verify();
}
```
-snippet source | anchor
+snippet source | anchor
Results in:
diff --git a/src/Verify.Tests/RecordingTests.StartIdentifier1.verified.txt b/src/Verify.Tests/RecordingTests.StartIdentifier1.verified.txt
new file mode 100644
index 0000000000..5f282702bb
--- /dev/null
+++ b/src/Verify.Tests/RecordingTests.StartIdentifier1.verified.txt
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Verify.Tests/RecordingTests.StopIdentifier2.verified.txt b/src/Verify.Tests/RecordingTests.StopIdentifier2.verified.txt
new file mode 100644
index 0000000000..5f282702bb
--- /dev/null
+++ b/src/Verify.Tests/RecordingTests.StopIdentifier2.verified.txt
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Verify.Tests/RecordingTests.StopIdentifierOverlap.verified.txt b/src/Verify.Tests/RecordingTests.StopIdentifierOverlap.verified.txt
new file mode 100644
index 0000000000..d09ad9b9f3
--- /dev/null
+++ b/src/Verify.Tests/RecordingTests.StopIdentifierOverlap.verified.txt
@@ -0,0 +1,5 @@
+[
+ {
+ name: value
+ }
+]
\ No newline at end of file
diff --git a/src/Verify.Tests/RecordingTests.cs b/src/Verify.Tests/RecordingTests.cs
index 0d70109f38..d854cf5879 100644
--- a/src/Verify.Tests/RecordingTests.cs
+++ b/src/Verify.Tests/RecordingTests.cs
@@ -167,11 +167,18 @@ public Task StopNotInResult()
#endregion
[Fact]
- public Task StopIdentifier()
+ public void StartIdentifierThatDoesntFinish()
{
- Recording.Start("identifier");
- Recording.Add("identifier", "name", "value");
- return Verify(Recording.Stop("identifier"));
+ Recording.Start("identifierOverlap");
+ Recording.Add("identifierOverlap", "name", "value");
+ }
+
+ [Fact]
+ public Task StopIdentifierOverlap()
+ {
+ Recording.Start("identifierOverlap");
+ Recording.Add("identifierOverlap", "name", "value");
+ return Verify(Recording.Stop("identifierOverlap"));
}
[Fact]
diff --git a/src/Verify/Recording/Recording_Named.cs b/src/Verify/Recording/Recording_Named.cs
index a9b436e66f..9575bacd62 100644
--- a/src/Verify/Recording/Recording_Named.cs
+++ b/src/Verify/Recording/Recording_Named.cs
@@ -2,7 +2,7 @@
public static partial class Recording
{
- static ConcurrentDictionary namedState = new(StringComparer.OrdinalIgnoreCase);
+ static AsyncLocal?> asyncLocalNamed = new();
public static void Add(string identifier, string name, object item) =>
CurrentStateNamed(identifier)
@@ -10,15 +10,25 @@ public static void Add(string identifier, string name, object item) =>
public static void TryAdd(string identifier, string name, object item)
{
- if (namedState.TryGetValue(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states != null)
{
- state.Add(name, item);
+ if (states.TryGetValue(identifier, out var state))
+ {
+ state.Add(name, item);
+ }
}
}
public static bool IsRecording(string identifier)
{
- if (!namedState.TryGetValue(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states == null)
+ {
+ return false;
+ }
+
+ if (!states.TryGetValue(identifier, out var state))
{
return false;
}
@@ -40,10 +50,14 @@ public static bool TryStop(
string identifier,
[NotNullWhen(true)] out IReadOnlyCollection? recorded)
{
- if (namedState.TryRemove(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states != null)
{
- recorded = state.Items;
- return true;
+ if (states.TryRemove(identifier, out var state))
+ {
+ recorded = state.Items;
+ return true;
+ }
}
recorded = null;
@@ -52,7 +66,9 @@ public static bool TryStop(
static State CurrentStateNamed(string identifier, [CallerMemberName] string caller = "")
{
- if (namedState.TryGetValue(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states != null &&
+ states.TryGetValue(identifier, out var state))
{
return state;
}
@@ -62,7 +78,9 @@ static State CurrentStateNamed(string identifier, [CallerMemberName] string call
public static IDisposable Start(string identifier)
{
- if (!namedState.TryAdd(identifier, new()))
+ var states = asyncLocalNamed.Value ??= new(StringComparer.OrdinalIgnoreCase);
+
+ if (!states.TryAdd(identifier, new()))
{
throw new("Recording already started");
}
@@ -83,7 +101,13 @@ public static void Pause(string identifier) =>
public static void TryPause(string identifier)
{
- if (namedState.TryGetValue(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states == null)
+ {
+ return;
+ }
+
+ if (states.TryGetValue(identifier, out var state))
{
state.Pause();
}
@@ -95,7 +119,13 @@ public static void Resume(string identifier) =>
public static void TryResume(string identifier)
{
- if (namedState.TryGetValue(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states == null)
+ {
+ return;
+ }
+
+ if (states.TryGetValue(identifier, out var state))
{
state.Resume();
}
@@ -107,7 +137,13 @@ public static void Clear(string identifier) =>
public static void TryClear(string identifier)
{
- if (namedState.TryGetValue(identifier, out var state))
+ var states = asyncLocalNamed.Value;
+ if (states == null)
+ {
+ return;
+ }
+
+ if (states.TryGetValue(identifier, out var state))
{
state.Clear();
}