Files
RpgRoller/RpgRoller.Tests/Services/ServiceSkillGroupAndOwnershipTests.cs
2026-04-05 01:32:52 +02:00

228 lines
13 KiB
C#

namespace RpgRoller.Tests;
public sealed class ServiceSkillGroupAndOwnershipTests
{
[Fact]
public void SkillGroups_CanBeManagedAndAssignedWithinCharacterScope()
{
using var harness = ServiceTestSupport.CreateHarness(4, 3, 2);
var service = harness.Service;
service.Register("gm", "Password123", "GM");
service.Register("owner", "Password123", "Owner");
service.Register("other", "Password123", "Other");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner", "Password123")).SessionToken;
var otherSession = ServiceTestSupport.GetValue(service.Login("other", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Main", "d6"));
var ownerCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Owner Char", campaign.Id));
var otherCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(otherSession, "Other Char", campaign.Id));
var ownerGroup = ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, ownerCharacter.Id, "Combat", "2D+1", 1, true));
Assert.False(service.CreateSkillGroup(ownerSession, otherCharacter.Id, "Not Allowed", "2D+1", 1, true).Succeeded);
Assert.False(service.UpdateSkillGroup(otherSession, ownerGroup.Id, "Renamed by Other", "2D+1", 1, true).Succeeded);
var renamedGroup = ServiceTestSupport.GetValue(service.UpdateSkillGroup(gmSession, ownerGroup.Id, "Battle", "3D+2", 2, false));
Assert.Equal("Battle", renamedGroup.Name);
Assert.Equal("3D+2", renamedGroup.DiceRollDefinition);
Assert.Equal(2, renamedGroup.WildDice);
Assert.False(renamedGroup.AllowFumble);
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, ownerCharacter.Id, "Strike", "2D+1", 1, true, renamedGroup.Id));
Assert.Equal(renamedGroup.Id, skill.SkillGroupId);
var otherGroup = ServiceTestSupport.GetValue(service.CreateSkillGroup(otherSession, otherCharacter.Id, "Other Group", "2D+1", 1, true));
Assert.False(service.UpdateSkill(ownerSession, skill.Id, "Strike", "2D+1", 1, true, otherGroup.Id).Succeeded);
var ungroupedSkill = ServiceTestSupport.GetValue(service.UpdateSkill(ownerSession, skill.Id, "Strike", "2D+1", 1, true));
Assert.Null(ungroupedSkill.SkillGroupId);
var regroupedSkill = ServiceTestSupport.GetValue(service.UpdateSkill(ownerSession, skill.Id, "Strike", "2D+1", 1, true, renamedGroup.Id));
Assert.Equal(renamedGroup.Id, regroupedSkill.SkillGroupId);
var deletedGroup = ServiceTestSupport.GetValue(service.DeleteSkillGroup(ownerSession, renamedGroup.Id));
Assert.True(deletedGroup);
var ownerSheetAfterGroupDelete = ServiceTestSupport.GetValue(service.GetCharacterSheet(ownerSession, ownerCharacter.Id));
var otherSheetAfterGroupDelete = ServiceTestSupport.GetValue(service.GetCharacterSheet(ownerSession, otherCharacter.Id));
Assert.DoesNotContain(ownerSheetAfterGroupDelete.SkillGroups, group => group.Id == renamedGroup.Id);
Assert.Contains(otherSheetAfterGroupDelete.SkillGroups, group => group.Id == otherGroup.Id);
Assert.Null(ownerSheetAfterGroupDelete.Skills.Single(s => s.Id == regroupedSkill.Id).SkillGroupId);
var deletedSkill = ServiceTestSupport.GetValue(service.DeleteSkill(ownerSession, regroupedSkill.Id));
Assert.True(deletedSkill);
var ownerView = ServiceTestSupport.GetValue(service.GetCharacterSheet(ownerSession, ownerCharacter.Id));
var otherView = ServiceTestSupport.GetValue(service.GetCharacterSheet(ownerSession, otherCharacter.Id));
Assert.DoesNotContain(ownerView.SkillGroups, group => group.Id == renamedGroup.Id);
Assert.Contains(otherView.SkillGroups, group => group.Id == otherGroup.Id);
Assert.DoesNotContain(ownerView.Skills, skillSummary => skillSummary.Id == regroupedSkill.Id);
}
[Fact]
public void CharacterOwnerTransfer_RequiresGmPrivileges()
{
using var harness = ServiceTestSupport.CreateHarness();
var service = harness.Service;
service.Register("gm", "Password123", "GM");
service.Register("owner", "Password123", "Owner");
service.Register("receiver", "Password123", "Receiver");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner", "Password123")).SessionToken;
var receiverSession = ServiceTestSupport.GetValue(service.Login("receiver", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Main", "d6"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Transfer Me", campaign.Id));
Assert.True(service.ActivateCharacter(ownerSession, character.Id).Succeeded);
var ownerTransferAttempt = service.UpdateCharacter(ownerSession, character.Id, "Transfer Me", campaign.Id, "receiver");
Assert.False(ownerTransferAttempt.Succeeded);
var missingOwnerAttempt = service.UpdateCharacter(gmSession, character.Id, "Transfer Me", campaign.Id, "missing-user");
Assert.False(missingOwnerAttempt.Succeeded);
var gmTransfer = ServiceTestSupport.GetValue(service.UpdateCharacter(gmSession, character.Id, "Transferred", campaign.Id, "receiver"));
var receiver = service.GetUserBySession(receiverSession);
Assert.NotNull(receiver);
Assert.Equal(receiver!.Id, gmTransfer.OwnerUserId);
var previousOwnerMe = ServiceTestSupport.GetValue(service.GetMe(ownerSession));
Assert.Null(previousOwnerMe.ActiveCharacterId);
Assert.False(service.ActivateCharacter(ownerSession, character.Id).Succeeded);
Assert.True(service.ActivateCharacter(receiverSession, character.Id).Succeeded);
}
[Fact]
public void CharacterUnlink_AllowsOwnerGmAndAdmin()
{
using var harness = ServiceTestSupport.CreateHarness();
var service = harness.Service;
service.Register("gm", "Password123", "GM");
service.Register("owner", "Password123", "Owner");
service.Register("outsider", "Password123", "Outsider");
service.Register("admin2", "Password123", "Admin Two");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner", "Password123")).SessionToken;
var outsiderSession = ServiceTestSupport.GetValue(service.Login("outsider", "Password123")).SessionToken;
var adminTwoSession = ServiceTestSupport.GetValue(service.Login("admin2", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Main", "d6"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Unlink Me", campaign.Id));
var outsiderUnlink = service.UpdateCharacter(outsiderSession, character.Id, "Unlink Me", null);
Assert.False(outsiderUnlink.Succeeded);
var ownerUnlink = ServiceTestSupport.GetValue(service.UpdateCharacter(ownerSession, character.Id, "Owner Unlink", null));
Assert.Null(ownerUnlink.CampaignId);
var relinkByOwner = ServiceTestSupport.GetValue(service.UpdateCharacter(ownerSession, character.Id, "Relink", campaign.Id));
Assert.Equal(campaign.Id, relinkByOwner.CampaignId);
var gmUnlink = ServiceTestSupport.GetValue(service.UpdateCharacter(gmSession, character.Id, "Gm Unlink", null));
Assert.Null(gmUnlink.CampaignId);
var relinkByGm = ServiceTestSupport.GetValue(service.UpdateCharacter(gmSession, character.Id, "Relink Again", campaign.Id));
Assert.Equal(campaign.Id, relinkByGm.CampaignId);
var adminTwo = service.GetUserBySession(adminTwoSession);
Assert.NotNull(adminTwo);
_ = ServiceTestSupport.GetValue(service.UpdateUserRoles(gmSession, adminTwo!.Id, ["admin"]));
var adminUnlink = ServiceTestSupport.GetValue(service.UpdateCharacter(adminTwoSession, character.Id, "Admin Unlink", null));
Assert.Null(adminUnlink.CampaignId);
}
[Fact]
public void CharacterDelete_AllowsOnlyOwnerOrAdmin()
{
using var harness = ServiceTestSupport.CreateHarness();
var service = harness.Service;
service.Register("admin", "Password123", "Admin");
service.Register("gm", "Password123", "GM");
service.Register("owner", "Password123", "Owner");
service.Register("other", "Password123", "Other");
var adminSession = ServiceTestSupport.GetValue(service.Login("admin", "Password123")).SessionToken;
var gmSession = ServiceTestSupport.GetValue(service.Login("gm", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner", "Password123")).SessionToken;
var otherSession = ServiceTestSupport.GetValue(service.Login("other", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Main", "d6"));
var ownerCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Owner Character", campaign.Id));
var otherCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(otherSession, "Other Character", campaign.Id));
var gmDeleteAttempt = service.DeleteCharacter(gmSession, ownerCharacter.Id);
Assert.False(gmDeleteAttempt.Succeeded);
var otherDeleteAttempt = service.DeleteCharacter(otherSession, ownerCharacter.Id);
Assert.False(otherDeleteAttempt.Succeeded);
var ownerDelete = ServiceTestSupport.GetValue(service.DeleteCharacter(ownerSession, ownerCharacter.Id));
Assert.True(ownerDelete);
var adminDelete = ServiceTestSupport.GetValue(service.DeleteCharacter(adminSession, otherCharacter.Id));
Assert.True(adminDelete);
var campaignAfterDeletes = ServiceTestSupport.GetValue(service.GetCampaign(gmSession, campaign.Id));
Assert.Empty(campaignAfterDeletes.Characters);
}
[Fact]
public void RolemasterSkillDefinitions_CanonicalizeAndKeepLegacyNegativeModifierRules()
{
using var harness = ServiceTestSupport.CreateHarness();
var service = harness.Service;
service.Register("gm-rm", "Password123", "GM");
service.Register("owner-rm", "Password123", "Owner");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-rm", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-rm", "Password123")).SessionToken;
var rolemasterCampaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Shadow World", "rolemaster"));
var dndCampaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Forgotten Realms", "dnd5e"));
var rolemasterCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Harn", rolemasterCampaign.Id));
var dndCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Mage", dndCampaign.Id));
var negativeDndSkill = service.CreateSkill(ownerSession, dndCharacter.Id, "Invalid", "1d20-1", 0, false);
Assert.False(negativeDndSkill.Succeeded);
var invalidRolemasterOptions = service.CreateSkillGroup(ownerSession, rolemasterCharacter.Id, "Invalid", "2d10-15", 3, true);
Assert.False(invalidRolemasterOptions.Succeeded);
var rolemasterGroup = ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, rolemasterCharacter.Id, "Awareness", "d100!+15", 0, false, 5));
Assert.Equal("d100!+15", rolemasterGroup.DiceRollDefinition);
Assert.Equal(0, rolemasterGroup.WildDice);
Assert.False(rolemasterGroup.AllowFumble);
Assert.Equal(5, rolemasterGroup.FumbleRange);
var percentileWithFumbleRange = service.CreateSkill(ownerSession, rolemasterCharacter.Id, "Bad Percentile", "1d100-20", 0, false, null, 5);
Assert.False(percentileWithFumbleRange.Succeeded);
var percentileSkill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, rolemasterCharacter.Id, "Perception", "1d100-20", 0, false, rolemasterGroup.Id));
Assert.Equal("d100-20", percentileSkill.DiceRollDefinition);
Assert.Equal(0, percentileSkill.WildDice);
Assert.False(percentileSkill.AllowFumble);
Assert.Null(percentileSkill.FumbleRange);
var missingOpenEndedFumbleRange = service.UpdateSkill(ownerSession, percentileSkill.Id, "Perception", "1d100!+85", 0, false, rolemasterGroup.Id);
Assert.False(missingOpenEndedFumbleRange.Succeeded);
var invalidOpenEndedFumbleRange = service.UpdateSkill(ownerSession, percentileSkill.Id, "Perception", "1d100!+85", 0, false, rolemasterGroup.Id, 96);
Assert.False(invalidOpenEndedFumbleRange.Succeeded);
var openEndedSkill = ServiceTestSupport.GetValue(service.UpdateSkill(ownerSession, percentileSkill.Id, "Perception", "1d100!+85", 0, false, rolemasterGroup.Id, 5));
Assert.Equal("d100!+85", openEndedSkill.DiceRollDefinition);
Assert.Equal(0, openEndedSkill.WildDice);
Assert.False(openEndedSkill.AllowFumble);
Assert.Equal(5, openEndedSkill.FumbleRange);
}
}