/// <summary> /// Introduces a step that will remember ('store') values written to it, returning them when read. It uses a dictionary /// for storage. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'stored' step is added.</param> /// <param name="step"> /// Returns the added step itself. It can be used to manipulate the store and check contents of the /// store. /// </param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static IStoredIndexer <TKey, TValue> StoredAsDictionary <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, out StoredAsDictionaryIndexerStep <TKey, TValue> step) { step = new StoredAsDictionaryIndexerStep <TKey, TValue>(); return(caller.SetNextStep(step)); }
public void SetNextStepRequiresStep() { ICanHaveNextIndexerStep <int, string> step = IndexerStep; var exception = Assert.Throws <ArgumentNullException>(() => step.SetNextStep((IIndexerStep <int, string>)null !)); Assert.Equal("step", exception.ParamName); }
/// <summary> /// Introduces an alternative branch that is used in lieu of the normal branch for a given number of uses. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'log' step is added.</param> /// <param name="times">The number of times the alternative branch should be used.</param> /// <param name="branch">An action to set up the alternative branch.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> Times <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, int times, Action <ICanHaveNextIndexerStep <TKey, TValue> > branch) { return(caller.SetNextStep(new TimesIndexerStep <TKey, TValue>(times, branch))); }
/// <summary> /// Introduces an alternative set of steps that can be chosen given the provided conditions, where the conditions can /// depend on the state of the entire mock instance. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'conditional' step is added.</param> /// <param name="getCondition"> /// A condition evaluated when the indexer is read from. If <c>true</c>, the alternative branch /// is taken. /// </param> /// <param name="setCondition"> /// A condition evaluated when the indexer is written to. If <c>true</c>, the alternative branch /// is taken. /// </param> /// <param name="branch"> /// An action to set up the alternative branch; it also provides a means of re-joining the normal /// branch. /// </param> /// <returns> /// An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps on the normal /// branch. /// </returns> public static ICanHaveNextIndexerStep <TKey, TValue> InstanceIf <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, Func <object, TKey, bool>?getCondition, Func <object, TKey, TValue, bool>?setCondition, Action <IfIndexerStepBase <TKey, TValue> .IfBranchCaller> branch) { return(caller.SetNextStep(new InstanceIfIndexerStep <TKey, TValue>(getCondition, setCondition, branch))); }
/// <summary> /// Introduces a step whose only purpose is to be joined to from another step. It forwards all indexer reads and /// writes. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'join' step is added.</param> /// <param name="joinPoint">A reference to this step that can be used in a Join step.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> JoinPoint <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, out IIndexerStep <TKey, TValue> joinPoint) { var joinStep = new IndexerStepWithNext <TKey, TValue>(); joinPoint = joinStep; return(caller.SetNextStep(joinStep)); }
/// <summary> /// Introduces a step that will record an entry before a value as been written to the indexer. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <typeparam name="TRecord">The type of the entries that will be recorded in the ledger.</typeparam> /// <param name="caller">The mock or step to which this 'record' step is added.</param> /// <param name="ledger">A list that contains recorded entries.</param> /// <param name="selector"> /// A Func that constructs an entry for when a value is written. /// Takes the mocked instance, the key used and the value as parameters. /// </param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> InstanceRecordBeforeSet <TKey, TValue, TRecord>( this ICanHaveNextIndexerStep <TKey, TValue> caller, out IReadOnlyList <TRecord> ledger, Func <object, TKey, TValue, TRecord> selector) { var newStep = new InstanceRecordBeforeSetIndexerStep <TKey, TValue, TRecord>(selector); ledger = newStep; return(caller.SetNextStep(newStep)); }
/// <summary> /// Introduces a step that will record an entry after a value is read from the indexer; optionally also recording /// exceptions. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <typeparam name="TRecord">The type of the entries that will be recorded in the ledger.</typeparam> /// <param name="caller">The mock or step to which this 'record' step is added.</param> /// <param name="ledger">A list that contains recorded entries.</param> /// <param name="successSelector"> /// A Func that constructs an entry for when a value has been read. /// Takes the mocked instance, the key used and the value as parameters. /// </param> /// <param name="failureSelector"> /// An Func that constructs an entry for an exception thrown when reading a value. /// Takes the mocked instance, the key used and the exception as parameters. /// </param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> InstanceRecordAfterGet <TKey, TValue, TRecord>( this ICanHaveNextIndexerStep <TKey, TValue> caller, out IReadOnlyList <TRecord> ledger, Func <object, TKey, TValue, TRecord>?successSelector, Func <object, TKey, Exception, TRecord>?failureSelector = null) { var newStep = new InstanceRecordAfterGetIndexerStep <TKey, TValue, TRecord>(successSelector, failureSelector); ledger = newStep; return(caller.SetNextStep(newStep)); }
/// <summary> /// Introduces a step that logs all gets and sets of the mocked indexer to a log context, where /// the log context is provided by an <see cref="ILogContextProvider" />. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'log' step is added.</param> /// <param name="logContextProvider">An instance from which we can get an <see cref="ILogContext" /> to use.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> Log <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, ILogContextProvider logContextProvider) { if (logContextProvider == null) { throw new ArgumentNullException(nameof(logContextProvider)); } return(caller.SetNextStep(new LogIndexerStep <TKey, TValue>(logContextProvider.LogContext))); }
/// <summary> /// Step that checks the number of times values have been read from or written to the indexer. Adds the check /// to the verification group provided. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'verification' step is added.</param> /// <param name="verificationGroup">The verification group to which this check is added.</param> /// <param name="name">A name that can be used to identify the check in its group.</param> /// <param name="expectedNumberOfGets">The expected number of times values have been read from the indexer.</param> /// <param name="expectedNumberOfSets">The expected number of times values have been written to the indexer.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> ExpectedUsage <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, VerificationGroup verificationGroup, string?name, int?expectedNumberOfGets = null, int?expectedNumberOfSets = null) { if (verificationGroup == null) { throw new ArgumentNullException(nameof(verificationGroup)); } var step = new ExpectedUsageIndexerStep <TKey, TValue>(name, expectedNumberOfGets, expectedNumberOfSets); verificationGroup.Add(step); return(caller.SetNextStep(step)); }
private static FakeNextIndexerStep <TKey, TValue> NextStepFor <TKey, TValue>(ICanHaveNextIndexerStep <TKey, TValue> mock, TValue value) { return(new FakeNextIndexerStep <TKey, TValue>(mock, value)); }
/// <summary> /// Introduces a step that will throw a <see cref="MockMissingException" /> whenever the indexer is read from or /// written to. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'missing' step is added.</param> public static void Missing <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller) { caller.SetNextStep(MissingIndexerStep <TKey, TValue> .Instance); }
/// <summary> /// Introduces a step that returns values from a list one-by-one when read, while passing on any writes to subsequent /// steps. It will also /// pass on reads once the list has been exhausted. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'return' step is added.</param> /// <param name="values">The values to be returned one-by-one.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> ReturnEach <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, IEnumerable <TValue> values) { return(caller.SetNextStep(new ReturnEachIndexerStep <TKey, TValue>(values))); }
/// <summary> /// Introduces a step that returns values from a list one-by-one when read, while passing on any writes to subsequent /// steps. It will also /// pass on reads once the list has been exhausted. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'return' step is added.</param> /// <param name="values">The values to be returned one-by-one.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> ReturnEach <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, params TValue[] values) { return(caller.ReturnEach(values.AsEnumerable())); }
/// <summary> /// Introduces a step that will remember ('store') values written to it, returning them when read. It uses a dictionary /// for storage. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'stored' step is added.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static IStoredIndexer <TKey, TValue> StoredAsDictionary <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller) { return(caller.SetNextStep(new StoredAsDictionaryIndexerStep <TKey, TValue>())); }
/// <summary> /// Introduces a step that returns a given value the first time it is read, while passing on any writes and further /// reads to subsequent steps. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'return' step is added.</param> /// <param name="value">The value to be returned.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> ReturnOnce <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, TValue value) { return(caller.SetNextStep(new ReturnOnceIndexerStep <TKey, TValue>(value))); }
/// <summary> /// Introduces a step that will throw an exception whenever a value is written to or read from the indexer. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'throw' step is added.</param> /// <param name="exceptionFactory">A Func that creates the exception to be thrown. Takes the indexer key as parameter.</param> public static void Throw <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, Func <TKey, Exception> exceptionFactory) { caller.InstanceThrow(AddInstanceParameter(exceptionFactory)); }
/// <summary> /// Introduces a step that will invoke an action whenever a value is set, while forwarding getting of values to a /// next step. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'lambda' step is added.</param> /// <param name="action">The action to be invoked when a value is set.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> InstanceSetAction <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, Action <object, TKey, TValue> action) { return(caller.SetNextStep(new InstanceSetActionIndexerStep <TKey, TValue>(action))); }
/// <summary> /// Introduces an alternative set of steps that is chosen when the indexer is written to. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'conditional' step is added.</param> /// <param name="branch"> /// An action to set up the alternative branch; it also provides a means of re-joining the normal /// branch. /// </param> /// <returns> /// An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps on the normal /// branch. /// </returns> public static ICanHaveNextIndexerStep <TKey, TValue> IfSet <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, Action <IfIndexerStepBase <TKey, TValue> .IfBranchCaller> branch) { return(caller.SetNextStep(new IfSetIndexerStep <TKey, TValue>(branch))); }
/// <summary> /// Introduces a step that will record an entry after a value is read from the indexer. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'record' step is added.</param> /// <param name="ledger">A list that contains recorded entries.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> RecordAfterGet <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, out IReadOnlyList <(TKey Key, TValue Value)> ledger)
/// <summary> /// Introduces a step that will forward getting and setting indexer values to another step. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'join' step is added.</param> /// <param name="joinPoint">The step to which getting and setting indexer values will be forwarded.</param> public static void Join <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, IIndexerStep <TKey, TValue> joinPoint) { caller.SetNextStep(joinPoint); }
/// <summary> /// Introduces a filter that will only progress to writing a value if it's different from the current value. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'conditional' step is added.</param> /// <param name="comparer"> /// An optional <see cref="IEqualityComparer{TValue}" /> that is used to determine whether the new /// value is different from the current one. /// </param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> OnlySetIfChanged <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, IEqualityComparer <TValue>?comparer = null) { return(caller.SetNextStep(new OnlySetIfChangedIndexerStep <TKey, TValue>(comparer))); }
/// <summary> /// Introduces a step that logs all gets and sets of the mocked indexer to a log context, or the console if none was /// provided. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'log' step is added.</param> /// <param name="logContext"> /// The <see cref="ILogContext" /> used to write the log entries. The default will write to the /// console. /// </param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> Log <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, ILogContext?logContext = null) { return(caller.SetNextStep(new LogIndexerStep <TKey, TValue>(logContext ?? WriteLineLogContext.Console))); }
/// <summary> /// Introduces a step that will get values by calculating them from the key, while forwarding setting of values to a /// next step. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'lambda' step is added.</param> /// <param name="func">The function used to calculate the value from the key.</param> /// <returns>An <see cref="ICanHaveNextIndexerStep{TKey, TValue}" /> that can be used to add further steps.</returns> public static ICanHaveNextIndexerStep <TKey, TValue> GetFunc <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, Func <TKey, TValue> func) { return(caller.SetNextStep(new GetFuncIndexerStep <TKey, TValue>(func))); }
public FakeNextIndexerStep(ICanHaveNextIndexerStep <TKey, TValue> mock, TValue value) { _value = value; mock.SetNextStep(this); }
/// <summary> /// Introduces a step that will throw an exception whenever a value is written to or read from the indexer. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'throw' step is added.</param> /// <param name="exceptionFactory"> /// A Func that creates the exception to be thrown. Takes the mocked instance and indexer /// key as parameters. /// </param> public static void InstanceThrow <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller, Func <object, TKey, Exception> exceptionFactory) { caller.SetNextStep(new ThrowIndexerStep <TKey, TValue>(exceptionFactory)); }
/// <summary> /// Introduces a step that will ignore all writes and return default values for all reads. /// </summary> /// <typeparam name="TKey">The type of the indexer key.</typeparam> /// <typeparam name="TValue">The type of the indexer value.</typeparam> /// <param name="caller">The mock or step to which this 'dummy' step is added.</param> public static void Dummy <TKey, TValue>( this ICanHaveNextIndexerStep <TKey, TValue> caller) { caller.SetNextStep(DummyIndexerStep <TKey, TValue> .Instance); }