Skip to content

Commit c77cda4

Browse files
chuntyCopilot
andcommitted
make TaskKeyConverter public; update wiki docs for object keys and testing
- TaskKeyConverter.ToKey is now public so consumers can resolve keys in tests - wiki/Testing.md: fix manual mock examples (string -> object), add TaskKeyConverter.ToKey section for store-level assertions, add object key example - wiki/Migrating-to-v2.md: note TaskKeyConverter.ToKey is public Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 12f8c69 commit c77cda4

3 files changed

Lines changed: 45 additions & 11 deletions

File tree

TaskKeyConverter.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,23 @@
55
namespace TaskTurnstile;
66

77
/// <summary>
8-
/// Converts an <see cref="object"/> task key to the string used by the backing store.
9-
/// Strings are used as-is. All other types are serialized to JSON and hashed with SHA-256,
10-
/// prefixed with the type name so keys are identifiable in the database.
8+
/// Converts an <see cref="object"/> task key to the string stored in the backing store.
119
/// </summary>
12-
internal static class TaskKeyConverter
10+
/// <remarks>
11+
/// Conversion rules:
12+
/// <list type="bullet">
13+
/// <item><description><see langword="string"/> — used as-is.</description></item>
14+
/// <item><description>Primitives, enums, <see cref="Guid"/>, <see cref="decimal"/>, <see cref="DateTime"/>, <see cref="DateOnly"/>, <see cref="TimeOnly"/>, <see cref="DateTimeOffset"/> — <c>{TypeFullName}:{value}</c>, e.g. <c>System.Int32:42</c>.</description></item>
15+
/// <item><description>All other types — JSON-serialised, SHA-256 hashed: <c>{TypeFullName}:{hex}</c>.</description></item>
16+
/// </list>
17+
/// Use this in tests to compute the expected store key when asserting against <see cref="ITaskStateStore"/>.
18+
/// </remarks>
19+
public static class TaskKeyConverter
1320
{
14-
internal static string ToKey(object key)
21+
/// <summary>
22+
/// Converts <paramref name="key"/> to the string used by the backing store.
23+
/// </summary>
24+
public static string ToKey(object key)
1525
{
1626
if (key is string s) return s;
1727
var type = key.GetType();

wiki/Migrating-to-v2.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ If you were calling these extension methods they will need updating to call the
5252

5353
- **Object task keys** — pass any type as a task key. Strings are unchanged; primitives, enums, `Guid`, `DateTime`, and other value types use `ToString()` prefixed with the type name; complex objects are JSON-serialised and SHA-256 hashed.
5454
- Keys are always human-readable in the database (type name prefix makes them identifiable).
55+
- **`TaskKeyConverter.ToKey(object key)`** is public — use it in tests to resolve the expected store key when asserting against `ITaskStateStore`.

wiki/Testing.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,13 @@ manager.SetupTryRunAsyncToSkip<int>();
5050
Pass `taskKey` to make the setup match only that key. Any other key falls through to the Moq / NSubstitute default. This is useful when the thing you're testing is *which* key gets passed:
5151

5252
```csharp
53-
// Moq
53+
// Moq — string key
5454
Mocker.GetMock<ITaskStateManager>().SetupTryRunAsync(returns: true, taskKey: "import-job");
5555

56-
// Verify the correct name was used
56+
// Moq — object key
57+
Mocker.GetMock<ITaskStateManager>().SetupTryRunAsync(returns: true, taskKey: new JobKey { TenantId = 42 });
58+
59+
// Verify the correct key was used
5760
Mocker.GetMock<ITaskStateManager>()
5861
.Verify(m => m.TryRunAsync(
5962
"import-job",
@@ -73,6 +76,26 @@ await manager.Received(1).TryRunAsync(
7376
Arg.Any<CancellationToken>());
7477
```
7578

79+
### Resolving object keys in store-level assertions
80+
81+
When asserting on `ITaskStateStore` calls directly (e.g., in custom store tests), you need the resolved string key. Use `TaskKeyConverter.ToKey` to compute it:
82+
83+
```csharp
84+
using TaskTurnstile;
85+
86+
var key = new JobKey { TenantId = 42 };
87+
var storeKey = TaskKeyConverter.ToKey(key); // e.g. "MyApp.JobKey:a3f9..."
88+
89+
storeMock.Verify(s => s.SetRunningAsync(storeKey, It.IsAny<TimeSpan?>(), It.IsAny<CancellationToken>()));
90+
```
91+
92+
For string and primitive keys:
93+
94+
```csharp
95+
TaskKeyConverter.ToKey("import-job") // → "import-job"
96+
TaskKeyConverter.ToKey(42) // → "System.Int32:42"
97+
```
98+
7699
---
77100

78101
## Manual mocking (without TaskTurnstile.Testing)
@@ -84,11 +107,11 @@ If you prefer to wire up your mocking framework directly without the helper exte
84107
```csharp
85108
Mocker.GetMock<ITaskStateManager>()
86109
.Setup(m => m.TryRunAsync(
87-
It.IsAny<string>(),
110+
It.IsAny<object>(),
88111
It.IsAny<Func<CancellationToken, Task>>(),
89112
It.IsAny<TimeSpan?>(),
90113
It.IsAny<CancellationToken>()))
91-
.Returns<string, Func<CancellationToken, Task>, TimeSpan?, CancellationToken>(
114+
.Returns<object, Func<CancellationToken, Task>, TimeSpan?, CancellationToken>(
92115
async (_, work, _, ct) => { await work(ct); return true; });
93116
```
94117

@@ -97,7 +120,7 @@ Mocker.GetMock<ITaskStateManager>()
97120
```csharp
98121
Mocker.GetMock<ITaskStateManager>()
99122
.Setup(m => m.TryRunAsync(
100-
It.IsAny<string>(),
123+
It.IsAny<object>(),
101124
It.IsAny<Func<CancellationToken, Task>>(),
102125
It.IsAny<TimeSpan?>(),
103126
It.IsAny<CancellationToken>()))
@@ -108,7 +131,7 @@ Mocker.GetMock<ITaskStateManager>()
108131

109132
```csharp
110133
manager.TryRunAsync(
111-
Arg.Any<string>(),
134+
Arg.Any<object>(),
112135
Arg.Any<Func<CancellationToken, Task>>(),
113136
Arg.Any<TimeSpan?>(),
114137
Arg.Any<CancellationToken>())

0 commit comments

Comments
 (0)