using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using UnitTestSharp;
using Action = System.Action;
namespace Amphora.UnitTests
{
public class ExceptionSandboxTests : TestFixture
{
public static readonly Assembly AmphoraAssembly = typeof(ExceptionSandbox).Assembly;
public static readonly ExceptionSite SiteA = new ExceptionSite(new object(), phase: 0);
public static readonly ExceptionSite SiteB = new ExceptionSite(new object(), phase: 0);
///
/// One throw site for whatever exception it's handed.
///
public static readonly Action Rethrow = exception => throw exception;
///
/// A comparer that throws when asked to compare, standing in for client code that Amphora calls.
///
public sealed class ThrowingComparer : IEqualityComparer
{
public bool Equals(int left, int right)
{
throw new InvalidOperationException("Thrown by client code.");
}
public int GetHashCode(int value)
{
return value;
}
}
///
/// Returns a dictionary whose lookups of its one key run a comparer that throws.
///
public static OrderedDictionary DictionaryWhoseComparerThrows()
{
var returnMe = new OrderedDictionary(new ThrowingComparer());
returnMe.Add(1, 1);
return returnMe;
}
///
/// A target built in client code.
///
public sealed class ClientTarget
{
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowFromClientHelper()
{
throw new InvalidOperationException("Thrown by a client helper.");
}
///
/// Does nothing. Calling it after another call keeps the caller's frame, which an x64 tail call would drop.
///
[MethodImpl(MethodImplOptions.NoInlining)]
public static void KeepsTheCallerOnTheStack()
{
}
public static int ClientFactory()
{
return 1;
}
public static ExceptionSandbox NewSandbox()
{
return new ExceptionSandbox(AmphoraAssembly);
}
public static ExceptionSandbox NewDroppingSandbox()
{
return new ExceptionSandbox(stackCanDropFrames: true, anchors: new[] { AmphoraAssembly });
}
public static ExceptionSandbox NewKeepingSandbox()
{
return new ExceptionSandbox(stackCanDropFrames: false, anchors: new[] { AmphoraAssembly });
}
public static ExceptionSite SiteAt(object target)
{
return new ExceptionSite(target, phase: 0);
}
public static Dictionary Notes(string label, string value)
{
return new Dictionary { { label, value } };
}
///
/// Runs behind a boundary filtered by , and returns
/// whether the sandbox claimed what it threw.
///
public static bool Run(ExceptionSandbox sandbox, ExceptionSite site, Action action,
IReadOnlyDictionary notes = null)
{
try
{
action();
}
catch (Exception exception) when (sandbox.Claims(exception, site, notes))
{
return true;
}
return false;
}
public static bool Run(ExceptionSandbox sandbox, ExceptionSite site, Action action, T argument,
IReadOnlyDictionary notes = null)
{
try
{
action(argument);
}
catch (Exception exception) when (sandbox.Claims(exception, site, notes))
{
return true;
}
return false;
}
public static bool Run(ExceptionSandbox sandbox, ExceptionSite site, Action action,
T1 first, T2 second)
{
try
{
action(first, second);
}
catch (Exception exception) when (sandbox.Claims(exception, site, notes: null))
{
return true;
}
return false;
}
public static bool RunFunc(ExceptionSandbox sandbox, ExceptionSite site, Func function,
T argument)
{
try
{
function(argument);
}
catch (Exception exception) when (sandbox.Claims(exception, site, notes: null))
{
return true;
}
return false;
}
///
/// Has client code throw a new at , and returns the
/// entry it landed in.
///
public static ExceptionEntry Hit(ExceptionSandbox sandbox, ExceptionSite site)
where TException : Exception, new()
{
Run(sandbox, site, Rethrow, new TException());
return sandbox.Entries.Single(entry => entry.Exception.GetType() == typeof(TException));
}
public class CtorTests : TestFixture
{
public void StartsAtFrameZero()
{
CheckEqual(0L, NewSandbox().Frame);
}
public void StartsAtTimeZero()
{
CheckEqual(Duration.Zero, NewSandbox().Now);
}
public void StartsWithNoEntries()
{
CheckEqual(0, NewSandbox().Entries.Count);
}
public void Default_LetsTheStackDropFramesOnlyOnX64()
{
CheckEqual(IntPtr.Size == 8, NewSandbox().StackCanDropFrames);
}
public void StackCanDropFrames_IsKept()
{
CheckTrue(NewDroppingSandbox().StackCanDropFrames);
CheckFalse(NewKeepingSandbox().StackCanDropFrames);
}
public void Anchors_AreKept()
{
Assembly other = typeof(UnitTestSharp.TestFixture).Assembly;
var sandbox = new ExceptionSandbox(AmphoraAssembly, other);
CheckEqual(new[] { AmphoraAssembly, other }, sandbox.Anchors.ToArray());
}
public void Anchors_AreCopied()
{
var anchors = new[] { AmphoraAssembly };
var sandbox = new ExceptionSandbox(stackCanDropFrames: false, anchors: anchors);
anchors[0] = typeof(UnitTestSharp.TestFixture).Assembly;
CheckEqual(new[] { AmphoraAssembly }, sandbox.Anchors.ToArray());
}
public void NoAnchors_Throws()
{
CheckThrow(typeof(ArgumentException));
new ExceptionSandbox();
}
public void NullAnchorList_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new ExceptionSandbox((Assembly[])null);
}
public void NullAnchor_Throws()
{
CheckThrow(typeof(ArgumentException));
new ExceptionSandbox(AmphoraAssembly, null);
}
}
public class AdvanceTests : TestFixture
{
private ExceptionSandbox sandbox;
private List announced;
public override void TestSetup()
{
sandbox = NewSandbox();
announced = new List();
sandbox.EntryAdded += entry => announced.Add(entry);
}
public void Always_CountsOneFrame()
{
sandbox.Advance(TimeSpan.FromMilliseconds(16));
sandbox.Advance(TimeSpan.FromMilliseconds(16));
CheckEqual(2L, sandbox.Frame);
}
public void Always_AccumulatesTheElapsedTime()
{
sandbox.Advance(TimeSpan.FromMilliseconds(16));
sandbox.Advance(TimeSpan.FromMilliseconds(4));
CheckEqual(Duration.FromMilliseconds(20), sandbox.Now);
}
public void InfiniteElapsed_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
sandbox.Advance(Duration.Forever);
}
public void NegativeInfiniteElapsed_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
sandbox.Advance(-Duration.Forever);
}
public void InfiniteElapsed_LeavesTheClockAlone()
{
try
{
sandbox.Advance(Duration.Forever);
}
catch (ArgumentOutOfRangeException)
{
}
CheckEqual(0L, sandbox.Frame);
CheckEqual(Duration.Zero, sandbox.Now);
}
public void ElapsedTimePastTheLargestFiniteDuration_ClampsTheClock()
{
sandbox.Advance(Duration.MaxValue);
sandbox.Advance(Duration.FromMilliseconds(16));
CheckEqual(Duration.MaxValue, sandbox.Now);
}
public void ZeroElapsed_StillCountsAFrame()
{
sandbox.Advance(TimeSpan.Zero);
CheckEqual(1L, sandbox.Frame);
CheckEqual(Duration.Zero, sandbox.Now);
}
public void NewEntry_IsAnnouncedOnlyOnceAdvanced()
{
ExceptionEntry entry = Hit(sandbox, SiteA);
CheckEqual(0, announced.Count);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(1, announced.Count);
CheckEqual(entry, announced[0]);
}
public void EntryHitAgain_IsNotAnnouncedAgain()
{
Hit(sandbox, SiteA);
sandbox.Advance(TimeSpan.Zero);
Hit(sandbox, SiteA);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(1, announced.Count);
}
public void EntryAddedWithNoSubscriber_IsNotAnnouncedToALaterOne()
{
ExceptionSandbox unsubscribed = NewSandbox();
Hit(unsubscribed, SiteA);
unsubscribed.Advance(TimeSpan.Zero);
unsubscribed.EntryAdded += entry => announced.Add(entry);
unsubscribed.Advance(TimeSpan.Zero);
CheckEqual(0, announced.Count);
}
public void SeveralNewEntries_AreAnnouncedInTheOrderTheyWereAdded()
{
ExceptionEntry first = Hit(sandbox, SiteA);
ExceptionEntry second = Hit(sandbox, SiteA);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(2, announced.Count);
CheckEqual(first, announced[0]);
CheckEqual(second, announced[1]);
}
}
public class SnoozeTests : TestFixture
{
public void Always_SnoozesUntilNowPlusTheDuration()
{
ExceptionSandbox sandbox = NewSandbox();
sandbox.Advance(TimeSpan.FromMilliseconds(16));
var entry = new ExceptionEntry(new InvalidOperationException(), sandbox.Frame, sandbox.Now);
sandbox.Snooze(entry, TimeSpan.FromMilliseconds(10));
CheckEqual(Duration.FromMilliseconds(26), entry.SnoozedUntil);
}
public void Forever_SnoozesUntilForever()
{
ExceptionSandbox sandbox = NewSandbox();
sandbox.Advance(TimeSpan.FromMilliseconds(16));
var entry = new ExceptionEntry(new InvalidOperationException(), sandbox.Frame, sandbox.Now);
sandbox.Snooze(entry, Duration.Forever);
CheckEqual(Duration.Forever, entry.SnoozedUntil);
}
public void ADurationPastTheLargestFiniteTime_ClampsInsteadOfWrapping()
{
ExceptionSandbox sandbox = NewSandbox();
sandbox.Advance(TimeSpan.FromMilliseconds(16));
var entry = new ExceptionEntry(new InvalidOperationException(), sandbox.Frame, sandbox.Now);
sandbox.Snooze(entry, Duration.MaxValue);
CheckEqual(Duration.MaxValue, entry.SnoozedUntil);
}
}
public class ClaimsTests : TestFixture
{
private ExceptionSandbox sandbox;
public override void TestSetup()
{
sandbox = NewSandbox();
}
public void ExceptionFromClientCode_IsClaimed()
{
CheckTrue(Run(sandbox, SiteA, () => throw new InvalidOperationException()));
CheckEqual(1, sandbox.Entries.Count);
}
public void ExceptionFromAnAnchorAlone_Propagates()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
Run(sandbox, SiteA, new DynamicArray().RemoveAt, 5);
}
public void ExceptionFromALibraryBeneathTheAnchorsAlone_Propagates()
{
var list = new List();
IEnumerator enumerator = list.GetEnumerator();
list.Add(1);
CheckThrow(typeof(InvalidOperationException));
Run(sandbox, SiteA, enumerator.Reset);
}
public void AnchorExceptionReachedThroughClientCode_IsClaimed()
{
CheckTrue(Run(sandbox, SiteA, () =>
{
new DynamicArray().RemoveAt(5);
KeepsTheCallerOnTheStack();
}));
}
public void ClientExceptionReachedThroughAnAnchor_IsClaimed()
{
OrderedDictionary dictionary = DictionaryWhoseComparerThrows();
CheckTrue(RunFunc(sandbox, SiteA, dictionary.ContainsKey, 1));
}
public void OutOfMemory_Propagates()
{
CheckThrow(typeof(OutOfMemoryException));
Run(sandbox, SiteA, () => throw new OutOfMemoryException());
}
public void ClientExceptionReachedThroughALibraryBeneathTheAnchors_IsClaimed()
{
CheckTrue(Run>(sandbox, SiteA, new List { 1 }.ForEach,
_ => throw new InvalidOperationException()));
}
public void DynamicCodeCalledFromClientCode_IsClaimed()
{
Action compiled = Expression.Lambda(
Expression.Throw(Expression.New(typeof(InvalidOperationException)))).Compile();
CheckTrue(Run(sandbox, SiteA, () =>
{
compiled();
KeepsTheCallerOnTheStack();
}));
}
public void SameDynamicThrowTwice_MakesOneEntry()
{
Action compiled = Expression.Lambda(
Expression.Throw(Expression.New(typeof(InvalidOperationException)))).Compile();
Action callCompiled = () =>
{
compiled();
KeepsTheCallerOnTheStack();
};
Run(sandbox, SiteA, callCompiled);
Run(sandbox, SiteA, callCompiled);
CheckEqual(1, sandbox.Entries.Count);
}
public void DifferentThrowSites_MakeSeparateEntries()
{
Run(sandbox, SiteA, () => throw new InvalidOperationException());
Run(sandbox, SiteA, () => throw new InvalidOperationException());
CheckEqual(2, sandbox.Entries.Count);
}
public void SameThrowSiteWithDifferentMessages_MakesOneEntry()
{
Run(sandbox, SiteA, Rethrow, new InvalidOperationException("one"));
Run(sandbox, SiteA, Rethrow, new InvalidOperationException("two"));
CheckEqual(1, sandbox.Entries.Count);
CheckEqual(2, sandbox.Entries[0].Count);
}
public void SameThrowSiteWithDifferentExceptionTypes_MakesSeparateEntries()
{
Run(sandbox, SiteA, Rethrow, new InvalidOperationException());
Run(sandbox, SiteA, Rethrow, new ArgumentException());
CheckEqual(2, sandbox.Entries.Count);
}
public void SameClientThrowReachedThroughDifferentAnchorCallers_MakesOneEntry()
{
OrderedDictionary dictionary = DictionaryWhoseComparerThrows();
RunFunc(sandbox, SiteA, dictionary.ContainsKey, 1);
RunFunc(sandbox, SiteB, dictionary.Remove, 1);
CheckEqual(1, sandbox.Entries.Count);
CheckEqual(2, sandbox.Entries[0].Count);
}
public void SameThrowSiteReachedFromDifferentClientCode_MakesSeparateEntries()
{
Run(sandbox, SiteA, () =>
{
ThrowFromClientHelper();
KeepsTheCallerOnTheStack();
});
Run(sandbox, SiteA, () =>
{
ThrowFromClientHelper();
KeepsTheCallerOnTheStack();
});
CheckEqual(2, sandbox.Entries.Count);
}
public void RepeatHit_KeepsTheFirstException()
{
var first = new InvalidOperationException("first");
Run(sandbox, SiteA, Rethrow, first);
Run(sandbox, SiteA, Rethrow, new InvalidOperationException("second"));
CheckEqual(first, sandbox.Entries[0].Exception);
}
public void SecondSiteHittingTheSameBug_JoinsItsEntry()
{
Hit(sandbox, SiteA);
Hit(sandbox, SiteB);
CheckEqual(1, sandbox.Entries.Count);
CheckEqualCommutative(new[] { SiteA, SiteB }, sandbox.Entries[0].Sites);
}
public void Always_RecordsTheNotesAtTheSite()
{
Run(sandbox, SiteA, Rethrow, new InvalidOperationException(), Notes("path", "screen > okButton"));
CheckEqual("screen > okButton", sandbox.Entries[0].NotesOf(SiteA).Single()["path"]);
}
public void NoNotes_RecordsOneEmptySet()
{
Run(sandbox, SiteA, Rethrow, new InvalidOperationException());
CheckEqual(0, sandbox.Entries[0].NotesOf(SiteA).Single().Count);
}
public void MultipleAnchors_AClientOfAnyOneIsClient()
{
Assembly unrelated = Assembly.Load(
"System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
var sandbox = new ExceptionSandbox(AmphoraAssembly, unrelated);
CheckTrue(Run(sandbox, SiteA, () => throw new InvalidOperationException()));
}
public void AnchorStackAtATargetWithAClientSubscriber_IsClaimedWhenFramesCanDrop()
{
var target = new Lazy(ClientFactory);
CheckTrue(Run(NewDroppingSandbox(), SiteAt(target), new DynamicArray().RemoveAt, 5));
}
public void AnchorStackAtATargetWithAClientSubscriber_PropagatesWhenFramesCannotDrop()
{
var target = new Lazy(ClientFactory);
CheckThrow(typeof(ArgumentOutOfRangeException));
Run(NewKeepingSandbox(), SiteAt(target), new DynamicArray().RemoveAt, 5);
}
public void AnchorStackAtAClientSubclass_IsClaimedWhenFramesCanDrop()
{
CheckTrue(Run(NewDroppingSandbox(), SiteAt(new ClientTarget()), new DynamicArray().RemoveAt,
5));
}
public void AnchorStackAtAClientSubscriberToABaseClassDelegate_IsClaimedWhenFramesCanDrop()
{
var target = new Task(ClientFactory);
CheckTrue(Run(NewDroppingSandbox(), SiteAt(target), new DynamicArray().RemoveAt, 5));
}
public void AnchorStackAtATargetWithLibraryAndClientSubscribers_IsClaimedWhenFramesCanDrop()
{
var combined = (Func)Delegate.Combine(new Func("text".GetHashCode),
new Func(ClientFactory));
var target = new Lazy(combined);
CheckTrue(Run(NewDroppingSandbox(), SiteAt(target), new DynamicArray().RemoveAt, 5));
}
public void AnchorStackAtATargetWithOnlyLibrarySubscribers_Propagates()
{
var target = new Lazy("text".GetHashCode);
CheckThrow(typeof(ArgumentOutOfRangeException));
Run(NewDroppingSandbox(), SiteAt(target), new DynamicArray().RemoveAt, 5);
}
public void AnchorStackAtATargetWithNoSubscribers_Propagates()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
Run(NewDroppingSandbox(), SiteAt(new object()), new DynamicArray().RemoveAt, 5);
}
public void AnchorStackWithNoTarget_Propagates()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
Run(NewDroppingSandbox(), SiteAt(null), new DynamicArray().RemoveAt, 5);
}
public void SameAnchorStackAtTwoTargetsWithClientCode_MakesOneEntry()
{
ExceptionSandbox dropping = NewDroppingSandbox();
Run(dropping, SiteAt(new ClientTarget()), new DynamicArray().RemoveAt, 5);
Run(dropping, SiteAt(new ClientTarget()), new DynamicArray().RemoveAt, 5);
CheckEqual(1, dropping.Entries.Count);
CheckEqual(2, dropping.Entries[0].Count);
}
public void DifferentAnchorCallersOfOneThrowAtATargetWithClientCode_MakeSeparateEntries()
{
ExceptionSandbox dropping = NewDroppingSandbox();
var target = new ClientTarget();
Run(dropping, SiteAt(target), new DynamicArray().RemoveAt, 5);
Run(dropping, SiteAt(target), new DynamicArray().Insert, 5, 0);
CheckEqual(2, dropping.Entries.Count);
}
}
public class QuarantineTests : TestFixture
{
private ExceptionSandbox sandbox;
private List<(ExceptionSite site, ExceptionEntry entry)> announced;
public override void TestSetup()
{
sandbox = NewSandbox();
announced = new List<(ExceptionSite site, ExceptionEntry entry)>();
sandbox.SiteQuarantined += (site, entry) => announced.Add((site, entry));
}
[IgnoreTest]
private bool Fault(ExceptionSite site, bool quarantine = true)
{
try
{
Rethrow(new InvalidOperationException());
}
catch (Exception exception) when (sandbox.Claims(exception, site, notes: null, quarantine))
{
return true;
}
return false;
}
public void NothingFaulted_HasNoQuarantinedSites()
{
CheckEqual(0, sandbox.QuarantinedSites.Count);
CheckFalse(sandbox.IsQuarantined(SiteA));
}
public void ClaimWithQuarantine_QuarantinesAndSkipsTheSite()
{
Fault(SiteA);
CheckTrue(sandbox.IsQuarantined(SiteA));
CheckTrue(sandbox.IsSkipped(SiteA));
CheckEqual(new[] { SiteA }, sandbox.QuarantinedSites.ToArray());
}
public void ClaimWithoutQuarantine_LeavesTheSiteRunning()
{
Fault(SiteA, quarantine: false);
CheckFalse(sandbox.IsQuarantined(SiteA));
CheckFalse(sandbox.IsSkipped(SiteA));
}
public void ClaimWithQuarantine_LeavesOtherSitesRunning()
{
Fault(SiteA);
CheckFalse(sandbox.IsSkipped(SiteB));
CheckFalse(sandbox.IsSkipped(new ExceptionSite(SiteA.Target, phase: 1)));
}
public void ExceptionThatPropagates_QuarantinesNothing()
{
bool propagated = false;
try
{
try
{
new DynamicArray().RemoveAt(5);
}
catch (ArgumentOutOfRangeException exception) when (
sandbox.Claims(exception, SiteA, notes: null, quarantine: true))
{
}
}
catch (ArgumentOutOfRangeException)
{
propagated = true;
}
CheckTrue(propagated);
CheckFalse(sandbox.IsQuarantined(SiteA));
}
public void Release_LetsTheSiteRunAndReportsItWasQuarantined()
{
Fault(SiteA);
CheckTrue(sandbox.Release(SiteA));
CheckFalse(sandbox.IsQuarantined(SiteA));
CheckFalse(sandbox.IsSkipped(SiteA));
}
public void ReleaseOfASiteThatIsNotQuarantined_ReportsNothingToDo()
{
CheckFalse(sandbox.Release(SiteA));
}
public void ReleasedSiteThatFaultsAgain_IsQuarantinedAgain()
{
Fault(SiteA);
sandbox.Release(SiteA);
Fault(SiteA);
CheckTrue(sandbox.IsSkipped(SiteA));
}
public void IgnoringOrSnoozingTheEntry_DoesNotReleaseTheSite()
{
Fault(SiteA);
ExceptionEntry entry = sandbox.Entries[0];
entry.Ignored = true;
entry.Ignored = false;
sandbox.Snooze(entry, TimeSpan.FromMilliseconds(10));
sandbox.Advance(TimeSpan.FromMilliseconds(20));
CheckTrue(sandbox.IsQuarantined(SiteA));
CheckTrue(sandbox.IsSkipped(SiteA));
}
public void SiteWithAnActiveEntry_IsStillSkippedWhileQuarantined()
{
Hit(sandbox, SiteA);
Fault(SiteA);
CheckTrue(sandbox.IsSkipped(SiteA));
}
public void Announcement_WaitsForTheNextAdvance()
{
Fault(SiteA);
CheckEqual(0, announced.Count);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(1, announced.Count);
CheckEqual(SiteA, announced[0].site);
CheckEqual(sandbox.Entries[0], announced[0].entry);
}
public void Announcement_IsOnceNoMatterHowOftenTheSiteFaults()
{
Fault(SiteA);
Fault(SiteA);
sandbox.Advance(TimeSpan.Zero);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(1, announced.Count);
}
public void SeveralSites_AreAnnouncedInTheOrderTheyFaulted()
{
Fault(SiteB);
Fault(SiteA);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(new[] { SiteB, SiteA }, announced.Select(pair => pair.site).ToArray());
}
public void ReleasedSiteThatFaultsAgain_IsAnnouncedAgain()
{
Fault(SiteA);
sandbox.Advance(TimeSpan.Zero);
sandbox.Release(SiteA);
Fault(SiteA);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(2, announced.Count);
}
public void ClaimWithoutQuarantine_IsNotAnnounced()
{
Fault(SiteA, quarantine: false);
sandbox.Advance(TimeSpan.Zero);
CheckEqual(0, announced.Count);
}
public void NoSubscriber_AdvanceStillClearsTheAnnouncement()
{
ExceptionSandbox quiet = NewSandbox();
try
{
Rethrow(new InvalidOperationException());
}
catch (Exception exception) when (quiet.Claims(exception, SiteA, notes: null, quarantine: true))
{
}
quiet.Advance(TimeSpan.Zero);
quiet.SiteQuarantined += (site, entry) => announced.Add((site, entry));
quiet.Advance(TimeSpan.Zero);
CheckEqual(0, announced.Count);
}
}
public class IsSkippedTests : TestFixture
{
private ExceptionSandbox sandbox;
public override void TestSetup()
{
sandbox = NewSandbox();
}
public void NothingEverThrown_IsNotSkipped()
{
CheckFalse(sandbox.IsSkipped(SiteA));
}
public void SiteOfAnActiveEntry_IsNotSkipped()
{
Hit(sandbox, SiteA);
CheckFalse(sandbox.IsSkipped(SiteA));
}
public void SiteOfAnIgnoredEntry_IsSkipped()
{
Hit(sandbox, SiteA).Ignored = true;
CheckTrue(sandbox.IsSkipped(SiteA));
}
public void SiteOfASnoozedEntry_IsSkipped()
{
sandbox.Snooze(Hit(sandbox, SiteA), TimeSpan.FromMilliseconds(10));
sandbox.Advance(TimeSpan.FromMilliseconds(9));
CheckTrue(sandbox.IsSkipped(SiteA));
}
public void SiteOfAnEntrySnoozedForever_StaysSkipped()
{
sandbox.Snooze(Hit(sandbox, SiteA), Duration.Forever);
sandbox.Advance(Duration.MaxValue);
CheckTrue(sandbox.IsSkipped(SiteA));
}
public void SiteOfAnExpiredSnooze_IsNotSkipped()
{
sandbox.Snooze(Hit(sandbox, SiteA), TimeSpan.FromMilliseconds(10));
sandbox.Advance(TimeSpan.FromMilliseconds(10));
CheckFalse(sandbox.IsSkipped(SiteA));
}
public void SameTargetInAnotherPhase_IsNotSkipped()
{
Hit(sandbox, SiteA).Ignored = true;
CheckFalse(sandbox.IsSkipped(new ExceptionSite(SiteA.Target, phase: 1)));
}
public void SiteThatNeverThrew_IsNotSkippedWhileAnotherIs()
{
Hit(sandbox, SiteA).Ignored = true;
CheckFalse(sandbox.IsSkipped(SiteB));
}
public void SiteOfAnActiveEntry_IsNotSkippedWhileAnotherEntryIs()
{
Hit(sandbox, SiteA).Ignored = true;
Hit(sandbox, SiteB);
CheckFalse(sandbox.IsSkipped(SiteB));
}
public void SiteWithAnIgnoredAndAnActiveEntry_IsNotSkipped()
{
Hit(sandbox, SiteA).Ignored = true;
Hit(sandbox, SiteA);
CheckFalse(sandbox.IsSkipped(SiteA));
}
public void SiteWithEveryEntryIgnoredOrSnoozed_IsSkipped()
{
Hit(sandbox, SiteA).Ignored = true;
sandbox.Snooze(Hit(sandbox, SiteA), TimeSpan.FromSeconds(1));
CheckTrue(sandbox.IsSkipped(SiteA));
}
}
}
}