293 lines
12 KiB
C#
293 lines
12 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using NeonSprawl.Server.Game.Items;
|
|
using NeonSprawl.Server.Game.Mastery;
|
|
using NeonSprawl.Server.Game.Quests;
|
|
using NeonSprawl.Server.Game.Rewards;
|
|
using NeonSprawl.Server.Game.Skills;
|
|
using NeonSprawl.Server.Tests;
|
|
using Xunit;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Quests;
|
|
|
|
public sealed class QuestAcceptApiTests
|
|
{
|
|
private const string PlayerId = "dev-local-1";
|
|
private const string GatherQuestId = PrototypeE7M1QuestCatalogRules.GatherIntroQuestId;
|
|
private const string RefineQuestId = PrototypeE7M1QuestCatalogRules.RefineIntroQuestId;
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldReturnNotFound_WhenPlayerUnknown()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/missing-player/quests/{GatherQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldReturnNotFound_WhenPlayerIdIsWhitespaceOnly()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/%20/quests/{GatherQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldReturnAcceptedTrue_WhenGatherIntroNotStarted()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.Equal(QuestAcceptResponse.CurrentSchemaVersion, body!.SchemaVersion);
|
|
Assert.True(body.Accepted);
|
|
Assert.Null(body.ReasonCode);
|
|
Assert.NotNull(body.Quest);
|
|
Assert.Equal(GatherQuestId, body.Quest!.QuestId);
|
|
Assert.Equal(QuestProgressApi.StatusActive, body.Quest.Status);
|
|
Assert.Equal(0, body.Quest.CurrentStepIndex);
|
|
Assert.Empty(body.Quest.ObjectiveCounters);
|
|
Assert.Null(body.Quest.CompletedAt);
|
|
Assert.Null(body.Quest.CompletionRewardSummary);
|
|
|
|
var getResponse = await client.GetAsync($"/game/players/{PlayerId}/quest-progress");
|
|
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
|
var progress = await getResponse.Content.ReadFromJsonAsync<QuestProgressListResponse>();
|
|
Assert.NotNull(progress);
|
|
var row = Assert.Single(progress!.Quests, static r => r.QuestId == GatherQuestId);
|
|
Assert.Equal(QuestProgressApi.StatusActive, row.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldReturnAcceptedTrue_WhenRequestBodyOmitted()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
content: null);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.True(body!.Accepted);
|
|
Assert.Equal(GatherQuestId, body.Quest!.QuestId);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldReturnAcceptedTrue_WhenRequestBodyIsEmptyObject()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
using var content = new StringContent("{}", Encoding.UTF8, "application/json");
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.True(body!.Accepted);
|
|
Assert.Equal(GatherQuestId, body.Quest!.QuestId);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldReturnBadRequest_WhenSchemaVersionInvalid()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
using var content = new StringContent(
|
|
JsonSerializer.Serialize(new { schemaVersion = 99 }),
|
|
Encoding.UTF8,
|
|
"application/json");
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
content);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldDenyPrerequisiteIncomplete_WhenRefineIntroBeforeGatherComplete()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{RefineQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.False(body!.Accepted);
|
|
Assert.Equal(QuestStateReasonCodes.PrerequisiteIncomplete, body.ReasonCode);
|
|
Assert.Null(body.Quest);
|
|
|
|
var getResponse = await client.GetAsync($"/game/players/{PlayerId}/quest-progress");
|
|
var progress = await getResponse.Content.ReadFromJsonAsync<QuestProgressListResponse>();
|
|
Assert.NotNull(progress);
|
|
var row = Assert.Single(progress!.Quests, static r => r.QuestId == RefineQuestId);
|
|
Assert.Equal(QuestProgressApi.StatusNotStarted, row.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldDenyAlreadyActive_WhenQuestAlreadyAccepted()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
_ = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.False(body!.Accepted);
|
|
Assert.Equal(QuestStateReasonCodes.AlreadyActive, body.ReasonCode);
|
|
Assert.NotNull(body.Quest);
|
|
Assert.Equal(QuestProgressApi.StatusActive, body.Quest!.Status);
|
|
Assert.Equal(0, body.Quest.CurrentStepIndex);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldDenyAlreadyCompleted_WhenQuestAlreadyCompleted()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
var services = factory.Services;
|
|
var questRegistry = services.GetRequiredService<IQuestDefinitionRegistry>();
|
|
var progressStore = services.GetRequiredService<IPlayerQuestStateStore>();
|
|
var inventoryStore = services.GetRequiredService<IPlayerInventoryStore>();
|
|
var itemRegistry = services.GetRequiredService<IItemDefinitionRegistry>();
|
|
var skillRegistry = services.GetRequiredService<ISkillDefinitionRegistry>();
|
|
var skillProgressionStore = services.GetRequiredService<IPlayerSkillProgressionStore>();
|
|
var levelCurve = services.GetRequiredService<ISkillLevelCurve>();
|
|
var perkUnlockEngine = services.GetRequiredService<PerkUnlockEngine>();
|
|
var perkStore = services.GetRequiredService<IPlayerPerkStateStore>();
|
|
var deliveryStore = services.GetRequiredService<IRewardDeliveryStore>();
|
|
var timeProvider = TimeProvider.System;
|
|
Assert.True(QuestStateOperations.TryAccept(
|
|
PlayerId,
|
|
GatherQuestId,
|
|
questRegistry,
|
|
progressStore,
|
|
inventoryStore,
|
|
itemRegistry,
|
|
skillRegistry,
|
|
skillProgressionStore,
|
|
levelCurve,
|
|
perkUnlockEngine,
|
|
perkStore,
|
|
deliveryStore,
|
|
timeProvider).Success);
|
|
Assert.True(QuestStateOperations.TryMarkComplete(
|
|
PlayerId,
|
|
GatherQuestId,
|
|
questRegistry,
|
|
progressStore,
|
|
itemRegistry,
|
|
inventoryStore,
|
|
skillRegistry,
|
|
skillProgressionStore,
|
|
levelCurve,
|
|
perkUnlockEngine,
|
|
perkStore,
|
|
deliveryStore,
|
|
timeProvider).Success);
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/{GatherQuestId}/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.False(body!.Accepted);
|
|
Assert.Equal(QuestStateReasonCodes.AlreadyCompleted, body.ReasonCode);
|
|
Assert.NotNull(body.Quest);
|
|
Assert.Equal(QuestProgressApi.StatusCompleted, body.Quest!.Status);
|
|
Assert.Equal(0, body.Quest.CurrentStepIndex);
|
|
Assert.NotNull(body.Quest.CompletedAt);
|
|
Assert.NotNull(body.Quest.CompletionRewardSummary);
|
|
Assert.Empty(body.Quest.CompletionRewardSummary!.ItemGrants);
|
|
Assert.Single(body.Quest.CompletionRewardSummary.SkillXpGrants);
|
|
Assert.Equal("salvage", body.Quest.CompletionRewardSummary.SkillXpGrants[0].SkillId);
|
|
Assert.Equal(25, body.Quest.CompletionRewardSummary.SkillXpGrants[0].Amount);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostQuestAccept_ShouldDenyUnknownQuest_WhenQuestIdNotInCatalog()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
|
|
// Act
|
|
var response = await client.PostAsync(
|
|
$"/game/players/{PlayerId}/quests/prototype_quest_missing/accept",
|
|
JsonContent.Create(new QuestAcceptRequest { SchemaVersion = QuestAcceptRequest.CurrentSchemaVersion }));
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<QuestAcceptResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.False(body!.Accepted);
|
|
Assert.Equal(QuestStateReasonCodes.UnknownQuest, body.ReasonCode);
|
|
Assert.Null(body.Quest);
|
|
}
|
|
}
|