feat(guild): /guild/create + populated /guild/info
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using SVSim.UnitTests.Infrastructure;
|
||||
|
||||
namespace SVSim.UnitTests.Integration.Guild;
|
||||
|
||||
public class GuildCreateInfoFlowTests
|
||||
{
|
||||
[Test]
|
||||
public async Task PostingCreate_then_Info_returns_populated_guild()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
long viewerId = await factory.SeedViewerAsync(
|
||||
steamId: 76_561_198_200_000_001UL,
|
||||
displayName: "AlphaIntPlayer");
|
||||
|
||||
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
// POST /guild/create — mirror the arena integration test style: include the base-request fields
|
||||
const string Vid = "0"; const int Sid = 0; const string Stk = "";
|
||||
var create = await client.PostAsync("/guild/create",
|
||||
System.Net.Http.Json.JsonContent.Create(new { guild_name = "AlphaInt", activity = 1, join_condition = 1,
|
||||
viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk }));
|
||||
Assert.That(create.IsSuccessStatusCode, Is.True, $"create failed ({create.StatusCode}): {await create.Content.ReadAsStringAsync()}");
|
||||
|
||||
// POST /guild/info — expect JOINING state with guild populated
|
||||
var info = await client.PostAsync("/guild/info",
|
||||
System.Net.Http.Json.JsonContent.Create(new { viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk }));
|
||||
var json = await info.Content.ReadAsStringAsync();
|
||||
Assert.That(info.IsSuccessStatusCode, Is.True, $"info failed: {json}");
|
||||
|
||||
// In test mode (no UnityPlayer user-agent) the translation middleware is a no-op;
|
||||
// the controller's raw DTO is returned directly (no {data_headers, data} envelope).
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
Assert.That(root.GetProperty("guild_status").GetString(), Is.EqualTo("2"),
|
||||
"guild_status should be JOINING (2)");
|
||||
Assert.That(root.GetProperty("guild").GetProperty("detail").GetProperty("guild_name").GetString(),
|
||||
Is.EqualTo("AlphaInt"));
|
||||
Assert.That(root.GetProperty("guild").GetProperty("members").GetArrayLength(),
|
||||
Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PostingCreate_twice_returns_error_second_time()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
long viewerId = await factory.SeedViewerAsync(
|
||||
steamId: 76_561_198_200_000_002UL,
|
||||
displayName: "DoubleCreatePlayer");
|
||||
|
||||
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
|
||||
const string Vid = "0"; const int Sid = 0; const string Stk = "";
|
||||
var createBody = new { guild_name = "OnlyOnce", activity = 1, join_condition = 1,
|
||||
viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk };
|
||||
|
||||
// First create should succeed
|
||||
var first = await client.PostAsync("/guild/create",
|
||||
System.Net.Http.Json.JsonContent.Create(createBody));
|
||||
Assert.That(first.IsSuccessStatusCode, Is.True, $"First create failed: {await first.Content.ReadAsStringAsync()}");
|
||||
var firstJson = await first.Content.ReadAsStringAsync();
|
||||
using var firstDoc = JsonDocument.Parse(firstJson);
|
||||
// In test mode (no envelope), result_code may be present (failure) or absent (success EmptyResponse).
|
||||
// Success path returns EmptyResponse ({}), so result_code will not be present.
|
||||
var firstRoot = firstDoc.RootElement;
|
||||
if (firstRoot.TryGetProperty("result_code", out var rc1))
|
||||
{
|
||||
// If present it must not be 2 (error code).
|
||||
Assert.That(rc1.GetInt32(), Is.Not.EqualTo(2), "First create must not error");
|
||||
}
|
||||
|
||||
// Second create for the same viewer should return an error envelope (result_code = 2).
|
||||
var secondBody = new { guild_name = "OnlyOnceAgain", activity = 1, join_condition = 1,
|
||||
viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk };
|
||||
var second = await client.PostAsync("/guild/create",
|
||||
System.Net.Http.Json.JsonContent.Create(secondBody));
|
||||
Assert.That(second.IsSuccessStatusCode, Is.True, "HTTP level should still be 200");
|
||||
var secondJson = await second.Content.ReadAsStringAsync();
|
||||
using var secondDoc = JsonDocument.Parse(secondJson);
|
||||
// Error path: the MapErrorToWire helper returns { result_code = 2 }
|
||||
Assert.That(secondDoc.RootElement.TryGetProperty("result_code", out var rc2), Is.True,
|
||||
$"Second create should return result_code field, got: {secondJson}");
|
||||
Assert.That(rc2.GetInt32(), Is.EqualTo(2), "Second create should fail with result_code=2");
|
||||
}
|
||||
}
|
||||
115
SVSim.UnitTests/Services/Guild/GuildServiceCreateTests.cs
Normal file
115
SVSim.UnitTests/Services/Guild/GuildServiceCreateTests.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SVSim.Database.Entities.Guild;
|
||||
using SVSim.Database.Services.Guild;
|
||||
using SVSim.UnitTests.Infrastructure;
|
||||
using GuildEntity = SVSim.Database.Entities.Guild.Guild;
|
||||
|
||||
namespace SVSim.UnitTests.Services.Guild;
|
||||
|
||||
public class GuildServiceCreateTests
|
||||
{
|
||||
private static async Task<long> CreateViewerAsync(SVSimTestFactory factory, ulong steamId = 76_561_198_100_000_001UL, string name = "GuildTestViewer")
|
||||
=> await factory.SeedViewerAsync(steamId: steamId, displayName: name);
|
||||
|
||||
private static IGuildService GuildService(SVSimTestFactory factory, out IServiceScope scope)
|
||||
{
|
||||
scope = factory.Services.CreateScope();
|
||||
return scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CreateAsync_makes_a_guild_with_caller_as_leader()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var viewerId = await CreateViewerAsync(factory, 76_561_198_100_000_001UL, "Alpha Leader");
|
||||
|
||||
GuildOpResult res;
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
res = await svc.CreateAsync(viewerId, new("Alpha", (int)GuildActivity.All, (int)GuildJoinCondition.Free));
|
||||
}
|
||||
|
||||
Assert.That(res.IsOk, Is.True);
|
||||
Assert.That(res.GuildId, Is.Not.Null);
|
||||
|
||||
GuildFullView? view;
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
view = await svc.GetMyGuildAsync(viewerId);
|
||||
}
|
||||
|
||||
Assert.That(view, Is.Not.Null);
|
||||
Assert.That(view!.Guild.Name, Is.EqualTo("Alpha"));
|
||||
Assert.That(view.Guild.LeaderViewerId, Is.EqualTo(viewerId));
|
||||
Assert.That(view.Members.Single().Role, Is.EqualTo(GuildRole.Leader));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CreateAsync_returns_AlreadyInGuild_when_viewer_already_in_a_guild()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var viewerId = await CreateViewerAsync(factory, 76_561_198_100_000_002UL, "Already In");
|
||||
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
var first = await svc.CreateAsync(viewerId, new("FirstGuild", (int)GuildActivity.All, (int)GuildJoinCondition.Free));
|
||||
Assert.That(first.IsOk, Is.True);
|
||||
}
|
||||
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
var second = await svc.CreateAsync(viewerId, new("SecondGuild", (int)GuildActivity.All, (int)GuildJoinCondition.Free));
|
||||
Assert.That(second.Code, Is.EqualTo(GuildOpResultCode.AlreadyInGuild));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CreateAsync_returns_NameTaken_when_guild_name_already_exists()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var v1 = await CreateViewerAsync(factory, 76_561_198_100_000_003UL, "Viewer1");
|
||||
var v2 = await CreateViewerAsync(factory, 76_561_198_100_000_004UL, "Viewer2");
|
||||
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
var first = await svc.CreateAsync(v1, new("SameName", (int)GuildActivity.All, (int)GuildJoinCondition.Free));
|
||||
Assert.That(first.IsOk, Is.True);
|
||||
}
|
||||
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
var second = await svc.CreateAsync(v2, new("SameName", (int)GuildActivity.All, (int)GuildJoinCondition.Free));
|
||||
Assert.That(second.Code, Is.EqualTo(GuildOpResultCode.NameTaken));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CreateAsync_returns_NameInvalid_for_empty_name()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var viewerId = await CreateViewerAsync(factory, 76_561_198_100_000_005UL);
|
||||
|
||||
using var scope = factory.Services.CreateScope();
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
var res = await svc.CreateAsync(viewerId, new("", (int)GuildActivity.All, (int)GuildJoinCondition.Free));
|
||||
Assert.That(res.Code, Is.EqualTo(GuildOpResultCode.NameInvalid));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetMyGuildAsync_returns_null_for_viewer_not_in_any_guild()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var viewerId = await CreateViewerAsync(factory, 76_561_198_100_000_006UL);
|
||||
|
||||
using var scope = factory.Services.CreateScope();
|
||||
var svc = scope.ServiceProvider.GetRequiredService<IGuildService>();
|
||||
var view = await svc.GetMyGuildAsync(viewerId);
|
||||
Assert.That(view, Is.Null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user