## Summary Many tests proved a specific change when it landed but don't need to run on every CI build forever. This removes **202 test methods and 9 files: 313 test cases, 2,247 → 1,934**. UOContent.Tests drops from about 14s to about 5s locally. Removed: - **Tautologies.** Asserting a constant, a constructor readback or a trivial getter, or testing BCL behavior. - **Exact duplicates** of a surviving test on the same code path. - **Obsolete regressions** whose failure can no longer be expressed. - **Game-content values** shard owners customize (era drop rates, loot and skill tables, single-creature tuning). Each customization would otherwise force a test fix. ## How it was decided 1. Every test was classified, with a reason, by a per-shard sweep over all 287 test files. 2. Each proposed deletion was then checked by a second, adversarial reviewer against the surviving tests and the production code. 3. Anything that was the only coverage of a separate code path was **kept**, even where it looked like a duplicate. Examples: the unsigned `SpanReader`/`SpanWriter` methods, the at-location versus bounds enumerators, null-map enumerables, the security filters, archive-journal state transitions. About 130 proposed deletions were rejected this way. Whole files removed: - `FishingTests`, apart from 3 tests: the map-edge scan, serpent cleanup, and SOS chest consumption. The SOS test now stops at the first chest instead of measuring a catch rate. The multi-million-cast rate simulations are gone. - `LordOaksTests` and `MeerEnragedTests` (single-creature tests). - `AutoArchiveHelperTests`, `JsonDiscoverableTypeAttributeTests`, `DecimalSerializationTests` and `EnumConversionTests` (tautologies, or tests of their own local helpers). - `NetworkStatsTests`. - `MigratedDataLoadTests` (a subset of `AllSpawnFilesLoadTests`). - `SpawnerFixtureCapture`: a capture tool, not a test, and its `version == 12` assert can no longer pass. The `.bin` fixtures it produced stay. ## Tests - Server.Tests: 811 pass. - UOContent.Tests: 1,123 pass. A follow-up PR, stacked on this one, fixes how the remaining tests behave: shared state, CI-vacuous tests, harness duplication.
120 lines
3.3 KiB
C#
120 lines
3.3 KiB
C#
using System;
|
|
using Xunit;
|
|
|
|
namespace Server.Tests;
|
|
|
|
/// <summary>
|
|
/// The interpolation buffer is rented by the handler ctor and returned by the closing Add, so every
|
|
/// hole is evaluated while it is live. A Reset()/Dispose() landing in that window used to leave the
|
|
/// next Append* spanning a null array: ArgumentNullException, parameter "array".
|
|
/// </summary>
|
|
// Sequential: building a list rents from STArrayPool, which is not thread-safe.
|
|
[Collection("Sequential Server Tests")]
|
|
public class ObjectPropertyListReentrancyTests
|
|
{
|
|
// Stands in for a property getter that invalidates while its own tooltip is being built.
|
|
private static string ResettingHole(ObjectPropertyList list, string value)
|
|
{
|
|
list.Reset();
|
|
return value;
|
|
}
|
|
|
|
private static string DisposingHole(ObjectPropertyList list, string value)
|
|
{
|
|
list.Dispose();
|
|
return value;
|
|
}
|
|
|
|
[Fact]
|
|
public void InterpolatedAdd_DisposeMidHole_DoesNotThrow()
|
|
{
|
|
var opl = new ObjectPropertyList(null);
|
|
|
|
var ex = Record.Exception(
|
|
() => opl.Add(1060776, $"{DisposingHole(opl, "Knight")}\t{"Council of Mages"}")
|
|
);
|
|
|
|
Assert.Null(ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The guard is per-list, so nested builds (a GetProperties override that reads another entity's
|
|
/// PropertyList) cannot unguard the outer one the way a single shared slot would.
|
|
/// </summary>
|
|
[Collection("Sequential Server Tests")]
|
|
public class ObjectPropertyListNestedBuildTests
|
|
{
|
|
[Fact]
|
|
public void Reset_MidInterpolation_LeavesTheListUsable()
|
|
{
|
|
var opl = new ObjectPropertyList(null);
|
|
|
|
opl.Add(1060776, $"{Reset(opl, "Knight")}\t{"Council of Mages"}");
|
|
opl.Add(1042971, "still working");
|
|
opl.Terminate();
|
|
|
|
Assert.NotNull(opl.Buffer);
|
|
}
|
|
|
|
private static string Reset(ObjectPropertyList list, string value)
|
|
{
|
|
list.Reset();
|
|
return value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Invalidating from inside GetProperties is a defect in the getter, not a case to recover from:
|
|
/// DEBUG throws, RELEASE keeps a possibly stale tooltip without crashing or leaking.
|
|
/// </summary>
|
|
[Collection("Sequential Server Tests")]
|
|
public class PropertyListInvalidationDuringBuildTests
|
|
{
|
|
private class SelfInvalidatingMobile : Mobile
|
|
{
|
|
public int Builds;
|
|
|
|
public override void GetProperties(IPropertyList list)
|
|
{
|
|
Builds++;
|
|
base.GetProperties(list);
|
|
InvalidateProperties();
|
|
list.Add(1060776, $"{"Knight"}\t{"Council of Mages"}");
|
|
}
|
|
}
|
|
|
|
private static SelfInvalidatingMobile Place(int x)
|
|
{
|
|
var m = new SelfInvalidatingMobile();
|
|
m.MoveToWorld(new Point3D(x, 1000, 0), Map.Felucca);
|
|
return m;
|
|
}
|
|
|
|
[Fact]
|
|
public void InvalidatingFromGetProperties_FailsLoudlyWithoutTearingDownTheBuild()
|
|
{
|
|
var wasEnabled = ObjectPropertyList.Enabled;
|
|
ObjectPropertyList.Enabled = true;
|
|
|
|
try
|
|
{
|
|
var m = Place(1000);
|
|
|
|
#if DEBUG
|
|
Assert.Throws<InvalidOperationException>(() => _ = m.PropertyList);
|
|
#else
|
|
Assert.Null(Record.Exception(() => _ = m.PropertyList));
|
|
#endif
|
|
|
|
// Refused, not retried.
|
|
Assert.Equal(1, m.Builds);
|
|
m.Delete();
|
|
}
|
|
finally
|
|
{
|
|
ObjectPropertyList.Enabled = wasEnabled;
|
|
}
|
|
}
|
|
}
|