using System.Collections.Generic;
using Server;
using Server.Factions;
using Xunit;
namespace UOContent.Tests;
///
/// PlayerState.Rank is read from GetProperties, so it must stay a plain field read. These pin what
/// that requires: the rank is never null, and it is correct without anyone having read it first.
///
[Collection("Sequential UOContent Tests")]
public class FactionRankTests
{
// The faction ctor builds its own Definition, so no world state is needed.
private static Faction NewFaction() => new CouncilOfMages();
private static PlayerState AddMember(Faction faction, List owner)
{
var state = new PlayerState(new Mobile(), faction, owner);
owner.Add(state);
return state;
}
[Fact]
public void Rank_IsPopulatedBeforeAnythingReadsIt()
{
var faction = NewFaction();
var state = new PlayerState(new Mobile(), faction, []);
// Nothing recomputes on read, so the ctor must leave a usable value or Rank.Title NREs.
Assert.NotNull(state.Rank);
Assert.NotNull(state.Rank.Title);
}
[Fact]
public void Rank_IsTheLowestRank_ForAnUnrankedMember()
{
var faction = NewFaction();
var owner = new List();
var a = AddMember(faction, owner);
var b = AddMember(faction, owner);
a.UpdateRank();
b.UpdateRank();
var lowest = faction.Definition.Ranks[^1];
Assert.Equal(lowest.Rank, a.Rank.Rank);
Assert.Equal(lowest.Rank, b.Rank.Rank);
}
[Fact]
public void SettingRankIndex_UpdatesRankWithoutAnyoneReadingIt()
{
var faction = NewFaction();
var owner = new List();
var top = AddMember(faction, owner);
var bottom = AddMember(faction, owner);
faction.ZeroRankOffset = 2;
top.RankIndex = 0;
bottom.RankIndex = 1;
// No read triggered these, yet the ordering is reflected.
Assert.True(top.Rank.Rank > bottom.Rank.Rank);
}
[Fact]
public void ReadingRank_IsStableAndSideEffectFree()
{
var faction = NewFaction();
var owner = new List();
var state = AddMember(faction, owner);
faction.ZeroRankOffset = 1;
state.RankIndex = 0;
var first = state.Rank;
var second = state.Rank;
Assert.Same(first, second);
}
[Fact]
public void RankIndexOutOfSyncWithZeroRankOffset_StillResolvesARank()
{
var faction = NewFaction();
var owner = new List();
var a = AddMember(faction, owner);
AddMember(faction, owner);
// A negative percent used to match no rank at all, leaving Rank null.
faction.ZeroRankOffset = 1;
a.RankIndex = 5;
Assert.NotNull(a.Rank);
}
}