test(card): snapshot-mismatch + protect-load round-trip
Add two spec-prescribed tests that the implementation plan missed: - Create_proceeds_when_client_possession_snapshot_disagrees_with_server - Protect_then_load_index_emits_is_protected_one Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -347,6 +347,39 @@ public class CardControllerTests
|
||||
Assert.That(body, Does.Contain("insufficient_vials"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Create_proceeds_when_client_possession_snapshot_disagrees_with_server()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
long viewerId = await factory.SeedViewerAsync();
|
||||
// Server has 0 owned; client thinks it has 5 (stale snapshot).
|
||||
await factory.SeedOwnedCardAsync(viewerId, cardId: 10001001L, count: 0, craftCost: 200);
|
||||
await factory.SetRedEtherAsync(viewerId, 1_000UL);
|
||||
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
// Inner JSON: create 1, client snapshot=5 (disagrees with server count=0).
|
||||
// Spec: snapshot mismatch is warn-log only, never blocks the request.
|
||||
var response = await client.PostAsync("/card/create",
|
||||
CreateBody("{\"10001001\":\"1,5\"}"));
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), body);
|
||||
|
||||
var entries = JsonDocument.Parse(body).RootElement
|
||||
.GetProperty("reward_list")
|
||||
.EnumerateArray()
|
||||
.Select(e => (Type: e.GetProperty("reward_type").GetInt32(),
|
||||
Id: e.GetProperty("reward_id").GetInt64(),
|
||||
Num: e.GetProperty("reward_num").GetInt32()))
|
||||
.ToList();
|
||||
|
||||
// RedEther and card count based on actual server state, not client snapshot.
|
||||
Assert.That(entries, Has.Member((Type: 1, Id: 0L, Num: 800)),
|
||||
"RedEther post-state total = 1000 - 200 = 800");
|
||||
Assert.That(entries, Has.Member((Type: 5, Id: 10001001L, Num: 1)),
|
||||
"Card post-state owned count = 0 + 1 = 1");
|
||||
}
|
||||
|
||||
private static StringContent ProtectBody(long cardId, bool isProtected) =>
|
||||
new(
|
||||
$$"""{"card_id":{{cardId}},"is_protected":{{(isProtected ? "true" : "false")}},"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""",
|
||||
@@ -431,4 +464,39 @@ public class CardControllerTests
|
||||
// controller payload, which for CardProtectResponse is an empty object.
|
||||
Assert.That(body.Trim(), Is.EqualTo("{}"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Protect_then_load_index_emits_is_protected_one()
|
||||
{
|
||||
// Spec: /load/index user_card_list[].is_protected is an int wire value (0 or 1),
|
||||
// not a bool. Protect a card then verify /load/index round-trips the flag correctly.
|
||||
using var factory = new SVSimTestFactory();
|
||||
long viewerId = await factory.SeedViewerAsync();
|
||||
await factory.SeedOwnedCardAsync(viewerId, cardId: 10001001L, count: 2);
|
||||
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
// Set the protect flag.
|
||||
var protectResponse = await client.PostAsync("/card/protect",
|
||||
ProtectBody(10001001L, isProtected: true));
|
||||
Assert.That(protectResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK),
|
||||
await protectResponse.Content.ReadAsStringAsync());
|
||||
|
||||
// Call /load/index and parse user_card_list.
|
||||
const string IndexRequestJson =
|
||||
"""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","carrier":"web","card_master_hash":""}""";
|
||||
var loadResponse = await client.PostAsync("/load/index",
|
||||
new StringContent(IndexRequestJson, Encoding.UTF8, "application/json"));
|
||||
var loadBody = await loadResponse.Content.ReadAsStringAsync();
|
||||
Assert.That(loadResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK), loadBody);
|
||||
|
||||
var cardEntry = JsonDocument.Parse(loadBody).RootElement
|
||||
.GetProperty("user_card_list")
|
||||
.EnumerateArray()
|
||||
.FirstOrDefault(e => e.GetProperty("card_id").GetInt64() == 10001001L);
|
||||
|
||||
Assert.That(cardEntry.ValueKind, Is.Not.EqualTo(JsonValueKind.Undefined),
|
||||
"Expected card 10001001 in user_card_list");
|
||||
Assert.That(cardEntry.GetProperty("is_protected").GetInt32(), Is.EqualTo(1),
|
||||
"is_protected wire value must be 1 (int) after protect call");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user