using System; using System.Linq; using UnitTestSharp; namespace Amphora.UnitTests { public class FailureKindRegistryTests : TestFixture { public static class AliasHolder { public static readonly MessageFailureKind Alias = FailureTestKinds.Unreachable; } public static class VariedHolder { private static readonly MessageFailureKind Hidden = new MessageFailureKind("Amphora.UnitTests.Hidden", "hidden"); public static string HiddenName => Hidden.Name; public static MessageFailureKind Property { get; } = new MessageFailureKind("Amphora.UnitTests.Property", "property"); public static readonly FailureKind BaseTyped = new MessageFailureKind("Amphora.UnitTests.BaseTyped", "base typed"); } public static class EmptyHolder { public static readonly MessageFailureKind Missing = null; } public class GenericHolder { public static readonly MessageFailureKind Kind = new MessageFailureKind("Amphora.UnitTests.Generic", "generic"); } public class RegisterTests : TestFixture { public void Null_Throws() { CheckThrow(typeof(ArgumentNullException)); new FailureKindRegistry().Register(null); } public void Placeholder_Throws() { CheckThrow(typeof(ArgumentException)); new FailureKindRegistry().Register(new UnknownFailureKind(5)); } public void SameKindTwice_KeepsIt() { var registry = new FailureKindRegistry(); registry.Register(FailureTestKinds.Unreachable); registry.Register(FailureTestKinds.Unreachable); CheckEqual(FailureTestKinds.Unreachable, registry.Resolve(FailureTestKinds.Unreachable.Id)); } public void AnotherKindWithTheSameId_Throws() { var registry = new FailureKindRegistry(); registry.Register(FailureTestKinds.Unreachable); CheckThrow(typeof(InvalidOperationException)); registry.Register(new MessageFailureKind(FailureTestKinds.Unreachable.Name, "other")); } } public class ResolveTests : TestFixture { public void Registered_ReturnsTheKind() { var registry = new FailureKindRegistry(); registry.Register(BlockedCellKind.Instance); CheckEqual(BlockedCellKind.Instance, registry.Resolve(BlockedCellKind.Instance.Id)); } public void OkWireId_ReturnsNull() { CheckNull(new FailureKindRegistry().Resolve(Status.OkWireId)); } public void Unregistered_ReturnsAPlaceholderWithTheId() { FailureKind kind = new FailureKindRegistry().Resolve(5); CheckEqual(typeof(UnknownFailureKind), kind.GetType()); CheckEqual(5UL, kind.Id); } public void Unregistered_ReturnsTheSamePlaceholderEachTime() { var registry = new FailureKindRegistry(); CheckTrue(ReferenceEquals(registry.Resolve(5), registry.Resolve(5))); } public void RegisteredAfterAPlaceholder_ReturnsTheRealKind() { var registry = new FailureKindRegistry(); registry.Resolve(BlockedCellKind.Instance.Id); registry.Register(BlockedCellKind.Instance); CheckEqual(BlockedCellKind.Instance, registry.Resolve(BlockedCellKind.Instance.Id)); } public void Registered_AllocatesNothing() { var registry = new FailureKindRegistry(); registry.Register(BlockedCellKind.Instance); CheckEqual(0L, Allocations.During( () => Allocations.ObjectSink = registry.Resolve(BlockedCellKind.Instance.Id))); } } public class FromWireTests : TestFixture { public void KnownFailure_RoundTrips() { var registry = new FailureKindRegistry(); registry.Register(BlockedCellKind.Instance); Status sent = BlockedCellKind.Instance.Fail(FailureTestKinds.Wall); Status received = registry.FromWire(sent.WireId, sent.WireRef, sent.Bits); CheckEqual(sent, received); } public void UnknownFailure_GoesBackOutUnchanged() { Status sent = BlockedCellKind.Instance.Fail(FailureTestKinds.Wall); Status relayed = new FailureKindRegistry().FromWire(sent.WireId, sent.WireRef, sent.Bits); CheckEqual(sent.WireId, relayed.WireId); CheckEqual(sent.WireRef, relayed.WireRef); CheckEqual(sent.Bits, relayed.Bits); } public void Ok_RoundTrips() { Status sent = Status.Ok; Status received = new FailureKindRegistry().FromWire(sent.WireId, sent.WireRef, sent.Bits); CheckEqual(sent, received); } public void OkWithARef_Throws() { CheckThrow(typeof(ArgumentException)); new FailureKindRegistry().FromWire(Status.OkWireId, reference: "ref", bits: 0); } public void OkWithBits_Throws() { CheckThrow(typeof(ArgumentException)); new FailureKindRegistry().FromWire(Status.OkWireId, reference: null, bits: 5); } } public class FailureKindsInTests : TestFixture { public void ReturnsOnlyFieldsHoldingKinds() { var kinds = FailureKindRegistry.FailureKindsIn(new[] { typeof(FailureTestKinds) }); CheckEqualCommutative(new[] { FailureTestKinds.Unreachable }, kinds); } public void FindsPrivateFields() { var kinds = FailureKindRegistry.FailureKindsIn(new[] { typeof(VariedHolder) }); CheckTrue(kinds.Any(kind => kind.Name == VariedHolder.HiddenName)); } public void FindsAutoProperties() { var kinds = FailureKindRegistry.FailureKindsIn(new[] { typeof(VariedHolder) }); CheckTrue(kinds.Contains(VariedHolder.Property)); } public void FindsFieldsTypedAsTheBaseKind() { var kinds = FailureKindRegistry.FailureKindsIn(new[] { typeof(VariedHolder) }); CheckTrue(kinds.Contains(VariedHolder.BaseTyped)); } public void SameKindInTwoFields_ComesBackForEach() { var kinds = FailureKindRegistry.FailureKindsIn(new[] { typeof(FailureTestKinds), typeof(AliasHolder) }); CheckEqualCommutative(new[] { FailureTestKinds.Unreachable, FailureTestKinds.Unreachable }, kinds); } public void NullField_Throws() { CheckThrow(typeof(InvalidOperationException)); FailureKindRegistry.FailureKindsIn(new[] { typeof(EmptyHolder) }); } public void GenericType_Throws() { CheckThrow(typeof(InvalidOperationException)); FailureKindRegistry.FailureKindsIn(new[] { typeof(GenericHolder<>) }); } } public class ScanAssembliesTests : TestFixture { public void AssemblyWithNoKinds_RegistersNothing() { var registry = FailureKindRegistry.ScanAssemblies(new[] { typeof(Status).Assembly }); CheckEqual(typeof(UnknownFailureKind), registry.Resolve(FailureTestKinds.Unreachable.Id).GetType()); } public void ReachesNestedTypes_SoThisAssemblysBrokenHoldersThrow() { CheckThrow(typeof(InvalidOperationException)); FailureKindRegistry.ScanAssemblies(new[] { typeof(FailureKindRegistryTests).Assembly }); } } } }