(() => calculator.Add(-2, -2));
44 | ```
45 |
--------------------------------------------------------------------------------
/docs/docs/2013-04-01-threading.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Threading
3 | ---
4 |
5 | It is fairly standard for production code to call a substitute from multiple threads, but we should avoid having our test code configure or assert on a substitute while it is also be used from other threads in production code.
6 |
7 | Although this particular issue has been mitigated by work in [#452]({{ site.repo }}/pull/462), issue [#256]({{ site.repo }}/issues/256) shows the types of problems that can occur if we're not careful with threading.
8 |
9 | To avoid this sort of problem, make sure your test has finished configuring its substitutes before exercising the production code, then make sure the production code has completed before your test asserts on `Received()` calls.
--------------------------------------------------------------------------------
/docs/docs/2019-01-01-search.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Search
3 | ---
4 |
5 |
16 |
17 |
--------------------------------------------------------------------------------
/docs/docs/toc.yml:
--------------------------------------------------------------------------------
1 | - href: 2010-01-01-getting-started.md
2 | - href: 2010-01-02-creating-a-substitute.md
3 | - href: 2010-02-01-set-return-value.md
4 | - href: 2010-02-02-return-for-args.md
5 | - href: 2010-02-03-return-for-any-args.md
6 | - href: 2010-02-03-return-from-function.md
7 | - href: 2010-02-04-multiple-returns.md
8 | - href: 2010-02-10-replacing-return-values.md
9 | - href: 2010-03-01-received-calls.md
10 | - href: 2010-03-10-clear-received-calls.md
11 | - href: 2010-04-01-argument-matchers.md
12 | - href: 2010-05-01-callbacks.md
13 | - href: 2010-05-02-throwing-exceptions.md
14 | - href: 2010-05-10-configure.md
15 | - href: 2010-06-01-raising-events.md
16 | - href: 2010-10-01-auto-and-recursive-mocks.md
17 | - href: 2010-11-01-setting-out-and-ref-arguments.md
18 | - href: 2010-12-01-actions-with-arguments.md
19 | - href: 2013-01-01-received-in-order.md
20 | - href: 2013-02-01-partial-subs.md
21 | - href: 2013-03-01-return-for-all.md
22 | - href: 2013-04-01-threading.md
23 | - href: 2013-04-15-compat-args.md
24 | - href: 2013-05-01-nsubstitute-analysers.md
25 | - href: 2015-01-01-how-nsub-works.md
26 | - href: 2019-01-01-search.md
27 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/help.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Docs and getting help
3 | permalink: /help.html
4 | ---
5 |
6 | Read Getting started for a quick tour of NSubstitute.
7 |
8 | For more in depth information start with Creating a substitute .
9 |
10 | If you can't find the answer you're looking for, or if you have feature requests or feedback on NSubstitute, please raise an issue on our project site. All questions are welcome via our project site, but for "how-to"-style questions you can also try StackOverflow with the [nsubstitute] tag , which often leads to very good answers from the larger programming community. StackOverflow is especially useful if your question also relates to other libraries that our team may not be as familiar with (e.g. NSubstitute with Entity Framework).
11 |
--------------------------------------------------------------------------------
/docs/images/NSubstitute.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/NSubstitute.ai
--------------------------------------------------------------------------------
/docs/images/github-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/github-16x16.png
--------------------------------------------------------------------------------
/docs/images/nsubstitute-100x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/nsubstitute-100x100.png
--------------------------------------------------------------------------------
/docs/images/nsubstitute-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/nsubstitute-16x16.png
--------------------------------------------------------------------------------
/docs/images/nsubstitute-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/nsubstitute-32x32.png
--------------------------------------------------------------------------------
/docs/images/nuget-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/nuget-16x16.png
--------------------------------------------------------------------------------
/docs/images/teamcity-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/teamcity-16x16.png
--------------------------------------------------------------------------------
/docs/images/teamcity-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/docs/images/teamcity-32x32.png
--------------------------------------------------------------------------------
/docs/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Documentation
2 | href: docs/
3 |
4 | - name: Getting help
5 | href: help.md
6 |
7 | - name: NSubstitute on GitHub
8 | href: https://github.com/nsubstitute/NSubstitute
--------------------------------------------------------------------------------
/src/NSubstitute/ClearOptions.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute;
2 |
3 | [Flags]
4 | public enum ClearOptions
5 | {
6 | ///
7 | /// Clear all the received calls
8 | ///
9 | ReceivedCalls = 1,
10 |
11 | ///
12 | /// Clear all configured return results (including auto-substituted values).
13 | ///
14 | ReturnValues = 2,
15 |
16 | ///
17 | /// Clear all call actions configured for this substitute (via When..Do, Arg.Invoke, and Arg.Do)
18 | ///
19 | CallActions = 4,
20 |
21 | ///
22 | /// Clears all received calls and configured return values and callbacks.
23 | ///
24 | All = ReceivedCalls | ReturnValues | CallActions
25 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Argument.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class Argument(ICall call, int argIndex)
4 | {
5 | private readonly ICall? _call = call;
6 |
7 | public object? Value
8 | {
9 | get => _call!.GetArguments()[argIndex];
10 | set => _call!.GetArguments()[argIndex] = value;
11 | }
12 |
13 | public bool IsByRef => DeclaredType.IsByRef;
14 |
15 | public Type DeclaredType => _call!.GetParameterInfos()[argIndex].ParameterType;
16 |
17 | public Type ActualType => Value == null ? DeclaredType : Value.GetType();
18 |
19 | public bool IsDeclaredTypeEqualToOrByRefVersionOf(Type type) =>
20 | AsNonByRefType(DeclaredType) == type;
21 |
22 | public bool IsValueAssignableTo(Type type) =>
23 | type.IsAssignableFrom(AsNonByRefType(ActualType));
24 |
25 | public bool CanSetValueWithInstanceOf(Type type) =>
26 | AsNonByRefType(DeclaredType).IsAssignableFrom(type);
27 |
28 | private static Type AsNonByRefType(Type type) =>
29 | type.IsByRef ? type.GetElementType()! : type;
30 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ArgumentSpecificationDequeue.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core.Arguments;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class ArgumentSpecificationDequeue(Func> dequeueAllQueuedArgSpecs) : IArgumentSpecificationDequeue
6 | {
7 | private static readonly IArgumentSpecification[] EmptySpecifications = [];
8 |
9 | public IList DequeueAllArgumentSpecificationsForMethod(int parametersCount)
10 | {
11 | if (parametersCount == 0)
12 | {
13 | // We violate public contract, as mutable list was expected as result.
14 | // However, in reality we never expect value to be mutated, so this optimization is fine.
15 | // We are not allowed to change public contract due to SemVer, so keeping that as it is.
16 | return EmptySpecifications;
17 | }
18 |
19 | var queuedArgSpecifications = dequeueAllQueuedArgSpecs.Invoke();
20 | return queuedArgSpecifications;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class AnyArgumentMatcher(Type typeArgMustBeCompatibleWith) : IArgumentMatcher
4 | {
5 | public override string ToString() => "any " + typeArgMustBeCompatibleWith.GetNonMangledTypeName();
6 |
7 | public bool IsSatisfiedBy(object? argument) => argument.IsCompatibleWith(typeArgMustBeCompatibleWith);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/ArgumentFormatter.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class ArgumentFormatter : IArgumentFormatter
4 | {
5 | internal static IArgumentFormatter Default { get; } = new ArgumentFormatter();
6 |
7 | public string Format(object? argument, bool highlight)
8 | {
9 | var formatted = Format(argument);
10 | return highlight ? "*" + formatted + "*" : formatted;
11 | }
12 |
13 | private string Format(object? arg)
14 | {
15 | return arg switch
16 | {
17 | null => "",
18 | string str => $"\"{str}\"",
19 | { } obj when HasDefaultToString(obj) => arg.GetType().GetNonMangledTypeName(),
20 | _ => arg.ToString() ?? string.Empty
21 | };
22 |
23 | static bool HasDefaultToString(object obj)
24 | => obj.GetType().GetMethod(nameof(ToString), Type.EmptyTypes)!.DeclaringType == typeof(object);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public record ArgumentMatchInfo
4 | {
5 | private readonly object? _argument;
6 | private readonly IArgumentSpecification _specification;
7 |
8 | public int Index { get; }
9 |
10 | public ArgumentMatchInfo(int index, object? argument, IArgumentSpecification specification)
11 | {
12 | _argument = argument;
13 | _specification = specification;
14 | Index = index;
15 | }
16 |
17 | public bool IsMatch => _specification.IsSatisfiedBy(_argument);
18 |
19 | public string DescribeNonMatch()
20 | {
21 | var describeNonMatch = _specification.DescribeNonMatch(_argument);
22 | if (string.IsNullOrEmpty(describeNonMatch)) return string.Empty;
23 | var argIndexPrefix = "arg[" + Index + "]: ";
24 | return string.Format("{0}{1}", argIndexPrefix, describeNonMatch.Replace("\n", "\n".PadRight(argIndexPrefix.Length + 1)));
25 | }
26 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/ArgumentSpecificationCompatibilityTester.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class ArgumentSpecificationCompatibilityTester(IDefaultChecker defaultChecker) : IArgumentSpecificationCompatibilityTester
4 | {
5 | public bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType)
6 | {
7 | var typeArgSpecIsFor = specification.ForType;
8 | return AreTypesCompatible(argumentType, typeArgSpecIsFor)
9 | && IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(argumentValue, typeArgSpecIsFor);
10 | }
11 |
12 | private bool IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(object? argument, Type typeArgSpecIsFor)
13 | {
14 | return defaultChecker.IsDefault(argument, typeArgSpecIsFor);
15 | }
16 |
17 | private bool AreTypesCompatible(Type argumentType, Type typeArgSpecIsFor)
18 | {
19 | return argumentType.IsAssignableFrom(typeArgSpecIsFor) ||
20 | (argumentType.IsByRef && !typeArgSpecIsFor.IsByRef && argumentType.IsAssignableFrom(typeArgSpecIsFor.MakeByRefType()));
21 | }
22 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/DefaultChecker.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class DefaultChecker(IDefaultForType defaultForType) : IDefaultChecker
4 | {
5 | public bool IsDefault(object? value, Type forType)
6 | {
7 | return EqualityComparer.Default.Equals(value, defaultForType.GetDefaultFor(forType));
8 | }
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/EqualsArgumentMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class EqualsArgumentMatcher(object? value) : IArgumentMatcher
4 | {
5 | public override string ToString() => ArgumentFormatter.Default.Format(value, false);
6 |
7 | public bool IsSatisfiedBy(object? argument) => EqualityComparer.Default.Equals(value, argument);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/ExpressionArgumentMatcher.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 |
3 | namespace NSubstitute.Core.Arguments;
4 |
5 | public class ExpressionArgumentMatcher(Expression> predicate) : IArgumentMatcher
6 | {
7 | private readonly string _predicateDescription = predicate.ToString();
8 | private readonly Predicate _predicate = predicate.Compile();
9 |
10 | public bool IsSatisfiedBy(object? argument) => _predicate((T?)argument);
11 |
12 | public override string ToString() => _predicateDescription;
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IArgumentFormatter.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface IArgumentFormatter
4 | {
5 | string Format(object? arg, bool highlight);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IArgumentMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | ///
4 | /// Provides a specification for arguments.
5 | /// Can implement to give descriptions when arguments do not match.
6 | /// Can implement to give descriptions of expected arguments (otherwise
7 | /// `ToString()` will be used for descriptions).
8 | ///
9 | public interface IArgumentMatcher
10 | {
11 | ///
12 | /// Checks whether the satisfies the condition of the matcher.
13 | /// If this throws an exception the argument will be treated as non-matching.
14 | ///
15 | bool IsSatisfiedBy(object? argument);
16 | }
17 |
18 | ///
19 | /// Provides a specification for arguments.
20 | /// Can implement to give descriptions when arguments do not match.
21 | /// Can implement to give descriptions of expected arguments (otherwise
22 | /// `ToString()` will be used for descriptions).
23 | ///
24 | /// Matches arguments of type or compatible type.
25 | public interface IArgumentMatcher
26 | {
27 | ///
28 | /// Checks whether the satisfies the condition of the matcher.
29 | /// If this throws an exception the argument will be treated as non-matching.
30 | ///
31 | bool IsSatisfiedBy(T? argument);
32 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IArgumentSpecification.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface IArgumentSpecification
4 | {
5 | bool IsSatisfiedBy(object? argument);
6 | Type ForType { get; }
7 | IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType);
8 | bool HasAction { get; }
9 | void RunAction(object? argument);
10 | string DescribeNonMatch(object? argument);
11 | string FormatArgument(object? argument);
12 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IArgumentSpecificationCompatibilityTester.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface IArgumentSpecificationCompatibilityTester
4 | {
5 | bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IArgumentSpecificationFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface IArgumentSpecificationFactory
4 | {
5 | IArgumentSpecification Create(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IArgumentSpecificationsFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core.Arguments;
4 |
5 | public interface IArgumentSpecificationsFactory
6 | {
7 | IEnumerable Create(IList argumentSpecs, object?[] arguments, IParameterInfo[] parameterInfos, MethodInfo methodInfo, MatchArgs matchArgs);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/IDefaultChecker.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface IDefaultChecker
4 | {
5 | bool IsDefault(object? value, Type forType);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecifications.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface ISuppliedArgumentSpecifications
4 | {
5 | bool AnyFor(object? argument, Type argumentType);
6 | bool IsNextFor(object? argument, Type argumentType);
7 | IArgumentSpecification Dequeue();
8 | IEnumerable DequeueRemaining();
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecificationsFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public interface ISuppliedArgumentSpecificationsFactory
4 | {
5 | ISuppliedArgumentSpecifications Create(IEnumerable argumentSpecifications);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecifications.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class SuppliedArgumentSpecifications : ISuppliedArgumentSpecifications
4 | {
5 | private readonly IArgumentSpecificationCompatibilityTester _argSpecCompatibilityTester;
6 | private readonly Queue _queue;
7 | private IReadOnlyCollection AllSpecifications { get; }
8 |
9 | public SuppliedArgumentSpecifications(IArgumentSpecificationCompatibilityTester argSpecCompatibilityTester, IEnumerable argumentSpecifications)
10 | {
11 | _argSpecCompatibilityTester = argSpecCompatibilityTester;
12 | AllSpecifications = argumentSpecifications.ToArray();
13 | _queue = new Queue(AllSpecifications);
14 | }
15 |
16 |
17 | public bool AnyFor(object? argument, Type argumentType)
18 | {
19 | return AllSpecifications.Any(x => _argSpecCompatibilityTester.IsSpecificationCompatible(x, argument, argumentType));
20 | }
21 |
22 | public bool IsNextFor(object? argument, Type argumentType)
23 | {
24 | if (_queue.Count == 0)
25 | {
26 | return false;
27 | }
28 |
29 | var nextArgSpec = _queue.Peek();
30 | return _argSpecCompatibilityTester.IsSpecificationCompatible(nextArgSpec, argument, argumentType);
31 | }
32 |
33 | public IArgumentSpecification Dequeue() => _queue.Dequeue();
34 |
35 | public IEnumerable DequeueRemaining()
36 | {
37 | var result = _queue.ToArray();
38 | _queue.Clear();
39 | return result;
40 | }
41 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecificationsFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Arguments;
2 |
3 | public class SuppliedArgumentSpecificationsFactory(IArgumentSpecificationCompatibilityTester argumentSpecificationCompatTester) : ISuppliedArgumentSpecificationsFactory
4 | {
5 | public ISuppliedArgumentSpecifications Create(IEnumerable argumentSpecifications)
6 | {
7 | return new SuppliedArgumentSpecifications(argumentSpecificationCompatTester, argumentSpecifications);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NSubstitute.Core.Arguments;
3 |
4 | namespace NSubstitute.Core;
5 |
6 | public class CallFactory : ICallFactory
7 | {
8 | public ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications, Func? baseMethod)
9 | {
10 | return new Call(methodInfo, arguments, target, argumentSpecifications, baseMethod);
11 | }
12 |
13 | public ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications)
14 | {
15 | return new Call(methodInfo, arguments, target, argumentSpecifications, baseMethod: null);
16 | }
17 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class CallFormatter : IMethodInfoFormatter
6 | {
7 | internal static IMethodInfoFormatter Default { get; } = new CallFormatter();
8 |
9 | private readonly IEnumerable _methodInfoFormatters;
10 |
11 | public CallFormatter()
12 | {
13 | _methodInfoFormatters = new IMethodInfoFormatter[] {
14 | new PropertyCallFormatter(),
15 | new EventCallFormatter(EventCallFormatter.IsSubscription),
16 | new EventCallFormatter(EventCallFormatter.IsUnsubscription),
17 | new MethodFormatter() };
18 | }
19 |
20 | public bool CanFormat(MethodInfo methodInfo) => true;
21 |
22 | public string Format(MethodInfo methodInfoOfCall, IEnumerable formattedArguments)
23 | {
24 | return _methodInfoFormatters
25 | .First(x => x.CanFormat(methodInfoOfCall))
26 | .Format(methodInfoOfCall, formattedArguments);
27 | }
28 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallInfoFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class CallInfoFactory : ICallInfoFactory
4 | {
5 | public CallInfo Create(ICall call)
6 | {
7 | var arguments = GetArgumentsFromCall(call);
8 | var genericArguments = call.GetMethodInfo().GetGenericArguments();
9 | return new CallInfo(arguments, genericArguments);
10 | }
11 |
12 | private static Argument[] GetArgumentsFromCall(ICall call)
13 | {
14 | var result = new Argument[call.GetOriginalArguments().Length];
15 |
16 | for (var i = 0; i < result.Length; i++)
17 | {
18 | result[i] = new Argument(call, i);
19 | }
20 |
21 | return result;
22 | }
23 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallRouterFactory.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Routing;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class CallRouterFactory(IThreadLocalContext threadLocalContext, IRouteFactory routeFactory) : ICallRouterFactory
6 | {
7 | public ICallRouter Create(ISubstituteState substituteState, bool canConfigureBaseCalls)
8 | {
9 | // Cache popular routes which are bound to the particular substitute state when it's possible.
10 | var factoryWithCachedRoutes = new RouteFactoryCacheWrapper(routeFactory);
11 | return new CallRouter(substituteState, threadLocalContext, factoryWithCachedRoutes, canConfigureBaseCalls);
12 | }
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallRouterResolver.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class CallRouterResolver : ICallRouterResolver
6 | {
7 | public ICallRouter ResolveFor(object substitute)
8 | {
9 | return substitute switch
10 | {
11 | null => throw new NullSubstituteReferenceException(),
12 | ICallRouterProvider provider => provider.GetCallRouter(),
13 | Delegate { Target: ICallRouterProvider provider } => provider.GetCallRouter(),
14 | _ => throw new NotASubstituteException()
15 | };
16 | }
17 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallSpecAndTarget.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class CallSpecAndTarget(ICallSpecification callSpecification, object target)
4 | {
5 | public ICallSpecification CallSpecification { get; } = callSpecification;
6 | public object Target { get; } = target;
7 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CallSpecificationFactory.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core.Arguments;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class CallSpecificationFactory(IArgumentSpecificationsFactory argumentSpecificationsFactory) : ICallSpecificationFactory
6 | {
7 | public ICallSpecification CreateFrom(ICall call, MatchArgs matchArgs)
8 | {
9 | var methodInfo = call.GetMethodInfo();
10 | var argumentSpecs = call.GetArgumentSpecifications();
11 | var arguments = call.GetOriginalArguments();
12 | var parameterInfos = call.GetParameterInfos();
13 | var argumentSpecificationsForCall = argumentSpecificationsFactory.Create(argumentSpecs, arguments, parameterInfos, methodInfo, matchArgs);
14 | return new CallSpecification(methodInfo, argumentSpecificationsForCall);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ConfigureCall.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class ConfigureCall(ICallResults configuredResults, ICallActions callActions, IGetCallSpec getCallSpec) : IConfigureCall
6 | {
7 | public ConfiguredCall SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo)
8 | {
9 | var spec = getCallSpec.FromPendingSpecification(matchArgs, pendingSpecInfo);
10 | CheckResultIsCompatibleWithCall(valueToReturn, spec);
11 | configuredResults.SetResult(spec, valueToReturn);
12 | return new ConfiguredCall(action => callActions.Add(spec, action));
13 | }
14 |
15 | public void SetResultForCall(ICall call, IReturn valueToReturn, MatchArgs matchArgs)
16 | {
17 | var spec = getCallSpec.FromCall(call, matchArgs);
18 | CheckResultIsCompatibleWithCall(valueToReturn, spec);
19 | configuredResults.SetResult(spec, valueToReturn);
20 | }
21 |
22 | private static void CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec)
23 | {
24 | var requiredReturnType = spec.ReturnType();
25 | if (!valueToReturn.CanBeAssignedTo(requiredReturnType))
26 | {
27 | throw new CouldNotSetReturnDueToTypeMismatchException(valueToReturn.TypeOrNull(), spec.GetMethodInfo());
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ConfiguredCall.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class ConfiguredCall(Action> addAction)
4 | {
5 |
6 | ///
7 | /// Adds a callback to execute for matching calls.
8 | ///
9 | /// an action to call
10 | ///
11 | public ConfiguredCall AndDoes(Action action)
12 | {
13 | addAction(action);
14 | return this;
15 | }
16 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/CustomHandlers.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class CustomHandlers(ISubstituteState substituteState) : ICustomHandlers
4 | {
5 | private readonly List _handlers = [];
6 |
7 | public IReadOnlyCollection Handlers => _handlers;
8 |
9 | public void AddCustomHandlerFactory(CallHandlerFactory factory)
10 | {
11 | _handlers.Add(factory.Invoke(substituteState));
12 | }
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/DefaultForType.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class DefaultForType : IDefaultForType
6 | {
7 | private static readonly object BoxedBoolean = default(bool);
8 | private static readonly object BoxedInt = default(int);
9 | private static readonly object BoxedLong = default(long);
10 | private static readonly object BoxedDouble = default(double);
11 |
12 | public object? GetDefaultFor(Type type)
13 | {
14 | if (IsVoid(type))
15 | {
16 | return null;
17 | }
18 |
19 | if (type.GetTypeInfo().IsValueType)
20 | {
21 | return DefaultInstanceOfValueType(type);
22 | }
23 |
24 | return null;
25 | }
26 |
27 | private bool IsVoid(Type returnType) => returnType == typeof(void);
28 |
29 | private object DefaultInstanceOfValueType(Type returnType)
30 | {
31 | // Performance optimization for the most popular types.
32 | if (returnType == typeof(bool))
33 | {
34 | return BoxedBoolean;
35 | }
36 | if (returnType == typeof(int))
37 | {
38 | return BoxedInt;
39 | }
40 | if (returnType == typeof(long))
41 | {
42 | return BoxedLong;
43 | }
44 | if (returnType == typeof(double))
45 | {
46 | return BoxedDouble;
47 | }
48 |
49 | return Activator.CreateInstance(returnType)!;
50 | }
51 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/DependencyInjection/NSubLifetime.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.DependencyInjection;
2 |
3 | public enum NSubLifetime
4 | {
5 | ///
6 | /// Value is created only once.
7 | ///
8 | Singleton,
9 | ///
10 | /// Value is created only once per scope. Allows to share the same instance across the objects in the same graph.
11 | /// If no explicit scope is created, an implicit scope is created per single resolve request.
12 | ///
13 | PerScope,
14 | ///
15 | /// New value is created for each time.
16 | ///
17 | Transient
18 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/EventCallFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class EventCallFormatter(Func> eventsToFormat) : IMethodInfoFormatter
6 | {
7 | public static readonly Func> IsSubscription =
8 | call => (eventInfo => eventInfo.GetAddMethod() == call);
9 | public static readonly Func> IsUnsubscription =
10 | call => (eventInfo => eventInfo.GetRemoveMethod() == call);
11 | private readonly string _eventOperator = eventsToFormat == IsSubscription ? "+=" : "-=";
12 |
13 | public bool CanFormat(MethodInfo methodInfo)
14 | {
15 | return methodInfo.DeclaringType!.GetEvents().Any(x => eventsToFormat(methodInfo)(x));
16 | }
17 |
18 | public string Format(MethodInfo methodInfo, IEnumerable arguments)
19 | {
20 | var eventInfo = methodInfo.DeclaringType!.GetEvents().First(x => eventsToFormat(methodInfo)(x));
21 | return Format(eventInfo, _eventOperator, arguments);
22 | }
23 |
24 | private string Format(EventInfo eventInfo, string eventOperator, IEnumerable arguments) =>
25 | $"{eventInfo.Name} {eventOperator} {arguments.Join(", ")}";
26 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/EventHandlerRegistry.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class EventHandlerRegistry : IEventHandlerRegistry
4 | {
5 | // Collection consideration - events are used very rarely, so it makes no sense to allocate concurrent collection.
6 | // Events are not expected to be configured/raised concurrently, so simple locking should be sufficient.
7 | // List lookup is O(n), but for really small size performance is comparable to dictionary.
8 | // Given that normally a few events are configured only, it should be totally fine.
9 | private readonly List>> _handlersForEvent = [];
10 |
11 | public void Add(string eventName, object handler)
12 | {
13 | lock (_handlersForEvent)
14 | {
15 | Handlers(eventName).Add(handler);
16 | }
17 | }
18 |
19 | public void Remove(string eventName, object handler)
20 | {
21 | lock (_handlersForEvent)
22 | {
23 | Handlers(eventName).Remove(handler);
24 | }
25 | }
26 |
27 | public IEnumerable GetHandlers(string eventName)
28 | {
29 | lock (_handlersForEvent)
30 | {
31 | // Make snapshot to make code thread-safe.
32 | return Handlers(eventName).ToArray();
33 | }
34 | }
35 |
36 | private List Handlers(string eventName)
37 | {
38 | foreach (var pair in _handlersForEvent)
39 | {
40 | if (pair.Item1 == eventName)
41 | {
42 | return pair.Item2;
43 | }
44 | }
45 |
46 | var newPair = Tuple.Create(eventName, new List());
47 | _handlersForEvent.Add(newPair);
48 | return newPair.Item2;
49 | }
50 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Events/EventHandlerWrapper.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core.Events;
2 |
3 | public class EventHandlerWrapper(object? sender, EventArgs? eventArgs) : RaiseEventWrapper where TEventArgs : EventArgs
4 | {
5 | private readonly object? _sender = sender;
6 | private readonly EventArgs? _eventArgs = eventArgs;
7 | protected override string RaiseMethodName => "Raise.EventWith";
8 |
9 | public EventHandlerWrapper() : this(null, null) { }
10 |
11 | public EventHandlerWrapper(EventArgs? eventArgs) : this(null, eventArgs) { }
12 |
13 |
14 | public static implicit operator EventHandler?(EventHandlerWrapper wrapper)
15 | {
16 | RaiseEvent(wrapper);
17 | return null;
18 | }
19 |
20 | public static implicit operator EventHandler?(EventHandlerWrapper wrapper)
21 | {
22 | RaiseEvent(wrapper);
23 | return null;
24 | }
25 |
26 | protected override object[] WorkOutRequiredArguments(ICall call)
27 | {
28 | var sender = _sender ?? call.Target();
29 | var eventArgs = _eventArgs ?? GetDefaultForEventArgType(typeof(TEventArgs));
30 | return [sender, eventArgs];
31 | }
32 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/GetCallSpec.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class GetCallSpec(
4 | ICallCollection receivedCalls,
5 | ICallSpecificationFactory callSpecificationFactory,
6 | ICallActions callActions) : IGetCallSpec
7 | {
8 | public ICallSpecification FromPendingSpecification(MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo)
9 | {
10 | return pendingSpecInfo.Handle(
11 | callSpec => FromExistingSpec(callSpec, matchArgs),
12 | lastCall =>
13 | {
14 | receivedCalls.Delete(lastCall);
15 | return FromCall(lastCall, matchArgs);
16 | });
17 | }
18 |
19 | public ICallSpecification FromCall(ICall call, MatchArgs matchArgs)
20 | {
21 | return callSpecificationFactory.CreateFrom(call, matchArgs);
22 | }
23 |
24 | public ICallSpecification FromExistingSpec(ICallSpecification spec, MatchArgs matchArgs)
25 | {
26 | return matchArgs == MatchArgs.AsSpecifiedInCall ? spec : UpdateCallSpecToMatchAnyArgs(spec);
27 | }
28 |
29 | private ICallSpecification UpdateCallSpecToMatchAnyArgs(ICallSpecification callSpecification)
30 | {
31 | var anyArgCallSpec = callSpecification.CreateCopyThatMatchesAnyArguments();
32 | callActions.MoveActionsForSpecToNewSpec(callSpecification, anyArgCallSpec);
33 | return anyArgCallSpec;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IArgumentSpecificationDequeue.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core.Arguments;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public interface IArgumentSpecificationDequeue
6 | {
7 | IList DequeueAllArgumentSpecificationsForMethod(int parametersCount);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICall.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NSubstitute.Core.Arguments;
3 |
4 | namespace NSubstitute.Core;
5 |
6 | public interface ICall
7 | {
8 | Type GetReturnType();
9 | MethodInfo GetMethodInfo();
10 | object?[] GetArguments();
11 | object?[] GetOriginalArguments();
12 | object Target();
13 | IParameterInfo[] GetParameterInfos();
14 | IList GetArgumentSpecifications();
15 | void AssignSequenceNumber(long number);
16 | long GetSequenceNumber();
17 | bool CanCallBase { get; }
18 | Maybe TryCallBase();
19 | }
20 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallActions.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallActions
4 | {
5 | void Add(ICallSpecification callSpecification, Action action);
6 | void Add(ICallSpecification callSpec);
7 | void InvokeMatchingActions(ICall callInfo);
8 | void MoveActionsForSpecToNewSpec(ICallSpecification oldCallSpecification, ICallSpecification newCallSpecification);
9 | void Clear();
10 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallBaseConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallBaseConfiguration
4 | {
5 | ///
6 | /// Gets or sets whether base method should be called by default.
7 | ///
8 | bool CallBaseByDefault { get; set; }
9 |
10 | ///
11 | /// Specifies whether base method should be always ignored for the matching call.
12 | /// If method is both explicitly excluded and included, base method is _not_ called.
13 | ///
14 | void Exclude(ICallSpecification callSpecification);
15 |
16 | ///
17 | /// Specifies whether base method should be called for the matching call.
18 | /// If method is both explicitly excluded and included, base method is _not_ called.
19 | ///
20 | void Include(ICallSpecification callSpecification);
21 |
22 | ///
23 | /// Tests whether base method should be called for the call given the existing configuration.
24 | ///
25 | bool ShouldCallBase(ICall call);
26 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallCollection.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallCollection
4 | {
5 | void Add(ICall call);
6 | void Delete(ICall call);
7 | IEnumerable AllCalls();
8 | void Clear();
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NSubstitute.Core.Arguments;
3 |
4 | namespace NSubstitute.Core;
5 |
6 | public interface ICallFactory
7 | {
8 | ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications, Func? baseMethod);
9 | ICall Create(MethodInfo methodInfo, object?[] getterArgs, object target, IList getArgumentSpecifications);
10 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallHandler.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallHandler
4 | {
5 | RouteAction Handle(ICall call);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallInfoFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallInfoFactory
4 | {
5 | CallInfo Create(ICall call);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallResults.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallResults
4 | {
5 | void SetResult(ICallSpecification callSpecification, IReturn result);
6 | bool TryGetResult(ICall call, out object? result);
7 | void Clear();
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallRouter.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallRouter
4 | {
5 | ///
6 | /// Specifies whether base method should be called by default.
7 | ///
8 | ///
9 | /// This configuration is considered only when base method exists (e.g. you created a substitute for
10 | /// the AbstractType with method implementation).
11 | ///
12 | bool CallBaseByDefault { get; set; }
13 | ConfiguredCall LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo);
14 | object? Route(ICall call);
15 | IEnumerable ReceivedCalls();
16 | void SetReturnForType(Type type, IReturn returnValue);
17 | void RegisterCustomCallHandlerFactory(CallHandlerFactory factory);
18 | void Clear(ClearOptions clear);
19 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallRouterFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallRouterFactory
4 | {
5 | ICallRouter Create(ISubstituteState substituteState, bool canConfigureBaseCalls);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallRouterProvider.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallRouterProvider
4 | {
5 | ICallRouter GetCallRouter();
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallRouterResolver.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallRouterResolver
4 | {
5 | ICallRouter ResolveFor(object substitute);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallSpecification.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NSubstitute.Core.Arguments;
3 |
4 | namespace NSubstitute.Core;
5 |
6 | public interface ICallSpecification
7 | {
8 | bool IsSatisfiedBy(ICall call);
9 | string Format(ICall call);
10 | ICallSpecification CreateCopyThatMatchesAnyArguments();
11 | void InvokePerArgumentActions(CallInfo callInfo);
12 | IEnumerable NonMatchingArguments(ICall call);
13 | MethodInfo GetMethodInfo();
14 | Type ReturnType();
15 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICallSpecificationFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ICallSpecificationFactory
4 | {
5 | ICallSpecification CreateFrom(ICall call, MatchArgs matchArgs);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IConfigureCall.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IConfigureCall
4 | {
5 | ConfiguredCall SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo);
6 | void SetResultForCall(ICall call, IReturn valueToReturn, MatchArgs matchArgs);
7 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ICustomHandlers.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | ///
4 | /// Factory method which creates from the .
5 | ///
6 | public delegate ICallHandler CallHandlerFactory(ISubstituteState substituteState);
7 |
8 | public interface ICustomHandlers
9 | {
10 | IReadOnlyCollection Handlers { get; }
11 |
12 | void AddCustomHandlerFactory(CallHandlerFactory factory);
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IDefaultForType.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IDefaultForType
4 | {
5 | object? GetDefaultFor(Type type);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IDescribeNonMatches.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | ///
4 | /// A type that can describe how an argument does not match a required condition.
5 | /// Use in conjunction with to provide information about
6 | /// non-matches.
7 | ///
8 | public interface IDescribeNonMatches
9 | {
10 | ///
11 | /// Describes how the does not match the condition specified by this class, or
12 | /// if a detailed description can not be provided for the argument.
13 | ///
14 | ///
15 | /// Description of the non-match, or if no description can be provided.
16 | string DescribeFor(object? argument);
17 | }
18 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IDescribeSpecification.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | ///
4 | /// A type that can describe the required conditions to meet a specification.
5 | /// Use in conjunction with to provide information about
6 | /// what it requires to match an argument.
7 | ///
8 | public interface IDescribeSpecification
9 | {
10 | ///
11 | /// A concise description of the conditions required to match this specification, or
12 | /// if a detailed description can not be provided.
13 | ///
14 | /// Description of the specification, or if no description can be provided.
15 | string DescribeSpecification();
16 | }
17 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IEventHandlerRegistry.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IEventHandlerRegistry
4 | {
5 | void Add(string eventName, object handler);
6 | void Remove(string eventName, object handler);
7 | IEnumerable GetHandlers(string eventName);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IGetCallSpec.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IGetCallSpec
4 | {
5 | ICallSpecification FromPendingSpecification(MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo);
6 | ICallSpecification FromExistingSpec(ICallSpecification spec, MatchArgs matchArgs);
7 | ICallSpecification FromCall(ICall call, MatchArgs matchArgs);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IMethodInfoFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public interface IMethodInfoFormatter
6 | {
7 | bool CanFormat(MethodInfo methodInfo);
8 | string Format(MethodInfo methodInfo, IEnumerable formattedArguments);
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IParameterInfo.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IParameterInfo
4 | {
5 | Type ParameterType { get; }
6 | bool IsParams { get; }
7 | bool IsOptional { get; }
8 | bool IsOut { get; }
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IPendingSpecification.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IPendingSpecification
4 | {
5 | bool HasPendingCallSpecInfo();
6 | PendingSpecificationInfo? UseCallSpecInfo();
7 | void SetCallSpecification(ICallSpecification callSpecification);
8 | void SetLastCall(ICall lastCall);
9 | void Clear();
10 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IPropertyHelper.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IPropertyHelper
4 | {
5 | bool IsCallToSetAReadWriteProperty(ICall call);
6 | ICall CreateCallToPropertyGetterFromSetterCall(ICall callToSetter);
7 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IProxyFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IProxyFactory
4 | {
5 | object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, bool isPartial, object?[]? constructorArguments);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IQuery.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IQuery
4 | {
5 | void RegisterCall(ICall call);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IQueryResults.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IQueryResults
4 | {
5 | IEnumerable MatchingCallsInOrder();
6 | IEnumerable QuerySpecification();
7 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IReceivedCallsExceptionThrower.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.ReceivedExtensions;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public interface IReceivedCallsExceptionThrower
6 | {
7 | void Throw(ICallSpecification callSpecification, IEnumerable matchingCalls, IEnumerable nonMatchingCalls, Quantity requiredQuantity);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/IResultsForType.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface IResultsForType
4 | {
5 | void SetResult(Type type, IReturn resultToReturn);
6 | bool TryGetResult(ICall call, out object? result);
7 | void Clear();
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ISubstituteFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ISubstituteFactory
4 | {
5 | object Create(Type[] typesToProxy, object[] constructorArguments);
6 | object CreatePartial(Type[] typesToProxy, object[] constructorArguments);
7 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ISubstituteState.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Routing.AutoValues;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public interface ISubstituteState
6 | {
7 | ICallBaseConfiguration CallBaseConfiguration { get; }
8 | ICallCollection ReceivedCalls { get; }
9 | ICallResults CallResults { get; }
10 | ICallActions CallActions { get; }
11 | IConfigureCall ConfigureCall { get; }
12 | IEventHandlerRegistry EventHandlerRegistry { get; }
13 | IReadOnlyCollection AutoValueProviders { get; }
14 | ICallResults AutoValuesCallResults { get; }
15 | IResultsForType ResultsForType { get; }
16 | ICustomHandlers CustomHandlers { get; }
17 | }
18 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ISubstituteStateFactory.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public interface ISubstituteStateFactory
4 | {
5 | ISubstituteState Create(ISubstituteFactory substituteFactory);
6 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ISubstitutionContext.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Routing;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public interface ISubstitutionContext
6 | {
7 | ISubstituteFactory SubstituteFactory { get; }
8 | IRouteFactory RouteFactory { get; }
9 | ICallSpecificationFactory CallSpecificationFactory { get; }
10 |
11 | ///
12 | /// A thread bound state of the NSubstitute context. Usually this API is used to provide the fluent
13 | /// features of the NSubstitute.
14 | ///
15 | IThreadLocalContext ThreadContext { get; }
16 |
17 | ICallRouter GetCallRouterFor(object substitute);
18 | }
19 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/MatchArgs.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | [DebuggerDisplay("{" + nameof(_name) + "}")]
6 | public class MatchArgs
7 | {
8 | private readonly string _name;
9 |
10 | public static readonly MatchArgs AsSpecifiedInCall = new(nameof(AsSpecifiedInCall));
11 | public static readonly MatchArgs Any = new(nameof(Any));
12 |
13 | private MatchArgs(string name)
14 | {
15 | _name = name;
16 | }
17 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Maybe.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | ///
6 | /// Particularly poor implementation of Maybe/Option type.
7 | /// This is just filling an immediate need; use FSharpOption or XSharpx or similar for a
8 | /// real implementation.
9 | ///
10 | ///
11 | public struct Maybe : IEnumerable
12 | {
13 | private readonly bool hasValue;
14 | private readonly T value;
15 |
16 | public Maybe(T value) : this()
17 | {
18 | this.value = value;
19 | hasValue = true;
20 | }
21 |
22 | public bool HasValue() { return hasValue; }
23 |
24 | public Maybe OrElse(Func> other) { var current = this; return Fold(other, _ => current); }
25 | public Maybe OrElse(Maybe other) { return OrElse(() => other); }
26 | public T ValueOr(Func other) { return Fold(other, x => x); }
27 | public T ValueOr(T other) { return ValueOr(() => other); }
28 | public T? ValueOrDefault() { return ValueOr(default(T)!); }
29 |
30 | public TResult Fold(Func handleNoValue, Func handleValue)
31 | {
32 | return HasValue() ? handleValue(value) : handleNoValue();
33 | }
34 |
35 | IEnumerator IEnumerable.GetEnumerator()
36 | {
37 | if (hasValue)
38 | {
39 | yield return value;
40 | }
41 | }
42 |
43 | IEnumerator IEnumerable.GetEnumerator()
44 | {
45 | return ((IEnumerable)this).GetEnumerator();
46 | }
47 | }
48 |
49 | public static class Maybe
50 | {
51 | public static Maybe Just(T value) { return new Maybe(value); }
52 | public static Maybe Nothing() { return new Maybe(); }
53 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/MethodFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class MethodFormatter : IMethodInfoFormatter
6 | {
7 | public bool CanFormat(MethodInfo methodInfo)
8 | {
9 | return true;
10 | }
11 |
12 | public string Format(MethodInfo methodInfo, IEnumerable arguments)
13 | {
14 | var args = string.Join(", ", arguments);
15 | return $"{methodInfo.Name}{FormatGenericType(methodInfo)}({args})";
16 | }
17 |
18 | private static string FormatGenericType(MethodInfo methodInfoOfCall)
19 | {
20 | if (!methodInfoOfCall.IsGenericMethod)
21 | {
22 | return string.Empty;
23 | }
24 |
25 | var genericArgs = methodInfoOfCall.GetGenericArguments();
26 | return $"<{string.Join(", ", genericArgs.Select(x => x.GetNonMangledTypeName()))}>";
27 | }
28 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ParameterInfoWrapper.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | internal class ParameterInfoWrapper(ParameterInfo parameterInfo) : IParameterInfo
6 | {
7 | public Type ParameterType => parameterInfo.ParameterType;
8 |
9 | public bool IsParams => parameterInfo.IsParams();
10 |
11 | public bool IsOptional => parameterInfo.IsOptional;
12 |
13 | public bool IsOut => parameterInfo.IsOut;
14 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/PendingSpecificationInfo.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class PendingSpecificationInfo
4 | {
5 | private readonly ICallSpecification? _callSpecification;
6 | private readonly ICall? _lastCall;
7 |
8 | private PendingSpecificationInfo(ICallSpecification? callSpecification, ICall? lastCall)
9 | {
10 | _callSpecification = callSpecification;
11 | _lastCall = lastCall;
12 | }
13 |
14 | public T Handle(Func onCallSpec, Func onLastCall)
15 | {
16 | return _callSpecification != null ? onCallSpec(_callSpecification) : onLastCall(_lastCall!);
17 | }
18 |
19 | public static PendingSpecificationInfo FromLastCall(ICall lastCall)
20 | {
21 | return new PendingSpecificationInfo(null, lastCall);
22 | }
23 |
24 | public static PendingSpecificationInfo FromCallSpecification(ICallSpecification callSpecification)
25 | {
26 | return new PendingSpecificationInfo(callSpecification, null);
27 | }
28 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/Query.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class Query(ICallSpecificationFactory callSpecificationFactory) : IQuery, IQueryResults
4 | {
5 | private readonly List _querySpec = [];
6 | private readonly HashSet _matchingCalls = new(new CallSequenceNumberComparer());
7 |
8 | public void RegisterCall(ICall call)
9 | {
10 | var target = call.Target();
11 | var callSpecification = callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall);
12 |
13 | _querySpec.Add(new CallSpecAndTarget(callSpecification, target));
14 |
15 | var allMatchingCallsOnTarget = target.ReceivedCalls().Where(callSpecification.IsSatisfiedBy);
16 | _matchingCalls.UnionWith(allMatchingCallsOnTarget);
17 | }
18 |
19 | public IQueryResults Result() => this;
20 |
21 | IEnumerable IQueryResults.MatchingCallsInOrder() => _matchingCalls.OrderBy(x => x.GetSequenceNumber());
22 |
23 | IEnumerable IQueryResults.QuerySpecification() => _querySpec.Select(x => x);
24 |
25 | private class CallSequenceNumberComparer : IEqualityComparer
26 | {
27 | public bool Equals(ICall? x, ICall? y) => x?.GetSequenceNumber() == y?.GetSequenceNumber();
28 |
29 | public int GetHashCode(ICall obj) => obj.GetSequenceNumber().GetHashCode();
30 | }
31 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ResultsForType.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NSubstitute.Core.Arguments;
3 |
4 | namespace NSubstitute.Core;
5 |
6 | public class ResultsForType(ICallInfoFactory callInfoFactory) : IResultsForType
7 | {
8 | private readonly CallResults _results = new CallResults(callInfoFactory);
9 |
10 | public void SetResult(Type type, IReturn resultToReturn)
11 | {
12 | _results.SetResult(new MatchingReturnTypeSpecification(type), resultToReturn);
13 | }
14 |
15 | public bool TryGetResult(ICall call, out object? result)
16 | {
17 | return _results.TryGetResult(call, out result);
18 | }
19 |
20 | public void Clear()
21 | {
22 | _results.Clear();
23 | }
24 |
25 | private class MatchingReturnTypeSpecification(Type expectedReturnType) : ICallSpecification
26 | {
27 | public bool IsSatisfiedBy(ICall call)
28 | => call.GetReturnType() == expectedReturnType;
29 |
30 | // ******* Rest methods are not required *******
31 |
32 | public string Format(ICall call)
33 | => throw new NotSupportedException();
34 |
35 | public ICallSpecification CreateCopyThatMatchesAnyArguments()
36 | => throw new NotSupportedException();
37 |
38 | public void InvokePerArgumentActions(CallInfo callInfo)
39 | => throw new NotSupportedException();
40 |
41 | public IEnumerable NonMatchingArguments(ICall call)
42 | => throw new NotSupportedException();
43 |
44 | public MethodInfo GetMethodInfo()
45 | => throw new NotSupportedException();
46 |
47 | public Type ReturnType()
48 | => throw new NotSupportedException();
49 | }
50 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/ReturnObservable.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | internal class ReturnObservable(T? value) : IObservable
4 | {
5 | public ReturnObservable() : this(default) { }
6 |
7 | public IDisposable Subscribe(IObserver observer)
8 | {
9 | observer.OnNext(value);
10 | observer.OnCompleted();
11 |
12 | return EmptyDisposable.Instance;
13 | }
14 | }
15 |
16 | internal class EmptyDisposable : IDisposable
17 | {
18 | public static IDisposable Instance { get; } = new EmptyDisposable();
19 |
20 | public void Dispose() { }
21 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/RobustThreadLocal.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | ///
4 | /// Delegates to ThreadLocal<T>, but wraps Value property access in try/catch to swallow ObjectDisposedExceptions.
5 | /// These can occur if the Value property is accessed from the finalizer thread. Because we can't detect this, we'll
6 | /// just swallow the exception (the finalizer thread won't be using any of the values from thread local storage anyway).
7 | ///
8 | internal class RobustThreadLocal
9 | {
10 | private readonly ThreadLocal _threadLocal;
11 | private readonly Func? _initialValueFactory;
12 |
13 | public RobustThreadLocal()
14 | {
15 | _threadLocal = new ThreadLocal();
16 | }
17 |
18 | public RobustThreadLocal(Func initialValueFactory)
19 | {
20 | _initialValueFactory = initialValueFactory;
21 | _threadLocal = new ThreadLocal(initialValueFactory);
22 | }
23 |
24 | public T Value
25 | {
26 | get
27 | {
28 | // Suppress nullability for result, as we trust type by usage.
29 | // For non-nullable we expect ctor with default to be used.
30 | try
31 | {
32 | return _threadLocal.Value!;
33 | }
34 | catch (ObjectDisposedException)
35 | {
36 | return _initialValueFactory != null ? _initialValueFactory.Invoke() : default!;
37 | }
38 | }
39 | set
40 | {
41 | try
42 | {
43 | _threadLocal.Value = value;
44 | }
45 | catch (ObjectDisposedException)
46 | {
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/RouteAction.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class RouteAction
4 | {
5 | private static readonly RouteAction _continue = new(hasReturnValue: false, null);
6 |
7 | public bool HasReturnValue { get; }
8 |
9 | public object? ReturnValue { get; }
10 |
11 | public static RouteAction Continue() => _continue;
12 | public static RouteAction Return(object? value) => new(hasReturnValue: true, value);
13 |
14 | private RouteAction(bool hasReturnValue, object? returnValue)
15 | {
16 | HasReturnValue = hasReturnValue;
17 | ReturnValue = returnValue;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/SequenceChecking/InstanceTracker.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | namespace NSubstitute.Core.SequenceChecking;
4 |
5 | public class InstanceTracker
6 | {
7 | private readonly Dictionary _instances = new(new ReferenceEqualityComparer());
8 | private int _counter = 0;
9 |
10 | public int InstanceNumber(object o)
11 | {
12 | if (_instances.TryGetValue(o, out var i))
13 | {
14 | return i;
15 | }
16 |
17 | var next = ++_counter;
18 | _instances.Add(o, next);
19 | return next;
20 | }
21 |
22 | public int NumberOfInstances() => _counter;
23 |
24 | private class ReferenceEqualityComparer : IEqualityComparer
25 | {
26 | public new bool Equals(object? x, object? y) => ReferenceEquals(x, y);
27 | public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/SequenceNumberGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Core;
2 |
3 | public class SequenceNumberGenerator
4 | {
5 | private long _current = long.MinValue;
6 |
7 | public virtual long Next()
8 | {
9 | return Interlocked.Increment(ref _current);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/SubstituteState.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Routing.AutoValues;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class SubstituteState : ISubstituteState
6 | {
7 | public ICallBaseConfiguration CallBaseConfiguration { get; }
8 | public ICallCollection ReceivedCalls { get; }
9 | public ICallResults CallResults { get; }
10 | public ICallActions CallActions { get; }
11 | public IConfigureCall ConfigureCall { get; }
12 | public IEventHandlerRegistry EventHandlerRegistry { get; }
13 | public IReadOnlyCollection AutoValueProviders { get; }
14 | public ICallResults AutoValuesCallResults { get; }
15 | public IResultsForType ResultsForType { get; }
16 | public ICustomHandlers CustomHandlers { get; }
17 |
18 | public SubstituteState(ICallSpecificationFactory callSpecificationFactory,
19 | ICallInfoFactory callInfoFactory,
20 | IReadOnlyCollection autoValueProviders)
21 | {
22 | AutoValueProviders = autoValueProviders;
23 |
24 | var callCollection = new CallCollection();
25 | ReceivedCalls = callCollection;
26 |
27 | CallBaseConfiguration = new CallBaseConfiguration();
28 | CallResults = new CallResults(callInfoFactory);
29 | AutoValuesCallResults = new CallResults(callInfoFactory);
30 | CallActions = new CallActions(callInfoFactory);
31 | ResultsForType = new ResultsForType(callInfoFactory);
32 | CustomHandlers = new CustomHandlers(this);
33 | var getCallSpec = new GetCallSpec(callCollection, callSpecificationFactory, CallActions);
34 | ConfigureCall = new ConfigureCall(CallResults, CallActions, getCallSpec);
35 | EventHandlerRegistry = new EventHandlerRegistry();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/NSubstitute/Core/SubstituteStateFactory.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Routing.AutoValues;
2 |
3 | namespace NSubstitute.Core;
4 |
5 | public class SubstituteStateFactory(ICallSpecificationFactory callSpecificationFactory,
6 | ICallInfoFactory callInfoFactory,
7 | IAutoValueProvidersFactory autoValueProvidersFactory) : ISubstituteStateFactory
8 | {
9 | public ISubstituteState Create(ISubstituteFactory substituteFactory)
10 | {
11 | var autoValueProviders = autoValueProvidersFactory.CreateProviders(substituteFactory);
12 | return new SubstituteState(callSpecificationFactory, callInfoFactory, autoValueProviders);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Core/SubstitutionContext.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core.DependencyInjection;
2 | using NSubstitute.Routing;
3 |
4 | namespace NSubstitute.Core;
5 |
6 | public class SubstitutionContext(
7 | ISubstituteFactory substituteFactory,
8 | IRouteFactory routeFactory,
9 | ICallSpecificationFactory callSpecificationFactory,
10 | IThreadLocalContext threadLocalContext,
11 | ICallRouterResolver callRouterResolver) : ISubstitutionContext
12 | {
13 | public static ISubstitutionContext Current { get; set; }
14 |
15 | public ISubstituteFactory SubstituteFactory { get; } = substituteFactory;
16 | public IRouteFactory RouteFactory { get; } = routeFactory;
17 | public IThreadLocalContext ThreadContext { get; } = threadLocalContext;
18 | public ICallSpecificationFactory CallSpecificationFactory { get; } = callSpecificationFactory;
19 |
20 | static SubstitutionContext()
21 | {
22 | Current = NSubstituteDefaultFactory.CreateSubstitutionContext();
23 | }
24 |
25 | public ICallRouter GetCallRouterFor(object substitute) =>
26 | callRouterResolver.ResolveFor(substitute);
27 | }
28 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/ArgumentIsNotOutOrRefException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class ArgumentIsNotOutOrRefException(int argumentIndex, Type argumentType) : SubstituteException(string.Format(WhatProbablyWentWrong, argumentIndex, argumentType.Name))
4 | {
5 | private const string WhatProbablyWentWrong = "Could not set argument {0} ({1}) as it is not an out or ref argument.";
6 | }
7 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/ArgumentNotFoundException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class ArgumentNotFoundException(string message) : SubstituteException(message)
4 | {
5 | }
6 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/ArgumentSetWithIncompatibleValueException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class ArgumentSetWithIncompatibleValueException(int argumentIndex, Type argumentType, Type typeOfValueWeTriedToAssign) : SubstituteException(string.Format(WhatProbablyWentWrong, argumentIndex, argumentType.Name, typeOfValueWeTriedToAssign.Name))
4 | {
5 | private const string WhatProbablyWentWrong =
6 | "Could not set value of type {2} to argument {0} ({1}) because the types are incompatible.";
7 | }
8 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/CallSequenceNotFoundException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class CallSequenceNotFoundException(string message) : SubstituteException(message)
4 | {
5 | }
6 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/CanNotPartiallySubForInterfaceOrDelegateException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class CanNotPartiallySubForInterfaceOrDelegateException(Type type) : SubstituteException(DescribeProblem(type))
4 | {
5 | private static string DescribeProblem(Type type)
6 | {
7 | return string.Format("Can only substitute for parts of classes, not interfaces or delegates. "
8 | + "Try `Substitute.For<{0}> instead.", type.Name);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/CannotCreateEventArgsException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class CannotCreateEventArgsException : SubstituteException
4 | {
5 | public CannotCreateEventArgsException() { }
6 | public CannotCreateEventArgsException(string message) : base(message) { }
7 | public CannotCreateEventArgsException(string message, Exception innerException) : base(message, innerException) { }
8 | }
9 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/CannotReturnNullforValueType.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class CannotReturnNullForValueType(Type valueType) : SubstituteException(string.Format(Description, valueType.Name))
4 | {
5 | private const string Description =
6 | "Cannot return null for {0} because it is a value type. " +
7 | "If you want to return the default value for this type use \"default({0})\".";
8 | }
9 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/CouldNotConfigureBaseMethodException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class CouldNotConfigureCallBaseException(string message) : SubstituteException(message)
4 | {
5 | private const string CannotConfigureSingleCallMessage =
6 | "Cannot configure the base method call as base method implementation is missing. " +
7 | "You can call base method only if you create a class substitute and the method is not abstract.";
8 |
9 | private const string CannotConfigureAllCallsMessage =
10 | "Base method calls can be configured for a class substitute only, " +
11 | "as otherwise base implementation does not exist.";
12 |
13 | internal static CouldNotConfigureCallBaseException ForSingleCall() =>
14 | new CouldNotConfigureCallBaseException(CannotConfigureSingleCallMessage);
15 |
16 | internal static CouldNotConfigureCallBaseException ForAllCalls() =>
17 | new CouldNotConfigureCallBaseException(CannotConfigureAllCallsMessage);
18 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/CouldNotRaiseEventException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class CouldNotRaiseEventException : SubstituteException
4 | {
5 | protected const string WhatProbablyWentWrong =
6 | "Make sure you are using Raise.Event() as part of an event subscription on a substitute.\n" +
7 | "For example:\n" +
8 | "\tmySub.Clicked += Raise.Event();\n" +
9 | "\n" +
10 | "If you substituted for a class rather than an interface, check that the event on your substitute is virtual/abstract.\n" +
11 | "Events on classes cannot be raised if they are not declared virtual or abstract.\n" +
12 | "\n" +
13 | "Note that the source of the problem may be prior to where this exception was thrown (possibly in a previous test!).\n" +
14 | "For example:\n" +
15 | "\tvar notASub = new Button();\n" +
16 | "\tnotASub.Clicked += Raise.Event(); // <-- Problem here. This is not a substitute.\n" +
17 | "\tvar sub = Substitute.For();\n" +
18 | "\tsub.Load(); // <-- Exception thrown here. NSubstitute thinks the earlier Raise.Event() was meant for this call.";
19 |
20 | public CouldNotRaiseEventException() : base(WhatProbablyWentWrong) { }
21 | }
22 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/MissingSequenceNumberException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class MissingSequenceNumberException : SubstituteException
4 | {
5 | public MissingSequenceNumberException() { }
6 | }
7 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/NotASubstituteException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class NotASubstituteException : SubstituteException
4 | {
5 | private const string Explanation =
6 | "NSubstitute extension methods like .Received() can only be called " +
7 | "on objects created using Substitute.For() and related methods.";
8 |
9 | public NotASubstituteException() : base(Explanation) { }
10 | }
11 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/NotRunningAQueryException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class NotRunningAQueryException : SubstituteException
4 | {
5 | public NotRunningAQueryException() { }
6 | }
7 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/NullSubstituteReferenceException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class NullSubstituteReferenceException : SubstituteException
4 | {
5 | private const string Explanation = "NSubstitute extension methods like .Received() can only be called on non-null objects.";
6 |
7 | public NullSubstituteReferenceException() : base(Explanation) { }
8 | }
9 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/ProtectedMethodNotFoundException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class ProtectedMethodNotFoundException(string message, Exception? innerException) : SubstituteException(message, innerException)
4 | {
5 | public ProtectedMethodNotFoundException() : this("", null)
6 | { }
7 |
8 | public ProtectedMethodNotFoundException(string message) : this(message, null)
9 | { }
10 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/ProtectedMethodNotVirtualException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class ProtectedMethodNotVirtualException(string message, Exception? innerException) : SubstituteException(message, innerException)
4 | {
5 | public ProtectedMethodNotVirtualException() : this("", null)
6 | { }
7 |
8 | public ProtectedMethodNotVirtualException(string message) : this(message, null)
9 | { }
10 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/ReceivedCallsException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class ReceivedCallsException : SubstituteException
4 | {
5 | public ReceivedCallsException() { }
6 | public ReceivedCallsException(string message) : base(message) { }
7 | public ReceivedCallsException(string message, Exception innerException) : base(message, innerException) { }
8 | }
9 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/SubstituteException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class SubstituteException(string message, Exception? innerException) : Exception(message, innerException)
4 | {
5 | public SubstituteException() : this("") { }
6 | public SubstituteException(string message) : this(message, null) { }
7 | }
8 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/SubstituteInternalException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 |
4 | public class SubstituteInternalException(string message, Exception? innerException) : SubstituteException("Please report this exception at https://github.com/nsubstitute/NSubstitute/issues: \n\n" + message,
5 | innerException)
6 | {
7 | public SubstituteInternalException() : this("") { }
8 | public SubstituteInternalException(string message) : this(message, null) { }
9 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/TypeForwardingException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public abstract class TypeForwardingException(string message) : SubstituteException(message)
4 | {
5 | }
6 |
7 | public sealed class CanNotForwardCallsToClassNotImplementingInterfaceException(Type type) : TypeForwardingException(DescribeProblem(type))
8 | {
9 | private static string DescribeProblem(Type type)
10 | {
11 | return string.Format("The provided class '{0}' doesn't implement all requested interfaces. ", type.Name);
12 | }
13 | }
14 |
15 | public sealed class CanNotForwardCallsToAbstractClassException(Type type) : TypeForwardingException(DescribeProblem(type))
16 | {
17 | private static string DescribeProblem(Type type)
18 | {
19 | return string.Format("The provided class '{0}' is abstract. ", type.Name);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/NSubstitute/Exceptions/UnexpectedArgumentMatcherException.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Exceptions;
2 |
3 | public class UnexpectedArgumentMatcherException(string message) : SubstituteException(message)
4 | {
5 | public static readonly string WhatProbablyWentWrong =
6 | "Argument matchers (Arg.Is, Arg.Any) should only be used in place of member arguments. " +
7 | "Do not use in a Returns() statement or anywhere else outside of a member call." + Environment.NewLine +
8 | "Correct use:" + Environment.NewLine +
9 | " sub.MyMethod(Arg.Any()).Returns(\"hi\")" + Environment.NewLine +
10 | "Incorrect use:" + Environment.NewLine +
11 | " sub.MyMethod(\"hi\").Returns(Arg.Any())";
12 | public UnexpectedArgumentMatcherException() : this(WhatProbablyWentWrong) { }
13 | }
14 |
--------------------------------------------------------------------------------
/src/NSubstitute/Extensions/ClearExtensions.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 |
4 | namespace NSubstitute.ClearExtensions;
5 |
6 | public static class ClearExtensions
7 | {
8 | ///
9 | /// Clears received calls, configured return values and/or call actions for this substitute.
10 | ///
11 | ///
12 | ///
13 | /// Specifies what to clear on the substitute. Can be combined with |
to
14 | /// clear multiple aspects at once.
15 | ///
16 | ///
17 | public static void ClearSubstitute(this T substitute, ClearOptions options = ClearOptions.All) where T : class
18 | {
19 | if (substitute == null) throw new NullSubstituteReferenceException();
20 |
21 | var context = SubstitutionContext.Current;
22 | var router = context.GetCallRouterFor(substitute!);
23 | router.Clear(options);
24 | }
25 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Extensions/ConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 |
4 | namespace NSubstitute.Extensions;
5 |
6 | public static class ConfigurationExtensions
7 | {
8 | ///
9 | /// A hint for the NSubstitute that the subsequent method/property call is about to be configured.
10 | /// For example: substitute.Configure().GetValue().Returns(1,2,3);
11 | ///
12 | /// NOTICE, you _don't need_ to invoke this method for the basic configuration scenarios.
13 | /// Ensure you don't overuse this method and it is applied only if strictly required.
14 | ///
15 | ///
16 | /// Due to the NSubstitute configuration syntax it is often impossible to recognise during the method call
17 | /// dispatch whether this is a setup phase or a regular method call.
18 | /// Usually it doesn't matter, however sometimes method invocation could lead to undesired side effects
19 | /// (e.g. the previously configured value is returned, base method is invoked). In that case you might want to
20 | /// provide NSubstitute with a hint that you are configuring a method, so it handles the call in configuration mode.
21 | ///
22 | ///
23 | public static T Configure(this T substitute) where T : class
24 | {
25 | if (substitute == null) throw new NullSubstituteReferenceException();
26 |
27 | var context = SubstitutionContext.Current;
28 | var callRouter = context.GetCallRouterFor(substitute!);
29 | context.ThreadContext.SetNextRoute(callRouter, context.RouteFactory.RecordCallSpecification);
30 |
31 | return substitute;
32 | }
33 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Extensions/ReturnsForAllExtensions.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 |
4 | namespace NSubstitute.Extensions;
5 |
6 | public static class ReturnsForAllExtensions
7 | {
8 | ///
9 | /// Configure default return value for all methods that return the specified type
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | public static void ReturnsForAll(this object substitute, T returnThis)
16 | {
17 | if (substitute == null) throw new NullSubstituteReferenceException();
18 |
19 | var callRouter = SubstitutionContext.Current.GetCallRouterFor(substitute);
20 | callRouter.SetReturnForType(typeof(T), new ReturnValue(returnThis));
21 | }
22 |
23 | ///
24 | /// Configure default return value for all methods that return the specified type, calculated by a function
25 | ///
26 | ///
27 | ///
28 | ///
29 | ///
30 | public static void ReturnsForAll(this object substitute, Func returnThis)
31 | {
32 | if (substitute == null) throw new NullSubstituteReferenceException();
33 |
34 | var callRouter = SubstitutionContext.Current.GetCallRouterFor(substitute);
35 | callRouter.SetReturnForType(typeof(T), new ReturnValueFromFunc(returnThis));
36 | }
37 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Proxies/CastleDynamicProxy/CastleForwardingInterceptor.cs:
--------------------------------------------------------------------------------
1 | using Castle.DynamicProxy;
2 | using NSubstitute.Core;
3 |
4 | namespace NSubstitute.Proxies.CastleDynamicProxy;
5 |
6 | public class CastleForwardingInterceptor(CastleInvocationMapper invocationMapper, ICallRouter callRouter) : IInterceptor
7 | {
8 | private bool _fullDispatchMode;
9 |
10 | public void Intercept(IInvocation invocation)
11 | {
12 | ICall mappedInvocation = invocationMapper.Map(invocation);
13 |
14 | if (_fullDispatchMode)
15 | {
16 | invocation.ReturnValue = callRouter.Route(mappedInvocation);
17 | return;
18 | }
19 |
20 | // Fallback to the base value until the full dispatch mode is activated.
21 | // Useful to ensure that object is initialized properly.
22 | if (callRouter.CallBaseByDefault)
23 | {
24 | invocation.ReturnValue = mappedInvocation.TryCallBase().ValueOrDefault();
25 | }
26 | }
27 |
28 | ///
29 | /// Switches interceptor to dispatch calls via the full pipeline.
30 | ///
31 | public void SwitchToFullDispatchMode()
32 | {
33 | _fullDispatchMode = true;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Proxies/CastleDynamicProxy/CastleInvocationMapper.cs:
--------------------------------------------------------------------------------
1 | using Castle.DynamicProxy;
2 | using NSubstitute.Core;
3 |
4 | namespace NSubstitute.Proxies.CastleDynamicProxy;
5 |
6 | public class CastleInvocationMapper(ICallFactory callFactory, IArgumentSpecificationDequeue argSpecificationDequeue)
7 | {
8 | public virtual ICall Map(IInvocation castleInvocation)
9 | {
10 | Func? baseMethod = null;
11 | if (castleInvocation.InvocationTarget != null &&
12 | castleInvocation.MethodInvocationTarget.IsVirtual &&
13 | !castleInvocation.MethodInvocationTarget.IsAbstract)
14 | {
15 | baseMethod = CreateBaseResultInvocation(castleInvocation);
16 | }
17 |
18 | var queuedArgSpecifications = argSpecificationDequeue.DequeueAllArgumentSpecificationsForMethod(castleInvocation.Arguments.Length);
19 | return callFactory.Create(castleInvocation.Method, castleInvocation.Arguments, castleInvocation.Proxy, queuedArgSpecifications, baseMethod);
20 | }
21 |
22 | private static Func CreateBaseResultInvocation(IInvocation invocation)
23 | {
24 | // Notice, it's important to keep this as a separate method, as methods with lambda closures
25 | // always allocate, even if delegate is not actually constructed.
26 | // This way we make allocation only if indeed required.
27 | Func baseResult = () => { invocation.Proceed(); return invocation.ReturnValue; };
28 | var result = new Lazy(baseResult);
29 | return () => result.Value;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/NSubstitute/Proxies/CastleDynamicProxy/ProxyIdInterceptor.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Reflection;
3 | using Castle.DynamicProxy;
4 | using NSubstitute.Core;
5 |
6 | namespace NSubstitute.Proxies.CastleDynamicProxy;
7 |
8 | public class ProxyIdInterceptor(Type primaryProxyType) : IInterceptor
9 | {
10 | private string? _cachedProxyId;
11 |
12 | public void Intercept(IInvocation invocation)
13 | {
14 | if (IsDefaultToStringMethod(invocation.Method))
15 | {
16 | invocation.ReturnValue = _cachedProxyId ??= GenerateId(invocation);
17 | return;
18 | }
19 |
20 | invocation.Proceed();
21 | }
22 |
23 | private string GenerateId(IInvocation invocation)
24 | {
25 | var proxy = invocation.InvocationTarget;
26 |
27 | var shortTypeName = primaryProxyType.GetNonMangledTypeName();
28 | var proxyHashCode = proxy.GetHashCode();
29 |
30 | return string.Format(CultureInfo.InvariantCulture, "Substitute.{0}|{1:x8}", shortTypeName, proxyHashCode);
31 | }
32 |
33 | public static bool IsDefaultToStringMethod(MethodInfo methodInfo)
34 | {
35 | return methodInfo.DeclaringType == typeof(object)
36 | && string.Equals(methodInfo.Name, nameof(ToString), StringComparison.Ordinal)
37 | && methodInfo.GetParameters().Length == 0;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Received.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Core.SequenceChecking;
3 |
4 | namespace NSubstitute;
5 |
6 | public class Received
7 | {
8 | ///
9 | /// Asserts the calls to the substitutes contained in the given Action were
10 | /// received by these substitutes in the same order. Calls to property getters are not included
11 | /// in the assertion.
12 | ///
13 | /// Action containing calls to substitutes in the expected order
14 | public static void InOrder(Action calls)
15 | {
16 | var query = new Query(SubstitutionContext.Current.CallSpecificationFactory);
17 | SubstitutionContext.Current.ThreadContext.RunInQueryContext(calls, query);
18 | new SequenceInOrderAssertion().Assert(query.Result());
19 | }
20 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/AutoArrayProvider.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Routing.AutoValues;
2 |
3 | public class AutoArrayProvider : IAutoValueProvider
4 | {
5 | public bool CanProvideValueFor(Type type) =>
6 | type.IsArray;
7 |
8 | public object GetValue(Type type)
9 | {
10 | var rank = type.GetArrayRank();
11 | var dimensionLengths = new int[rank];
12 | return Array.CreateInstance(type.GetElementType()!, dimensionLengths);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/AutoObservableProvider.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using System.Reflection;
3 |
4 | namespace NSubstitute.Routing.AutoValues;
5 |
6 | public class AutoObservableProvider(Lazy> autoValueProviders) : IAutoValueProvider
7 | {
8 | public bool CanProvideValueFor(Type type) =>
9 | type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IObservable<>);
10 |
11 | public object? GetValue(Type type)
12 | {
13 | if (!CanProvideValueFor(type))
14 | throw new InvalidOperationException();
15 |
16 | Type innerType = type.GetGenericArguments()[0];
17 | var valueProvider = autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(innerType));
18 | var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(innerType);
19 | return Activator.CreateInstance(typeof(ReturnObservable<>).MakeGenericType(innerType), [value]);
20 | }
21 |
22 | private static object? GetDefault(Type type)
23 | {
24 | return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/AutoQueryableProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Routing.AutoValues;
4 |
5 | public class AutoQueryableProvider : IAutoValueProvider
6 | {
7 | public bool CanProvideValueFor(Type type) =>
8 | type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IQueryable<>);
9 |
10 | public object GetValue(Type type)
11 | {
12 | if (!CanProvideValueFor(type))
13 | throw new InvalidOperationException();
14 |
15 | Type innerType = type.GetGenericArguments()[0];
16 |
17 | return Array.CreateInstance(innerType, 0).AsQueryable();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/AutoStringProvider.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Routing.AutoValues;
2 |
3 | public class AutoStringProvider : IAutoValueProvider
4 | {
5 | public bool CanProvideValueFor(Type type) => type == typeof(string);
6 |
7 | public object GetValue(Type type)
8 | {
9 | return string.Empty;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/AutoTaskProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace NSubstitute.Routing.AutoValues;
4 |
5 | public class AutoTaskProvider(Lazy> autoValueProviders) : IAutoValueProvider
6 | {
7 | public bool CanProvideValueFor(Type type) => typeof(Task).IsAssignableFrom(type);
8 |
9 | public object GetValue(Type type)
10 | {
11 | if (!CanProvideValueFor(type))
12 | throw new InvalidOperationException();
13 |
14 | if (type.GetTypeInfo().IsGenericType)
15 | {
16 | var taskType = type.GetGenericArguments()[0];
17 | var valueProvider = autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(taskType));
18 |
19 | var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(taskType);
20 | var taskCompletionSourceType = typeof(TaskCompletionSource<>).MakeGenericType(taskType);
21 | var taskCompletionSource = Activator.CreateInstance(taskCompletionSourceType);
22 | taskCompletionSourceType.GetMethod(nameof(TaskCompletionSource.SetResult))!.Invoke(taskCompletionSource, [value]);
23 | return taskCompletionSourceType.GetProperty(nameof(TaskCompletionSource.Task))!.GetValue(taskCompletionSource, null)!;
24 | }
25 | else
26 | {
27 | var taskCompletionSource = new TaskCompletionSource();
28 | taskCompletionSource.SetResult(null);
29 | return taskCompletionSource.Task;
30 | }
31 | }
32 |
33 | private static object? GetDefault(Type type)
34 | {
35 | return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/AutoValueProvidersFactory.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 |
4 | namespace NSubstitute.Routing.AutoValues;
5 |
6 | public class AutoValueProvidersFactory : IAutoValueProvidersFactory
7 | {
8 | public IReadOnlyCollection CreateProviders(ISubstituteFactory substituteFactory)
9 | {
10 | IAutoValueProvider[]? result = null;
11 | var lazyResult = new Lazy>(
12 | () => result ?? throw new SubstituteInternalException("Value was not constructed yet."),
13 | LazyThreadSafetyMode.PublicationOnly);
14 |
15 | result =
16 | [
17 | new AutoObservableProvider(lazyResult),
18 | new AutoQueryableProvider(),
19 | new AutoSubstituteProvider(substituteFactory),
20 | new AutoStringProvider(),
21 | new AutoArrayProvider(),
22 | new AutoTaskProvider(lazyResult)
23 | ];
24 |
25 | return result;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/IAutoValueProvider.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Routing.AutoValues;
2 |
3 | public interface IAutoValueProvider
4 | {
5 | bool CanProvideValueFor(Type type);
6 | object? GetValue(Type type);
7 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/AutoValues/IAutoValueProvidersFactory.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.AutoValues;
4 |
5 | public interface IAutoValueProvidersFactory
6 | {
7 | IReadOnlyCollection CreateProviders(ISubstituteFactory substituteFactory);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/AddCallToQueryResultHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class AddCallToQueryResultHandler(IThreadLocalContext threadContext) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | threadContext.RegisterInContextQuery(call);
10 |
11 | return RouteAction.Continue();
12 | }
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/CallBaseForCallHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 |
4 | namespace NSubstitute.Routing.Handlers;
5 |
6 | public class CallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseConfiguration callBaseConfig, MatchArgs matchArgs) : ICallHandler
7 | {
8 | public RouteAction Handle(ICall call)
9 | {
10 | if (!call.CanCallBase) throw CouldNotConfigureCallBaseException.ForSingleCall();
11 |
12 | var callSpec = callSpecificationFactory.CreateFrom(call, matchArgs);
13 | callBaseConfig.Include(callSpec);
14 |
15 | return RouteAction.Continue();
16 | }
17 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/CheckReceivedCallsHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.ReceivedExtensions;
3 |
4 | namespace NSubstitute.Routing.Handlers;
5 |
6 | public class CheckReceivedCallsHandler(ICallCollection receivedCalls, ICallSpecificationFactory callSpecificationFactory, IReceivedCallsExceptionThrower exceptionThrower, MatchArgs matchArgs, Quantity requiredQuantity) : ICallHandler
7 | {
8 | public RouteAction Handle(ICall call)
9 | {
10 | var callSpecification = callSpecificationFactory.CreateFrom(call, matchArgs);
11 | var allCallsToMethodSpec = callSpecificationFactory.CreateFrom(call, MatchArgs.Any);
12 |
13 | var allCalls = receivedCalls.AllCalls().ToList();
14 | var matchingCalls = allCalls.Where(callSpecification.IsSatisfiedBy).ToList();
15 |
16 | if (!requiredQuantity.Matches(matchingCalls))
17 | {
18 | var relatedCalls = allCalls.Where(allCallsToMethodSpec.IsSatisfiedBy).Except(matchingCalls);
19 | exceptionThrower.Throw(callSpecification, matchingCalls, relatedCalls, requiredQuantity);
20 | }
21 |
22 | return RouteAction.Continue();
23 | }
24 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ClearLastCallRouterHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | ///
6 | /// Clears last call router on SubstitutionContext for routes that do not require it.
7 | ///
8 | ///
9 | /// This is to help prevent static state bleeding over into future calls.
10 | ///
11 | public class ClearLastCallRouterHandler(IThreadLocalContext threadContext) : ICallHandler
12 | {
13 | public RouteAction Handle(ICall call)
14 | {
15 | threadContext.ClearLastCallRouter();
16 |
17 | return RouteAction.Continue();
18 | }
19 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ClearUnusedCallSpecHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class ClearUnusedCallSpecHandler(IPendingSpecification pendingSpecification) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | pendingSpecification.Clear();
10 |
11 | return RouteAction.Continue();
12 | }
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/DoActionsCallHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class DoActionsCallHandler(ICallActions callActions) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | callActions.InvokeMatchingActions(call);
10 |
11 | return RouteAction.Continue();
12 | }
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/DoNotCallBaseForCallHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 |
4 | namespace NSubstitute.Routing.Handlers;
5 |
6 | public class DoNotCallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseConfiguration callBaseConfig, MatchArgs matchArgs) : ICallHandler
7 | {
8 | public RouteAction Handle(ICall call)
9 | {
10 | if (!call.CanCallBase) throw CouldNotConfigureCallBaseException.ForSingleCall();
11 |
12 | var callSpec = callSpecificationFactory.CreateFrom(call, matchArgs);
13 | callBaseConfig.Exclude(callSpec);
14 |
15 | return RouteAction.Continue();
16 | }
17 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/PropertySetterHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class PropertySetterHandler(IPropertyHelper propertyHelper, IConfigureCall configureCall) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | if (propertyHelper.IsCallToSetAReadWriteProperty(call))
10 | {
11 | var callToPropertyGetter = propertyHelper.CreateCallToPropertyGetterFromSetterCall(call);
12 | // It's important to use original arguments, as it provides better performance.
13 | // It's safe to use original arguments here, as only by-ref arguments might be modified,
14 | // which should never happen for this case.
15 | var valueBeingSetOnProperty = call.GetOriginalArguments().Last();
16 | configureCall.SetResultForCall(callToPropertyGetter, new ReturnValue(valueBeingSetOnProperty), MatchArgs.AsSpecifiedInCall);
17 | }
18 |
19 | return RouteAction.Continue();
20 | }
21 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/RaiseEventHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NSubstitute.Core;
3 | using NSubstitute.Exceptions;
4 |
5 | namespace NSubstitute.Routing.Handlers;
6 |
7 | public class RaiseEventHandler(IEventHandlerRegistry eventHandlerRegistry, Func getEventArguments) : ICallHandler
8 | {
9 | public RouteAction Handle(ICall call)
10 | {
11 | var methodInfo = call.GetMethodInfo();
12 | var eventInfo = FindEventInfo(methodInfo);
13 | if (eventInfo == null)
14 | {
15 | throw new CouldNotRaiseEventException();
16 | }
17 |
18 | object?[] eventArguments = getEventArguments(call);
19 | var handlers = eventHandlerRegistry.GetHandlers(eventInfo.Name);
20 | foreach (Delegate handler in handlers)
21 | {
22 | if (handler == null)
23 | {
24 | continue;
25 | }
26 |
27 | try
28 | {
29 | (handler.DynamicInvoke(eventArguments) as Task)?.GetAwaiter().GetResult();
30 | }
31 | catch (TargetInvocationException e)
32 | {
33 | throw e.InnerException!;
34 | }
35 | }
36 |
37 | return RouteAction.Continue();
38 |
39 | static EventInfo? FindEventInfo(MethodInfo mi)
40 | {
41 | return mi.DeclaringType!.GetEvents().FirstOrDefault(
42 | e => e.GetAddMethod() == mi || e.GetRemoveMethod() == mi);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/RecordCallHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class RecordCallHandler(ICallCollection callCollection, SequenceNumberGenerator generator) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | call.AssignSequenceNumber(generator.Next());
10 | callCollection.Add(call);
11 |
12 | return RouteAction.Continue();
13 | }
14 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/RecordCallSpecificationHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class RecordCallSpecificationHandler(IPendingSpecification pendingCallSpecification, ICallSpecificationFactory callSpecificationFactory, ICallActions callActions) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | var callSpec = callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall);
10 | pendingCallSpecification.SetCallSpecification(callSpec);
11 |
12 | // Performance optimization - don't register call actions if current argument matchers
13 | // don't have any callbacks.
14 | if (call.GetArgumentSpecifications().Any(x => x.HasAction))
15 | {
16 | callActions.Add(callSpec);
17 | }
18 |
19 | return RouteAction.Continue();
20 | }
21 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ReturnConfiguredResultHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class ReturnConfiguredResultHandler(ICallResults callResults) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | if (callResults.TryGetResult(call, out var configuredResult))
10 | {
11 | return RouteAction.Return(configuredResult);
12 | }
13 |
14 | return RouteAction.Continue();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ReturnDefaultForReturnTypeHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class ReturnDefaultForReturnTypeHandler(IDefaultForType defaultForType) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | var returnValue = defaultForType.GetDefaultFor(call.GetMethodInfo().ReturnType);
10 | return RouteAction.Return(returnValue);
11 | }
12 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ReturnFromBaseIfRequired.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class ReturnFromBaseIfRequired(ICallBaseConfiguration config) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | if (config.ShouldCallBase(call))
10 | {
11 | return call
12 | .TryCallBase()
13 | .Fold(RouteAction.Continue, RouteAction.Return);
14 | }
15 |
16 | return RouteAction.Continue();
17 | }
18 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ReturnFromCustomHandlers.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class ReturnFromCustomHandlers(ICustomHandlers customHandlers) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | // Performance optimization, as enumerator retrieval allocates.
10 | if (customHandlers.Handlers.Count == 0)
11 | {
12 | return RouteAction.Continue();
13 | }
14 |
15 | foreach (var handler in customHandlers.Handlers)
16 | {
17 | var result = handler.Handle(call);
18 | if (result.HasReturnValue)
19 | {
20 | return result;
21 | }
22 | }
23 |
24 | return RouteAction.Continue();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/ReturnResultForTypeHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class ReturnResultForTypeHandler(IResultsForType resultsForType) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | if (resultsForType.TryGetResult(call, out var result))
10 | {
11 | return RouteAction.Return(result);
12 | }
13 |
14 | return RouteAction.Continue();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/SetActionForCallHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class SetActionForCallHandler(
6 | ICallSpecificationFactory callSpecificationFactory,
7 | ICallActions callActions,
8 | Action action,
9 | MatchArgs matchArgs) : ICallHandler
10 | {
11 | public RouteAction Handle(ICall call)
12 | {
13 | var callSpec = callSpecificationFactory.CreateFrom(call, matchArgs);
14 | callActions.Add(callSpec, action);
15 |
16 | return RouteAction.Continue();
17 | }
18 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Handlers/TrackLastCallHandler.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing.Handlers;
4 |
5 | public class TrackLastCallHandler(IPendingSpecification pendingSpecification) : ICallHandler
6 | {
7 | public RouteAction Handle(ICall call)
8 | {
9 | pendingSpecification.SetLastCall(call);
10 |
11 | return RouteAction.Continue();
12 | }
13 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/IRoute.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing;
4 |
5 | public interface IRoute
6 | {
7 | object? Handle(ICall call);
8 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/IRouteFactory.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.ReceivedExtensions;
3 |
4 | namespace NSubstitute.Routing;
5 |
6 | public interface IRouteFactory
7 | {
8 | IRoute CallQuery(ISubstituteState state);
9 | IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity);
10 | IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs);
11 | IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs);
12 | IRoute CallBase(ISubstituteState state, MatchArgs matchArgs);
13 | IRoute RaiseEvent(ISubstituteState state, Func getEventArguments);
14 | IRoute RecordCallSpecification(ISubstituteState state);
15 | IRoute RecordReplay(ISubstituteState state);
16 | }
--------------------------------------------------------------------------------
/src/NSubstitute/Routing/Route.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute.Routing;
4 |
5 | public class Route(ICallHandler[] handlers) : IRoute
6 | {
7 | public IEnumerable Handlers => handlers;
8 |
9 | public object? Handle(ICall call)
10 | {
11 | // This is a hot method which is invoked frequently and has major impact on performance.
12 | // Therefore, the LINQ cycle was unwinded to for loop.
13 | for (int i = 0; i < handlers.Length; i++)
14 | {
15 | var result = handlers[i].Handle(call);
16 | if (result.HasReturnValue)
17 | {
18 | return result.ReturnValue;
19 | }
20 | }
21 |
22 | return null;
23 | }
24 | }
--------------------------------------------------------------------------------
/src/NSubstitute/SubstituteExtensions.When.Task.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute;
4 |
5 | public static partial class SubstituteExtensions
6 | {
7 | ///
8 | /// Perform an action when this member is called.
9 | /// Must be followed by to provide the callback.
10 | ///
11 | public static WhenCalled When(this T substitute, Func substituteCall) where T : class
12 | {
13 | return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.AsSpecifiedInCall);
14 | }
15 |
16 | ///
17 | /// Perform an action when this member is called with any arguments.
18 | /// Must be followed by to provide the callback.
19 | ///
20 | public static WhenCalled WhenForAnyArgs(this T substitute, Func substituteCall) where T : class
21 | {
22 | return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.Any);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/NSubstitute/SubstituteExtensions.When.ValueTask.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 |
3 | namespace NSubstitute;
4 |
5 | public static partial class SubstituteExtensions
6 | {
7 | ///
8 | /// Perform an action when this member is called.
9 | /// Must be followed by to provide the callback.
10 | ///
11 | public static WhenCalled When(this TSubstitute substitute,
12 | Func> substituteCall) where TSubstitute : class
13 | {
14 | return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.AsSpecifiedInCall);
15 | }
16 |
17 | ///
18 | /// Perform an action when this member is called with any arguments.
19 | /// Must be followed by to provide the callback.
20 | ///
21 | public static WhenCalled WhenForAnyArgs(this TSubstitute substitute,
22 | Func> substituteCall) where TSubstitute : class
23 | {
24 | return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.Any);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/NSubstitute/SubstituteExtensions.When.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Core;
2 | using NSubstitute.Exceptions;
3 | namespace NSubstitute;
4 |
5 | public static partial class SubstituteExtensions
6 | {
7 | ///
8 | /// Perform an action when this member is called.
9 | /// Must be followed by to provide the callback.
10 | ///
11 | public static WhenCalled When(this T substitute, Action substituteCall) where T : class
12 | {
13 | return MakeWhenCalled(substitute, substituteCall, MatchArgs.AsSpecifiedInCall);
14 | }
15 |
16 | ///
17 | /// Perform an action when this member is called with any arguments.
18 | /// Must be followed by to provide the callback.
19 | ///
20 | public static WhenCalled WhenForAnyArgs(this T substitute, Action substituteCall) where T : class
21 | {
22 | return MakeWhenCalled(substitute, substituteCall, MatchArgs.Any);
23 | }
24 |
25 | private static WhenCalled MakeWhenCalled(TSubstitute? substitute,
26 | Action action, MatchArgs matchArgs)
27 | {
28 | if (substitute == null) throw new NullSubstituteReferenceException();
29 |
30 | var context = SubstitutionContext.Current;
31 | return new WhenCalled(context, substitute, action, matchArgs);
32 | }
33 | }
--------------------------------------------------------------------------------
/src/NSubstitute/nsubstitute.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nsubstitute/NSubstitute/af8df59f2df7435d613e840f600750814370567d/src/NSubstitute/nsubstitute.snk
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/AssemblySigningTest.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs;
5 |
6 | public class AssemblySigningTest
7 | {
8 | [Test]
9 | public void NSubstitute_assembly_should_be_signed()
10 | {
11 | var assemblyName = typeof(Substitute).GetTypeInfo().Assembly.GetName();
12 | var publicKeyToken = string.Join("", assemblyName.GetPublicKeyToken().Select(x => x.ToString("x")));
13 |
14 | Assert.That(publicKeyToken, Is.EqualTo("92dd2e9066daa5ca"));
15 | }
16 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/AsyncEventHandlers/ITestInterface.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.AsyncEventHandlers;
2 |
3 | public delegate Task TestEventHandler();
4 |
5 | public interface ITestInterface
6 | {
7 | #region Events
8 |
9 | event TestEventHandler TestEvent;
10 |
11 | #endregion
12 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/AsyncEventHandlers/TestImplementation.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.AsyncEventHandlers;
2 |
3 | public class TestImplementation : ITestInterface
4 | {
5 | #region Events
6 |
7 | public event TestEventHandler? TestEvent;
8 |
9 | #endregion
10 |
11 | #region Public Methods
12 |
13 | public async Task RaiseEventAsync()
14 | {
15 | if (TestEvent != null)
16 | {
17 | await TestEvent();
18 | }
19 | }
20 |
21 | #endregion
22 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithNestedSubCalls.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class ArgMatchingWithNestedSubCalls
6 | {
7 | public interface IHaveAMethod { void Method(int a, string b); }
8 | public interface IStealArgMatchers
9 | {
10 | string StealMatcherBeforeUsedElsewhere { get; }
11 | string this[int i] { get; }
12 | }
13 |
14 | [Test]
15 | public void Use_arg_matcher_then_access_another_sub_without_args_before_call_spec_is_created()
16 | {
17 | var sub = Substitute.For();
18 | var stealer = Substitute.For();
19 |
20 | sub.Method(2, stealer.StealMatcherBeforeUsedElsewhere);
21 |
22 | sub.Received().Method(Arg.Any(), stealer.StealMatcherBeforeUsedElsewhere);
23 | }
24 |
25 | [Test]
26 | [Pending, Explicit]
27 | public void Use_arg_matcher_then_access_another_sub_with_args_before_call_spec_is_created()
28 | {
29 | var sub = Substitute.For();
30 | var stealer = Substitute.For();
31 | stealer[0].Returns("a");
32 |
33 | sub.Method(2, stealer[0]);
34 |
35 | //This example still blows up because the call to stealer[0] takes the Arg.Any() matcher
36 | //away. The call router thinks the Arg.Any belongs to that call, not the sub.Method() call.
37 | sub.Received().Method(Arg.Any(), stealer[0]);
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/DisposeWithThreadLocal.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class DisposeWithThreadLocal
6 | {
7 | [Test]
8 | public void DisposeSubstituteAndPerformGC()
9 | {
10 | using (var s = Substitute.For()) { }
11 | GC.Collect();
12 | GC.WaitForPendingFinalizers();
13 |
14 | //Exception thrown on background thread. Can view this from output of test runner.
15 | }
16 |
17 | public class DisposableClass : IDisposable
18 | {
19 | bool disposed = false;
20 | ~DisposableClass() { Dispose(false); }
21 | public virtual void Dispose() { Dispose(true); }
22 | protected virtual void Dispose(bool disposing)
23 | {
24 | if (!disposed) { if (disposing) { disposed = true; } }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/EqualsBehaviourOnClassSubs.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using NUnit.Framework.Legacy;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class EqualsBehaviourOnClassSubs
7 | {
8 | [Test]
9 | public void Equals_should_work_as_expected_for_class_substitutes()
10 | {
11 | var firstSub = Substitute.For();
12 | var secondSub = Substitute.For();
13 |
14 | ClassicAssert.AreEqual(firstSub, firstSub);
15 | ClassicAssert.AreNotEqual(firstSub, secondSub);
16 | }
17 |
18 | public class AClass { }
19 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue110_CustomExceptions.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue110_CustomExceptions
6 | {
7 | public class MyException : Exception { }
8 |
9 | public interface IThrow { void Throw(); }
10 | public interface IDoStuff { event Action StuffDone; }
11 |
12 | [Test]
13 | public void ThrowExceptionWithoutSerialisationConstructor()
14 | {
15 | var ithrow = Substitute.For();
16 | var doStuff = Substitute.For();
17 |
18 | ithrow.When(x => x.Throw()).Do(x => { throw new MyException(); });
19 | doStuff.StuffDone += ithrow.Throw;
20 |
21 | Assert.Throws(() => doStuff.StuffDone += Raise.Event());
22 | }
23 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue125_MethodWithSealedClassReturnType.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue125_MethodWithSealedClassReturnType
6 | {
7 | public sealed class SealedClass { }
8 |
9 | public interface IInterface
10 | {
11 | SealedClass MethodWithSealedClassReturnType();
12 | }
13 |
14 | [Test]
15 | public void MethodWithSealedClassReturnTypeReturnsCorrectResult()
16 | {
17 | var substitute = Substitute.For();
18 | var expected = new SealedClass();
19 | substitute.MethodWithSealedClassReturnType().Returns(expected);
20 |
21 | var result = substitute.MethodWithSealedClassReturnType();
22 |
23 | Assert.That(result, Is.EqualTo(expected));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue149_ArgMatcherInReturns.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue149_ArgMatcherInReturns
7 | {
8 | public interface ISub1 { Item GetItem(string s); }
9 | public interface ISub2 { string GetSignature(int i); }
10 | public class Item { }
11 |
12 | [Test]
13 | public void MatcherInReturnsShouldThrow()
14 | {
15 | var sub2 = Substitute.For();
16 | Assert.Throws(
17 | () => sub2.GetSignature(1).Returns(Arg.Any()));
18 | }
19 |
20 | // Original example from https://github.com/nsubstitute/NSubstitute/issues/149
21 | [Test]
22 | public void OriginalMatcherInReturnsExample()
23 | {
24 | var sub1 = Substitute.For();
25 | var sub2 = Substitute.For();
26 | sub1.GetItem(Arg.Any()).Returns(new Item());
27 |
28 | Assert.Throws(() =>
29 | sub2.GetSignature(1).Returns(Arg.Any()) // <-- THIS IS THE PROBLEM
30 | );
31 |
32 | sub1.GetItem("mystring");
33 |
34 | sub1.ReceivedWithAnyArgs(1).GetItem("mystring");
35 | }
36 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue170_MultidimensionalArray.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue170_MultidimensionalArray
6 | {
7 | public interface ITest
8 | {
9 | bool[,] Method();
10 | }
11 |
12 | [Test]
13 | public void Method_Works()
14 | {
15 | var test = Substitute.For();
16 | test.Method();
17 | }
18 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue225_ConfiguredValueIsUsedInSubsequentSetups.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Acceptance.Specs.Infrastructure;
2 | using NUnit.Framework;
3 | using NUnit.Framework.Legacy;
4 |
5 | namespace NSubstitute.Acceptance.Specs.FieldReports;
6 |
7 | public class Issue225_ConfiguredValueIsUsedInSubsequentSetups
8 | {
9 | [Test]
10 | public void ShouldNotUseTheConfiguredValueDuringSubsequentSetup()
11 | {
12 | // Arrange
13 | var target = Substitute.For();
14 |
15 | // Act
16 | target.Echo(Arg.Is(0)).Returns("00", "01", "02");
17 | target.Echo(Arg.Is(1)).Returns("10", "11", "12");
18 |
19 | // Assert
20 | ClassicAssert.AreEqual("00", target.Echo(0));
21 | ClassicAssert.AreEqual("10", target.Echo(1));
22 | ClassicAssert.AreEqual("01", target.Echo(0));
23 | ClassicAssert.AreEqual("11", target.Echo(1));
24 | ClassicAssert.AreEqual("02", target.Echo(0));
25 | ClassicAssert.AreEqual("12", target.Echo(1));
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue271_DelegateOutArgument.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using NUnit.Framework.Legacy;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue271_DelegateOutArgument
7 | {
8 | public delegate void Foo(out int bar);
9 |
10 | [Test]
11 | public void DelegateReturnsOutParameter()
12 | {
13 | var foo = Substitute.For();
14 | int bar;
15 | foo.When(x => x(out bar)).Do(x => { x[0] = 42; });
16 |
17 | foo(out bar);
18 |
19 | ClassicAssert.AreEqual(42, bar);
20 | }
21 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue279_ShouldFailOnRedundantArguments.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue279_ShouldFailOnRedundantArguments
7 | {
8 | public interface IFoo
9 | {
10 | int Blah(double s);
11 | }
12 |
13 | [Test]
14 | public void Should_fail_with_redundant_exception_if_matcher_is_not_used_due_to_implicit_cast_scenario_1()
15 | {
16 | var foo = Substitute.For();
17 |
18 | Assert.Throws(() =>
19 | {
20 | foo.Blah(Arg.Any()).Returns(42);
21 | });
22 | }
23 |
24 | [Test]
25 | public void Should_fail_with_redundant_exception_if_matcher_is_not_used_due_to_implicit_cast_scenario_2()
26 | {
27 | var foo = Substitute.For();
28 |
29 | Assert.Throws(() =>
30 | {
31 | // Fails because Is() type is deduced to int, so specifier is not matched later.
32 | foo.Blah(Arg.Is(10)).Returns(42);
33 | });
34 | }
35 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue282_MultipleReturnValuesParallelism.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using NUnit.Framework.Legacy;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | [TestFixture]
7 | public class Issue282_MultipleReturnValuesParallelism
8 | {
9 | public interface IFoo
10 | {
11 | string Foo();
12 | }
13 |
14 | [Test]
15 | public void ReturnsMultipleValuesInParallel()
16 | {
17 | var ret1 = "One";
18 | var ret2 = "Two";
19 |
20 | var substitute = Substitute.For();
21 | substitute.Foo().Returns(ret1, ret2);
22 |
23 | var runningTask1 = Task.Run(() => substitute.Foo());
24 | var runningTask2 = Task.Run(() => substitute.Foo());
25 |
26 | var results = Task.WhenAll(runningTask1, runningTask2).Result;
27 |
28 | ClassicAssert.Contains(ret1, results);
29 | ClassicAssert.Contains(ret2, results);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue33_RaisingINotifyPropertyChangedEvents.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue33_RaisingINotifyPropertyChangedEvents
7 | {
8 | [Test]
9 | public void Should_be_able_to_raise_event()
10 | {
11 | var sub = Substitute.For();
12 | bool wasCalled = false;
13 | sub.PropertyChanged += (sender, args) => wasCalled = true;
14 |
15 | sub.PropertyChanged += Raise.Event(this, new PropertyChangedEventArgs("test"));
16 |
17 | Assert.That(wasCalled);
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue372_InterfaceSameNameOfMethods.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using NUnit.Framework.Legacy;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue372_InterfaceSameNameOfMethods
7 | {
8 | public interface A
9 | {
10 | }
11 |
12 | public interface B
13 | {
14 | }
15 |
16 | public interface X
17 | {
18 | Task Foo(B bar);
19 | Task Foo(A bar);
20 | }
21 |
22 | [Test]
23 | public void Should_create_substitute()
24 | {
25 | var sut = Substitute.For();
26 | ClassicAssert.NotNull(sut);
27 | }
28 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue38_SettingNullReturnValue.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue38_SettingNullReturnValue
7 | {
8 | public interface IDoSomething
9 | {
10 | object Something();
11 | int SomethingWithValueType();
12 | }
13 |
14 | [Test]
15 | public void CanSetCallToReturnNull()
16 | {
17 | var doSomething = Substitute.For();
18 | doSomething.Something().Returns(null);
19 | var result = doSomething.Something();
20 | Assert.That(result, Is.Null);
21 | }
22 |
23 | [Test]
24 | public void SettingCallWhichReturnsAValueTypeToNullShouldThrow()
25 | {
26 | var doSomething = Substitute.For();
27 | Assert.That(() => doSomething.SomethingWithValueType().Returns(null), Throws.TypeOf());
28 | }
29 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue45_CallInfoArgAccessFailsForNull.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue45_CallInfoArgAccessFailsForNull
6 | {
7 | public interface IAmAnInterface
8 | {
9 | bool ThatHasAMethodWithArgs(string s, object o);
10 | }
11 |
12 | [Test]
13 | public void Should_be_able_to_find_a_null_arg_by_type()
14 | {
15 | string stringArgumentUsed = "";
16 |
17 | var sub = Substitute.For();
18 | sub.ThatHasAMethodWithArgs(null, null)
19 | .ReturnsForAnyArgs(x => { stringArgumentUsed = x.Arg(); return true; });
20 |
21 | sub.ThatHasAMethodWithArgs(null, 42);
22 |
23 | Assert.That(stringArgumentUsed, Is.Null);
24 | }
25 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue47_RaisingEventsWithNullArg.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue47_RaisingEventsWithNullArg
6 | {
7 | public delegate void ProgressEventHandler(int progress, string message);
8 | public delegate void EventLikeHandler(object sender, EventArgs args);
9 | public interface IFoo
10 | {
11 | event ProgressEventHandler OnProgress;
12 | event EventLikeHandler OnEventishThing;
13 | }
14 |
15 | [Test]
16 | public void Pass_null_when_raising_delegate_event()
17 | {
18 | var sub = Substitute.For();
19 | sub.OnProgress += Raise.Event(1, null);
20 | }
21 |
22 | [Test]
23 | public void Pass_null_when_raising_eventhandlerish_event()
24 | {
25 | var sub = Substitute.For();
26 | sub.OnEventishThing += Raise.Event([null]);
27 | }
28 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue57_SettingVirtualPropertyInCtor.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue57_SettingVirtualPropertyInCtorCausesReturnsToUseAutoSub
6 | {
7 | public class MyEntity
8 | {
9 | public MyEntity() { Name = "Name1"; }
10 | public virtual Guid Id { get; set; }
11 | public virtual string Name { get; set; }
12 | }
13 |
14 | public interface IEntityRepository { MyEntity Get(Guid id); }
15 |
16 | [Test]
17 | public void TestGetFromRepository()
18 | {
19 | var repository = Substitute.For();
20 | var fakeEntity = new MyEntity { Id = Guid.NewGuid() };
21 |
22 | repository.Get(Arg.Any()).Returns(fakeEntity);
23 |
24 | var result = repository.Get(fakeEntity.Id);
25 | Assert.That(result, Is.SameAs(fakeEntity));
26 | Assert.That(result.Id, Is.EqualTo(fakeEntity.Id));
27 | }
28 |
29 | [Test]
30 | public void TestGetUsingAutoSubs()
31 | {
32 | var repository = Substitute.For();
33 | var fakeEntity = repository.Get(Arg.Any());
34 | fakeEntity.Id = Guid.NewGuid();
35 |
36 | var result = repository.Get(fakeEntity.Id);
37 |
38 | Assert.That(result, Is.SameAs(fakeEntity));
39 | Assert.That(result.Id, Is.EqualTo(fakeEntity.Id));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue61_ArgAnyStringRegression.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using NUnit.Framework.Legacy;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class ArgAnyStringRegression
7 | {
8 | public interface IFoo { string Bar(string a, double b); }
9 |
10 | [Test]
11 | public void Stub_any_string_and_call_with_null()
12 | {
13 | var foo = Substitute.For();
14 | foo.Bar(Arg.Any(), Arg.Any()).ReturnsForAnyArgs("hello");
15 |
16 | ClassicAssert.AreEqual("hello", foo.Bar(null, 0));
17 | }
18 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue631_NamespaceDelegate.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace Na { public delegate void DoNothing(); }
4 | namespace Ns { public delegate void DoNothing(); }
5 | namespace Nt { public delegate void DoNothing(); }
6 | namespace Nz { public delegate void DoNothing(); }
7 |
8 | namespace NSubstitute.Acceptance.Specs.FieldReports
9 | {
10 | public class Issue631_NamespaceDelegate
11 | {
12 | [Test] public void Na() { Substitute.For(); }
13 | [Test] public void Ns() { Substitute.For(); }
14 | [Test] public void Nt() { Substitute.For(); }
15 | [Test] public void Nz() { Substitute.For(); }
16 | }
17 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue83_MethodsWithGenericStructConstraint.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Issue83_MethodsWithGenericStructConstraint
6 | {
7 | public interface IService { T Get(T arg) where T : struct; }
8 |
9 | [Test]
10 | public void TestGenericCalls()
11 | {
12 | var id = Guid.NewGuid();
13 | var service = Substitute.For();
14 | service.Get(id);
15 | service.Received().Get(id);
16 | }
17 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue_RaiseEventOnNonSubstitute.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class Issue_RaiseEventOnNonSubstitute
7 | {
8 | public class Button
9 | {
10 | public virtual event EventHandler Clicked = (s, e) => { };
11 | }
12 |
13 | public interface IController { void Load(); }
14 |
15 | [Test]
16 | public void RaiseEventOnNonSub()
17 | {
18 | var notASub = new Button();
19 | notASub.Clicked += Raise.Event();
20 | var sub = Substitute.For();
21 | // Next call to a substitute will fail as it will attempt to raise an event
22 | Assert.Throws(() =>
23 | sub.Load()
24 | );
25 | }
26 |
27 | [Test]
28 | public void RaiseEventOnSub()
29 | {
30 | var clicked = false;
31 | var sub = Substitute.For();
32 | sub.Clicked += (s, e) => clicked = true;
33 | sub.Clicked += Raise.Event();
34 | Assert.That(clicked);
35 | }
36 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/MigratingToCompatArgs.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Compatibility;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | #pragma warning disable CS0618 // Type or member is obsolete
7 |
8 | ///
9 | /// Can migrate from the old matchers to by putting a
10 | /// field named Arg in a fixture (or ideally in a project's
11 | /// fixture base class). All old references to static Arg will then go through CompatArg instead.
12 | ///
13 | /// To migrate back(once project switches to C#7+), just delete the CompatArgInstance field.
14 | ///
15 | public class MigratingToCompatArgs
16 | {
17 |
18 | public class TestBaseClass
19 | {
20 | protected static readonly CompatArg Arg = CompatArg.Instance;
21 | }
22 |
23 | public interface IMessageServer
24 | {
25 | void SendMessage(int code, string description);
26 | }
27 |
28 | public class SampleTestFixture : TestBaseClass
29 | {
30 | [Test]
31 | public void ArgMatcherUsingBaseClass()
32 | {
33 | var sub = Substitute.For();
34 |
35 | sub.SendMessage(42, "meaning of life?");
36 |
37 | sub.Received().SendMessage(Arg.Is(42), Arg.Any());
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/Regression_ReceivedClearsStub.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class Regression_ReceivedClearsStub
6 | {
7 | public interface IFoo
8 | {
9 | IList GetTheStrings();
10 | }
11 |
12 | [Test]
13 | public void MockShouldReturnTheStringListAfterCheckingCallHistory()
14 | {
15 | IFoo foo = Substitute.For();
16 | foo.GetTheStrings().Returns(new[] { "a", "b" });
17 |
18 | foo.DidNotReceive().GetTheStrings();
19 | var strings = foo.GetTheStrings();
20 |
21 | Assert.That(strings, Is.EquivalentTo(new[] { "a", "b" }));
22 | }
23 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/StaticStateBleeding.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs.FieldReports;
5 |
6 | public class StaticStateBleeding
7 | {
8 | [Test]
9 | public void Test_0()
10 | {
11 | var bar = Substitute.For();
12 | bar.GetInt();
13 | bar.Received().GetInt();
14 | }
15 |
16 | [Test]
17 | public void Test_1_affected_by_test_0()
18 | {
19 | Assert.Throws(() => 2.Returns(2));
20 | }
21 |
22 | public interface IFoo { }
23 |
24 | public interface IBar { int GetInt(); }
25 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/FieldReports/SubbingSynchronizationContext.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs.FieldReports;
4 |
5 | public class SubbingSynchronizationContext
6 | {
7 | [Test]
8 | public void Create_substitute_for_synchronization_context()
9 | {
10 | Substitute.For();
11 | }
12 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/Infrastructure/BackgroundTask.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.Infrastructure;
2 |
3 | public class BackgroundTask
4 | {
5 | readonly Action _start;
6 | readonly Action _await;
7 | private Exception _exception;
8 | public BackgroundTask(Action action)
9 | {
10 | var thread = new Thread(() =>
11 | {
12 | try { action(); }
13 | catch (Exception ex) { _exception = ex; }
14 | });
15 | _await = () => { thread.Join(); ThrowIfError(); };
16 | _start = () => thread.Start();
17 | }
18 | void ThrowIfError() { if (_exception != null) throw new Exception("Thread threw", _exception); }
19 |
20 | public static void StartAll(BackgroundTask[] tasks) { foreach (var task in tasks) { task._start(); } }
21 | public static void AwaitAll(BackgroundTask[] tasks) { foreach (var task in tasks) { task._await(); } }
22 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/Infrastructure/FluentSomething.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.Infrastructure;
2 |
3 | public class FluentSomething : IFluentSomething
4 | {
5 | public IFluentSomething Chain()
6 | {
7 | return this;
8 | }
9 |
10 | public IFluentSomething Me()
11 | {
12 | return this;
13 | }
14 |
15 | public IFluentSomething Together()
16 | {
17 | return this;
18 | }
19 |
20 | public ISomething SorryNoChainingHere()
21 | {
22 | return null;
23 | }
24 |
25 | public ISomething SorryNoChainingHereEither()
26 | {
27 | return null;
28 | }
29 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/Infrastructure/IFluentSomething.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.Infrastructure;
2 |
3 | public interface IFluentSomething
4 | {
5 | IFluentSomething Chain();
6 | IFluentSomething Me();
7 | IFluentSomething Together();
8 | ISomething SorryNoChainingHere();
9 | ISomething SorryNoChainingHereEither();
10 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/Infrastructure/ISomethingWithGenericMethods.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.Infrastructure;
2 |
3 | public interface ISomethingWithGenericMethods
4 | {
5 | void Log(int level, TState state);
6 | string Format(T state);
7 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/Infrastructure/PendingAttribute.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs;
4 |
5 | public class PendingAttribute : CategoryAttribute
6 | {
7 | public PendingAttribute() : base("Pending") { }
8 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/Infrastructure/SomeClass.cs:
--------------------------------------------------------------------------------
1 | namespace NSubstitute.Acceptance.Specs.Infrastructure;
2 |
3 | public class SomeClass
4 | {
5 | }
6 |
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/NSubstitute.Acceptance.Specs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0;net8.0;net462
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/NotASubstituteExceptions.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.Exceptions;
2 | using NUnit.Framework;
3 |
4 | namespace NSubstitute.Acceptance.Specs;
5 |
6 | public class NotASubstituteExceptions
7 | {
8 | object _notASub;
9 |
10 | [SetUp]
11 | public void SetUp()
12 | {
13 | _notASub = new object();
14 | }
15 |
16 | [Test]
17 | public void Should_describe_how_exception_can_occur()
18 | {
19 | Assert.That(
20 | () => _notASub.Received(),
21 | Throws
22 | .TypeOf()
23 | .And
24 | .Message.EqualTo(
25 | "NSubstitute extension methods like .Received() can only be called on objects created using Substitute.For() and related methods."
26 | )
27 | );
28 | }
29 |
30 | [Test]
31 | public void Calling_received_on_a_non_sub()
32 | {
33 | AssertThrowsNotASubstituteException(() => _notASub.Received());
34 | }
35 |
36 | [Test]
37 | public void Calling_when_on_a_non_sub()
38 | {
39 | AssertThrowsNotASubstituteException(() => _notASub.When(x => x.GetHashCode()));
40 | }
41 |
42 |
43 | private static void AssertThrowsNotASubstituteException(Action action)
44 | {
45 | Assert.That(() => action(), Throws.TypeOf());
46 | }
47 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/SubbingForEventHandler.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace NSubstitute.Acceptance.Specs;
4 |
5 | public class SubbingForEventHandler
6 | {
7 | [Test]
8 | public void Should_not_die_when_trying_to_sub_for_an_event_handler()
9 | {
10 | var sut = new Something();
11 | var handler = Substitute.For>();
12 | sut.SomethingHappened += handler;
13 | sut.DoSomething();
14 | handler.Received().Invoke(sut, Arg.Is(e => e.Somethings == 2));
15 | }
16 |
17 | public class Something
18 | {
19 | public void DoSomething()
20 | {
21 | OnSomething(2);
22 | }
23 |
24 | public event EventHandler SomethingHappened;
25 |
26 | public void OnSomething(int somethings)
27 | {
28 | var handler = SomethingHappened;
29 | if (handler != null) handler(this, new SomethingEventArgs() { Somethings = somethings });
30 | }
31 | }
32 |
33 | public class SomethingEventArgs : EventArgs
34 | {
35 | public int Somethings;
36 | }
37 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Acceptance.Specs/SubstitutingForDelegates.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using NUnit.Framework.Legacy;
3 |
4 | namespace NSubstitute.Acceptance.Specs;
5 |
6 | [TestFixture]
7 | public class SubstitutingForDelegates
8 | {
9 | [Test]
10 | public void SubForAction()
11 | {
12 | var action = Substitute.For();
13 | action();
14 | action.Received()();
15 | }
16 |
17 | [Test]
18 | public void SubForActionWith2Parameters()
19 | {
20 | var action = Substitute.For>();
21 | action(4, 2);
22 | action.Received()(4, 2);
23 | }
24 |
25 | [Test]
26 | public void SubForFunc()
27 | {
28 | var func = Substitute.For>();
29 | func(1).Returns("1");
30 |
31 | Assert.That(func(1), Is.EqualTo("1"));
32 | func.Received()(1);
33 | }
34 |
35 | [Test]
36 | public void SubForFuncThatReturnsValueType()
37 | {
38 | var func = Substitute.For>();
39 | func().Returns(10);
40 | ClassicAssert.AreEqual(10, func());
41 | }
42 |
43 | [Test]
44 | public void substitute_for_an_event_handler()
45 | {
46 | var eventHandler = Substitute.For();
47 | eventHandler.Invoke(null, null);
48 |
49 | eventHandler.Received().Invoke(null, null);
50 | }
51 |
52 | [Test]
53 | public void substitute_for_an_eventhandler()
54 | {
55 | var eventHandler = Substitute.For();
56 | eventHandler(null, null);
57 |
58 | eventHandler.Received()(null, null);
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/tests/NSubstitute.Benchmarks/ActivationBenchmark.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using NSubstitute.Benchmarks.TestTypes;
3 |
4 | namespace NSubstitute.Benchmarks;
5 |
6 | [SimpleJob]
7 | [MemoryDiagnoser]
8 | public class ActivationBenchmark
9 | {
10 | [Benchmark]
11 | public IInterfaceWithSingleMethod CreateInterfaceSubstitute()
12 | {
13 | return Substitute.For();
14 | }
15 |
16 | [Benchmark]
17 | public AbstractClassWithSingleMethod CreateAbstractClassSubstitute()
18 | {
19 | return Substitute.For();
20 | }
21 |
22 | [Benchmark]
23 | public ClassWithSingleMethod CreateNonAbstractClassSubstitute()
24 | {
25 | return Substitute.For();
26 | }
27 |
28 | [Benchmark]
29 | public IntDelegate CreateDelegateSubstitute()
30 | {
31 | return Substitute.For