diff --git a/.editorconfig b/.editorconfig index 0df0c455c..84059808e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,6 +17,7 @@ dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_property = false:suggestion dotnet_style_qualification_for_method = false:suggestion dotnet_style_qualification_for_event = false:suggestion +csharp_style_namespace_declarations=file_scoped:warning # ReSharper properties resharper_int_align_switch_expressions = true diff --git a/src/NSubstitute/Arg.cs b/src/NSubstitute/Arg.cs index 63716ca34..458499bf3 100644 --- a/src/NSubstitute/Arg.cs +++ b/src/NSubstitute/Arg.cs @@ -6,225 +6,224 @@ #pragma warning disable CS1574 #pragma warning disable CS0419 -namespace NSubstitute +namespace NSubstitute; + +/// +/// Argument matchers used for specifying calls to substitutes. +/// +public static class Arg { /// - /// Argument matchers used for specifying calls to substitutes. + /// This type can be used with any matcher to match a generic type parameter. /// - public static class Arg + /// + /// If the generic type parameter has constraints, you will have to create a derived class/struct that + /// implements those constraints. + /// + public interface AnyType { - /// - /// This type can be used with any matcher to match a generic type parameter. - /// - /// - /// If the generic type parameter has constraints, you will have to create a derived class/struct that - /// implements those constraints. - /// - public interface AnyType - { - } + } + + /// + /// Match any argument value compatible with type . + /// + public static ref T Any() + { + return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(T))); + } + + /// + /// Match argument that is equal to . + /// + public static ref T Is(T value) + { + return ref ArgumentMatcher.Enqueue(new EqualsArgumentMatcher(value)); + } + + /// + /// Match argument that satisfies . + /// If the throws an exception for an argument it will be treated as non-matching. + /// + public static ref T Is(Expression> predicate) + { + return ref ArgumentMatcher.Enqueue(new ExpressionArgumentMatcher(predicate)); + } + + /// + /// Match argument that satisfies . + /// If the throws an exception for an argument it will be treated as non-matching. + /// + public static ref T Is(Expression> predicate) where T : AnyType + { + return ref ArgumentMatcher.Enqueue(new ExpressionArgumentMatcher(predicate)); + } + + /// + /// Invoke any argument whenever a matching call is made to the substitute. + /// + public static ref Action Invoke() + { + return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction()); + } + /// + /// Invoke any argument with specified argument whenever a matching call is made to the substitute. + /// + public static ref Action Invoke(T arg) + { + return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg)); + } + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// + public static ref Action Invoke(T1 arg1, T2 arg2) + { + return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg1, arg2)); + } + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// + public static ref Action Invoke(T1 arg1, T2 arg2, T3 arg3) + { + return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg1, arg2, arg3)); + } + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// + public static ref Action Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg1, arg2, arg3, arg4)); + } + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// + /// Arguments to pass to delegate. + public static ref TDelegate InvokeDelegate(params object[] arguments) + { + return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(TDelegate)), InvokeDelegateAction(arguments)); + } + + /// + /// Capture any argument compatible with type and use it to call the function + /// whenever a matching call is made to the substitute. + /// + public static ref T Do(Action useArgument) + { + return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(T)), x => useArgument((T)x!)); + } + + /// + /// Capture any argument compatible with type and use it to call the function + /// whenever a matching call is made to the substitute. + /// + public static ref T Do(Action useArgument) where T : AnyType + { + return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(AnyType)), x => useArgument(x!)); + } + + /// + /// Alternate version of matchers for compatibility with pre-C#7 compilers + /// which do not support ref return types. Do not use unless you are unable to use . + /// + /// For more information see Compatibility Argument + /// Matchers in the NSubstitute documentation. + /// + public static class Compat + { /// /// Match any argument value compatible with type . + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref T Any() - { - return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(T))); - } + public static T Any() => Arg.Any(); /// /// Match argument that is equal to . + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref T Is(T value) - { - return ref ArgumentMatcher.Enqueue(new EqualsArgumentMatcher(value)); - } + public static T Is(T value) => Arg.Is(value); /// /// Match argument that satisfies . /// If the throws an exception for an argument it will be treated as non-matching. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref T Is(Expression> predicate) - { - return ref ArgumentMatcher.Enqueue(new ExpressionArgumentMatcher(predicate)); - } + public static T Is(Expression> predicate) => Arg.Is(predicate); /// /// Match argument that satisfies . /// If the throws an exception for an argument it will be treated as non-matching. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref T Is(Expression> predicate) where T : AnyType - { - return ref ArgumentMatcher.Enqueue(new ExpressionArgumentMatcher(predicate)); - } + public static AnyType Is(Expression> predicate) where T : AnyType => Arg.Is(predicate); /// /// Invoke any argument whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref Action Invoke() - { - return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction()); - } + public static Action Invoke() => Arg.Invoke(); /// /// Invoke any argument with specified argument whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref Action Invoke(T arg) - { - return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg)); - } + public static Action Invoke(T arg) => Arg.Invoke(arg); /// /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref Action Invoke(T1 arg1, T2 arg2) - { - return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg1, arg2)); - } + public static Action Invoke(T1 arg1, T2 arg2) => Arg.Invoke(arg1, arg2); /// /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref Action Invoke(T1 arg1, T2 arg2, T3 arg3) - { - return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg1, arg2, arg3)); - } + public static Action Invoke(T1 arg1, T2 arg2, T3 arg3) => Arg.Invoke(arg1, arg2, arg3); /// /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref Action Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - return ref ArgumentMatcher.Enqueue>(new AnyArgumentMatcher(typeof(Action)), InvokeDelegateAction(arg1, arg2, arg3, arg4)); - } + public static Action Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) => Arg.Invoke(arg1, arg2, arg3, arg4); /// /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// /// Arguments to pass to delegate. - public static ref TDelegate InvokeDelegate(params object[] arguments) - { - return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(TDelegate)), InvokeDelegateAction(arguments)); - } + public static TDelegate InvokeDelegate(params object[] arguments) => Arg.InvokeDelegate(arguments); /// /// Capture any argument compatible with type and use it to call the function /// whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. /// - public static ref T Do(Action useArgument) - { - return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(T)), x => useArgument((T)x!)); - } + public static T Do(Action useArgument) => Arg.Do(useArgument); /// /// Capture any argument compatible with type and use it to call the function /// whenever a matching call is made to the substitute. /// - public static ref T Do(Action useArgument) where T : AnyType - { - return ref ArgumentMatcher.Enqueue(new AnyArgumentMatcher(typeof(AnyType)), x => useArgument(x!)); - } + public static AnyType Do(Action useArgument) where T : AnyType => Arg.Do(useArgument); + } - /// - /// Alternate version of matchers for compatibility with pre-C#7 compilers - /// which do not support ref return types. Do not use unless you are unable to use . - /// - /// For more information see Compatibility Argument - /// Matchers in the NSubstitute documentation. - /// - public static class Compat - { - /// - /// Match any argument value compatible with type . - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static T Any() => Arg.Any(); - - /// - /// Match argument that is equal to . - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static T Is(T value) => Arg.Is(value); - - /// - /// Match argument that satisfies . - /// If the throws an exception for an argument it will be treated as non-matching. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static T Is(Expression> predicate) => Arg.Is(predicate); - - /// - /// Match argument that satisfies . - /// If the throws an exception for an argument it will be treated as non-matching. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static AnyType Is(Expression> predicate) where T : AnyType => Arg.Is(predicate); - - /// - /// Invoke any argument whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static Action Invoke() => Arg.Invoke(); - - /// - /// Invoke any argument with specified argument whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static Action Invoke(T arg) => Arg.Invoke(arg); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static Action Invoke(T1 arg1, T2 arg2) => Arg.Invoke(arg1, arg2); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static Action Invoke(T1 arg1, T2 arg2, T3 arg3) => Arg.Invoke(arg1, arg2, arg3); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static Action Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) => Arg.Invoke(arg1, arg2, arg3, arg4); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - /// Arguments to pass to delegate. - public static TDelegate InvokeDelegate(params object[] arguments) => Arg.InvokeDelegate(arguments); - - /// - /// Capture any argument compatible with type and use it to call the function - /// whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public static T Do(Action useArgument) => Arg.Do(useArgument); - - /// - /// Capture any argument compatible with type and use it to call the function - /// whenever a matching call is made to the substitute. - /// - public static AnyType Do(Action useArgument) where T : AnyType => Arg.Do(useArgument); - } - - private static Action InvokeDelegateAction(params object[] arguments) - { - return x => ((Delegate)x).DynamicInvoke(arguments); - } + private static Action InvokeDelegateAction(params object[] arguments) + { + return x => ((Delegate)x).DynamicInvoke(arguments); } } diff --git a/src/NSubstitute/Callback.cs b/src/NSubstitute/Callback.cs index b7d5e0cc6..22a08901c 100644 --- a/src/NSubstitute/Callback.cs +++ b/src/NSubstitute/Callback.cs @@ -1,127 +1,126 @@ -using System.Collections.Concurrent; -using NSubstitute.Callbacks; +using NSubstitute.Callbacks; using NSubstitute.Core; +using System.Collections.Concurrent; // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +/// +/// Perform this chain of callbacks and/or always callback when called. +/// +public class Callback { /// - /// Perform this chain of callbacks and/or always callback when called. + /// Perform as first in chain of callback when called. /// - public class Callback + /// + /// + public static ConfiguredCallback First(Action doThis) { - /// - /// Perform as first in chain of callback when called. - /// - /// - /// - public static ConfiguredCallback First(Action doThis) - { - return new ConfiguredCallback().Then(doThis); - } + return new ConfiguredCallback().Then(doThis); + } - /// - /// Perform this action always when callback is called. - /// - /// - /// - public static Callback Always(Action doThis) - { - return new ConfiguredCallback().AndAlways(doThis); - } + /// + /// Perform this action always when callback is called. + /// + /// + /// + public static Callback Always(Action doThis) + { + return new ConfiguredCallback().AndAlways(doThis); + } - /// - /// Throw exception returned by function as first callback in chain of callback when called. - /// - /// - /// - public static ConfiguredCallback FirstThrow(Func throwThis) where TException : Exception - { - return new ConfiguredCallback().ThenThrow(throwThis); - } + /// + /// Throw exception returned by function as first callback in chain of callback when called. + /// + /// + /// + public static ConfiguredCallback FirstThrow(Func throwThis) where TException : Exception + { + return new ConfiguredCallback().ThenThrow(throwThis); + } - /// - /// Throw this exception as first callback in chain of callback when called. - /// - /// - /// - public static ConfiguredCallback FirstThrow(TException exception) where TException : Exception - { - return new ConfiguredCallback().ThenThrow(info => exception); - } + /// + /// Throw this exception as first callback in chain of callback when called. + /// + /// + /// + public static ConfiguredCallback FirstThrow(TException exception) where TException : Exception + { + return new ConfiguredCallback().ThenThrow(info => exception); + } - /// - /// Throw exception returned by function always when callback is called. - /// - /// The type of the exception. - /// The throw this. - /// - public static Callback AlwaysThrow(Func throwThis) where TException : Exception - { - return new ConfiguredCallback().AndAlways(ToCallback(throwThis)); - } + /// + /// Throw exception returned by function always when callback is called. + /// + /// The type of the exception. + /// The throw this. + /// + public static Callback AlwaysThrow(Func throwThis) where TException : Exception + { + return new ConfiguredCallback().AndAlways(ToCallback(throwThis)); + } - /// - /// Throw this exception always when callback is called. - /// - /// The type of the exception. - /// The exception. - /// - public static Callback AlwaysThrow(TException exception) where TException : Exception - { - return AlwaysThrow(_ => exception); - } + /// + /// Throw this exception always when callback is called. + /// + /// The type of the exception. + /// The exception. + /// + public static Callback AlwaysThrow(TException exception) where TException : Exception + { + return AlwaysThrow(_ => exception); + } - protected static Action ToCallback(Func throwThis) - where TException : notnull, Exception - { - return ci => { if (throwThis != null) throw throwThis(ci); }; - } + protected static Action ToCallback(Func throwThis) + where TException : notnull, Exception + { + return ci => { if (throwThis != null) throw throwThis(ci); }; + } - internal Callback() { } - private readonly ConcurrentQueue> callbackQueue = new ConcurrentQueue>(); - private Action alwaysDo = x => { }; - private Action keepDoing = x => { }; + internal Callback() { } + private readonly ConcurrentQueue> callbackQueue = new ConcurrentQueue>(); + private Action alwaysDo = x => { }; + private Action keepDoing = x => { }; - protected void AddCallback(Action doThis) - { - callbackQueue.Enqueue(doThis); - } + protected void AddCallback(Action doThis) + { + callbackQueue.Enqueue(doThis); + } - protected void SetAlwaysDo(Action always) + protected void SetAlwaysDo(Action always) + { + alwaysDo = always ?? (_ => { }); + } + + protected void SetKeepDoing(Action keep) + { + keepDoing = keep ?? (_ => { }); + } + + public void Call(CallInfo callInfo) + { + try { - alwaysDo = always ?? (_ => { }); + CallFromStack(callInfo); } - - protected void SetKeepDoing(Action keep) + finally { - keepDoing = keep ?? (_ => { }); + alwaysDo(callInfo); } + } - public void Call(CallInfo callInfo) + private void CallFromStack(CallInfo callInfo) + { + if (callbackQueue.TryDequeue(out var callback)) { - try - { - CallFromStack(callInfo); - } - finally - { - alwaysDo(callInfo); - } + callback(callInfo); } - - private void CallFromStack(CallInfo callInfo) + else { - if (callbackQueue.TryDequeue(out var callback)) - { - callback(callInfo); - } - else - { - keepDoing(callInfo); - } + keepDoing(callInfo); } } } \ No newline at end of file diff --git a/src/NSubstitute/Callbacks/ConfiguredCallback.cs b/src/NSubstitute/Callbacks/ConfiguredCallback.cs index 2ae2c0019..b017af2d8 100644 --- a/src/NSubstitute/Callbacks/ConfiguredCallback.cs +++ b/src/NSubstitute/Callbacks/ConfiguredCallback.cs @@ -3,74 +3,73 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.Callbacks +namespace NSubstitute.Callbacks; + +public class ConfiguredCallback : EndCallbackChain { - public class ConfiguredCallback : EndCallbackChain + internal ConfiguredCallback() { } + + /// + /// Perform this action once in chain of called callbacks. + /// + public ConfiguredCallback Then(Action doThis) { - internal ConfiguredCallback() { } + AddCallback(doThis); + return this; + } - /// - /// Perform this action once in chain of called callbacks. - /// - public ConfiguredCallback Then(Action doThis) - { - AddCallback(doThis); - return this; - } + /// + /// Keep doing this action after the other callbacks have run. + /// + public EndCallbackChain ThenKeepDoing(Action doThis) + { + SetKeepDoing(doThis); + return this; + } - /// - /// Keep doing this action after the other callbacks have run. - /// - public EndCallbackChain ThenKeepDoing(Action doThis) - { - SetKeepDoing(doThis); - return this; - } + /// + /// Keep throwing this exception after the other callbacks have run. + /// + public EndCallbackChain ThenKeepThrowing(Func throwThis) where TException : Exception => + ThenKeepDoing(ToCallback(throwThis)); - /// - /// Keep throwing this exception after the other callbacks have run. - /// - public EndCallbackChain ThenKeepThrowing(Func throwThis) where TException : Exception => - ThenKeepDoing(ToCallback(throwThis)); + /// + /// Keep throwing this exception after the other callbacks have run. + /// + public EndCallbackChain ThenKeepThrowing(TException throwThis) where TException : Exception => + ThenKeepThrowing(info => throwThis); - /// - /// Keep throwing this exception after the other callbacks have run. - /// - public EndCallbackChain ThenKeepThrowing(TException throwThis) where TException : Exception => - ThenKeepThrowing(info => throwThis); + /// + /// Throw exception returned by function once when called in a chain of callbacks. + /// + /// The type of the exception + /// Produce the exception to throw for a CallInfo + public ConfiguredCallback ThenThrow(Func throwThis) where TException : Exception + { + AddCallback(ToCallback(throwThis)); + return this; + } - /// - /// Throw exception returned by function once when called in a chain of callbacks. - /// - /// The type of the exception - /// Produce the exception to throw for a CallInfo - public ConfiguredCallback ThenThrow(Func throwThis) where TException : Exception - { - AddCallback(ToCallback(throwThis)); - return this; - } + /// + /// Throw this exception once when called in a chain of callbacks. + /// + /// The type of the exception + /// The exception to throw + public ConfiguredCallback ThenThrow(TException exception) where TException : Exception => + ThenThrow(_ => exception); +} - /// - /// Throw this exception once when called in a chain of callbacks. - /// - /// The type of the exception - /// The exception to throw - public ConfiguredCallback ThenThrow(TException exception) where TException : Exception => - ThenThrow(_ => exception); - } +public class EndCallbackChain : Callback +{ + internal EndCallbackChain() { } - public class EndCallbackChain : Callback + /// + /// Perform the given action for every call. + /// + /// The action to perform for every call + public Callback AndAlways(Action doThis) { - internal EndCallbackChain() { } - - /// - /// Perform the given action for every call. - /// - /// The action to perform for every call - public Callback AndAlways(Action doThis) - { - SetAlwaysDo(doThis); - return this; - } + SetAlwaysDo(doThis); + return this; } } \ No newline at end of file diff --git a/src/NSubstitute/ClearOptions.cs b/src/NSubstitute/ClearOptions.cs index 3bc1e7ac8..55cd3b397 100644 --- a/src/NSubstitute/ClearOptions.cs +++ b/src/NSubstitute/ClearOptions.cs @@ -1,26 +1,25 @@ -namespace NSubstitute +namespace NSubstitute; + +[Flags] +public enum ClearOptions { - [Flags] - public enum ClearOptions - { - /// - /// Clear all the received calls - /// - ReceivedCalls = 1, + /// + /// Clear all the received calls + /// + ReceivedCalls = 1, - /// - /// Clear all configured return results (including auto-substituted values). - /// - ReturnValues = 2, + /// + /// Clear all configured return results (including auto-substituted values). + /// + ReturnValues = 2, - /// - /// Clear all call actions configured for this substitute (via When..Do, Arg.Invoke, and Arg.Do) - /// - CallActions = 4, + /// + /// Clear all call actions configured for this substitute (via When..Do, Arg.Invoke, and Arg.Do) + /// + CallActions = 4, - /// - /// Clears all received calls and configured return values and callbacks. - /// - All = ReceivedCalls | ReturnValues | CallActions - } + /// + /// Clears all received calls and configured return values and callbacks. + /// + All = ReceivedCalls | ReturnValues | CallActions } \ No newline at end of file diff --git a/src/NSubstitute/Compatibility/CompatArg.cs b/src/NSubstitute/Compatibility/CompatArg.cs index 4ea2cc272..7d1a84f41 100644 --- a/src/NSubstitute/Compatibility/CompatArg.cs +++ b/src/NSubstitute/Compatibility/CompatArg.cs @@ -5,113 +5,112 @@ #pragma warning disable CS1574 #pragma warning disable CS0419 -namespace NSubstitute.Compatibility +namespace NSubstitute.Compatibility; + +/// +/// Alternate version of matchers for compatibility with pre-C#7 compilers +/// which do not support ref return types. Do not use unless you are unable to use . +/// +/// provides a non-static version of , which can make it easier +/// to use from an abstract base class. You can get a reference to this instance using the static +/// field. +/// +/// For more information see Compatibility Argument +/// Matchers in the NSubstitute documentation. +/// +public class CompatArg { + private CompatArg() { } + + /// + /// Get the CompatArg instance. + /// + public static readonly CompatArg Instance = new CompatArg(); + + /// + /// Match any argument value compatible with type . + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public T Any() => Arg.Any(); + + /// + /// Match argument that is equal to . + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public T Is(T value) => Arg.Is(value); + + /// + /// Match argument that satisfies . + /// If the throws an exception for an argument it will be treated as non-matching. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public T Is(Expression> predicate) => Arg.Is(predicate); + + /// + /// Match argument that satisfies . + /// If the throws an exception for an argument it will be treated as non-matching. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public Arg.AnyType Is(Expression> predicate) where T : Arg.AnyType => Arg.Is(predicate); + + /// + /// Invoke any argument whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public Action Invoke() => Arg.Invoke(); + + /// + /// Invoke any argument with specified argument whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public Action Invoke(T arg) => Arg.Invoke(arg); + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public Action Invoke(T1 arg1, T2 arg2) => Arg.Invoke(arg1, arg2); + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public Action Invoke(T1 arg1, T2 arg2, T3 arg3) => Arg.Invoke(arg1, arg2, arg3); + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public Action Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) => Arg.Invoke(arg1, arg2, arg3, arg4); + + /// + /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + /// Arguments to pass to delegate. + public TDelegate InvokeDelegate(params object[] arguments) => Arg.InvokeDelegate(arguments); + + /// + /// Capture any argument compatible with type and use it to call the function + /// whenever a matching call is made to the substitute. + /// This is provided for compatibility with older compilers -- + /// if possible use instead. + /// + public T Do(Action useArgument) => Arg.Do(useArgument); + /// - /// Alternate version of matchers for compatibility with pre-C#7 compilers - /// which do not support ref return types. Do not use unless you are unable to use . - /// - /// provides a non-static version of , which can make it easier - /// to use from an abstract base class. You can get a reference to this instance using the static - /// field. - /// - /// For more information see Compatibility Argument - /// Matchers in the NSubstitute documentation. + /// Capture any argument compatible with type and use it to call the function + /// whenever a matching call is made to the substitute. /// - public class CompatArg - { - private CompatArg() { } - - /// - /// Get the CompatArg instance. - /// - public static readonly CompatArg Instance = new CompatArg(); - - /// - /// Match any argument value compatible with type . - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public T Any() => Arg.Any(); - - /// - /// Match argument that is equal to . - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public T Is(T value) => Arg.Is(value); - - /// - /// Match argument that satisfies . - /// If the throws an exception for an argument it will be treated as non-matching. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public T Is(Expression> predicate) => Arg.Is(predicate); - - /// - /// Match argument that satisfies . - /// If the throws an exception for an argument it will be treated as non-matching. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public Arg.AnyType Is(Expression> predicate) where T : Arg.AnyType => Arg.Is(predicate); - - /// - /// Invoke any argument whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public Action Invoke() => Arg.Invoke(); - - /// - /// Invoke any argument with specified argument whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public Action Invoke(T arg) => Arg.Invoke(arg); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public Action Invoke(T1 arg1, T2 arg2) => Arg.Invoke(arg1, arg2); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public Action Invoke(T1 arg1, T2 arg2, T3 arg3) => Arg.Invoke(arg1, arg2, arg3); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public Action Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4) => Arg.Invoke(arg1, arg2, arg3, arg4); - - /// - /// Invoke any argument with specified arguments whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - /// Arguments to pass to delegate. - public TDelegate InvokeDelegate(params object[] arguments) => Arg.InvokeDelegate(arguments); - - /// - /// Capture any argument compatible with type and use it to call the function - /// whenever a matching call is made to the substitute. - /// This is provided for compatibility with older compilers -- - /// if possible use instead. - /// - public T Do(Action useArgument) => Arg.Do(useArgument); - - /// - /// Capture any argument compatible with type and use it to call the function - /// whenever a matching call is made to the substitute. - /// - public static Arg.AnyType Do(Action useArgument) where T : Arg.AnyType => Arg.Do(useArgument); - } + public static Arg.AnyType Do(Action useArgument) where T : Arg.AnyType => Arg.Do(useArgument); } diff --git a/src/NSubstitute/Compatibility/DiagnosticsNullabilityAttributes.cs b/src/NSubstitute/Compatibility/DiagnosticsNullabilityAttributes.cs index fbe8ff36a..a016b1f35 100644 --- a/src/NSubstitute/Compatibility/DiagnosticsNullabilityAttributes.cs +++ b/src/NSubstitute/Compatibility/DiagnosticsNullabilityAttributes.cs @@ -2,141 +2,140 @@ // This was copied from https://github.com/dotnet/runtime/blob/39b9607807f29e48cae4652cd74735182b31182e/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs // and updated to have the scope of the attributes be internal. -namespace System.Diagnostics.CodeAnalysis -{ +namespace System.Diagnostics.CodeAnalysis; - /// Specifies that null is allowed as an input even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] - internal sealed class AllowNullAttribute : Attribute { } - /// Specifies that null is disallowed as an input even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] - internal sealed class DisallowNullAttribute : Attribute { } +/// Specifies that null is allowed as an input even if the corresponding type disallows it. +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +internal sealed class AllowNullAttribute : Attribute { } - /// Specifies that an output may be null even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] - internal sealed class MaybeNullAttribute : Attribute { } +/// Specifies that null is disallowed as an input even if the corresponding type allows it. +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +internal sealed class DisallowNullAttribute : Attribute { } - /// Specifies that an output will not be null even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] - internal sealed class NotNullAttribute : Attribute { } +/// Specifies that an output may be null even if the corresponding type disallows it. +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +internal sealed class MaybeNullAttribute : Attribute { } - /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - internal sealed class MaybeNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter may be null. - /// - public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - - /// Gets the return value condition. - public bool ReturnValue { get; } - } +/// Specifies that an output will not be null even if the corresponding type allows it. +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +internal sealed class NotNullAttribute : Attribute { } - /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - internal sealed class NotNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - - /// Gets the return value condition. - public bool ReturnValue { get; } - } +/// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. +[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +internal sealed class MaybeNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } +} - /// Specifies that the output will be non-null if the named parameter is non-null. - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] - internal sealed class NotNullIfNotNullAttribute : Attribute - { - /// Initializes the attribute with the associated parameter name. - /// - /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. - /// - public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; - - /// Gets the associated parameter name. - public string ParameterName { get; } - } +/// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. +[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +internal sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } +} + +/// Specifies that the output will be non-null if the named parameter is non-null. +[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +internal sealed class NotNullIfNotNullAttribute : Attribute +{ + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } +} - /// Applied to a method that will never return under any circumstance. - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - internal sealed class DoesNotReturnAttribute : Attribute { } +/// Applied to a method that will never return under any circumstance. +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +internal sealed class DoesNotReturnAttribute : Attribute { } - /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - internal sealed class DoesNotReturnIfAttribute : Attribute - { - /// Initializes the attribute with the specified parameter value. - /// - /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to - /// the associated parameter matches this value. - /// - public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; - - /// Gets the condition parameter value. - public bool ParameterValue { get; } - } +/// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. +[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +internal sealed class DoesNotReturnIfAttribute : Attribute +{ + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } +} - /// Specifies that the method or property will ensure that the listed field and property members have not-null values. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - internal sealed class MemberNotNullAttribute : Attribute +/// Specifies that the method or property will ensure that the listed field and property members have not-null values. +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +internal sealed class MemberNotNullAttribute : Attribute +{ + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } +} + +/// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +internal sealed class MemberNotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) { - /// Initializes the attribute with a field or property member. - /// - /// The field or property member that is promised to be not-null. - /// - public MemberNotNullAttribute(string member) => Members = new[] { member }; - - /// Initializes the attribute with the list of field and property members. - /// - /// The list of field and property members that are promised to be not-null. - /// - public MemberNotNullAttribute(params string[] members) => Members = members; - - /// Gets field or property member names. - public string[] Members { get; } + ReturnValue = returnValue; + Members = new[] { member }; } - /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - internal sealed class MemberNotNullWhenAttribute : Attribute + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { - /// Initializes the attribute with the specified return value condition and a field or property member. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - /// - /// The field or property member that is promised to be not-null. - /// - public MemberNotNullWhenAttribute(bool returnValue, string member) - { - ReturnValue = returnValue; - Members = new[] { member }; - } - - /// Initializes the attribute with the specified return value condition and list of field and property members. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - /// - /// The list of field and property members that are promised to be not-null. - /// - public MemberNotNullWhenAttribute(bool returnValue, params string[] members) - { - ReturnValue = returnValue; - Members = members; - } - - /// Gets the return value condition. - public bool ReturnValue { get; } - - /// Gets field or property member names. - public string[] Members { get; } + ReturnValue = returnValue; + Members = members; } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } } #endif diff --git a/src/NSubstitute/Core/Argument.cs b/src/NSubstitute/Core/Argument.cs index b8d594cc5..a2709736f 100644 --- a/src/NSubstitute/Core/Argument.cs +++ b/src/NSubstitute/Core/Argument.cs @@ -1,60 +1,59 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class Argument { - public class Argument - { - private readonly ICall? _call; - private readonly int _argIndex; + private readonly ICall? _call; + private readonly int _argIndex; - private readonly Type? _declaredType; - private readonly Func? _getValue; - private readonly Action? _setValue; + private readonly Type? _declaredType; + private readonly Func? _getValue; + private readonly Action? _setValue; - [Obsolete("This constructor overload is deprecated and will be removed in the next version.")] - public Argument(Type declaredType, Func getValue, Action setValue) - { - _declaredType = declaredType; - _getValue = getValue; - _setValue = setValue; - } + [Obsolete("This constructor overload is deprecated and will be removed in the next version.")] + public Argument(Type declaredType, Func getValue, Action setValue) + { + _declaredType = declaredType; + _getValue = getValue; + _setValue = setValue; + } - public Argument(ICall call, int argIndex) - { - _call = call; - _argIndex = argIndex; - } + public Argument(ICall call, int argIndex) + { + _call = call; + _argIndex = argIndex; + } - public object? Value + public object? Value + { + get => _getValue != null ? _getValue() : _call!.GetArguments()[_argIndex]; + set { - get => _getValue != null ? _getValue() : _call!.GetArguments()[_argIndex]; - set + if (_setValue != null) { - if (_setValue != null) - { - _setValue(value); - } - else - { - _call!.GetArguments()[_argIndex] = value; - } + _setValue(value); + } + else + { + _call!.GetArguments()[_argIndex] = value; } } + } - public bool IsByRef => DeclaredType.IsByRef; + public bool IsByRef => DeclaredType.IsByRef; - public Type DeclaredType => _declaredType ?? _call!.GetParameterInfos()[_argIndex].ParameterType; + public Type DeclaredType => _declaredType ?? _call!.GetParameterInfos()[_argIndex].ParameterType; - public Type ActualType => Value == null ? DeclaredType : Value.GetType(); + public Type ActualType => Value == null ? DeclaredType : Value.GetType(); - public bool IsDeclaredTypeEqualToOrByRefVersionOf(Type type) => - AsNonByRefType(DeclaredType) == type; + public bool IsDeclaredTypeEqualToOrByRefVersionOf(Type type) => + AsNonByRefType(DeclaredType) == type; - public bool IsValueAssignableTo(Type type) => - type.IsAssignableFrom(AsNonByRefType(ActualType)); + public bool IsValueAssignableTo(Type type) => + type.IsAssignableFrom(AsNonByRefType(ActualType)); - public bool CanSetValueWithInstanceOf(Type type) => - AsNonByRefType(DeclaredType).IsAssignableFrom(type); + public bool CanSetValueWithInstanceOf(Type type) => + AsNonByRefType(DeclaredType).IsAssignableFrom(type); - private static Type AsNonByRefType(Type type) => - type.IsByRef ? type.GetElementType()! : type; - } + private static Type AsNonByRefType(Type type) => + type.IsByRef ? type.GetElementType()! : type; } \ No newline at end of file diff --git a/src/NSubstitute/Core/ArgumentSpecificationDequeue.cs b/src/NSubstitute/Core/ArgumentSpecificationDequeue.cs index 4ce507c64..0c251d6d3 100644 --- a/src/NSubstitute/Core/ArgumentSpecificationDequeue.cs +++ b/src/NSubstitute/Core/ArgumentSpecificationDequeue.cs @@ -1,36 +1,35 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class ArgumentSpecificationDequeue : IArgumentSpecificationDequeue { - public class ArgumentSpecificationDequeue : IArgumentSpecificationDequeue - { - private static readonly IArgumentSpecification[] EmptySpecifications = new IArgumentSpecification[0]; + private static readonly IArgumentSpecification[] EmptySpecifications = new IArgumentSpecification[0]; - private readonly Func> _dequeueAllQueuedArgSpecs; + private readonly Func> _dequeueAllQueuedArgSpecs; - public ArgumentSpecificationDequeue(Func> dequeueAllQueuedArgSpecs) - { - _dequeueAllQueuedArgSpecs = dequeueAllQueuedArgSpecs; - } + public ArgumentSpecificationDequeue(Func> dequeueAllQueuedArgSpecs) + { + _dequeueAllQueuedArgSpecs = dequeueAllQueuedArgSpecs; + } - public IList DequeueAllArgumentSpecificationsForMethod(int parametersCount) + public IList DequeueAllArgumentSpecificationsForMethod(int parametersCount) + { + if (parametersCount == 0) { - if (parametersCount == 0) - { - // We violate public contract, as mutable list was expected as result. - // However, in reality we never expect value to be mutated, so this optimization is fine. - // We are not allowed to change public contract due to SemVer, so keeping that as it is. - return EmptySpecifications; - } - - var queuedArgSpecifications = _dequeueAllQueuedArgSpecs.Invoke(); - return queuedArgSpecifications; + // We violate public contract, as mutable list was expected as result. + // However, in reality we never expect value to be mutated, so this optimization is fine. + // We are not allowed to change public contract due to SemVer, so keeping that as it is. + return EmptySpecifications; } - public IList DequeueAllArgumentSpecificationsForMethod(MethodInfo methodInfo) - { - return DequeueAllArgumentSpecificationsForMethod(methodInfo.GetParameters().Length); - } + var queuedArgSpecifications = _dequeueAllQueuedArgSpecs.Invoke(); + return queuedArgSpecifications; + } + + public IList DequeueAllArgumentSpecificationsForMethod(MethodInfo methodInfo) + { + return DequeueAllArgumentSpecificationsForMethod(methodInfo.GetParameters().Length); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs b/src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs index 903331327..2f46784c2 100644 --- a/src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs +++ b/src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs @@ -1,16 +1,15 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class AnyArgumentMatcher : IArgumentMatcher { - public class AnyArgumentMatcher : IArgumentMatcher - { - private readonly Type _typeArgMustBeCompatibleWith; + private readonly Type _typeArgMustBeCompatibleWith; - public AnyArgumentMatcher(Type typeArgMustBeCompatibleWith) - { - _typeArgMustBeCompatibleWith = typeArgMustBeCompatibleWith; - } + public AnyArgumentMatcher(Type typeArgMustBeCompatibleWith) + { + _typeArgMustBeCompatibleWith = typeArgMustBeCompatibleWith; + } - public override string ToString() => "any " + _typeArgMustBeCompatibleWith.GetNonMangledTypeName(); + public override string ToString() => "any " + _typeArgMustBeCompatibleWith.GetNonMangledTypeName(); - public bool IsSatisfiedBy(object? argument) => argument.IsCompatibleWith(_typeArgMustBeCompatibleWith); - } + public bool IsSatisfiedBy(object? argument) => argument.IsCompatibleWith(_typeArgMustBeCompatibleWith); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentFormatter.cs b/src/NSubstitute/Core/Arguments/ArgumentFormatter.cs index cf1491d67..1bfb5ff7b 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentFormatter.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentFormatter.cs @@ -1,27 +1,26 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArgumentFormatter : IArgumentFormatter { - public class ArgumentFormatter : IArgumentFormatter - { - internal static IArgumentFormatter Default { get; } = new ArgumentFormatter(); + internal static IArgumentFormatter Default { get; } = new ArgumentFormatter(); - public string Format(object? argument, bool highlight) - { - var formatted = Format(argument); - return highlight ? "*" + formatted + "*" : formatted; - } + public string Format(object? argument, bool highlight) + { + var formatted = Format(argument); + return highlight ? "*" + formatted + "*" : formatted; + } - private string Format(object? arg) + private string Format(object? arg) + { + return arg switch { - return arg switch - { - null => "", - string str => $"\"{str}\"", - { } obj when HasDefaultToString(obj) => arg.GetType().GetNonMangledTypeName(), - _ => arg.ToString() ?? string.Empty - }; + null => "", + string str => $"\"{str}\"", + { } obj when HasDefaultToString(obj) => arg.GetType().GetNonMangledTypeName(), + _ => arg.ToString() ?? string.Empty + }; - static bool HasDefaultToString(object obj) - => obj.GetType().GetMethod(nameof(ToString), Type.EmptyTypes)!.DeclaringType == typeof(object); - } + static bool HasDefaultToString(object obj) + => obj.GetType().GetMethod(nameof(ToString), Type.EmptyTypes)!.DeclaringType == typeof(object); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs b/src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs index e60e5fc65..fc2d2303c 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs @@ -1,52 +1,51 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArgumentMatchInfo { - public class ArgumentMatchInfo + public ArgumentMatchInfo(int index, object? argument, IArgumentSpecification specification) { - public ArgumentMatchInfo(int index, object? argument, IArgumentSpecification specification) - { - Index = index; - _argument = argument; - _specification = specification; - } + Index = index; + _argument = argument; + _specification = specification; + } - private readonly object? _argument; - private readonly IArgumentSpecification _specification; - public int Index { get; } + private readonly object? _argument; + private readonly IArgumentSpecification _specification; + public int Index { get; } - public bool IsMatch => _specification.IsSatisfiedBy(_argument); + public bool IsMatch => _specification.IsSatisfiedBy(_argument); - public string DescribeNonMatch() - { - var describeNonMatch = _specification.DescribeNonMatch(_argument); - if (string.IsNullOrEmpty(describeNonMatch)) return string.Empty; - var argIndexPrefix = "arg[" + Index + "]: "; - return string.Format("{0}{1}", argIndexPrefix, describeNonMatch.Replace("\n", "\n".PadRight(argIndexPrefix.Length + 1))); - } + public string DescribeNonMatch() + { + var describeNonMatch = _specification.DescribeNonMatch(_argument); + if (string.IsNullOrEmpty(describeNonMatch)) return string.Empty; + var argIndexPrefix = "arg[" + Index + "]: "; + return string.Format("{0}{1}", argIndexPrefix, describeNonMatch.Replace("\n", "\n".PadRight(argIndexPrefix.Length + 1))); + } - public bool Equals(ArgumentMatchInfo? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Index == Index && Equals(other._argument, _argument) && Equals(other._specification, _specification); - } + public bool Equals(ArgumentMatchInfo? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Index == Index && Equals(other._argument, _argument) && Equals(other._specification, _specification); + } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof(ArgumentMatchInfo)) return false; - return Equals((ArgumentMatchInfo)obj); - } + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(ArgumentMatchInfo)) return false; + return Equals((ArgumentMatchInfo)obj); + } - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - int result = Index; - result = (result * 397) ^ (_argument != null ? _argument.GetHashCode() : 0); - result = (result * 397) ^ _specification.GetHashCode(); - return result; - } + int result = Index; + result = (result * 397) ^ (_argument != null ? _argument.GetHashCode() : 0); + result = (result * 397) ^ _specification.GetHashCode(); + return result; } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentMatcher.cs b/src/NSubstitute/Core/Arguments/ArgumentMatcher.cs index a84168103..f4d4bbeec 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentMatcher.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentMatcher.cs @@ -1,63 +1,62 @@ using NSubstitute.Exceptions; -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public static class ArgumentMatcher { - public static class ArgumentMatcher + /// + /// Enqueues a matcher for the method argument in current position and returns the value which should be + /// passed back to the method you invoke. + /// + public static ref T? Enqueue(IArgumentMatcher argumentMatcher) { - /// - /// Enqueues a matcher for the method argument in current position and returns the value which should be - /// passed back to the method you invoke. - /// - public static ref T? Enqueue(IArgumentMatcher argumentMatcher) + if (argumentMatcher == null) throw new ArgumentNullException(nameof(argumentMatcher)); + + IArgumentMatcher nonGenericMatcher = argumentMatcher switch { - if (argumentMatcher == null) throw new ArgumentNullException(nameof(argumentMatcher)); + IDescribeNonMatches => new GenericToNonGenericMatcherProxyWithDescribe(argumentMatcher), + _ => new GenericToNonGenericMatcherProxy(argumentMatcher) + }; - IArgumentMatcher nonGenericMatcher = argumentMatcher switch - { - IDescribeNonMatches => new GenericToNonGenericMatcherProxyWithDescribe(argumentMatcher), - _ => new GenericToNonGenericMatcherProxy(argumentMatcher) - }; + return ref EnqueueArgSpecification(new ArgumentSpecification(typeof(T), nonGenericMatcher)); + } - return ref EnqueueArgSpecification(new ArgumentSpecification(typeof(T), nonGenericMatcher)); - } + internal static ref T? Enqueue(IArgumentMatcher argumentMatcher) => + ref EnqueueArgSpecification(new ArgumentSpecification(typeof(T), argumentMatcher)); - internal static ref T? Enqueue(IArgumentMatcher argumentMatcher) => - ref EnqueueArgSpecification(new ArgumentSpecification(typeof(T), argumentMatcher)); + internal static ref T? Enqueue(IArgumentMatcher argumentMatcher, Action action) => + ref EnqueueArgSpecification(new ArgumentSpecification(typeof(T), argumentMatcher, action)); - internal static ref T? Enqueue(IArgumentMatcher argumentMatcher, Action action) => - ref EnqueueArgSpecification(new ArgumentSpecification(typeof(T), argumentMatcher, action)); + private static ref T? EnqueueArgSpecification(IArgumentSpecification specification) + { + SubstitutionContext.Current.ThreadContext.EnqueueArgumentSpecification(specification); + return ref new DefaultValueContainer().Value; + } - private static ref T? EnqueueArgSpecification(IArgumentSpecification specification) - { - SubstitutionContext.Current.ThreadContext.EnqueueArgumentSpecification(specification); - return ref new DefaultValueContainer().Value; - } + private class GenericToNonGenericMatcherProxy : IArgumentMatcher + { + protected readonly IArgumentMatcher _matcher; - private class GenericToNonGenericMatcherProxy : IArgumentMatcher + public GenericToNonGenericMatcherProxy(IArgumentMatcher matcher) { - protected readonly IArgumentMatcher _matcher; - - public GenericToNonGenericMatcherProxy(IArgumentMatcher matcher) - { - _matcher = matcher; - } - - public bool IsSatisfiedBy(object? argument) => _matcher.IsSatisfiedBy((T?)argument!); + _matcher = matcher; } - private class GenericToNonGenericMatcherProxyWithDescribe : GenericToNonGenericMatcherProxy, IDescribeNonMatches - { - public GenericToNonGenericMatcherProxyWithDescribe(IArgumentMatcher matcher) : base(matcher) - { - if (matcher is not IDescribeNonMatches) throw new SubstituteInternalException("Should implement IDescribeNonMatches type."); - } - - public string DescribeFor(object? argument) => ((IDescribeNonMatches)_matcher).DescribeFor(argument); - } + public bool IsSatisfiedBy(object? argument) => _matcher.IsSatisfiedBy((T?)argument!); + } - private class DefaultValueContainer + private class GenericToNonGenericMatcherProxyWithDescribe : GenericToNonGenericMatcherProxy, IDescribeNonMatches + { + public GenericToNonGenericMatcherProxyWithDescribe(IArgumentMatcher matcher) : base(matcher) { - public T? Value; + if (matcher is not IDescribeNonMatches) throw new SubstituteInternalException("Should implement IDescribeNonMatches type."); } + + public string DescribeFor(object? argument) => ((IDescribeNonMatches)_matcher).DescribeFor(argument); + } + + private class DefaultValueContainer + { + public T? Value; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentSpecification.cs b/src/NSubstitute/Core/Arguments/ArgumentSpecification.cs index 7f8cbf1c3..67147f0b2 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentSpecification.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentSpecification.cs @@ -1,92 +1,91 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArgumentSpecification : IArgumentSpecification { - public class ArgumentSpecification : IArgumentSpecification - { - private static readonly Action NoOpAction = _ => { }; + private static readonly Action NoOpAction = _ => { }; - private readonly IArgumentMatcher _matcher; - private readonly Action _action; - public Type ForType { get; } - public bool HasAction => _action != NoOpAction; + private readonly IArgumentMatcher _matcher; + private readonly Action _action; + public Type ForType { get; } + public bool HasAction => _action != NoOpAction; - public ArgumentSpecification(Type forType, IArgumentMatcher matcher) : this(forType, matcher, NoOpAction) { } + public ArgumentSpecification(Type forType, IArgumentMatcher matcher) : this(forType, matcher, NoOpAction) { } + + public ArgumentSpecification(Type forType, IArgumentMatcher matcher, Action action) + { + ForType = forType; + _matcher = matcher; + _action = action; + } - public ArgumentSpecification(Type forType, IArgumentMatcher matcher, Action action) + public bool IsSatisfiedBy(object? argument) + { + if (!IsCompatibleWith(argument)) { - ForType = forType; - _matcher = matcher; - _action = action; + return false; } - public bool IsSatisfiedBy(object? argument) + try { - if (!IsCompatibleWith(argument)) - { - return false; - } - - try - { - return _matcher.IsSatisfiedBy(argument); - } - catch - { - return false; - } + return _matcher.IsSatisfiedBy(argument); } - - public string DescribeNonMatch(object? argument) + catch { - if (!IsCompatibleWith(argument)) - { - return GetIncompatibleTypeMessage(argument); - } - - return _matcher is IDescribeNonMatches describe - ? describe.DescribeFor(argument) - : string.Empty; + return false; } + } - public string FormatArgument(object? argument) + public string DescribeNonMatch(object? argument) + { + if (!IsCompatibleWith(argument)) { - var isSatisfiedByArg = IsSatisfiedBy(argument); - - return _matcher is IArgumentFormatter matcherFormatter - ? matcherFormatter.Format(argument, highlight: !isSatisfiedByArg) - : ArgumentFormatter.Default.Format(argument, highlight: !isSatisfiedByArg); + return GetIncompatibleTypeMessage(argument); } - public override string ToString() => _matcher.ToString() ?? string.Empty; + return _matcher is IDescribeNonMatches describe + ? describe.DescribeFor(argument) + : string.Empty; + } - public IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType) - { - // Don't pass RunActionIfTypeIsCompatible method if no action is present. - // Otherwise, unnecessary closure will keep reference to this and will keep it alive. - return new ArgumentSpecification( - requiredType, - new AnyArgumentMatcher(requiredType), - _action == NoOpAction ? NoOpAction : RunActionIfTypeIsCompatible); - } + public string FormatArgument(object? argument) + { + var isSatisfiedByArg = IsSatisfiedBy(argument); - public void RunAction(object? argument) - { - _action(argument); - } + return _matcher is IArgumentFormatter matcherFormatter + ? matcherFormatter.Format(argument, highlight: !isSatisfiedByArg) + : ArgumentFormatter.Default.Format(argument, highlight: !isSatisfiedByArg); + } - private void RunActionIfTypeIsCompatible(object? argument) - { - if (argument.IsCompatibleWith(ForType)) - { - _action(argument); - } - } + public override string ToString() => _matcher.ToString() ?? string.Empty; - private bool IsCompatibleWith(object? argument) => argument.IsCompatibleWith(ForType); + public IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType) + { + // Don't pass RunActionIfTypeIsCompatible method if no action is present. + // Otherwise, unnecessary closure will keep reference to this and will keep it alive. + return new ArgumentSpecification( + requiredType, + new AnyArgumentMatcher(requiredType), + _action == NoOpAction ? NoOpAction : RunActionIfTypeIsCompatible); + } - private string GetIncompatibleTypeMessage(object? argument) + public void RunAction(object? argument) + { + _action(argument); + } + + private void RunActionIfTypeIsCompatible(object? argument) + { + if (argument.IsCompatibleWith(ForType)) { - var argumentType = argument == null ? typeof(object) : argument.GetType(); - return $"Expected an argument compatible with type '{ForType}'. Actual type was '{argumentType}'."; + _action(argument); } } + + private bool IsCompatibleWith(object? argument) => argument.IsCompatibleWith(ForType); + + private string GetIncompatibleTypeMessage(object? argument) + { + var argumentType = argument == null ? typeof(object) : argument.GetType(); + return $"Expected an argument compatible with type '{ForType}'. Actual type was '{argumentType}'."; + } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentSpecificationCompatibilityTester.cs b/src/NSubstitute/Core/Arguments/ArgumentSpecificationCompatibilityTester.cs index 3db39d2e9..05dbe80ea 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentSpecificationCompatibilityTester.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentSpecificationCompatibilityTester.cs @@ -1,30 +1,29 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArgumentSpecificationCompatibilityTester : IArgumentSpecificationCompatibilityTester { - public class ArgumentSpecificationCompatibilityTester : IArgumentSpecificationCompatibilityTester - { - private readonly IDefaultChecker _defaultChecker; + private readonly IDefaultChecker _defaultChecker; - public ArgumentSpecificationCompatibilityTester(IDefaultChecker defaultChecker) - { - _defaultChecker = defaultChecker; - } + public ArgumentSpecificationCompatibilityTester(IDefaultChecker defaultChecker) + { + _defaultChecker = defaultChecker; + } - public bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType) - { - var typeArgSpecIsFor = specification.ForType; - return AreTypesCompatible(argumentType, typeArgSpecIsFor) - && IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(argumentValue, typeArgSpecIsFor); - } + public bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType) + { + var typeArgSpecIsFor = specification.ForType; + return AreTypesCompatible(argumentType, typeArgSpecIsFor) + && IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(argumentValue, typeArgSpecIsFor); + } - private bool IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(object? argument, Type typeArgSpecIsFor) - { - return _defaultChecker.IsDefault(argument, typeArgSpecIsFor); - } + private bool IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(object? argument, Type typeArgSpecIsFor) + { + return _defaultChecker.IsDefault(argument, typeArgSpecIsFor); + } - private bool AreTypesCompatible(Type argumentType, Type typeArgSpecIsFor) - { - return argumentType.IsAssignableFrom(typeArgSpecIsFor) || - (argumentType.IsByRef && !typeArgSpecIsFor.IsByRef && argumentType.IsAssignableFrom(typeArgSpecIsFor.MakeByRefType())); - } + private bool AreTypesCompatible(Type argumentType, Type typeArgSpecIsFor) + { + return argumentType.IsAssignableFrom(typeArgSpecIsFor) || + (argumentType.IsByRef && !typeArgSpecIsFor.IsByRef && argumentType.IsAssignableFrom(typeArgSpecIsFor.MakeByRefType())); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentSpecificationFactory.cs b/src/NSubstitute/Core/Arguments/ArgumentSpecificationFactory.cs index c1054b493..ed0945bca 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentSpecificationFactory.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentSpecificationFactory.cs @@ -1,99 +1,98 @@ using NSubstitute.Exceptions; -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArgumentSpecificationFactory : IArgumentSpecificationFactory { - public class ArgumentSpecificationFactory : IArgumentSpecificationFactory + public IArgumentSpecification Create(object? argument, IParameterInfo parameterInfo, + ISuppliedArgumentSpecifications suppliedArgumentSpecifications) { - public IArgumentSpecification Create(object? argument, IParameterInfo parameterInfo, - ISuppliedArgumentSpecifications suppliedArgumentSpecifications) + return parameterInfo.IsParams + ? CreateSpecFromParamsArg(argument, parameterInfo, suppliedArgumentSpecifications) + : CreateSpecFromNonParamsArg(argument, parameterInfo, suppliedArgumentSpecifications); + } + + private IArgumentSpecification CreateSpecFromNonParamsArg(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications) + { + if (suppliedArgumentSpecifications.IsNextFor(argument, parameterInfo.ParameterType)) { - return parameterInfo.IsParams - ? CreateSpecFromParamsArg(argument, parameterInfo, suppliedArgumentSpecifications) - : CreateSpecFromNonParamsArg(argument, parameterInfo, suppliedArgumentSpecifications); + return suppliedArgumentSpecifications.Dequeue(); } - private IArgumentSpecification CreateSpecFromNonParamsArg(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications) + bool isAmbiguousSpecificationPresent = suppliedArgumentSpecifications.AnyFor(argument, parameterInfo.ParameterType); + if (!isAmbiguousSpecificationPresent || parameterInfo.IsOptional || parameterInfo.IsOut) { - if (suppliedArgumentSpecifications.IsNextFor(argument, parameterInfo.ParameterType)) - { - return suppliedArgumentSpecifications.Dequeue(); - } + return new ArgumentSpecification(parameterInfo.ParameterType, new EqualsArgumentMatcher(argument)); + } - bool isAmbiguousSpecificationPresent = suppliedArgumentSpecifications.AnyFor(argument, parameterInfo.ParameterType); - if (!isAmbiguousSpecificationPresent || parameterInfo.IsOptional || parameterInfo.IsOut) - { - return new ArgumentSpecification(parameterInfo.ParameterType, new EqualsArgumentMatcher(argument)); - } + throw new AmbiguousArgumentsException(); + } + private IArgumentSpecification CreateSpecFromParamsArg(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications) + { + // Next specification is for the whole params array. + if (suppliedArgumentSpecifications.IsNextFor(argument, parameterInfo.ParameterType)) + { + return suppliedArgumentSpecifications.Dequeue(); + } + + // Check whether the specification ambiguity could happen. + bool isAmbiguousSpecificationPresent = suppliedArgumentSpecifications.AnyFor(argument, parameterInfo.ParameterType); + if (isAmbiguousSpecificationPresent) + { throw new AmbiguousArgumentsException(); } - private IArgumentSpecification CreateSpecFromParamsArg(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications) + // User passed "null" as the params array value. + if (argument == null) { - // Next specification is for the whole params array. - if (suppliedArgumentSpecifications.IsNextFor(argument, parameterInfo.ParameterType)) - { - return suppliedArgumentSpecifications.Dequeue(); - } + return new ArgumentSpecification(parameterInfo.ParameterType, new EqualsArgumentMatcher(null)); + } - // Check whether the specification ambiguity could happen. - bool isAmbiguousSpecificationPresent = suppliedArgumentSpecifications.AnyFor(argument, parameterInfo.ParameterType); - if (isAmbiguousSpecificationPresent) - { - throw new AmbiguousArgumentsException(); - } + // User specified arguments using the native params syntax. + var arrayArg = argument as Array; + if (arrayArg == null) + { + throw new SubstituteInternalException($"Expected to get array argument, but got argument of '{argument.GetType().FullName}' type."); + } - // User passed "null" as the params array value. - if (argument == null) - { - return new ArgumentSpecification(parameterInfo.ParameterType, new EqualsArgumentMatcher(null)); - } + var arrayArgumentSpecifications = UnwrapParamsArguments(arrayArg.Cast(), parameterInfo.ParameterType.GetElementType()!, suppliedArgumentSpecifications); + return new ArgumentSpecification(parameterInfo.ParameterType, new ArrayContentsArgumentMatcher(arrayArgumentSpecifications)); + } - // User specified arguments using the native params syntax. - var arrayArg = argument as Array; - if (arrayArg == null) + private IEnumerable UnwrapParamsArguments(IEnumerable args, Type paramsElementType, ISuppliedArgumentSpecifications suppliedArgumentSpecifications) + { + var fakeParameterInfo = new ParameterInfoFromType(paramsElementType); + var result = new List(); + foreach (var arg in args) + { + try { - throw new SubstituteInternalException($"Expected to get array argument, but got argument of '{argument.GetType().FullName}' type."); + result.Add(CreateSpecFromNonParamsArg(arg, fakeParameterInfo, suppliedArgumentSpecifications)); } - - var arrayArgumentSpecifications = UnwrapParamsArguments(arrayArg.Cast(), parameterInfo.ParameterType.GetElementType()!, suppliedArgumentSpecifications); - return new ArgumentSpecification(parameterInfo.ParameterType, new ArrayContentsArgumentMatcher(arrayArgumentSpecifications)); - } - - private IEnumerable UnwrapParamsArguments(IEnumerable args, Type paramsElementType, ISuppliedArgumentSpecifications suppliedArgumentSpecifications) - { - var fakeParameterInfo = new ParameterInfoFromType(paramsElementType); - var result = new List(); - foreach (var arg in args) + catch (AmbiguousArgumentsException ex) { - try - { - result.Add(CreateSpecFromNonParamsArg(arg, fakeParameterInfo, suppliedArgumentSpecifications)); - } - catch (AmbiguousArgumentsException ex) - { - ex.Data[AmbiguousArgumentsException.NonReportedResolvedSpecificationsKey] = result; - throw; - } + ex.Data[AmbiguousArgumentsException.NonReportedResolvedSpecificationsKey] = result; + throw; } - - return result; } - private class ParameterInfoFromType : IParameterInfo + return result; + } + + private class ParameterInfoFromType : IParameterInfo + { + public ParameterInfoFromType(Type parameterType) { - public ParameterInfoFromType(Type parameterType) - { - ParameterType = parameterType; - } + ParameterType = parameterType; + } - public Type ParameterType { get; } + public Type ParameterType { get; } - public bool IsParams => false; + public bool IsParams => false; - public bool IsOptional => false; + public bool IsOptional => false; - public bool IsOut => false; - } + public bool IsOut => false; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArgumentSpecificationsFactory.cs b/src/NSubstitute/Core/Arguments/ArgumentSpecificationsFactory.cs index 093e9bbd5..109af96a2 100644 --- a/src/NSubstitute/Core/Arguments/ArgumentSpecificationsFactory.cs +++ b/src/NSubstitute/Core/Arguments/ArgumentSpecificationsFactory.cs @@ -1,59 +1,58 @@ using System.Reflection; using NSubstitute.Exceptions; -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArgumentSpecificationsFactory : IArgumentSpecificationsFactory { - public class ArgumentSpecificationsFactory : IArgumentSpecificationsFactory + private readonly IArgumentSpecificationFactory _argumentSpecificationFactory; + private readonly ISuppliedArgumentSpecificationsFactory _suppliedArgumentSpecificationsFactory; + + public ArgumentSpecificationsFactory(IArgumentSpecificationFactory argumentSpecificationFactory, ISuppliedArgumentSpecificationsFactory suppliedArgumentSpecificationsFactory) { - private readonly IArgumentSpecificationFactory _argumentSpecificationFactory; - private readonly ISuppliedArgumentSpecificationsFactory _suppliedArgumentSpecificationsFactory; + _argumentSpecificationFactory = argumentSpecificationFactory; + _suppliedArgumentSpecificationsFactory = suppliedArgumentSpecificationsFactory; + } - public ArgumentSpecificationsFactory(IArgumentSpecificationFactory argumentSpecificationFactory, ISuppliedArgumentSpecificationsFactory suppliedArgumentSpecificationsFactory) - { - _argumentSpecificationFactory = argumentSpecificationFactory; - _suppliedArgumentSpecificationsFactory = suppliedArgumentSpecificationsFactory; - } + public IEnumerable Create(IList argumentSpecs, object?[] arguments, IParameterInfo[] parameterInfos, MethodInfo methodInfo, MatchArgs matchArgs) + { + var suppliedArgumentSpecifications = _suppliedArgumentSpecificationsFactory.Create(argumentSpecs); - public IEnumerable Create(IList argumentSpecs, object?[] arguments, IParameterInfo[] parameterInfos, MethodInfo methodInfo, MatchArgs matchArgs) + var result = new List(); + for (var i = 0; i < arguments.Length; i++) { - var suppliedArgumentSpecifications = _suppliedArgumentSpecificationsFactory.Create(argumentSpecs); + var arg = arguments[i]; + var paramInfo = parameterInfos[i]; - var result = new List(); - for (var i = 0; i < arguments.Length; i++) + try { - var arg = arguments[i]; - var paramInfo = parameterInfos[i]; - - try - { - result.Add(_argumentSpecificationFactory.Create(arg, paramInfo, suppliedArgumentSpecifications)); - } - catch (AmbiguousArgumentsException ex) when (ex.ContainsDefaultMessage) + result.Add(_argumentSpecificationFactory.Create(arg, paramInfo, suppliedArgumentSpecifications)); + } + catch (AmbiguousArgumentsException ex) when (ex.ContainsDefaultMessage) + { + IEnumerable alreadyResolvedSpecs = result; + if (ex.Data[AmbiguousArgumentsException.NonReportedResolvedSpecificationsKey] is IEnumerable additional) { - IEnumerable alreadyResolvedSpecs = result; - if (ex.Data[AmbiguousArgumentsException.NonReportedResolvedSpecificationsKey] is IEnumerable additional) - { - alreadyResolvedSpecs = alreadyResolvedSpecs.Concat(additional); - } - - throw new AmbiguousArgumentsException(methodInfo, arguments, alreadyResolvedSpecs, argumentSpecs); + alreadyResolvedSpecs = alreadyResolvedSpecs.Concat(additional); } - } - var remainingArgumentSpecifications = suppliedArgumentSpecifications.DequeueRemaining(); - if (remainingArgumentSpecifications.Any()) - { - throw new RedundantArgumentMatcherException(remainingArgumentSpecifications, argumentSpecs); + throw new AmbiguousArgumentsException(methodInfo, arguments, alreadyResolvedSpecs, argumentSpecs); } - - return matchArgs == MatchArgs.Any - ? ConvertToMatchAnyValue(result) - : result; } - private static IEnumerable ConvertToMatchAnyValue(IEnumerable specs) + var remainingArgumentSpecifications = suppliedArgumentSpecifications.DequeueRemaining(); + if (remainingArgumentSpecifications.Any()) { - return specs.Select(x => x.CreateCopyMatchingAnyArgOfType(x.ForType)).ToArray(); + throw new RedundantArgumentMatcherException(remainingArgumentSpecifications, argumentSpecs); } + + return matchArgs == MatchArgs.Any + ? ConvertToMatchAnyValue(result) + : result; + } + + private static IEnumerable ConvertToMatchAnyValue(IEnumerable specs) + { + return specs.Select(x => x.CreateCopyMatchingAnyArgOfType(x.ForType)).ToArray(); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ArrayContentsArgumentMatcher.cs b/src/NSubstitute/Core/Arguments/ArrayContentsArgumentMatcher.cs index 1b9f873af..cfeb2555d 100644 --- a/src/NSubstitute/Core/Arguments/ArrayContentsArgumentMatcher.cs +++ b/src/NSubstitute/Core/Arguments/ArrayContentsArgumentMatcher.cs @@ -1,51 +1,50 @@ using System.Collections; -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ArrayContentsArgumentMatcher : IArgumentMatcher, IArgumentFormatter { - public class ArrayContentsArgumentMatcher : IArgumentMatcher, IArgumentFormatter - { - private readonly IArgumentSpecification[] _argumentSpecifications; + private readonly IArgumentSpecification[] _argumentSpecifications; - public ArrayContentsArgumentMatcher(IEnumerable argumentSpecifications) - { - _argumentSpecifications = argumentSpecifications.ToArray(); - } + public ArrayContentsArgumentMatcher(IEnumerable argumentSpecifications) + { + _argumentSpecifications = argumentSpecifications.ToArray(); + } - public bool IsSatisfiedBy(object? argument) + public bool IsSatisfiedBy(object? argument) + { + if (argument != null) { - if (argument != null) + var argumentArray = ((IEnumerable)argument).Cast().ToArray(); + if (argumentArray.Length == _argumentSpecifications.Length) { - var argumentArray = ((IEnumerable)argument).Cast().ToArray(); - if (argumentArray.Length == _argumentSpecifications.Length) - { - return _argumentSpecifications - .Select((spec, index) => spec.IsSatisfiedBy(argumentArray[index])) - .All(x => x); - } + return _argumentSpecifications + .Select((spec, index) => spec.IsSatisfiedBy(argumentArray[index])) + .All(x => x); } - - return false; } - public override string ToString() => string.Join(", ", _argumentSpecifications.Select(x => x.ToString())); + return false; + } - public string Format(object? argument, bool highlight) - { - var argArray = argument is IEnumerable enumerableArgs ? enumerableArgs.Cast().ToArray() : new object[0]; - return Format(argArray, _argumentSpecifications).Join(", "); - } + public override string ToString() => string.Join(", ", _argumentSpecifications.Select(x => x.ToString())); - private IEnumerable Format(object[] args, IArgumentSpecification[] specs) + public string Format(object? argument, bool highlight) + { + var argArray = argument is IEnumerable enumerableArgs ? enumerableArgs.Cast().ToArray() : new object[0]; + return Format(argArray, _argumentSpecifications).Join(", "); + } + + private IEnumerable Format(object[] args, IArgumentSpecification[] specs) + { + if (specs.Any() && !args.Any()) { - if (specs.Any() && !args.Any()) - { - return new[] { "**" }; - } - return args.Select((arg, index) => - { - var hasSpecForThisArg = index < specs.Length; - return hasSpecForThisArg ? specs[index].FormatArgument(arg) : ArgumentFormatter.Default.Format(arg, true); - }); + return new[] { "**" }; } + return args.Select((arg, index) => + { + var hasSpecForThisArg = index < specs.Length; + return hasSpecForThisArg ? specs[index].FormatArgument(arg) : ArgumentFormatter.Default.Format(arg, true); + }); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/DefaultChecker.cs b/src/NSubstitute/Core/Arguments/DefaultChecker.cs index b8d63e5b0..f31f62494 100644 --- a/src/NSubstitute/Core/Arguments/DefaultChecker.cs +++ b/src/NSubstitute/Core/Arguments/DefaultChecker.cs @@ -1,17 +1,16 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class DefaultChecker : IDefaultChecker { - public class DefaultChecker : IDefaultChecker - { - private readonly IDefaultForType _defaultForType; + private readonly IDefaultForType _defaultForType; - public DefaultChecker(IDefaultForType defaultForType) - { - _defaultForType = defaultForType; - } + public DefaultChecker(IDefaultForType defaultForType) + { + _defaultForType = defaultForType; + } - public bool IsDefault(object? value, Type forType) - { - return EqualityComparer.Default.Equals(value, _defaultForType.GetDefaultFor(forType)); - } + public bool IsDefault(object? value, Type forType) + { + return EqualityComparer.Default.Equals(value, _defaultForType.GetDefaultFor(forType)); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/EqualsArgumentMatcher.cs b/src/NSubstitute/Core/Arguments/EqualsArgumentMatcher.cs index 60cacb5df..1494c605b 100644 --- a/src/NSubstitute/Core/Arguments/EqualsArgumentMatcher.cs +++ b/src/NSubstitute/Core/Arguments/EqualsArgumentMatcher.cs @@ -1,16 +1,15 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class EqualsArgumentMatcher : IArgumentMatcher { - public class EqualsArgumentMatcher : IArgumentMatcher - { - private readonly object? _value; + private readonly object? _value; - public EqualsArgumentMatcher(object? value) - { - _value = value; - } + public EqualsArgumentMatcher(object? value) + { + _value = value; + } - public override string ToString() => ArgumentFormatter.Default.Format(_value, false); + public override string ToString() => ArgumentFormatter.Default.Format(_value, false); - public bool IsSatisfiedBy(object? argument) => EqualityComparer.Default.Equals(_value, argument); - } + public bool IsSatisfiedBy(object? argument) => EqualityComparer.Default.Equals(_value, argument); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ExpressionArgumentMatcher.cs b/src/NSubstitute/Core/Arguments/ExpressionArgumentMatcher.cs index acd6f63e1..860738a15 100644 --- a/src/NSubstitute/Core/Arguments/ExpressionArgumentMatcher.cs +++ b/src/NSubstitute/Core/Arguments/ExpressionArgumentMatcher.cs @@ -1,20 +1,19 @@ using System.Linq.Expressions; -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class ExpressionArgumentMatcher : IArgumentMatcher { - public class ExpressionArgumentMatcher : IArgumentMatcher - { - private readonly string _predicateDescription; - private readonly Predicate _predicate; + private readonly string _predicateDescription; + private readonly Predicate _predicate; - public ExpressionArgumentMatcher(Expression> predicate) - { - _predicate = predicate.Compile(); - _predicateDescription = predicate.ToString(); - } + public ExpressionArgumentMatcher(Expression> predicate) + { + _predicate = predicate.Compile(); + _predicateDescription = predicate.ToString(); + } - public bool IsSatisfiedBy(object? argument) => _predicate((T?)argument!); + public bool IsSatisfiedBy(object? argument) => _predicate((T?)argument!); - public override string ToString() => _predicateDescription; - } + public override string ToString() => _predicateDescription; } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IArgumentFormatter.cs b/src/NSubstitute/Core/Arguments/IArgumentFormatter.cs index 47f1e6d40..6a9da203c 100644 --- a/src/NSubstitute/Core/Arguments/IArgumentFormatter.cs +++ b/src/NSubstitute/Core/Arguments/IArgumentFormatter.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface IArgumentFormatter { - public interface IArgumentFormatter - { - string Format(object? arg, bool highlight); - } + string Format(object? arg, bool highlight); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IArgumentMatcher.cs b/src/NSubstitute/Core/Arguments/IArgumentMatcher.cs index 01d5c9ea2..b0000d893 100644 --- a/src/NSubstitute/Core/Arguments/IArgumentMatcher.cs +++ b/src/NSubstitute/Core/Arguments/IArgumentMatcher.cs @@ -1,29 +1,28 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +/// +/// Provides a specification for arguments for use with . +/// Can additionally implement to give descriptions when arguments do not match. +/// +public interface IArgumentMatcher { /// - /// Provides a specification for arguments for use with . - /// Can additionally implement to give descriptions when arguments do not match. + /// Checks whether the satisfies the condition of the matcher. + /// If this throws an exception the argument will be treated as non-matching. /// - public interface IArgumentMatcher - { - /// - /// Checks whether the satisfies the condition of the matcher. - /// If this throws an exception the argument will be treated as non-matching. - /// - bool IsSatisfiedBy(object? argument); - } + bool IsSatisfiedBy(object? argument); +} +/// +/// Provides a specification for arguments for use with . +/// Can additionally implement to give descriptions when arguments do not match. +/// +/// Matches arguments of type or compatible type. +public interface IArgumentMatcher +{ /// - /// Provides a specification for arguments for use with . - /// Can additionally implement to give descriptions when arguments do not match. + /// Checks whether the satisfies the condition of the matcher. + /// If this throws an exception the argument will be treated as non-matching. /// - /// Matches arguments of type or compatible type. - public interface IArgumentMatcher - { - /// - /// Checks whether the satisfies the condition of the matcher. - /// If this throws an exception the argument will be treated as non-matching. - /// - bool IsSatisfiedBy(T? argument); - } + bool IsSatisfiedBy(T? argument); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IArgumentSpecification.cs b/src/NSubstitute/Core/Arguments/IArgumentSpecification.cs index 5a3620e2c..f51b69fc4 100644 --- a/src/NSubstitute/Core/Arguments/IArgumentSpecification.cs +++ b/src/NSubstitute/Core/Arguments/IArgumentSpecification.cs @@ -1,13 +1,12 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface IArgumentSpecification { - public interface IArgumentSpecification - { - bool IsSatisfiedBy(object? argument); - Type ForType { get; } - IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType); - bool HasAction { get; } - void RunAction(object? argument); - string DescribeNonMatch(object? argument); - string FormatArgument(object? argument); - } + bool IsSatisfiedBy(object? argument); + Type ForType { get; } + IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType); + bool HasAction { get; } + void RunAction(object? argument); + string DescribeNonMatch(object? argument); + string FormatArgument(object? argument); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IArgumentSpecificationCompatibilityTester.cs b/src/NSubstitute/Core/Arguments/IArgumentSpecificationCompatibilityTester.cs index facaf8434..7b1d12090 100644 --- a/src/NSubstitute/Core/Arguments/IArgumentSpecificationCompatibilityTester.cs +++ b/src/NSubstitute/Core/Arguments/IArgumentSpecificationCompatibilityTester.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface IArgumentSpecificationCompatibilityTester { - public interface IArgumentSpecificationCompatibilityTester - { - bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType); - } + bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IArgumentSpecificationFactory.cs b/src/NSubstitute/Core/Arguments/IArgumentSpecificationFactory.cs index 9800095f9..7db552703 100644 --- a/src/NSubstitute/Core/Arguments/IArgumentSpecificationFactory.cs +++ b/src/NSubstitute/Core/Arguments/IArgumentSpecificationFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface IArgumentSpecificationFactory { - public interface IArgumentSpecificationFactory - { - IArgumentSpecification Create(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications); - } + IArgumentSpecification Create(object? argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IArgumentSpecificationsFactory.cs b/src/NSubstitute/Core/Arguments/IArgumentSpecificationsFactory.cs index beae80fe2..a174ee0f3 100644 --- a/src/NSubstitute/Core/Arguments/IArgumentSpecificationsFactory.cs +++ b/src/NSubstitute/Core/Arguments/IArgumentSpecificationsFactory.cs @@ -1,9 +1,8 @@ using System.Reflection; -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface IArgumentSpecificationsFactory { - public interface IArgumentSpecificationsFactory - { - IEnumerable Create(IList argumentSpecs, object?[] arguments, IParameterInfo[] parameterInfos, MethodInfo methodInfo, MatchArgs matchArgs); - } + IEnumerable Create(IList argumentSpecs, object?[] arguments, IParameterInfo[] parameterInfos, MethodInfo methodInfo, MatchArgs matchArgs); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/IDefaultChecker.cs b/src/NSubstitute/Core/Arguments/IDefaultChecker.cs index 1749cccf3..f7c6ccfec 100644 --- a/src/NSubstitute/Core/Arguments/IDefaultChecker.cs +++ b/src/NSubstitute/Core/Arguments/IDefaultChecker.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface IDefaultChecker { - public interface IDefaultChecker - { - bool IsDefault(object? value, Type forType); - } + bool IsDefault(object? value, Type forType); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecifications.cs b/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecifications.cs index cad2bd16b..c9c9f7d8b 100644 --- a/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecifications.cs +++ b/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecifications.cs @@ -1,10 +1,9 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface ISuppliedArgumentSpecifications { - public interface ISuppliedArgumentSpecifications - { - bool AnyFor(object? argument, Type argumentType); - bool IsNextFor(object? argument, Type argumentType); - IArgumentSpecification Dequeue(); - IEnumerable DequeueRemaining(); - } + bool AnyFor(object? argument, Type argumentType); + bool IsNextFor(object? argument, Type argumentType); + IArgumentSpecification Dequeue(); + IEnumerable DequeueRemaining(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecificationsFactory.cs b/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecificationsFactory.cs index c58de88b2..1093f9bb1 100644 --- a/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecificationsFactory.cs +++ b/src/NSubstitute/Core/Arguments/ISuppliedArgumentSpecificationsFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public interface ISuppliedArgumentSpecificationsFactory { - public interface ISuppliedArgumentSpecificationsFactory - { - ISuppliedArgumentSpecifications Create(IEnumerable argumentSpecifications); - } + ISuppliedArgumentSpecifications Create(IEnumerable argumentSpecifications); } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecifications.cs b/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecifications.cs index 6144b91c8..085b472d8 100644 --- a/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecifications.cs +++ b/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecifications.cs @@ -1,42 +1,41 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class SuppliedArgumentSpecifications : ISuppliedArgumentSpecifications { - public class SuppliedArgumentSpecifications : ISuppliedArgumentSpecifications + private readonly IArgumentSpecificationCompatibilityTester _argSpecCompatibilityTester; + private readonly Queue _queue; + private IReadOnlyCollection AllSpecifications { get; } + + public SuppliedArgumentSpecifications(IArgumentSpecificationCompatibilityTester argSpecCompatibilityTester, IEnumerable argumentSpecifications) { - private readonly IArgumentSpecificationCompatibilityTester _argSpecCompatibilityTester; - private readonly Queue _queue; - private IReadOnlyCollection AllSpecifications { get; } + _argSpecCompatibilityTester = argSpecCompatibilityTester; + AllSpecifications = argumentSpecifications.ToArray(); + _queue = new Queue(AllSpecifications); + } - public SuppliedArgumentSpecifications(IArgumentSpecificationCompatibilityTester argSpecCompatibilityTester, IEnumerable argumentSpecifications) - { - _argSpecCompatibilityTester = argSpecCompatibilityTester; - AllSpecifications = argumentSpecifications.ToArray(); - _queue = new Queue(AllSpecifications); - } + public bool AnyFor(object? argument, Type argumentType) + { + return AllSpecifications.Any(x => _argSpecCompatibilityTester.IsSpecificationCompatible(x, argument, argumentType)); + } - public bool AnyFor(object? argument, Type argumentType) + public bool IsNextFor(object? argument, Type argumentType) + { + if (_queue.Count == 0) { - return AllSpecifications.Any(x => _argSpecCompatibilityTester.IsSpecificationCompatible(x, argument, argumentType)); + return false; } - public bool IsNextFor(object? argument, Type argumentType) - { - if (_queue.Count == 0) - { - return false; - } - - var nextArgSpec = _queue.Peek(); - return _argSpecCompatibilityTester.IsSpecificationCompatible(nextArgSpec, argument, argumentType); - } + var nextArgSpec = _queue.Peek(); + return _argSpecCompatibilityTester.IsSpecificationCompatible(nextArgSpec, argument, argumentType); + } - public IArgumentSpecification Dequeue() => _queue.Dequeue(); + public IArgumentSpecification Dequeue() => _queue.Dequeue(); - public IEnumerable DequeueRemaining() - { - var result = _queue.ToArray(); - _queue.Clear(); - return result; - } + public IEnumerable DequeueRemaining() + { + var result = _queue.ToArray(); + _queue.Clear(); + return result; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecificationsFactory.cs b/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecificationsFactory.cs index 53cfd4419..ec5904aef 100644 --- a/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecificationsFactory.cs +++ b/src/NSubstitute/Core/Arguments/SuppliedArgumentSpecificationsFactory.cs @@ -1,17 +1,16 @@ -namespace NSubstitute.Core.Arguments +namespace NSubstitute.Core.Arguments; + +public class SuppliedArgumentSpecificationsFactory : ISuppliedArgumentSpecificationsFactory { - public class SuppliedArgumentSpecificationsFactory : ISuppliedArgumentSpecificationsFactory - { - private readonly IArgumentSpecificationCompatibilityTester _argumentSpecificationCompatTester; + private readonly IArgumentSpecificationCompatibilityTester _argumentSpecificationCompatTester; - public SuppliedArgumentSpecificationsFactory(IArgumentSpecificationCompatibilityTester argumentSpecificationCompatTester) - { - _argumentSpecificationCompatTester = argumentSpecificationCompatTester; - } + public SuppliedArgumentSpecificationsFactory(IArgumentSpecificationCompatibilityTester argumentSpecificationCompatTester) + { + _argumentSpecificationCompatTester = argumentSpecificationCompatTester; + } - public ISuppliedArgumentSpecifications Create(IEnumerable argumentSpecifications) - { - return new SuppliedArgumentSpecifications(_argumentSpecificationCompatTester, argumentSpecifications); - } + public ISuppliedArgumentSpecifications Create(IEnumerable argumentSpecifications) + { + return new SuppliedArgumentSpecifications(_argumentSpecificationCompatTester, argumentSpecifications); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Call.cs b/src/NSubstitute/Core/Call.cs index 5eae11ad3..4bf094243 100644 --- a/src/NSubstitute/Core/Call.cs +++ b/src/NSubstitute/Core/Call.cs @@ -2,124 +2,123 @@ using NSubstitute.Core.Arguments; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class Call : ICall, /* Performance optimization */ CallCollection.IReceivedCallEntry { - public class Call : ICall, /* Performance optimization */ CallCollection.IReceivedCallEntry + private readonly MethodInfo _methodInfo; + private readonly object?[] _arguments; + private object?[] _originalArguments; + private readonly object _target; + private readonly IList _argumentSpecifications; + private IParameterInfo[]? _parameterInfosCached; + private long? _sequenceNumber; + private readonly Func? _baseMethod; + + [Obsolete("This constructor is deprecated and will be removed in future version of product.")] + public Call(MethodInfo methodInfo, + object?[] arguments, + object target, + IList argumentSpecifications, + IParameterInfo[] parameterInfos, + Func baseMethod) + : this(methodInfo, arguments, target, argumentSpecifications, baseMethod) { - private readonly MethodInfo _methodInfo; - private readonly object?[] _arguments; - private object?[] _originalArguments; - private readonly object _target; - private readonly IList _argumentSpecifications; - private IParameterInfo[]? _parameterInfosCached; - private long? _sequenceNumber; - private readonly Func? _baseMethod; - - [Obsolete("This constructor is deprecated and will be removed in future version of product.")] - public Call(MethodInfo methodInfo, - object?[] arguments, - object target, - IList argumentSpecifications, - IParameterInfo[] parameterInfos, - Func baseMethod) - : this(methodInfo, arguments, target, argumentSpecifications, baseMethod) - { - _parameterInfosCached = parameterInfos ?? throw new ArgumentNullException(nameof(parameterInfos)); - } + _parameterInfosCached = parameterInfos ?? throw new ArgumentNullException(nameof(parameterInfos)); + } - public Call(MethodInfo methodInfo, - object?[] arguments, - object target, - IList argumentSpecifications, - Func? baseMethod) - { - _methodInfo = methodInfo; - _arguments = arguments; - _target = target; - _argumentSpecifications = argumentSpecifications; - _baseMethod = baseMethod; - - // Performance optimization - we don't want to create a copy on each call. - // Instead, we want to guard array only if "mutable" array property is accessed. - // Therefore, we keep tracking whether the "mutable" version is accessed and if so - create a copy on demand. - _originalArguments = _arguments; - } + public Call(MethodInfo methodInfo, + object?[] arguments, + object target, + IList argumentSpecifications, + Func? baseMethod) + { + _methodInfo = methodInfo; + _arguments = arguments; + _target = target; + _argumentSpecifications = argumentSpecifications; + _baseMethod = baseMethod; + + // Performance optimization - we don't want to create a copy on each call. + // Instead, we want to guard array only if "mutable" array property is accessed. + // Therefore, we keep tracking whether the "mutable" version is accessed and if so - create a copy on demand. + _originalArguments = _arguments; + } - public IParameterInfo[] GetParameterInfos() - { - // Don't worry about concurrency. - // Normally call is processed in a single thread. - // However even if race condition happens, we'll create an extra set of wrappers, which behaves the same. - return _parameterInfosCached ??= GetParameterInfoFromMethod(_methodInfo); - } + public IParameterInfo[] GetParameterInfos() + { + // Don't worry about concurrency. + // Normally call is processed in a single thread. + // However even if race condition happens, we'll create an extra set of wrappers, which behaves the same. + return _parameterInfosCached ??= GetParameterInfoFromMethod(_methodInfo); + } - public IList GetArgumentSpecifications() => _argumentSpecifications; + public IList GetArgumentSpecifications() => _argumentSpecifications; - public void AssignSequenceNumber(long number) - { - _sequenceNumber = number; - } + public void AssignSequenceNumber(long number) + { + _sequenceNumber = number; + } - public long GetSequenceNumber() => _sequenceNumber ?? throw new MissingSequenceNumberException(); + public long GetSequenceNumber() => _sequenceNumber ?? throw new MissingSequenceNumberException(); - public bool CanCallBase => _baseMethod != null; + public bool CanCallBase => _baseMethod != null; - public Maybe TryCallBase() - { - return _baseMethod == null ? Maybe.Nothing() : Maybe.Just(_baseMethod()); - } + public Maybe TryCallBase() + { + return _baseMethod == null ? Maybe.Nothing() : Maybe.Just(_baseMethod()); + } - public Type GetReturnType() => _methodInfo.ReturnType; + public Type GetReturnType() => _methodInfo.ReturnType; - public MethodInfo GetMethodInfo() => _methodInfo; + public MethodInfo GetMethodInfo() => _methodInfo; - public object?[] GetArguments() + public object?[] GetArguments() + { + // This method assumes that result might be mutated. + // Therefore, we should guard our array with original values to ensure it's unmodified. + // Also if array is empty - no sense to make a copy. + object?[] originalArray = _originalArguments; + if (originalArray == _arguments && originalArray.Length > 0) { - // This method assumes that result might be mutated. - // Therefore, we should guard our array with original values to ensure it's unmodified. - // Also if array is empty - no sense to make a copy. - object?[] originalArray = _originalArguments; - if (originalArray == _arguments && originalArray.Length > 0) - { - object?[] copy = originalArray.ToArray(); - // If it happens that _originalArguments doesn't point to the `_arguments` anymore - - // it might happen that other thread already created a copy and mutated the original `_arguments` array. - // In this case it's unsafe to replace it with a copy. - Interlocked.CompareExchange(ref _originalArguments, copy, originalArray); - } - - return _arguments; + object?[] copy = originalArray.ToArray(); + // If it happens that _originalArguments doesn't point to the `_arguments` anymore - + // it might happen that other thread already created a copy and mutated the original `_arguments` array. + // In this case it's unsafe to replace it with a copy. + Interlocked.CompareExchange(ref _originalArguments, copy, originalArray); } - public object?[] GetOriginalArguments() => _originalArguments; + return _arguments; + } - public object Target() => _target; + public object?[] GetOriginalArguments() => _originalArguments; - private static IParameterInfo[] GetParameterInfoFromMethod(MethodInfo methodInfo) - { - var parameters = methodInfo.GetParameters(); - var parameterInfos = new IParameterInfo[parameters.Length]; + public object Target() => _target; - for (var i = 0; i < parameters.Length; i++) - { - parameterInfos[i] = new ParameterInfoWrapper(parameters[i]); - } + private static IParameterInfo[] GetParameterInfoFromMethod(MethodInfo methodInfo) + { + var parameters = methodInfo.GetParameters(); + var parameterInfos = new IParameterInfo[parameters.Length]; - return parameterInfos; + for (var i = 0; i < parameters.Length; i++) + { + parameterInfos[i] = new ParameterInfoWrapper(parameters[i]); } - /* Performance optimization. - Allows Call to carry additional information, required by received calls registry. */ + return parameterInfos; + } - // 0 - not owned, default; 1 - owned; -1 - skipped. Use int because of Interlocked compatibility. - private int _callEntryState; - ICall CallCollection.IReceivedCallEntry.Call => this; - bool CallCollection.IReceivedCallEntry.IsSkipped => _callEntryState == -1; - void CallCollection.IReceivedCallEntry.Skip() => _callEntryState = -1; + /* Performance optimization. + Allows Call to carry additional information, required by received calls registry. */ - bool CallCollection.IReceivedCallEntry.TryTakeEntryOwnership() - { - return Interlocked.CompareExchange(ref _callEntryState, 1, 0) == 0; - } + // 0 - not owned, default; 1 - owned; -1 - skipped. Use int because of Interlocked compatibility. + private int _callEntryState; + ICall CallCollection.IReceivedCallEntry.Call => this; + bool CallCollection.IReceivedCallEntry.IsSkipped => _callEntryState == -1; + void CallCollection.IReceivedCallEntry.Skip() => _callEntryState = -1; + + bool CallCollection.IReceivedCallEntry.TryTakeEntryOwnership() + { + return Interlocked.CompareExchange(ref _callEntryState, 1, 0) == 0; } } diff --git a/src/NSubstitute/Core/CallActions.cs b/src/NSubstitute/Core/CallActions.cs index a78b2b9f8..f0a3821b9 100644 --- a/src/NSubstitute/Core/CallActions.cs +++ b/src/NSubstitute/Core/CallActions.cs @@ -1,91 +1,90 @@ using System.Collections.Concurrent; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallActions : ICallActions { - public class CallActions : ICallActions - { - private static readonly Action EmptyAction = x => { }; + private static readonly Action EmptyAction = x => { }; - private readonly ICallInfoFactory _callInfoFactory; - // Collection consideration. - // We need to have a thread-safe collection which should be enumerated in add order. - // Even though Queue allocates on each enumeration, we expect callbacks to occur rarely, - // so it shouldn't be a big issue. - // If we want to optimize it later, we should probably take a look at System.Collections.Immutable. - private ConcurrentQueue _actions = new(); + private readonly ICallInfoFactory _callInfoFactory; + // Collection consideration. + // We need to have a thread-safe collection which should be enumerated in add order. + // Even though Queue allocates on each enumeration, we expect callbacks to occur rarely, + // so it shouldn't be a big issue. + // If we want to optimize it later, we should probably take a look at System.Collections.Immutable. + private ConcurrentQueue _actions = new(); - public CallActions(ICallInfoFactory callInfoFactory) - { - _callInfoFactory = callInfoFactory; - } + public CallActions(ICallInfoFactory callInfoFactory) + { + _callInfoFactory = callInfoFactory; + } - public void Add(ICallSpecification callSpecification, Action action) - { - _actions.Enqueue(new CallAction(callSpecification, action)); - } + public void Add(ICallSpecification callSpecification, Action action) + { + _actions.Enqueue(new CallAction(callSpecification, action)); + } - public void Add(ICallSpecification callSpecification) - { - Add(callSpecification, EmptyAction); - } + public void Add(ICallSpecification callSpecification) + { + Add(callSpecification, EmptyAction); + } - public void MoveActionsForSpecToNewSpec(ICallSpecification oldCallSpecification, ICallSpecification newCallSpecification) + public void MoveActionsForSpecToNewSpec(ICallSpecification oldCallSpecification, ICallSpecification newCallSpecification) + { + foreach (var action in _actions) { - foreach (var action in _actions) + if (action.IsFor(oldCallSpecification)) { - if (action.IsFor(oldCallSpecification)) - { - action.UpdateCallSpecification(newCallSpecification); - } + action.UpdateCallSpecification(newCallSpecification); } } + } - public void Clear() + public void Clear() + { + // Collection doesn't have a clear method. + _actions = new ConcurrentQueue(); + } + + public void InvokeMatchingActions(ICall call) + { + // Performance optimization - enumeration allocates enumerator object. + if (_actions.IsEmpty) { - // Collection doesn't have a clear method. - _actions = new ConcurrentQueue(); + return; } - public void InvokeMatchingActions(ICall call) + CallInfo? callInfo = null; + foreach (var action in _actions) { - // Performance optimization - enumeration allocates enumerator object. - if (_actions.IsEmpty) - { - return; - } - - CallInfo? callInfo = null; - foreach (var action in _actions) - { - if (!action.IsSatisfiedBy(call)) - continue; + if (!action.IsSatisfiedBy(call)) + continue; - // Optimization. Initialize call lazily, as most of times there are no callbacks. - callInfo ??= _callInfoFactory.Create(call); + // Optimization. Initialize call lazily, as most of times there are no callbacks. + callInfo ??= _callInfoFactory.Create(call); - action.Invoke(callInfo); - } + action.Invoke(callInfo); } + } - private class CallAction + private class CallAction + { + public CallAction(ICallSpecification callSpecification, Action action) { - public CallAction(ICallSpecification callSpecification, Action action) - { - _callSpecification = callSpecification; - _action = action; - } + _callSpecification = callSpecification; + _action = action; + } - private ICallSpecification _callSpecification; - private readonly Action _action; - public bool IsSatisfiedBy(ICall call) => _callSpecification.IsSatisfiedBy(call); + private ICallSpecification _callSpecification; + private readonly Action _action; + public bool IsSatisfiedBy(ICall call) => _callSpecification.IsSatisfiedBy(call); - public void Invoke(CallInfo callInfo) - { - _action(callInfo); - _callSpecification.InvokePerArgumentActions(callInfo); - } - public bool IsFor(ICallSpecification spec) => _callSpecification == spec; - public void UpdateCallSpecification(ICallSpecification spec) => _callSpecification = spec; + public void Invoke(CallInfo callInfo) + { + _action(callInfo); + _callSpecification.InvokePerArgumentActions(callInfo); } + public bool IsFor(ICallSpecification spec) => _callSpecification == spec; + public void UpdateCallSpecification(ICallSpecification spec) => _callSpecification = spec; } } diff --git a/src/NSubstitute/Core/CallBaseConfiguration.cs b/src/NSubstitute/Core/CallBaseConfiguration.cs index 19a2de5ca..d25c7a9e3 100644 --- a/src/NSubstitute/Core/CallBaseConfiguration.cs +++ b/src/NSubstitute/Core/CallBaseConfiguration.cs @@ -1,71 +1,70 @@ using System.Collections.Concurrent; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallBaseConfiguration : ICallBaseConfiguration { - public class CallBaseConfiguration : ICallBaseConfiguration + // Even though ConcurrentStack allocates on each push, we expect that configuration happens rarely. + // Stack allows us to perform reverse enumeration (which is the most common operation) cheaply. + private ConcurrentStack Rules { get; } = new(); + + /// + public bool CallBaseByDefault { get; set; } + + /// + public void Exclude(ICallSpecification callSpecification) { - // Even though ConcurrentStack allocates on each push, we expect that configuration happens rarely. - // Stack allows us to perform reverse enumeration (which is the most common operation) cheaply. - private ConcurrentStack Rules { get; } = new(); + Rules.Push(new CallBaseRule(callSpecification, callBase: false)); + } - /// - public bool CallBaseByDefault { get; set; } + /// + public void Include(ICallSpecification callSpecification) + { + Rules.Push(new CallBaseRule(callSpecification, callBase: true)); + } - /// - public void Exclude(ICallSpecification callSpecification) - { - Rules.Push(new CallBaseRule(callSpecification, callBase: false)); - } + /// + public bool ShouldCallBase(ICall call) + { + return TryGetExplicitConfiguration(call, out bool callBase) + ? callBase + : CallBaseByDefault; + } - /// - public void Include(ICallSpecification callSpecification) - { - Rules.Push(new CallBaseRule(callSpecification, callBase: true)); - } + private bool TryGetExplicitConfiguration(ICall call, out bool callBase) + { + callBase = default; - /// - public bool ShouldCallBase(ICall call) + // Performance optimization, as enumerator retrieval allocates. + if (Rules.IsEmpty) { - return TryGetExplicitConfiguration(call, out bool callBase) - ? callBase - : CallBaseByDefault; + return false; } - private bool TryGetExplicitConfiguration(ICall call, out bool callBase) + // Use explicit foreach instead of LINQ to improve performance (avoid delegate construction). + foreach (var rule in Rules) { - callBase = default; - - // Performance optimization, as enumerator retrieval allocates. - if (Rules.IsEmpty) - { - return false; - } - - // Use explicit foreach instead of LINQ to improve performance (avoid delegate construction). - foreach (var rule in Rules) + if (rule.IsSatisfiedBy(call)) { - if (rule.IsSatisfiedBy(call)) - { - callBase = rule.CallBase; - return true; - } + callBase = rule.CallBase; + return true; } - - return false; } - private readonly struct CallBaseRule - { - private ICallSpecification CallSpecification { get; } - public bool CallBase { get; } + return false; + } - public CallBaseRule(ICallSpecification callSpecification, bool callBase) - { - CallSpecification = callSpecification; - CallBase = callBase; - } + private readonly struct CallBaseRule + { + private ICallSpecification CallSpecification { get; } + public bool CallBase { get; } - public bool IsSatisfiedBy(ICall call) => CallSpecification.IsSatisfiedBy(call); + public CallBaseRule(ICallSpecification callSpecification, bool callBase) + { + CallSpecification = callSpecification; + CallBase = callBase; } + + public bool IsSatisfiedBy(ICall call) => CallSpecification.IsSatisfiedBy(call); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallCollection.cs b/src/NSubstitute/Core/CallCollection.cs index 5260d015f..1c5f4e75b 100644 --- a/src/NSubstitute/Core/CallCollection.cs +++ b/src/NSubstitute/Core/CallCollection.cs @@ -2,86 +2,85 @@ using System.Diagnostics.CodeAnalysis; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallCollection : ICallCollection { - public class CallCollection : ICallCollection - { - private ConcurrentQueue _callEntries = new(); + private ConcurrentQueue _callEntries = new(); - public void Add(ICall call) + public void Add(ICall call) + { + IReceivedCallEntry callEntry; + if (call is IReceivedCallEntry callAsEntry && callAsEntry.TryTakeEntryOwnership()) { - IReceivedCallEntry callEntry; - if (call is IReceivedCallEntry callAsEntry && callAsEntry.TryTakeEntryOwnership()) - { - callEntry = callAsEntry; - } - else - { - callEntry = new ReceivedCallEntry(call); - } - - _callEntries.Enqueue(callEntry); + callEntry = callAsEntry; } - - public void Delete(ICall call) + else { - var callWrapper = _callEntries.FirstOrDefault(e => !e.IsSkipped && call.Equals(e.Call)); - if (callWrapper == null) - { - throw new SubstituteInternalException("CallCollection.Delete - collection doesn't contain the call"); - } - - callWrapper.Skip(); + callEntry = new ReceivedCallEntry(call); } - public IEnumerable AllCalls() - { - return _callEntries - .Where(e => !e.IsSkipped) - .Select(e => e.Call!) - .ToArray(); - } + _callEntries.Enqueue(callEntry); + } - public void Clear() + public void Delete(ICall call) + { + var callWrapper = _callEntries.FirstOrDefault(e => !e.IsSkipped && call.Equals(e.Call)); + if (callWrapper == null) { - // Queue doesn't have a Clear method. - _callEntries = new ConcurrentQueue(); + throw new SubstituteInternalException("CallCollection.Delete - collection doesn't contain the call"); } - /// - /// Performance optimization. Allows to mark call as deleted without allocating extra wrapper. - /// To play safely, we track ownership, so object can be re-used only once. - /// - internal interface IReceivedCallEntry - { - ICall? Call { get; } - [MemberNotNullWhen(false, nameof(Call))] - bool IsSkipped { get; } - void Skip(); - bool TryTakeEntryOwnership(); - } + callWrapper.Skip(); + } - /// - /// Wrapper to track that particular entry was deleted. - /// That is needed because concurrent collections don't have a Delete method. - /// Notice, in most cases the original instance will be used as a wrapper itself. - /// - private class ReceivedCallEntry : IReceivedCallEntry - { - public ICall? Call { get; private set; } + public IEnumerable AllCalls() + { + return _callEntries + .Where(e => !e.IsSkipped) + .Select(e => e.Call!) + .ToArray(); + } + + public void Clear() + { + // Queue doesn't have a Clear method. + _callEntries = new ConcurrentQueue(); + } - [MemberNotNullWhen(false, nameof(Call))] - public bool IsSkipped => Call == null; + /// + /// Performance optimization. Allows to mark call as deleted without allocating extra wrapper. + /// To play safely, we track ownership, so object can be re-used only once. + /// + internal interface IReceivedCallEntry + { + ICall? Call { get; } + [MemberNotNullWhen(false, nameof(Call))] + bool IsSkipped { get; } + void Skip(); + bool TryTakeEntryOwnership(); + } + + /// + /// Wrapper to track that particular entry was deleted. + /// That is needed because concurrent collections don't have a Delete method. + /// Notice, in most cases the original instance will be used as a wrapper itself. + /// + private class ReceivedCallEntry : IReceivedCallEntry + { + public ICall? Call { get; private set; } + + [MemberNotNullWhen(false, nameof(Call))] + public bool IsSkipped => Call == null; - public void Skip() => Call = null; // Null the hold value to reclaim a bit of memory. + public void Skip() => Call = null; // Null the hold value to reclaim a bit of memory. - public bool TryTakeEntryOwnership() => - throw new SubstituteInternalException("Ownership is never expected to be obtained for this entry."); + public bool TryTakeEntryOwnership() => + throw new SubstituteInternalException("Ownership is never expected to be obtained for this entry."); - public ReceivedCallEntry(ICall call) - { - Call = call; - } + public ReceivedCallEntry(ICall call) + { + Call = call; } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallFactory.cs b/src/NSubstitute/Core/CallFactory.cs index 9f4741b9c..f7c3bb2c2 100644 --- a/src/NSubstitute/Core/CallFactory.cs +++ b/src/NSubstitute/Core/CallFactory.cs @@ -1,18 +1,17 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallFactory : ICallFactory { - public class CallFactory : ICallFactory + public ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications, Func? baseMethod) { - public ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications, Func? baseMethod) - { - return new Call(methodInfo, arguments, target, argumentSpecifications, baseMethod); - } + return new Call(methodInfo, arguments, target, argumentSpecifications, baseMethod); + } - public ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications) - { - return new Call(methodInfo, arguments, target, argumentSpecifications, baseMethod: null); - } + public ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications) + { + return new Call(methodInfo, arguments, target, argumentSpecifications, baseMethod: null); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallFormatter.cs b/src/NSubstitute/Core/CallFormatter.cs index 11f64c973..246ab5415 100644 --- a/src/NSubstitute/Core/CallFormatter.cs +++ b/src/NSubstitute/Core/CallFormatter.cs @@ -1,29 +1,28 @@ using System.Reflection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallFormatter : IMethodInfoFormatter { - public class CallFormatter : IMethodInfoFormatter - { - internal static IMethodInfoFormatter Default { get; } = new CallFormatter(); + internal static IMethodInfoFormatter Default { get; } = new CallFormatter(); - private readonly IEnumerable _methodInfoFormatters; + private readonly IEnumerable _methodInfoFormatters; - public CallFormatter() - { - _methodInfoFormatters = new IMethodInfoFormatter[] { - new PropertyCallFormatter(), - new EventCallFormatter(EventCallFormatter.IsSubscription), - new EventCallFormatter(EventCallFormatter.IsUnsubscription), - new MethodFormatter() }; - } + public CallFormatter() + { + _methodInfoFormatters = new IMethodInfoFormatter[] { + new PropertyCallFormatter(), + new EventCallFormatter(EventCallFormatter.IsSubscription), + new EventCallFormatter(EventCallFormatter.IsUnsubscription), + new MethodFormatter() }; + } - public bool CanFormat(MethodInfo methodInfo) => true; + public bool CanFormat(MethodInfo methodInfo) => true; - public string Format(MethodInfo methodInfoOfCall, IEnumerable formattedArguments) - { - return _methodInfoFormatters - .First(x => x.CanFormat(methodInfoOfCall)) - .Format(methodInfoOfCall, formattedArguments); - } + public string Format(MethodInfo methodInfoOfCall, IEnumerable formattedArguments) + { + return _methodInfoFormatters + .First(x => x.CanFormat(methodInfoOfCall)) + .Format(methodInfoOfCall, formattedArguments); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallInfo.cs b/src/NSubstitute/Core/CallInfo.cs index 2635ab0ad..cd543855b 100644 --- a/src/NSubstitute/Core/CallInfo.cs +++ b/src/NSubstitute/Core/CallInfo.cs @@ -4,123 +4,122 @@ // Disable nullability for entry-point API #nullable disable annotations -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallInfo { - public class CallInfo + private readonly Argument[] _callArguments; + + public CallInfo(Argument[] callArguments) { - private readonly Argument[] _callArguments; + _callArguments = callArguments; + } - public CallInfo(Argument[] callArguments) + /// + /// Gets the nth argument to this call. + /// + /// Index of argument + /// The value of the argument at the given index + public object this[int index] + { + get => _callArguments[index].Value; + set { - _callArguments = callArguments; + var argument = _callArguments[index]; + EnsureArgIsSettable(argument, index, value); + argument.Value = value; } + } - /// - /// Gets the nth argument to this call. - /// - /// Index of argument - /// The value of the argument at the given index - public object this[int index] + private void EnsureArgIsSettable(Argument argument, int index, object value) + { + if (!argument.IsByRef) { - get => _callArguments[index].Value; - set - { - var argument = _callArguments[index]; - EnsureArgIsSettable(argument, index, value); - argument.Value = value; - } + throw new ArgumentIsNotOutOrRefException(index, argument.DeclaredType); } - private void EnsureArgIsSettable(Argument argument, int index, object value) + if (value != null && !argument.CanSetValueWithInstanceOf(value.GetType())) { - if (!argument.IsByRef) - { - throw new ArgumentIsNotOutOrRefException(index, argument.DeclaredType); - } - - if (value != null && !argument.CanSetValueWithInstanceOf(value.GetType())) - { - throw new ArgumentSetWithIncompatibleValueException(index, argument.DeclaredType, value.GetType()); - } + throw new ArgumentSetWithIncompatibleValueException(index, argument.DeclaredType, value.GetType()); } + } - /// - /// Get the arguments passed to this call. - /// - /// Array of all arguments passed to this call - public object[] Args() => _callArguments.Select(x => x.Value).ToArray(); - - /// - /// Gets the types of all the arguments passed to this call. - /// - /// Array of types of all arguments passed to this call - public Type[] ArgTypes() => _callArguments.Select(x => x.DeclaredType).ToArray(); - - /// - /// Gets the argument of type `T` passed to this call. This will throw if there are no arguments - /// of this type, or if there is more than one matching argument. - /// - /// The type of the argument to retrieve - /// The argument passed to the call, or throws if there is not exactly one argument of this type - public T Arg() - { - T arg; - if (TryGetArg(x => x.IsDeclaredTypeEqualToOrByRefVersionOf(typeof(T)), out arg)) return arg; - if (TryGetArg(x => x.IsValueAssignableTo(typeof(T)), out arg)) return arg; - throw new ArgumentNotFoundException("Can not find an argument of type " + typeof(T).FullName + " to this call."); - } + /// + /// Get the arguments passed to this call. + /// + /// Array of all arguments passed to this call + public object[] Args() => _callArguments.Select(x => x.Value).ToArray(); + + /// + /// Gets the types of all the arguments passed to this call. + /// + /// Array of types of all arguments passed to this call + public Type[] ArgTypes() => _callArguments.Select(x => x.DeclaredType).ToArray(); + + /// + /// Gets the argument of type `T` passed to this call. This will throw if there are no arguments + /// of this type, or if there is more than one matching argument. + /// + /// The type of the argument to retrieve + /// The argument passed to the call, or throws if there is not exactly one argument of this type + public T Arg() + { + T arg; + if (TryGetArg(x => x.IsDeclaredTypeEqualToOrByRefVersionOf(typeof(T)), out arg)) return arg; + if (TryGetArg(x => x.IsValueAssignableTo(typeof(T)), out arg)) return arg; + throw new ArgumentNotFoundException("Can not find an argument of type " + typeof(T).FullName + " to this call."); + } - private bool TryGetArg(Func condition, [MaybeNullWhen(false)] out T value) - { - value = default; + private bool TryGetArg(Func condition, [MaybeNullWhen(false)] out T value) + { + value = default; - var matchingArgs = _callArguments.Where(condition); - if (!matchingArgs.Any()) return false; - ThrowIfMoreThanOne(matchingArgs); + var matchingArgs = _callArguments.Where(condition); + if (!matchingArgs.Any()) return false; + ThrowIfMoreThanOne(matchingArgs); - value = (T)matchingArgs.First().Value!; - return true; - } + value = (T)matchingArgs.First().Value!; + return true; + } - private void ThrowIfMoreThanOne(IEnumerable arguments) + private void ThrowIfMoreThanOne(IEnumerable arguments) + { + if (arguments.Skip(1).Any()) { - if (arguments.Skip(1).Any()) - { - throw new AmbiguousArgumentsException( - "There is more than one argument of type " + typeof(T).FullName + " to this call.\n" + - "The call signature is (" + DisplayTypes(ArgTypes()) + ")\n" + - " and was called with (" + DisplayTypes(_callArguments.Select(x => x.ActualType)) + ")" - ); - } + throw new AmbiguousArgumentsException( + "There is more than one argument of type " + typeof(T).FullName + " to this call.\n" + + "The call signature is (" + DisplayTypes(ArgTypes()) + ")\n" + + " and was called with (" + DisplayTypes(_callArguments.Select(x => x.ActualType)) + ")" + ); } + } - /// - /// Gets the argument passed to this call at the specified zero-based position, converted to type `T`. - /// This will throw if there are no arguments, if the argument is out of range or if it - /// cannot be converted to the specified type. - /// - /// The type of the argument to retrieve - /// The zero-based position of the argument to retrieve - /// The argument passed to the call, or throws if there is not exactly one argument of this type - public T ArgAt(int position) + /// + /// Gets the argument passed to this call at the specified zero-based position, converted to type `T`. + /// This will throw if there are no arguments, if the argument is out of range or if it + /// cannot be converted to the specified type. + /// + /// The type of the argument to retrieve + /// The zero-based position of the argument to retrieve + /// The argument passed to the call, or throws if there is not exactly one argument of this type + public T ArgAt(int position) + { + if (position >= _callArguments.Length) { - if (position >= _callArguments.Length) - { - throw new ArgumentOutOfRangeException(nameof(position), $"There is no argument at position {position}"); - } - - try - { - return (T)_callArguments[position].Value!; - } - catch (InvalidCastException) - { - throw new InvalidCastException( - $"Couldn't convert parameter at position {position} to type {typeof(T).FullName}"); - } + throw new ArgumentOutOfRangeException(nameof(position), $"There is no argument at position {position}"); } - private static string DisplayTypes(IEnumerable types) => - string.Join(", ", types.Select(x => x.Name).ToArray()); + try + { + return (T)_callArguments[position].Value!; + } + catch (InvalidCastException) + { + throw new InvalidCastException( + $"Couldn't convert parameter at position {position} to type {typeof(T).FullName}"); + } } + + private static string DisplayTypes(IEnumerable types) => + string.Join(", ", types.Select(x => x.Name).ToArray()); } diff --git a/src/NSubstitute/Core/CallInfoFactory.cs b/src/NSubstitute/Core/CallInfoFactory.cs index fa7662d07..983c652e0 100644 --- a/src/NSubstitute/Core/CallInfoFactory.cs +++ b/src/NSubstitute/Core/CallInfoFactory.cs @@ -1,23 +1,22 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallInfoFactory : ICallInfoFactory { - public class CallInfoFactory : ICallInfoFactory + public CallInfo Create(ICall call) { - public CallInfo Create(ICall call) - { - var arguments = GetArgumentsFromCall(call); - return new CallInfo(arguments); - } - - private static Argument[] GetArgumentsFromCall(ICall call) - { - var result = new Argument[call.GetOriginalArguments().Length]; + var arguments = GetArgumentsFromCall(call); + return new CallInfo(arguments); + } - for (var i = 0; i < result.Length; i++) - { - result[i] = new Argument(call, i); - } + private static Argument[] GetArgumentsFromCall(ICall call) + { + var result = new Argument[call.GetOriginalArguments().Length]; - return result; + for (var i = 0; i < result.Length; i++) + { + result[i] = new Argument(call, i); } + + return result; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallResults.cs b/src/NSubstitute/Core/CallResults.cs index a97e737a4..becab0bb5 100644 --- a/src/NSubstitute/Core/CallResults.cs +++ b/src/NSubstitute/Core/CallResults.cs @@ -1,97 +1,96 @@ using System.Collections.Concurrent; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallResults : ICallResults { - public class CallResults : ICallResults + private readonly ICallInfoFactory _callInfoFactory; + // There was made a decision to use ConcurrentStack instead of ConcurrentQueue here. + // The pros is that reverse enumeration is cheap. The cons is that stack allocates on each push. + // We presume that read operations will dominate, so stack suits better. + private readonly ConcurrentStack _results; + + public CallResults(ICallInfoFactory callInfoFactory) { - private readonly ICallInfoFactory _callInfoFactory; - // There was made a decision to use ConcurrentStack instead of ConcurrentQueue here. - // The pros is that reverse enumeration is cheap. The cons is that stack allocates on each push. - // We presume that read operations will dominate, so stack suits better. - private readonly ConcurrentStack _results; + _results = new ConcurrentStack(); + _callInfoFactory = callInfoFactory; + } - public CallResults(ICallInfoFactory callInfoFactory) - { - _results = new ConcurrentStack(); - _callInfoFactory = callInfoFactory; - } + public void SetResult(ICallSpecification callSpecification, IReturn result) + { + _results.Push(new ResultForCallSpec(callSpecification, result)); + } - public void SetResult(ICallSpecification callSpecification, IReturn result) + public bool TryGetResult(ICall call, out object? result) + { + result = default; + if (ReturnsVoidFrom(call)) { - _results.Push(new ResultForCallSpec(callSpecification, result)); + return false; } - public bool TryGetResult(ICall call, out object? result) + if (!TryFindResultForCall(call, out var configuredResult)) { - result = default; - if (ReturnsVoidFrom(call)) - { - return false; - } + return false; + } - if (!TryFindResultForCall(call, out var configuredResult)) - { - return false; - } + result = configuredResult.GetResult(call, _callInfoFactory); + return true; + } - result = configuredResult.GetResult(call, _callInfoFactory); - return true; + private bool TryFindResultForCall(ICall call, out ResultForCallSpec configuredResult) + { + // Optimization for performance - enumerator makes allocation. + if (_results.IsEmpty) + { + configuredResult = default; + return false; } - private bool TryFindResultForCall(ICall call, out ResultForCallSpec configuredResult) + foreach (var result in _results) { - // Optimization for performance - enumerator makes allocation. - if (_results.IsEmpty) + if (result.IsResultFor(call)) { - configuredResult = default; - return false; + configuredResult = result; + return true; } + } - foreach (var result in _results) - { - if (result.IsResultFor(call)) - { - configuredResult = result; - return true; - } - } + configuredResult = default; + return false; + } - configuredResult = default; - return false; - } + public void Clear() + { + _results.Clear(); + } - public void Clear() - { - _results.Clear(); - } + private static bool ReturnsVoidFrom(ICall call) + { + return call.GetReturnType() == typeof(void); + } + + private readonly struct ResultForCallSpec + { + private readonly ICallSpecification _callSpecification; + private readonly IReturn _resultToReturn; - private static bool ReturnsVoidFrom(ICall call) + public ResultForCallSpec(ICallSpecification callSpecification, IReturn resultToReturn) { - return call.GetReturnType() == typeof(void); + _callSpecification = callSpecification; + _resultToReturn = resultToReturn; } - private readonly struct ResultForCallSpec + public bool IsResultFor(ICall call) => _callSpecification.IsSatisfiedBy(call); + public object? GetResult(ICall call, ICallInfoFactory callInfoFactory) { - private readonly ICallSpecification _callSpecification; - private readonly IReturn _resultToReturn; - - public ResultForCallSpec(ICallSpecification callSpecification, IReturn resultToReturn) + if (_resultToReturn is ICallIndependentReturn callIndependentReturn) { - _callSpecification = callSpecification; - _resultToReturn = resultToReturn; + return callIndependentReturn.GetReturnValue(); } - public bool IsResultFor(ICall call) => _callSpecification.IsSatisfiedBy(call); - public object? GetResult(ICall call, ICallInfoFactory callInfoFactory) - { - if (_resultToReturn is ICallIndependentReturn callIndependentReturn) - { - return callIndependentReturn.GetReturnValue(); - } - - var callInfo = callInfoFactory.Create(call); - return _resultToReturn.ReturnFor(callInfo); - } + var callInfo = callInfoFactory.Create(call); + return _resultToReturn.ReturnFor(callInfo); } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallRouter.cs b/src/NSubstitute/Core/CallRouter.cs index 9eba0e14e..05bba69aa 100644 --- a/src/NSubstitute/Core/CallRouter.cs +++ b/src/NSubstitute/Core/CallRouter.cs @@ -1,117 +1,116 @@ using NSubstitute.Exceptions; using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallRouter : ICallRouter { - public class CallRouter : ICallRouter + private readonly ISubstituteState _substituteState; + private readonly IThreadLocalContext _threadContext; + private readonly IRouteFactory _routeFactory; + private readonly bool _canConfigureBaseCalls; + + public CallRouter(ISubstituteState substituteState, IThreadLocalContext threadContext, IRouteFactory routeFactory, bool canConfigureBaseCalls) { - private readonly ISubstituteState _substituteState; - private readonly IThreadLocalContext _threadContext; - private readonly IRouteFactory _routeFactory; - private readonly bool _canConfigureBaseCalls; + _substituteState = substituteState; + _threadContext = threadContext; + _routeFactory = routeFactory; + _canConfigureBaseCalls = canConfigureBaseCalls; + } - public CallRouter(ISubstituteState substituteState, IThreadLocalContext threadContext, IRouteFactory routeFactory, bool canConfigureBaseCalls) + public bool CallBaseByDefault + { + get => _substituteState.CallBaseConfiguration.CallBaseByDefault; + set { - _substituteState = substituteState; - _threadContext = threadContext; - _routeFactory = routeFactory; - _canConfigureBaseCalls = canConfigureBaseCalls; + if (!_canConfigureBaseCalls) throw CouldNotConfigureCallBaseException.ForAllCalls(); + + _substituteState.CallBaseConfiguration.CallBaseByDefault = value; } + } - public bool CallBaseByDefault + public void Clear(ClearOptions options) + { + if ((options & ClearOptions.CallActions) == ClearOptions.CallActions) { - get => _substituteState.CallBaseConfiguration.CallBaseByDefault; - set - { - if (!_canConfigureBaseCalls) throw CouldNotConfigureCallBaseException.ForAllCalls(); - - _substituteState.CallBaseConfiguration.CallBaseByDefault = value; - } + _substituteState.CallActions.Clear(); } - - public void Clear(ClearOptions options) + if ((options & ClearOptions.ReturnValues) == ClearOptions.ReturnValues) { - if ((options & ClearOptions.CallActions) == ClearOptions.CallActions) - { - _substituteState.CallActions.Clear(); - } - if ((options & ClearOptions.ReturnValues) == ClearOptions.ReturnValues) - { - _substituteState.CallResults.Clear(); - _substituteState.ResultsForType.Clear(); - } - if ((options & ClearOptions.ReceivedCalls) == ClearOptions.ReceivedCalls) - { - _substituteState.ReceivedCalls.Clear(); - } + _substituteState.CallResults.Clear(); + _substituteState.ResultsForType.Clear(); } - - public IEnumerable ReceivedCalls() + if ((options & ClearOptions.ReceivedCalls) == ClearOptions.ReceivedCalls) { - return _substituteState.ReceivedCalls.AllCalls(); + _substituteState.ReceivedCalls.Clear(); } + } - public void SetRoute(Func getRoute) => - _threadContext.SetNextRoute(this, getRoute); + public IEnumerable ReceivedCalls() + { + return _substituteState.ReceivedCalls.AllCalls(); + } - public object? Route(ICall call) - { - _threadContext.SetLastCallRouter(this); + public void SetRoute(Func getRoute) => + _threadContext.SetNextRoute(this, getRoute); - var isQuerying = _threadContext.IsQuerying; - var pendingRaisingEventArgs = _threadContext.UsePendingRaisingEventArgumentsFactory(); - var queuedNextRouteFactory = _threadContext.UseNextRoute(this); + public object? Route(ICall call) + { + _threadContext.SetLastCallRouter(this); - IRoute routeToUse = ResolveCurrentRoute(call, isQuerying, pendingRaisingEventArgs, queuedNextRouteFactory); + var isQuerying = _threadContext.IsQuerying; + var pendingRaisingEventArgs = _threadContext.UsePendingRaisingEventArgumentsFactory(); + var queuedNextRouteFactory = _threadContext.UseNextRoute(this); - return routeToUse.Handle(call); - } + IRoute routeToUse = ResolveCurrentRoute(call, isQuerying, pendingRaisingEventArgs, queuedNextRouteFactory); - private IRoute ResolveCurrentRoute(ICall call, bool isQuerying, Func? pendingRaisingEventArgs, Func? queuedNextRouteFactory) + return routeToUse.Handle(call); + } + + private IRoute ResolveCurrentRoute(ICall call, bool isQuerying, Func? pendingRaisingEventArgs, Func? queuedNextRouteFactory) + { + if (isQuerying) { - if (isQuerying) - { - return _routeFactory.CallQuery(_substituteState); - } - - if (pendingRaisingEventArgs != null) - { - return _routeFactory.RaiseEvent(_substituteState, pendingRaisingEventArgs); - } - - if (queuedNextRouteFactory != null) - { - return queuedNextRouteFactory.Invoke(_substituteState); - } - - if (IsSpecifyingACall(call)) - { - return _routeFactory.RecordCallSpecification(_substituteState); - } - - return _routeFactory.RecordReplay(_substituteState); + return _routeFactory.CallQuery(_substituteState); } - private static bool IsSpecifyingACall(ICall call) + if (pendingRaisingEventArgs != null) { - return call.GetOriginalArguments().Length != 0 && call.GetArgumentSpecifications().Count != 0; + return _routeFactory.RaiseEvent(_substituteState, pendingRaisingEventArgs); } - public ConfiguredCall LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo) + if (queuedNextRouteFactory != null) { - return _substituteState.ConfigureCall.SetResultForLastCall(returnValue, matchArgs, pendingSpecInfo); + return queuedNextRouteFactory.Invoke(_substituteState); } - public void SetReturnForType(Type type, IReturn returnValue) + if (IsSpecifyingACall(call)) { - _substituteState.ResultsForType.SetResult(type, returnValue); + return _routeFactory.RecordCallSpecification(_substituteState); } - public void RegisterCustomCallHandlerFactory(CallHandlerFactory factory) - { - if (factory == null) throw new ArgumentNullException(nameof(factory)); + return _routeFactory.RecordReplay(_substituteState); + } - _substituteState.CustomHandlers.AddCustomHandlerFactory(factory); - } + private static bool IsSpecifyingACall(ICall call) + { + return call.GetOriginalArguments().Length != 0 && call.GetArgumentSpecifications().Count != 0; + } + + public ConfiguredCall LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo) + { + return _substituteState.ConfigureCall.SetResultForLastCall(returnValue, matchArgs, pendingSpecInfo); + } + + public void SetReturnForType(Type type, IReturn returnValue) + { + _substituteState.ResultsForType.SetResult(type, returnValue); + } + + public void RegisterCustomCallHandlerFactory(CallHandlerFactory factory) + { + if (factory == null) throw new ArgumentNullException(nameof(factory)); + + _substituteState.CustomHandlers.AddCustomHandlerFactory(factory); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallRouterFactory.cs b/src/NSubstitute/Core/CallRouterFactory.cs index ed4959b91..392008389 100644 --- a/src/NSubstitute/Core/CallRouterFactory.cs +++ b/src/NSubstitute/Core/CallRouterFactory.cs @@ -1,23 +1,22 @@ using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallRouterFactory : ICallRouterFactory { - public class CallRouterFactory : ICallRouterFactory - { - private readonly IThreadLocalContext _threadLocalContext; - private readonly IRouteFactory _routeFactory; + private readonly IThreadLocalContext _threadLocalContext; + private readonly IRouteFactory _routeFactory; - public CallRouterFactory(IThreadLocalContext threadLocalContext, IRouteFactory routeFactory) - { - _threadLocalContext = threadLocalContext; - _routeFactory = routeFactory; - } + public CallRouterFactory(IThreadLocalContext threadLocalContext, IRouteFactory routeFactory) + { + _threadLocalContext = threadLocalContext; + _routeFactory = routeFactory; + } - public ICallRouter Create(ISubstituteState substituteState, bool canConfigureBaseCalls) - { - // Cache popular routes which are bound to the particular substitute state when it's possible. - var factoryWithCachedRoutes = new RouteFactoryCacheWrapper(_routeFactory); - return new CallRouter(substituteState, _threadLocalContext, factoryWithCachedRoutes, canConfigureBaseCalls); - } + public ICallRouter Create(ISubstituteState substituteState, bool canConfigureBaseCalls) + { + // Cache popular routes which are bound to the particular substitute state when it's possible. + var factoryWithCachedRoutes = new RouteFactoryCacheWrapper(_routeFactory); + return new CallRouter(substituteState, _threadLocalContext, factoryWithCachedRoutes, canConfigureBaseCalls); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallRouterResolver.cs b/src/NSubstitute/Core/CallRouterResolver.cs index 5adac6f95..0a6d61f4a 100644 --- a/src/NSubstitute/Core/CallRouterResolver.cs +++ b/src/NSubstitute/Core/CallRouterResolver.cs @@ -1,18 +1,17 @@ using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallRouterResolver : ICallRouterResolver { - public class CallRouterResolver : ICallRouterResolver + public ICallRouter ResolveFor(object substitute) { - public ICallRouter ResolveFor(object substitute) + return substitute switch { - return substitute switch - { - null => throw new NullSubstituteReferenceException(), - ICallRouterProvider provider => provider.GetCallRouter(), - Delegate { Target: ICallRouterProvider provider } => provider.GetCallRouter(), - _ => throw new NotASubstituteException() - }; - } + null => throw new NullSubstituteReferenceException(), + ICallRouterProvider provider => provider.GetCallRouter(), + Delegate { Target: ICallRouterProvider provider } => provider.GetCallRouter(), + _ => throw new NotASubstituteException() + }; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallSpecAndTarget.cs b/src/NSubstitute/Core/CallSpecAndTarget.cs index ccdd488be..ba016f21e 100644 --- a/src/NSubstitute/Core/CallSpecAndTarget.cs +++ b/src/NSubstitute/Core/CallSpecAndTarget.cs @@ -1,14 +1,13 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallSpecAndTarget { - public class CallSpecAndTarget - { - public ICallSpecification CallSpecification { get; } - public object Target { get; } + public ICallSpecification CallSpecification { get; } + public object Target { get; } - public CallSpecAndTarget(ICallSpecification callSpecification, object target) - { - CallSpecification = callSpecification; - Target = target; - } + public CallSpecAndTarget(ICallSpecification callSpecification, object target) + { + CallSpecification = callSpecification; + Target = target; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallSpecification.cs b/src/NSubstitute/Core/CallSpecification.cs index 32660cb62..0dfa04cfe 100644 --- a/src/NSubstitute/Core/CallSpecification.cs +++ b/src/NSubstitute/Core/CallSpecification.cs @@ -1,168 +1,167 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallSpecification : ICallSpecification { - public class CallSpecification : ICallSpecification - { - private readonly MethodInfo _methodInfo; - private readonly IArgumentSpecification[] _argumentSpecifications; + private readonly MethodInfo _methodInfo; + private readonly IArgumentSpecification[] _argumentSpecifications; - public CallSpecification(MethodInfo methodInfo, IEnumerable argumentSpecifications) - { - _methodInfo = methodInfo; - _argumentSpecifications = argumentSpecifications.ToArray(); - } + public CallSpecification(MethodInfo methodInfo, IEnumerable argumentSpecifications) + { + _methodInfo = methodInfo; + _argumentSpecifications = argumentSpecifications.ToArray(); + } - public MethodInfo GetMethodInfo() => _methodInfo; + public MethodInfo GetMethodInfo() => _methodInfo; - public Type ReturnType() => _methodInfo.ReturnType; + public Type ReturnType() => _methodInfo.ReturnType; - public bool IsSatisfiedBy(ICall call) + public bool IsSatisfiedBy(ICall call) + { + if (!AreComparable(GetMethodInfo(), call.GetMethodInfo())) { - if (!AreComparable(GetMethodInfo(), call.GetMethodInfo())) - { - return false; - } - - if (HasDifferentNumberOfArguments(call)) - { - return false; - } - - if (!IsMatchingArgumentSpecifications(call)) - { - return false; - } - - return true; + return false; } - private static bool AreComparable(MethodInfo a, MethodInfo b) + if (HasDifferentNumberOfArguments(call)) { - if (a == b) - { - return true; - } - - if (a.IsGenericMethod && b.IsGenericMethod) - { - return CanCompareGenericMethods(a, b); - } - return false; } - private static bool CanCompareGenericMethods(MethodInfo a, MethodInfo b) + if (!IsMatchingArgumentSpecifications(call)) { - return - AreEquivalentDefinitions(a, b) - && TypesAreAllEquivalent(ParameterTypes(a), ParameterTypes(b)) - && TypesAreAllEquivalent(a.GetGenericArguments(), b.GetGenericArguments()); + return false; } - private static Type[] ParameterTypes(MethodInfo info) - { - return info.GetParameters().Select(p => p.ParameterType).ToArray(); - } + return true; + } - internal static bool TypesAreAllEquivalent(Type[] aArgs, Type[] bArgs) + private static bool AreComparable(MethodInfo a, MethodInfo b) + { + if (a == b) { - if (aArgs.Length != bArgs.Length) return false; - for (var i = 0; i < aArgs.Length; i++) - { - var first = aArgs[i]; - var second = bArgs[i]; - - if (first.IsGenericType && second.IsGenericType - && first.GetGenericTypeDefinition() == second.GetGenericTypeDefinition()) - { - // both are the same generic type. If their GenericTypeArguments match then they are equivalent - if (!TypesAreAllEquivalent(first.GenericTypeArguments, second.GenericTypeArguments)) - { - return false; - } - continue; - } - - var areEquivalent = first.IsAssignableFrom(second) || second.IsAssignableFrom(first) || - typeof(Arg.AnyType).IsAssignableFrom(first) || typeof(Arg.AnyType).IsAssignableFrom(second); - if (!areEquivalent) return false; - } return true; } - private static bool AreEquivalentDefinitions(MethodInfo a, MethodInfo b) + if (a.IsGenericMethod && b.IsGenericMethod) { - return a.IsGenericMethod == b.IsGenericMethod - && a.ReturnType == b.ReturnType - && a.Name.Equals(b.Name, StringComparison.Ordinal); + return CanCompareGenericMethods(a, b); } - private bool IsMatchingArgumentSpecifications(ICall call) + return false; + } + + private static bool CanCompareGenericMethods(MethodInfo a, MethodInfo b) + { + return + AreEquivalentDefinitions(a, b) + && TypesAreAllEquivalent(ParameterTypes(a), ParameterTypes(b)) + && TypesAreAllEquivalent(a.GetGenericArguments(), b.GetGenericArguments()); + } + + private static Type[] ParameterTypes(MethodInfo info) + { + return info.GetParameters().Select(p => p.ParameterType).ToArray(); + } + + internal static bool TypesAreAllEquivalent(Type[] aArgs, Type[] bArgs) + { + if (aArgs.Length != bArgs.Length) return false; + for (var i = 0; i < aArgs.Length; i++) { - object?[] arguments = call.GetOriginalArguments(); - for (int i = 0; i < arguments.Length; i++) + var first = aArgs[i]; + var second = bArgs[i]; + + if (first.IsGenericType && second.IsGenericType + && first.GetGenericTypeDefinition() == second.GetGenericTypeDefinition()) { - if (!_argumentSpecifications[i].IsSatisfiedBy(arguments[i])) + // both are the same generic type. If their GenericTypeArguments match then they are equivalent + if (!TypesAreAllEquivalent(first.GenericTypeArguments, second.GenericTypeArguments)) { return false; } + continue; } - return true; + var areEquivalent = first.IsAssignableFrom(second) || second.IsAssignableFrom(first) || + typeof(Arg.AnyType).IsAssignableFrom(first) || typeof(Arg.AnyType).IsAssignableFrom(second); + if (!areEquivalent) return false; } + return true; + } - public IEnumerable NonMatchingArguments(ICall call) - { - var arguments = call.GetOriginalArguments(); - return arguments - .Select((arg, index) => new ArgumentMatchInfo(index, arg, _argumentSpecifications[index])) - .Where(x => !x.IsMatch); - } + private static bool AreEquivalentDefinitions(MethodInfo a, MethodInfo b) + { + return a.IsGenericMethod == b.IsGenericMethod + && a.ReturnType == b.ReturnType + && a.Name.Equals(b.Name, StringComparison.Ordinal); + } - public override string ToString() + private bool IsMatchingArgumentSpecifications(ICall call) + { + object?[] arguments = call.GetOriginalArguments(); + for (int i = 0; i < arguments.Length; i++) { - var argSpecsAsStrings = _argumentSpecifications.Select(x => x.ToString() ?? string.Empty).ToArray(); - return CallFormatter.Default.Format(GetMethodInfo(), argSpecsAsStrings); + if (!_argumentSpecifications[i].IsSatisfiedBy(arguments[i])) + { + return false; + } } - public string Format(ICall call) - { - return CallFormatter.Default.Format(call.GetMethodInfo(), FormatArguments(call.GetOriginalArguments())); - } + return true; + } - private IEnumerable FormatArguments(IEnumerable arguments) - { - return arguments.Zip(_argumentSpecifications, (arg, spec) => spec.FormatArgument(arg)).ToArray(); - } + public IEnumerable NonMatchingArguments(ICall call) + { + var arguments = call.GetOriginalArguments(); + return arguments + .Select((arg, index) => new ArgumentMatchInfo(index, arg, _argumentSpecifications[index])) + .Where(x => !x.IsMatch); + } - public ICallSpecification CreateCopyThatMatchesAnyArguments() - { - var anyArgs = GetMethodInfo() - .GetParameters() - .Zip( - _argumentSpecifications, - (p, spec) => spec.CreateCopyMatchingAnyArgOfType(p.ParameterType) - ) - .ToArray(); - return new CallSpecification(GetMethodInfo(), anyArgs); - } + public override string ToString() + { + var argSpecsAsStrings = _argumentSpecifications.Select(x => x.ToString() ?? string.Empty).ToArray(); + return CallFormatter.Default.Format(GetMethodInfo(), argSpecsAsStrings); + } - public void InvokePerArgumentActions(CallInfo callInfo) - { - var arguments = callInfo.Args(); - var argSpecs = _argumentSpecifications; + public string Format(ICall call) + { + return CallFormatter.Default.Format(call.GetMethodInfo(), FormatArguments(call.GetOriginalArguments())); + } - for (var i = 0; i < arguments.Length; i++) - { - argSpecs[i].RunAction(arguments[i]); - } - } + private IEnumerable FormatArguments(IEnumerable arguments) + { + return arguments.Zip(_argumentSpecifications, (arg, spec) => spec.FormatArgument(arg)).ToArray(); + } + + public ICallSpecification CreateCopyThatMatchesAnyArguments() + { + var anyArgs = GetMethodInfo() + .GetParameters() + .Zip( + _argumentSpecifications, + (p, spec) => spec.CreateCopyMatchingAnyArgOfType(p.ParameterType) + ) + .ToArray(); + return new CallSpecification(GetMethodInfo(), anyArgs); + } - private bool HasDifferentNumberOfArguments(ICall call) + public void InvokePerArgumentActions(CallInfo callInfo) + { + var arguments = callInfo.Args(); + var argSpecs = _argumentSpecifications; + + for (var i = 0; i < arguments.Length; i++) { - return _argumentSpecifications.Length != call.GetOriginalArguments().Length; + argSpecs[i].RunAction(arguments[i]); } } + + private bool HasDifferentNumberOfArguments(ICall call) + { + return _argumentSpecifications.Length != call.GetOriginalArguments().Length; + } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CallSpecificationFactory.cs b/src/NSubstitute/Core/CallSpecificationFactory.cs index 22ccb4c72..d37e8e52f 100644 --- a/src/NSubstitute/Core/CallSpecificationFactory.cs +++ b/src/NSubstitute/Core/CallSpecificationFactory.cs @@ -1,24 +1,23 @@ using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CallSpecificationFactory : ICallSpecificationFactory { - public class CallSpecificationFactory : ICallSpecificationFactory - { - private readonly IArgumentSpecificationsFactory _argumentSpecificationsFactory; + private readonly IArgumentSpecificationsFactory _argumentSpecificationsFactory; - public CallSpecificationFactory(IArgumentSpecificationsFactory argumentSpecificationsFactory) - { - _argumentSpecificationsFactory = argumentSpecificationsFactory; - } + public CallSpecificationFactory(IArgumentSpecificationsFactory argumentSpecificationsFactory) + { + _argumentSpecificationsFactory = argumentSpecificationsFactory; + } - public ICallSpecification CreateFrom(ICall call, MatchArgs matchArgs) - { - var methodInfo = call.GetMethodInfo(); - var argumentSpecs = call.GetArgumentSpecifications(); - var arguments = call.GetOriginalArguments(); - var parameterInfos = call.GetParameterInfos(); - var argumentSpecificationsForCall = _argumentSpecificationsFactory.Create(argumentSpecs, arguments, parameterInfos, methodInfo, matchArgs); - return new CallSpecification(methodInfo, argumentSpecificationsForCall); - } + public ICallSpecification CreateFrom(ICall call, MatchArgs matchArgs) + { + var methodInfo = call.GetMethodInfo(); + var argumentSpecs = call.GetArgumentSpecifications(); + var arguments = call.GetOriginalArguments(); + var parameterInfos = call.GetParameterInfos(); + var argumentSpecificationsForCall = _argumentSpecificationsFactory.Create(argumentSpecs, arguments, parameterInfos, methodInfo, matchArgs); + return new CallSpecification(methodInfo, argumentSpecificationsForCall); } } diff --git a/src/NSubstitute/Core/CallSpecificationFactoryFactoryYesThatsRight.cs b/src/NSubstitute/Core/CallSpecificationFactoryFactoryYesThatsRight.cs index b47483d14..abf0f2b29 100644 --- a/src/NSubstitute/Core/CallSpecificationFactoryFactoryYesThatsRight.cs +++ b/src/NSubstitute/Core/CallSpecificationFactoryFactoryYesThatsRight.cs @@ -1,15 +1,14 @@ using NSubstitute.Core.DependencyInjection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public static class CallSpecificationFactoryFactoryYesThatsRight { - public static class CallSpecificationFactoryFactoryYesThatsRight - { - [Obsolete("This factory is deprecated and will be removed in future versions of the product. " + - "Please use '" + nameof(SubstitutionContext) + "." + nameof(SubstitutionContext.Current) + "." + - nameof(SubstitutionContext.Current.CallSpecificationFactory) + "' instead. " + - "Use " + nameof(NSubstituteDefaultFactory) + " services if you need to activate a new instance.")] - // ReSharper disable once UnusedMember.Global - is left for API compatibility from other libraries. - public static ICallSpecificationFactory CreateCallSpecFactory() => - NSubstituteDefaultFactory.DefaultContainer.Resolve(); - } + [Obsolete("This factory is deprecated and will be removed in future versions of the product. " + + "Please use '" + nameof(SubstitutionContext) + "." + nameof(SubstitutionContext.Current) + "." + + nameof(SubstitutionContext.Current.CallSpecificationFactory) + "' instead. " + + "Use " + nameof(NSubstituteDefaultFactory) + " services if you need to activate a new instance.")] + // ReSharper disable once UnusedMember.Global - is left for API compatibility from other libraries. + public static ICallSpecificationFactory CreateCallSpecFactory() => + NSubstituteDefaultFactory.DefaultContainer.Resolve(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ConfigureCall.cs b/src/NSubstitute/Core/ConfigureCall.cs index 8904ae694..7ea684d14 100644 --- a/src/NSubstitute/Core/ConfigureCall.cs +++ b/src/NSubstitute/Core/ConfigureCall.cs @@ -1,42 +1,41 @@ using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class ConfigureCall : IConfigureCall { - public class ConfigureCall : IConfigureCall - { - private readonly ICallResults _configuredResults; - private readonly ICallActions _callActions; - private readonly IGetCallSpec _getCallSpec; + private readonly ICallResults _configuredResults; + private readonly ICallActions _callActions; + private readonly IGetCallSpec _getCallSpec; - public ConfigureCall(ICallResults configuredResults, ICallActions callActions, IGetCallSpec getCallSpec) - { - _configuredResults = configuredResults; - _callActions = callActions; - _getCallSpec = getCallSpec; - } + public ConfigureCall(ICallResults configuredResults, ICallActions callActions, IGetCallSpec getCallSpec) + { + _configuredResults = configuredResults; + _callActions = callActions; + _getCallSpec = getCallSpec; + } - public ConfiguredCall SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo) - { - var spec = _getCallSpec.FromPendingSpecification(matchArgs, pendingSpecInfo); - CheckResultIsCompatibleWithCall(valueToReturn, spec); - _configuredResults.SetResult(spec, valueToReturn); - return new ConfiguredCall(action => _callActions.Add(spec, action)); - } + public ConfiguredCall SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo) + { + var spec = _getCallSpec.FromPendingSpecification(matchArgs, pendingSpecInfo); + CheckResultIsCompatibleWithCall(valueToReturn, spec); + _configuredResults.SetResult(spec, valueToReturn); + return new ConfiguredCall(action => _callActions.Add(spec, action)); + } - public void SetResultForCall(ICall call, IReturn valueToReturn, MatchArgs matchArgs) - { - var spec = _getCallSpec.FromCall(call, matchArgs); - CheckResultIsCompatibleWithCall(valueToReturn, spec); - _configuredResults.SetResult(spec, valueToReturn); - } + public void SetResultForCall(ICall call, IReturn valueToReturn, MatchArgs matchArgs) + { + var spec = _getCallSpec.FromCall(call, matchArgs); + CheckResultIsCompatibleWithCall(valueToReturn, spec); + _configuredResults.SetResult(spec, valueToReturn); + } - private static void CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec) + private static void CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec) + { + var requiredReturnType = spec.ReturnType(); + if (!valueToReturn.CanBeAssignedTo(requiredReturnType)) { - var requiredReturnType = spec.ReturnType(); - if (!valueToReturn.CanBeAssignedTo(requiredReturnType)) - { - throw new CouldNotSetReturnDueToTypeMismatchException(valueToReturn.TypeOrNull(), spec.GetMethodInfo()); - } + throw new CouldNotSetReturnDueToTypeMismatchException(valueToReturn.TypeOrNull(), spec.GetMethodInfo()); } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/ConfiguredCall.cs b/src/NSubstitute/Core/ConfiguredCall.cs index c261a30fb..ebc6ad5b9 100644 --- a/src/NSubstitute/Core/ConfiguredCall.cs +++ b/src/NSubstitute/Core/ConfiguredCall.cs @@ -1,26 +1,25 @@ // Disable nullability for entry-point API #nullable disable annotations -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class ConfiguredCall { - public class ConfiguredCall - { - private readonly Action> _addAction; + private readonly Action> _addAction; - public ConfiguredCall(Action> addAction) - { - _addAction = addAction; - } + public ConfiguredCall(Action> addAction) + { + _addAction = addAction; + } - /// - /// Adds a callback to execute for matching calls. - /// - /// an action to call - /// - public ConfiguredCall AndDoes(Action action) - { - _addAction(action); - return this; - } + /// + /// Adds a callback to execute for matching calls. + /// + /// an action to call + /// + public ConfiguredCall AndDoes(Action action) + { + _addAction(action); + return this; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/CustomHandlers.cs b/src/NSubstitute/Core/CustomHandlers.cs index c601ae405..882e8aa59 100644 --- a/src/NSubstitute/Core/CustomHandlers.cs +++ b/src/NSubstitute/Core/CustomHandlers.cs @@ -1,20 +1,19 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class CustomHandlers : ICustomHandlers { - public class CustomHandlers : ICustomHandlers - { - private readonly List _handlers = new(); - private readonly ISubstituteState _substituteState; + private readonly List _handlers = new(); + private readonly ISubstituteState _substituteState; - public IReadOnlyCollection Handlers => _handlers; + public IReadOnlyCollection Handlers => _handlers; - public CustomHandlers(ISubstituteState substituteState) - { - _substituteState = substituteState; - } + public CustomHandlers(ISubstituteState substituteState) + { + _substituteState = substituteState; + } - public void AddCustomHandlerFactory(CallHandlerFactory factory) - { - _handlers.Add(factory.Invoke(_substituteState)); - } + public void AddCustomHandlerFactory(CallHandlerFactory factory) + { + _handlers.Add(factory.Invoke(_substituteState)); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/DefaultForType.cs b/src/NSubstitute/Core/DefaultForType.cs index 37fa851bf..f1fde93a4 100644 --- a/src/NSubstitute/Core/DefaultForType.cs +++ b/src/NSubstitute/Core/DefaultForType.cs @@ -1,52 +1,51 @@ using System.Reflection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class DefaultForType : IDefaultForType { - public class DefaultForType : IDefaultForType - { - private static readonly object BoxedBoolean = default(bool); - private static readonly object BoxedInt = default(int); - private static readonly object BoxedLong = default(long); - private static readonly object BoxedDouble = default(double); + private static readonly object BoxedBoolean = default(bool); + private static readonly object BoxedInt = default(int); + private static readonly object BoxedLong = default(long); + private static readonly object BoxedDouble = default(double); - public object? GetDefaultFor(Type type) + public object? GetDefaultFor(Type type) + { + if (IsVoid(type)) { - if (IsVoid(type)) - { - return null; - } - - if (type.GetTypeInfo().IsValueType) - { - return DefaultInstanceOfValueType(type); - } - return null; } - private bool IsVoid(Type returnType) => returnType == typeof(void); + if (type.GetTypeInfo().IsValueType) + { + return DefaultInstanceOfValueType(type); + } + + return null; + } + + private bool IsVoid(Type returnType) => returnType == typeof(void); - private object DefaultInstanceOfValueType(Type returnType) + private object DefaultInstanceOfValueType(Type returnType) + { + // Performance optimization for the most popular types. + if (returnType == typeof(bool)) { - // Performance optimization for the most popular types. - if (returnType == typeof(bool)) - { - return BoxedBoolean; - } - if (returnType == typeof(int)) - { - return BoxedInt; - } - if (returnType == typeof(long)) - { - return BoxedLong; - } - if (returnType == typeof(double)) - { - return BoxedDouble; - } - - return Activator.CreateInstance(returnType)!; + return BoxedBoolean; } + if (returnType == typeof(int)) + { + return BoxedInt; + } + if (returnType == typeof(long)) + { + return BoxedLong; + } + if (returnType == typeof(double)) + { + return BoxedDouble; + } + + return Activator.CreateInstance(returnType)!; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/DependencyInjection/INSubContainer.cs b/src/NSubstitute/Core/DependencyInjection/INSubContainer.cs index f456261fb..6a1f95fed 100644 --- a/src/NSubstitute/Core/DependencyInjection/INSubContainer.cs +++ b/src/NSubstitute/Core/DependencyInjection/INSubContainer.cs @@ -1,63 +1,62 @@ -namespace NSubstitute.Core.DependencyInjection +namespace NSubstitute.Core.DependencyInjection; + +public interface INSubResolver { - public interface INSubResolver - { - T Resolve() where T : notnull; - } + T Resolve() where T : notnull; +} - public interface INSubContainer : INSubResolver +public interface INSubContainer : INSubResolver +{ + /// + /// Creates a new container based on the current one, + /// which can be configured to override the existing registrations without affecting the existing container. + /// + IConfigurableNSubContainer Customize(); + + /// + /// Create an explicit scope, so all dependencies with the lifetime + /// are preserved for multiple resolve requests. + /// + INSubResolver CreateScope(); +} + +public interface IConfigurableNSubContainer : INSubContainer +{ + IConfigurableNSubContainer Register(NSubLifetime lifetime) + where TKey : notnull + where TImpl : TKey; + + IConfigurableNSubContainer Register(Func factory, NSubLifetime lifetime) + where TKey : notnull; + + /// + /// Decorates the original implementation with a custom decorator. + /// The factory method is provided with an original implementation instance. + /// The lifetime of decorated implementation is used. + /// + IConfigurableNSubContainer Decorate(Func factory) + where TKey : notnull; +} + +public static class ConfigurableNSubContainerExtensions +{ + public static IConfigurableNSubContainer RegisterPerScope(this IConfigurableNSubContainer container) + where TKey : notnull + where TImpl : TKey { - /// - /// Creates a new container based on the current one, - /// which can be configured to override the existing registrations without affecting the existing container. - /// - IConfigurableNSubContainer Customize(); - - /// - /// Create an explicit scope, so all dependencies with the lifetime - /// are preserved for multiple resolve requests. - /// - INSubResolver CreateScope(); + return container.Register(NSubLifetime.PerScope); } - public interface IConfigurableNSubContainer : INSubContainer + public static IConfigurableNSubContainer RegisterPerScope(this IConfigurableNSubContainer container, Func factory) + where TKey : notnull { - IConfigurableNSubContainer Register(NSubLifetime lifetime) - where TKey : notnull - where TImpl : TKey; - - IConfigurableNSubContainer Register(Func factory, NSubLifetime lifetime) - where TKey : notnull; - - /// - /// Decorates the original implementation with a custom decorator. - /// The factory method is provided with an original implementation instance. - /// The lifetime of decorated implementation is used. - /// - IConfigurableNSubContainer Decorate(Func factory) - where TKey : notnull; + return container.Register(factory, NSubLifetime.PerScope); } - public static class ConfigurableNSubContainerExtensions + public static IConfigurableNSubContainer RegisterSingleton(this IConfigurableNSubContainer container) + where TKey : notnull + where TImpl : TKey { - public static IConfigurableNSubContainer RegisterPerScope(this IConfigurableNSubContainer container) - where TKey : notnull - where TImpl : TKey - { - return container.Register(NSubLifetime.PerScope); - } - - public static IConfigurableNSubContainer RegisterPerScope(this IConfigurableNSubContainer container, Func factory) - where TKey : notnull - { - return container.Register(factory, NSubLifetime.PerScope); - } - - public static IConfigurableNSubContainer RegisterSingleton(this IConfigurableNSubContainer container) - where TKey : notnull - where TImpl : TKey - { - return container.Register(NSubLifetime.Singleton); - } + return container.Register(NSubLifetime.Singleton); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/DependencyInjection/NSubContainer.cs b/src/NSubstitute/Core/DependencyInjection/NSubContainer.cs index 88a6619bf..1d519ecba 100644 --- a/src/NSubstitute/Core/DependencyInjection/NSubContainer.cs +++ b/src/NSubstitute/Core/DependencyInjection/NSubContainer.cs @@ -1,224 +1,223 @@ using System.Diagnostics.CodeAnalysis; -namespace NSubstitute.Core.DependencyInjection +namespace NSubstitute.Core.DependencyInjection; + +/// +/// Tiny and very limited implementation of the DI services. +/// Container supports the following features required by NSubstitute: +/// - Registration by type with automatic constructor injection +/// - Registration of factory methods for the complex objects +/// - Support of the most required lifetimes: +/// - +/// - +/// - +/// - Immutability (via interfaces) and customization by creating a nested container +/// +public class NSubContainer : IConfigurableNSubContainer { - /// - /// Tiny and very limited implementation of the DI services. - /// Container supports the following features required by NSubstitute: - /// - Registration by type with automatic constructor injection - /// - Registration of factory methods for the complex objects - /// - Support of the most required lifetimes: - /// - - /// - - /// - - /// - Immutability (via interfaces) and customization by creating a nested container - /// - public class NSubContainer : IConfigurableNSubContainer + private readonly NSubContainer? _parentContainer; + private readonly object _syncRoot; + private readonly Dictionary _registrations = new(); + + public NSubContainer() { - private readonly NSubContainer? _parentContainer; - private readonly object _syncRoot; - private readonly Dictionary _registrations = new(); + _syncRoot = new object(); + } - public NSubContainer() - { - _syncRoot = new object(); - } + private NSubContainer(NSubContainer parentContainer) + { + _parentContainer = parentContainer; - private NSubContainer(NSubContainer parentContainer) - { - _parentContainer = parentContainer; + // Use the same synchronization object in descendant containers. + // It's required to e.g. ensure that singleton dependencies are resolved only once. + _syncRoot = parentContainer._syncRoot; + } + + public T Resolve() where T : notnull => CreateScope().Resolve(); - // Use the same synchronization object in descendant containers. - // It's required to e.g. ensure that singleton dependencies are resolved only once. - _syncRoot = parentContainer._syncRoot; + public IConfigurableNSubContainer Register(NSubLifetime lifetime) + where TKey : notnull + where TImpl : TKey + { + var constructors = typeof(TImpl).GetConstructors(); + if (constructors.Length != 1) + { + throw new ArgumentException( + $"Type '{typeof(TImpl).FullName}' should contain only single public constructor. " + + $"Please register type using factory method to avoid ambiguity."); } - public T Resolve() where T : notnull => CreateScope().Resolve(); + var ctor = constructors[0]; - public IConfigurableNSubContainer Register(NSubLifetime lifetime) - where TKey : notnull - where TImpl : TKey + object Factory(Scope scope) { - var constructors = typeof(TImpl).GetConstructors(); - if (constructors.Length != 1) - { - throw new ArgumentException( - $"Type '{typeof(TImpl).FullName}' should contain only single public constructor. " + - $"Please register type using factory method to avoid ambiguity."); - } - - var ctor = constructors[0]; + var args = ctor.GetParameters() + .Select(p => scope.Resolve(p.ParameterType)) + .ToArray(); + return ctor.Invoke(args); + } - object Factory(Scope scope) - { - var args = ctor.GetParameters() - .Select(p => scope.Resolve(p.ParameterType)) - .ToArray(); - return ctor.Invoke(args); - } + SetRegistration(typeof(TKey), new Registration(Factory, lifetime)); - SetRegistration(typeof(TKey), new Registration(Factory, lifetime)); + return this; + } - return this; + public IConfigurableNSubContainer Register(Func factory, NSubLifetime lifetime) + where TKey : notnull + { + object Factory(Scope scope) + { + return factory.Invoke(scope); } - public IConfigurableNSubContainer Register(Func factory, NSubLifetime lifetime) - where TKey : notnull - { - object Factory(Scope scope) - { - return factory.Invoke(scope); - } + SetRegistration(typeof(TKey), new Registration(Factory, lifetime)); - SetRegistration(typeof(TKey), new Registration(Factory, lifetime)); + return this; + } - return this; + public IConfigurableNSubContainer Decorate(Func factory) + where TKey : notnull + { + Registration? existingRegistration = TryFindRegistration(typeof(TKey)); + if (existingRegistration == null) + { + throw new ArgumentException("Cannot decorate type " + typeof(TKey).FullName + " as implementation is not registered."); } - public IConfigurableNSubContainer Decorate(Func factory) - where TKey : notnull + object Factory(Scope scope) { - Registration? existingRegistration = TryFindRegistration(typeof(TKey)); - if (existingRegistration == null) - { - throw new ArgumentException("Cannot decorate type " + typeof(TKey).FullName + " as implementation is not registered."); - } - - object Factory(Scope scope) - { - // Freeze original registration discovered during decoration. - // This way we avoid recursion and support nested decorators. - var originalInstance = (TKey)scope.Resolve(existingRegistration); - return factory.Invoke(originalInstance, scope); - } + // Freeze original registration discovered during decoration. + // This way we avoid recursion and support nested decorators. + var originalInstance = (TKey)scope.Resolve(existingRegistration); + return factory.Invoke(originalInstance, scope); + } - SetRegistration(typeof(TKey), new Registration(Factory, existingRegistration.Lifetime)); + SetRegistration(typeof(TKey), new Registration(Factory, existingRegistration.Lifetime)); - return this; - } + return this; + } - public IConfigurableNSubContainer Customize() - { - return new NSubContainer(this); - } + public IConfigurableNSubContainer Customize() + { + return new NSubContainer(this); + } - public INSubResolver CreateScope() - { - return new Scope(this); - } + public INSubResolver CreateScope() + { + return new Scope(this); + } - private void SetRegistration(Type type, Registration registration) + private void SetRegistration(Type type, Registration registration) + { + lock (_syncRoot) { - lock (_syncRoot) - { - _registrations[type] = registration; - } + _registrations[type] = registration; } + } - private Registration? TryFindRegistration(Type type) + private Registration? TryFindRegistration(Type type) + { + // Both read and write accesses to dictionary should be synchronized. + // The same lock object is shared among all the nested containers, + // so we synchronize across the whole containers graph. + lock (_syncRoot) { - // Both read and write accesses to dictionary should be synchronized. - // The same lock object is shared among all the nested containers, - // so we synchronize across the whole containers graph. - lock (_syncRoot) + var currentContainer = this; + while (currentContainer != null) { - var currentContainer = this; - while (currentContainer != null) + if (currentContainer._registrations.TryGetValue(type, out var registration)) { - if (currentContainer._registrations.TryGetValue(type, out var registration)) - { - return registration; - } - - currentContainer = currentContainer._parentContainer; + return registration; } - return null; + currentContainer = currentContainer._parentContainer; } + + return null; } + } - private class Registration - { - private readonly Func _factory; - private object? _singletonValue; - public NSubLifetime Lifetime { get; } + private class Registration + { + private readonly Func _factory; + private object? _singletonValue; + public NSubLifetime Lifetime { get; } - public Registration(Func factory, NSubLifetime lifetime) - { - _factory = factory; - Lifetime = lifetime; - } + public Registration(Func factory, NSubLifetime lifetime) + { + _factory = factory; + Lifetime = lifetime; + } - public object Resolve(Scope scope) + public object Resolve(Scope scope) + { + switch (Lifetime) { - switch (Lifetime) - { - case NSubLifetime.Transient: - return _factory.Invoke(scope); + case NSubLifetime.Transient: + return _factory.Invoke(scope); - case NSubLifetime.Singleton: - return _singletonValue ??= _factory.Invoke(scope); + case NSubLifetime.Singleton: + return _singletonValue ??= _factory.Invoke(scope); - case NSubLifetime.PerScope: - if (scope.TryGetCached(this, out var result)) - { - return result; - } - - result = _factory.Invoke(scope); - scope.Set(this, result); + case NSubLifetime.PerScope: + if (scope.TryGetCached(this, out var result)) + { return result; + } - default: - throw new InvalidOperationException("Unknown lifetime"); - } + result = _factory.Invoke(scope); + scope.Set(this, result); + return result; + + default: + throw new InvalidOperationException("Unknown lifetime"); } } + } - private class Scope : INSubResolver - { - private readonly Dictionary _cache = new Dictionary(); - private readonly NSubContainer _mostNestedContainer; + private class Scope : INSubResolver + { + private readonly Dictionary _cache = new Dictionary(); + private readonly NSubContainer _mostNestedContainer; - public Scope(NSubContainer mostNestedContainer) - { - _mostNestedContainer = mostNestedContainer; - } + public Scope(NSubContainer mostNestedContainer) + { + _mostNestedContainer = mostNestedContainer; + } - public T Resolve() where T : notnull => (T)Resolve(typeof(T)); + public T Resolve() where T : notnull => (T)Resolve(typeof(T)); - public bool TryGetCached(Registration registration, [MaybeNullWhen(false)] out object result) - { - return _cache.TryGetValue(registration, out result); - } + public bool TryGetCached(Registration registration, [MaybeNullWhen(false)] out object result) + { + return _cache.TryGetValue(registration, out result); + } - public void Set(Registration registration, object value) - { - _cache[registration] = value; - } + public void Set(Registration registration, object value) + { + _cache[registration] = value; + } - public object Resolve(Type type) + public object Resolve(Type type) + { + // The same lock object is shared among all the nested containers, + // so we synchronize across the whole containers graph. + lock (_mostNestedContainer._syncRoot) { - // The same lock object is shared among all the nested containers, - // so we synchronize across the whole containers graph. - lock (_mostNestedContainer._syncRoot) - { - Registration? registration = _mostNestedContainer.TryFindRegistration(type); - if (registration == null) - throw new InvalidOperationException($"Type is not registered: {type.FullName}"); + Registration? registration = _mostNestedContainer.TryFindRegistration(type); + if (registration == null) + throw new InvalidOperationException($"Type is not registered: {type.FullName}"); - return registration.Resolve(this); - } + return registration.Resolve(this); } + } - public object Resolve(Registration registration) + public object Resolve(Registration registration) + { + // The same lock object is shared among all the nested containers, + // so we synchronize across the whole containers graph. + lock (_mostNestedContainer._syncRoot) { - // The same lock object is shared among all the nested containers, - // so we synchronize across the whole containers graph. - lock (_mostNestedContainer._syncRoot) - { - return registration.Resolve(this); - } + return registration.Resolve(this); } } } diff --git a/src/NSubstitute/Core/DependencyInjection/NSubLifetime.cs b/src/NSubstitute/Core/DependencyInjection/NSubLifetime.cs index b304d528b..9ef63bb31 100644 --- a/src/NSubstitute/Core/DependencyInjection/NSubLifetime.cs +++ b/src/NSubstitute/Core/DependencyInjection/NSubLifetime.cs @@ -1,19 +1,18 @@ -namespace NSubstitute.Core.DependencyInjection +namespace NSubstitute.Core.DependencyInjection; + +public enum NSubLifetime { - public enum NSubLifetime - { - /// - /// Value is created only once. - /// - Singleton, - /// - /// Value is created only once per scope. Allows to share the same instance across the objects in the same graph. - /// If no explicit scope is created, an implicit scope is created per single resolve request. - /// - PerScope, - /// - /// New value is created for each time. - /// - Transient - } + /// + /// Value is created only once. + /// + Singleton, + /// + /// Value is created only once per scope. Allows to share the same instance across the objects in the same graph. + /// If no explicit scope is created, an implicit scope is created per single resolve request. + /// + PerScope, + /// + /// New value is created for each time. + /// + Transient } \ No newline at end of file diff --git a/src/NSubstitute/Core/DependencyInjection/NSubstituteDefaultFactory.cs b/src/NSubstitute/Core/DependencyInjection/NSubstituteDefaultFactory.cs index fd63ba493..c532475ec 100644 --- a/src/NSubstitute/Core/DependencyInjection/NSubstituteDefaultFactory.cs +++ b/src/NSubstitute/Core/DependencyInjection/NSubstituteDefaultFactory.cs @@ -3,44 +3,43 @@ using NSubstitute.Routing; using NSubstitute.Routing.AutoValues; -namespace NSubstitute.Core.DependencyInjection +namespace NSubstitute.Core.DependencyInjection; + +public static class NSubstituteDefaultFactory { - public static class NSubstituteDefaultFactory - { - /// - /// The default NSubstitute registrations. Feel free to configure the existing container to customize - /// and override NSubstitute parts. - /// - public static INSubContainer DefaultContainer { get; } = CreateDefaultContainer(); + /// + /// The default NSubstitute registrations. Feel free to configure the existing container to customize + /// and override NSubstitute parts. + /// + public static INSubContainer DefaultContainer { get; } = CreateDefaultContainer(); - public static ISubstitutionContext CreateSubstitutionContext() => DefaultContainer.Resolve(); + public static ISubstitutionContext CreateSubstitutionContext() => DefaultContainer.Resolve(); - private static INSubContainer CreateDefaultContainer() - { - return new NSubContainer() - .RegisterSingleton() - .RegisterPerScope() - .RegisterPerScope(r => - new ArgumentSpecificationDequeue(r.Resolve().DequeueAllArgumentSpecifications)) - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterPerScope() - .RegisterSingleton(); - } + private static INSubContainer CreateDefaultContainer() + { + return new NSubContainer() + .RegisterSingleton() + .RegisterPerScope() + .RegisterPerScope(r => + new ArgumentSpecificationDequeue(r.Resolve().DequeueAllArgumentSpecifications)) + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterPerScope() + .RegisterSingleton(); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/EventCallFormatter.cs b/src/NSubstitute/Core/EventCallFormatter.cs index 57f380e71..6494ce4f3 100644 --- a/src/NSubstitute/Core/EventCallFormatter.cs +++ b/src/NSubstitute/Core/EventCallFormatter.cs @@ -1,35 +1,34 @@ using System.Reflection; -namespace NSubstitute.Core -{ - public class EventCallFormatter : IMethodInfoFormatter - { - public static readonly Func> IsSubscription = - call => (eventInfo => eventInfo.GetAddMethod() == call); - public static readonly Func> IsUnsubscription = - call => (eventInfo => eventInfo.GetRemoveMethod() == call); +namespace NSubstitute.Core; - private readonly Func> _eventsToFormat; - private readonly string _eventOperator; +public class EventCallFormatter : IMethodInfoFormatter +{ + public static readonly Func> IsSubscription = + call => (eventInfo => eventInfo.GetAddMethod() == call); + public static readonly Func> IsUnsubscription = + call => (eventInfo => eventInfo.GetRemoveMethod() == call); - public EventCallFormatter(Func> eventsToFormat) - { - _eventsToFormat = eventsToFormat; - _eventOperator = eventsToFormat == IsSubscription ? "+=" : "-="; - } + private readonly Func> _eventsToFormat; + private readonly string _eventOperator; - public bool CanFormat(MethodInfo methodInfo) - { - return methodInfo.DeclaringType!.GetEvents().Any(x => _eventsToFormat(methodInfo)(x)); - } + public EventCallFormatter(Func> eventsToFormat) + { + _eventsToFormat = eventsToFormat; + _eventOperator = eventsToFormat == IsSubscription ? "+=" : "-="; + } - public string Format(MethodInfo methodInfo, IEnumerable arguments) - { - var eventInfo = methodInfo.DeclaringType!.GetEvents().First(x => _eventsToFormat(methodInfo)(x)); - return Format(eventInfo, _eventOperator, arguments); - } + public bool CanFormat(MethodInfo methodInfo) + { + return methodInfo.DeclaringType!.GetEvents().Any(x => _eventsToFormat(methodInfo)(x)); + } - private string Format(EventInfo eventInfo, string eventOperator, IEnumerable arguments) => - $"{eventInfo.Name} {eventOperator} {arguments.Join(", ")}"; + public string Format(MethodInfo methodInfo, IEnumerable arguments) + { + var eventInfo = methodInfo.DeclaringType!.GetEvents().First(x => _eventsToFormat(methodInfo)(x)); + return Format(eventInfo, _eventOperator, arguments); } + + private string Format(EventInfo eventInfo, string eventOperator, IEnumerable arguments) => + $"{eventInfo.Name} {eventOperator} {arguments.Join(", ")}"; } \ No newline at end of file diff --git a/src/NSubstitute/Core/EventHandlerRegistry.cs b/src/NSubstitute/Core/EventHandlerRegistry.cs index be25e656b..824859273 100644 --- a/src/NSubstitute/Core/EventHandlerRegistry.cs +++ b/src/NSubstitute/Core/EventHandlerRegistry.cs @@ -1,51 +1,50 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class EventHandlerRegistry : IEventHandlerRegistry { - public class EventHandlerRegistry : IEventHandlerRegistry - { - // Collection consideration - events are used very rarely, so it makes no sense to allocate concurrent collection. - // Events are not expected to be configured/raised concurrently, so simple locking should be sufficient. - // List lookup is O(n), but for really small size performance is comparable to dictionary. - // Given that normally a few events are configured only, it should be totally fine. - private readonly List>> _handlersForEvent = new(); + // Collection consideration - events are used very rarely, so it makes no sense to allocate concurrent collection. + // Events are not expected to be configured/raised concurrently, so simple locking should be sufficient. + // List lookup is O(n), but for really small size performance is comparable to dictionary. + // Given that normally a few events are configured only, it should be totally fine. + private readonly List>> _handlersForEvent = new(); - public void Add(string eventName, object handler) + public void Add(string eventName, object handler) + { + lock (_handlersForEvent) { - lock (_handlersForEvent) - { - Handlers(eventName).Add(handler); - } + Handlers(eventName).Add(handler); } + } - public void Remove(string eventName, object handler) + public void Remove(string eventName, object handler) + { + lock (_handlersForEvent) { - lock (_handlersForEvent) - { - Handlers(eventName).Remove(handler); - } + Handlers(eventName).Remove(handler); } + } - public IEnumerable GetHandlers(string eventName) + public IEnumerable GetHandlers(string eventName) + { + lock (_handlersForEvent) { - lock (_handlersForEvent) - { - // Make snapshot to make code thread-safe. - return Handlers(eventName).ToArray(); - } + // Make snapshot to make code thread-safe. + return Handlers(eventName).ToArray(); } + } - private List Handlers(string eventName) + private List Handlers(string eventName) + { + foreach (var pair in _handlersForEvent) { - foreach (var pair in _handlersForEvent) + if (pair.Item1 == eventName) { - if (pair.Item1 == eventName) - { - return pair.Item2; - } + return pair.Item2; } - - var newPair = Tuple.Create(eventName, new List()); - _handlersForEvent.Add(newPair); - return newPair.Item2; } + + var newPair = Tuple.Create(eventName, new List()); + _handlersForEvent.Add(newPair); + return newPair.Item2; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Events/DelegateEventWrapper.cs b/src/NSubstitute/Core/Events/DelegateEventWrapper.cs index bba465825..f2bfb3721 100644 --- a/src/NSubstitute/Core/Events/DelegateEventWrapper.cs +++ b/src/NSubstitute/Core/Events/DelegateEventWrapper.cs @@ -1,100 +1,99 @@ using System.Reflection; -namespace NSubstitute.Core.Events +namespace NSubstitute.Core.Events; + +public class DelegateEventWrapper : RaiseEventWrapper { - public class DelegateEventWrapper : RaiseEventWrapper - { - private readonly object?[] _providedArguments; - protected override string RaiseMethodName => "Raise.Event"; + private readonly object?[] _providedArguments; + protected override string RaiseMethodName => "Raise.Event"; - public DelegateEventWrapper(params object?[] arguments) - { - _providedArguments = arguments; - } + public DelegateEventWrapper(params object?[] arguments) + { + _providedArguments = arguments; + } - // Disable nullability for client API, so it does not affect clients. + // Disable nullability for client API, so it does not affect clients. #nullable disable annotations - public static implicit operator T(DelegateEventWrapper wrapper) + public static implicit operator T(DelegateEventWrapper wrapper) + { + RaiseEvent(wrapper); + return default; + } +#nullable restore annotations + + protected override object?[] WorkOutRequiredArguments(ICall call) + { + var requiredArgs = typeof(T).GetInvokeMethod().GetParameters(); + + if (_providedArguments.Length < 2 && LooksLikeAnEventStyleCall(requiredArgs)) { - RaiseEvent(wrapper); - return default; + return WorkOutSenderAndEventArgs(requiredArgs[1].ParameterType, call); } -#nullable restore annotations - protected override object?[] WorkOutRequiredArguments(ICall call) + if (!RequiredArgsHaveBeenProvided(_providedArguments, requiredArgs)) { - var requiredArgs = typeof(T).GetInvokeMethod().GetParameters(); + ThrowBecauseRequiredArgsNotProvided(requiredArgs); + } - if (_providedArguments.Length < 2 && LooksLikeAnEventStyleCall(requiredArgs)) - { - return WorkOutSenderAndEventArgs(requiredArgs[1].ParameterType, call); - } + return _providedArguments; + } - if (!RequiredArgsHaveBeenProvided(_providedArguments, requiredArgs)) - { - ThrowBecauseRequiredArgsNotProvided(requiredArgs); - } + private bool LooksLikeAnEventStyleCall(ParameterInfo[] parameters) + { + return parameters.Length == 2 && + parameters[0].ParameterType == typeof(object) && + typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType); + } - return _providedArguments; + private object?[] WorkOutSenderAndEventArgs(Type eventArgsType, ICall call) + { + object? sender; + object? eventArgs; + if (_providedArguments.Length == 0) + { + sender = call.Target(); + eventArgs = GetDefaultForEventArgType(eventArgsType); } - - private bool LooksLikeAnEventStyleCall(ParameterInfo[] parameters) + else if (_providedArguments[0].IsCompatibleWith(eventArgsType)) + { + sender = call.Target(); + eventArgs = _providedArguments[0]; + } + else { - return parameters.Length == 2 && - parameters[0].ParameterType == typeof(object) && - typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType); + sender = _providedArguments[0]; + eventArgs = GetDefaultForEventArgType(eventArgsType); } + return new[] { sender, eventArgs }; + } - private object?[] WorkOutSenderAndEventArgs(Type eventArgsType, ICall call) + private static bool RequiredArgsHaveBeenProvided(object?[] providedArgs, ParameterInfo[] requiredArgs) + { + if (providedArgs.Length != requiredArgs.Length) { - object? sender; - object? eventArgs; - if (_providedArguments.Length == 0) - { - sender = call.Target(); - eventArgs = GetDefaultForEventArgType(eventArgsType); - } - else if (_providedArguments[0].IsCompatibleWith(eventArgsType)) - { - sender = call.Target(); - eventArgs = _providedArguments[0]; - } - else - { - sender = _providedArguments[0]; - eventArgs = GetDefaultForEventArgType(eventArgsType); - } - return new[] { sender, eventArgs }; + return false; } - private static bool RequiredArgsHaveBeenProvided(object?[] providedArgs, ParameterInfo[] requiredArgs) + for (var i = 0; i < providedArgs.Length; i++) { - if (providedArgs.Length != requiredArgs.Length) + var requiredArgType = requiredArgs[i].ParameterType; + var providedArg = providedArgs[i]; + if (!providedArg.IsCompatibleWith(requiredArgType)) { return false; } - - for (var i = 0; i < providedArgs.Length; i++) - { - var requiredArgType = requiredArgs[i].ParameterType; - var providedArg = providedArgs[i]; - if (!providedArg.IsCompatibleWith(requiredArgType)) - { - return false; - } - } - - return true; } - private static void ThrowBecauseRequiredArgsNotProvided(ParameterInfo[] requiredArgs) - { - var message = string.Format( - "Cannot raise event with the provided arguments. Use Raise.Event<{0}>({1}) to raise this event.", - typeof(T).Name, - string.Join(", ", requiredArgs.Select(x => x.ParameterType.Name).ToArray())); + return true; + } - throw new ArgumentException(message); - } + private static void ThrowBecauseRequiredArgsNotProvided(ParameterInfo[] requiredArgs) + { + var message = string.Format( + "Cannot raise event with the provided arguments. Use Raise.Event<{0}>({1}) to raise this event.", + typeof(T).Name, + string.Join(", ", requiredArgs.Select(x => x.ParameterType.Name).ToArray())); + + throw new ArgumentException(message); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Events/EventHandlerWrapper.cs b/src/NSubstitute/Core/Events/EventHandlerWrapper.cs index 1c84ab10b..767784b90 100644 --- a/src/NSubstitute/Core/Events/EventHandlerWrapper.cs +++ b/src/NSubstitute/Core/Events/EventHandlerWrapper.cs @@ -1,41 +1,40 @@ -namespace NSubstitute.Core.Events +namespace NSubstitute.Core.Events; + +public class EventHandlerWrapper : RaiseEventWrapper where TEventArgs : EventArgs { - public class EventHandlerWrapper : RaiseEventWrapper where TEventArgs : EventArgs - { - private readonly object? _sender; - private readonly EventArgs? _eventArgs; - protected override string RaiseMethodName => "Raise.EventWith"; + private readonly object? _sender; + private readonly EventArgs? _eventArgs; + protected override string RaiseMethodName => "Raise.EventWith"; - public EventHandlerWrapper() : this(null, null) { } + public EventHandlerWrapper() : this(null, null) { } - public EventHandlerWrapper(EventArgs? eventArgs) : this(null, eventArgs) { } + public EventHandlerWrapper(EventArgs? eventArgs) : this(null, eventArgs) { } - public EventHandlerWrapper(object? sender, EventArgs? eventArgs) - { - _sender = sender; - _eventArgs = eventArgs; - } + public EventHandlerWrapper(object? sender, EventArgs? eventArgs) + { + _sender = sender; + _eventArgs = eventArgs; + } - // Disable nullability for client API, so it does not affect clients. + // Disable nullability for client API, so it does not affect clients. #nullable disable annotations - public static implicit operator EventHandler(EventHandlerWrapper wrapper) - { - RaiseEvent(wrapper); - return null; - } + public static implicit operator EventHandler(EventHandlerWrapper wrapper) + { + RaiseEvent(wrapper); + return null; + } - public static implicit operator EventHandler(EventHandlerWrapper wrapper) - { - RaiseEvent(wrapper); - return null; - } + public static implicit operator EventHandler(EventHandlerWrapper wrapper) + { + RaiseEvent(wrapper); + return null; + } #nullable restore annotations - protected override object[] WorkOutRequiredArguments(ICall call) - { - var sender = _sender ?? call.Target(); - var eventArgs = _eventArgs ?? GetDefaultForEventArgType(typeof(TEventArgs)); - return new[] { sender, eventArgs }; - } + protected override object[] WorkOutRequiredArguments(ICall call) + { + var sender = _sender ?? call.Target(); + var eventArgs = _eventArgs ?? GetDefaultForEventArgType(typeof(TEventArgs)); + return new[] { sender, eventArgs }; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Events/RaiseEventWrapper.cs b/src/NSubstitute/Core/Events/RaiseEventWrapper.cs index a49aad93b..4b762b7d0 100644 --- a/src/NSubstitute/Core/Events/RaiseEventWrapper.cs +++ b/src/NSubstitute/Core/Events/RaiseEventWrapper.cs @@ -1,35 +1,34 @@ using System.Reflection; using NSubstitute.Exceptions; -namespace NSubstitute.Core.Events +namespace NSubstitute.Core.Events; + +public abstract class RaiseEventWrapper { - public abstract class RaiseEventWrapper + protected abstract object?[] WorkOutRequiredArguments(ICall call); + protected abstract string RaiseMethodName { get; } + + protected EventArgs GetDefaultForEventArgType(Type type) { - protected abstract object?[] WorkOutRequiredArguments(ICall call); - protected abstract string RaiseMethodName { get; } + if (type == typeof(EventArgs)) return EventArgs.Empty; - protected EventArgs GetDefaultForEventArgType(Type type) + var defaultConstructor = GetDefaultConstructor(type); + if (defaultConstructor == null) { - if (type == typeof(EventArgs)) return EventArgs.Empty; - - var defaultConstructor = GetDefaultConstructor(type); - if (defaultConstructor == null) - { - var message = string.Format( - "Cannot create {0} for this event as it has no default constructor. " + - "Provide arguments for this event by calling {1}({0})." - , type.Name, RaiseMethodName); - throw new CannotCreateEventArgsException(message); - } - return (EventArgs)defaultConstructor.Invoke(new object[0]); + var message = string.Format( + "Cannot create {0} for this event as it has no default constructor. " + + "Provide arguments for this event by calling {1}({0})." + , type.Name, RaiseMethodName); + throw new CannotCreateEventArgsException(message); } + return (EventArgs)defaultConstructor.Invoke(new object[0]); + } - private static ConstructorInfo? GetDefaultConstructor(Type type) => type.GetConstructor(Type.EmptyTypes); + private static ConstructorInfo? GetDefaultConstructor(Type type) => type.GetConstructor(Type.EmptyTypes); - protected static void RaiseEvent(RaiseEventWrapper wrapper) - { - var context = SubstitutionContext.Current; - context.ThreadContext.SetPendingRaisingEventArgumentsFactory(call => wrapper.WorkOutRequiredArguments(call)); - } + protected static void RaiseEvent(RaiseEventWrapper wrapper) + { + var context = SubstitutionContext.Current; + context.ThreadContext.SetPendingRaisingEventArgumentsFactory(call => wrapper.WorkOutRequiredArguments(call)); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Extensions.cs b/src/NSubstitute/Core/Extensions.cs index 1778e4344..bb3a4880a 100644 --- a/src/NSubstitute/Core/Extensions.cs +++ b/src/NSubstitute/Core/Extensions.cs @@ -2,135 +2,134 @@ using System.Text; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +internal static class Extensions { - internal static class Extensions + /// + /// Checks if the instance can be used when a is expected. + /// + public static bool IsCompatibleWith(this object? instance, Type type) { - /// - /// Checks if the instance can be used when a is expected. - /// - public static bool IsCompatibleWith(this object? instance, Type type) + if (typeof(Arg.AnyType).IsAssignableFrom(type)) { - if (typeof(Arg.AnyType).IsAssignableFrom(type)) - { - return true; - } - - var requiredType = type.IsByRef ? type.GetElementType()! : type; - - if (instance == null) - { - return TypeCanBeNull(requiredType); - } - - var instanceType = instance.GetType(); - - if (instanceType.IsGenericType && type.IsGenericType - && instanceType.GetGenericTypeDefinition() == type.GetGenericTypeDefinition()) - { - // both are the same generic type. If their GenericTypeArguments match then they are equivalent - return CallSpecification.TypesAreAllEquivalent(instanceType.GenericTypeArguments, type.GenericTypeArguments); - } - - return requiredType.IsInstanceOfType(instance); + return true; } - /// - /// Join the using . - /// - public static string Join(this IEnumerable strings, string separator) => - string.Join(separator, strings); + var requiredType = type.IsByRef ? type.GetElementType()! : type; - public static bool IsDelegate(this Type type) + if (instance == null) { - // From CLR via C# (see full answer here: https://stackoverflow.com/a/4833071/2009373) - // > The System.MulticastDelegate class is derived from System.Delegate, - // > which is itself derived from System.Object. - // > The reason why there are two delegate classes is historical and unfortunate; - // > there should be just one delegate class in the FCL. - // > Sadly, you need to be aware of both of these classes - // > because even though all delegate types you create have MulticastDelegate as a base class, - // > you'll occasionally manipulate your delegate types by using methods defined by the Delegate class - // > instead of the MulticastDelegate class. - // - // Basically, MulticastDelegate and Delegate mean the same, but using MulticastDelegate for base check - // is slightly faster, as internally type.BaseType is walked in a loop and MulticastDelegate is reached faster. - return type.GetTypeInfo().IsSubclassOf(typeof(MulticastDelegate)); + return TypeCanBeNull(requiredType); } - public static MethodInfo GetInvokeMethod(this Type type) + var instanceType = instance.GetType(); + + if (instanceType.IsGenericType && type.IsGenericType + && instanceType.GetGenericTypeDefinition() == type.GetGenericTypeDefinition()) { - return type.GetMethod("Invoke") ?? throw new SubstituteInternalException("Expected delegate type"); + // both are the same generic type. If their GenericTypeArguments match then they are equivalent + return CallSpecification.TypesAreAllEquivalent(instanceType.GenericTypeArguments, type.GenericTypeArguments); } - private static bool TypeCanBeNull(Type type) + return requiredType.IsInstanceOfType(instance); + } + + /// + /// Join the using . + /// + public static string Join(this IEnumerable strings, string separator) => + string.Join(separator, strings); + + public static bool IsDelegate(this Type type) + { + // From CLR via C# (see full answer here: https://stackoverflow.com/a/4833071/2009373) + // > The System.MulticastDelegate class is derived from System.Delegate, + // > which is itself derived from System.Object. + // > The reason why there are two delegate classes is historical and unfortunate; + // > there should be just one delegate class in the FCL. + // > Sadly, you need to be aware of both of these classes + // > because even though all delegate types you create have MulticastDelegate as a base class, + // > you'll occasionally manipulate your delegate types by using methods defined by the Delegate class + // > instead of the MulticastDelegate class. + // + // Basically, MulticastDelegate and Delegate mean the same, but using MulticastDelegate for base check + // is slightly faster, as internally type.BaseType is walked in a loop and MulticastDelegate is reached faster. + return type.GetTypeInfo().IsSubclassOf(typeof(MulticastDelegate)); + } + + public static MethodInfo GetInvokeMethod(this Type type) + { + return type.GetMethod("Invoke") ?? throw new SubstituteInternalException("Expected delegate type"); + } + + private static bool TypeCanBeNull(Type type) + { + return !type.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(type) != null; + } + + public static string GetNonMangledTypeName(this Type type) + { + // Handle simple case without invoking more complex logic. + if (!type.GetTypeInfo().IsGenericType && !type.IsNested) { - return !type.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(type) != null; + return type.Name; } - public static string GetNonMangledTypeName(this Type type) + Type[] genericTypeArguments = type.GetGenericArguments(); + int alreadyHandledGenericArgumentsCount = 0; + var resultTypeName = new StringBuilder(); + + void AppendTypeNameRecursively(Type currentType) { - // Handle simple case without invoking more complex logic. - if (!type.GetTypeInfo().IsGenericType && !type.IsNested) + Type? declaringType = currentType.DeclaringType; + if (declaringType != null) { - return type.Name; + AppendTypeNameRecursively(declaringType); + resultTypeName.Append('+'); } - Type[] genericTypeArguments = type.GetGenericArguments(); - int alreadyHandledGenericArgumentsCount = 0; - var resultTypeName = new StringBuilder(); + resultTypeName.Append(GetTypeNameWithoutGenericArity(currentType)); + + // When you take the generic type arguments for a nested type, the type arguments from parent types + // are included as well. We don't want to include them again, so simply skip all the already + // handled arguments. + // Notice, we expect generic type arguments order to always be parent to child, left to right. + string[] ownGenericArguments = genericTypeArguments + .Take(currentType.GetGenericArguments().Length) + .Skip(alreadyHandledGenericArgumentsCount) + .Select(t => t.GetNonMangledTypeName()) + .ToArray(); - void AppendTypeNameRecursively(Type currentType) + if (ownGenericArguments.Length == 0) { - Type? declaringType = currentType.DeclaringType; - if (declaringType != null) - { - AppendTypeNameRecursively(declaringType); - resultTypeName.Append('+'); - } - - resultTypeName.Append(GetTypeNameWithoutGenericArity(currentType)); - - // When you take the generic type arguments for a nested type, the type arguments from parent types - // are included as well. We don't want to include them again, so simply skip all the already - // handled arguments. - // Notice, we expect generic type arguments order to always be parent to child, left to right. - string[] ownGenericArguments = genericTypeArguments - .Take(currentType.GetGenericArguments().Length) - .Skip(alreadyHandledGenericArgumentsCount) - .Select(t => t.GetNonMangledTypeName()) - .ToArray(); - - if (ownGenericArguments.Length == 0) - { - return; - } - - alreadyHandledGenericArgumentsCount += ownGenericArguments.Length; - - resultTypeName.Append('<'); - resultTypeName.Append(ownGenericArguments.Join(", ")); - resultTypeName.Append('>'); + return; } - AppendTypeNameRecursively(type); - return resultTypeName.ToString(); + alreadyHandledGenericArgumentsCount += ownGenericArguments.Length; - static string GetTypeNameWithoutGenericArity(Type type) - { - var tn = type.Name!; - var indexOfBacktick = tn.IndexOf('`'); - // For nested generic types the back stick symbol might be missing. - return indexOfBacktick > -1 ? tn.Substring(0, indexOfBacktick) : tn; - } + resultTypeName.Append('<'); + resultTypeName.Append(ownGenericArguments.Join(", ")); + resultTypeName.Append('>'); } - /// - /// Tries to cast sequence to array first before making a new array sequence. - /// - public static T[] AsArray(this IEnumerable sequence) + AppendTypeNameRecursively(type); + return resultTypeName.ToString(); + + static string GetTypeNameWithoutGenericArity(Type type) { - return sequence is T[] array ? array : sequence.ToArray(); + var tn = type.Name!; + var indexOfBacktick = tn.IndexOf('`'); + // For nested generic types the back stick symbol might be missing. + return indexOfBacktick > -1 ? tn.Substring(0, indexOfBacktick) : tn; } } + + /// + /// Tries to cast sequence to array first before making a new array sequence. + /// + public static T[] AsArray(this IEnumerable sequence) + { + return sequence is T[] array ? array : sequence.ToArray(); + } } \ No newline at end of file diff --git a/src/NSubstitute/Core/GetCallSpec.cs b/src/NSubstitute/Core/GetCallSpec.cs index b2c0bd0de..4e42d8ec3 100644 --- a/src/NSubstitute/Core/GetCallSpec.cs +++ b/src/NSubstitute/Core/GetCallSpec.cs @@ -1,44 +1,43 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class GetCallSpec : IGetCallSpec { - public class GetCallSpec : IGetCallSpec - { - private readonly ICallCollection _receivedCalls; - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly ICallActions _callActions; + private readonly ICallCollection _receivedCalls; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly ICallActions _callActions; - public GetCallSpec(ICallCollection receivedCalls, ICallSpecificationFactory callSpecificationFactory, ICallActions callActions) - { - _receivedCalls = receivedCalls; - _callSpecificationFactory = callSpecificationFactory; - _callActions = callActions; - } + public GetCallSpec(ICallCollection receivedCalls, ICallSpecificationFactory callSpecificationFactory, ICallActions callActions) + { + _receivedCalls = receivedCalls; + _callSpecificationFactory = callSpecificationFactory; + _callActions = callActions; + } - public ICallSpecification FromPendingSpecification(MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo) - { - return pendingSpecInfo.Handle( - callSpec => FromExistingSpec(callSpec, matchArgs), - lastCall => - { - _receivedCalls.Delete(lastCall); - return FromCall(lastCall, matchArgs); - }); - } + public ICallSpecification FromPendingSpecification(MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo) + { + return pendingSpecInfo.Handle( + callSpec => FromExistingSpec(callSpec, matchArgs), + lastCall => + { + _receivedCalls.Delete(lastCall); + return FromCall(lastCall, matchArgs); + }); + } - public ICallSpecification FromCall(ICall call, MatchArgs matchArgs) - { - return _callSpecificationFactory.CreateFrom(call, matchArgs); - } + public ICallSpecification FromCall(ICall call, MatchArgs matchArgs) + { + return _callSpecificationFactory.CreateFrom(call, matchArgs); + } - public ICallSpecification FromExistingSpec(ICallSpecification spec, MatchArgs matchArgs) - { - return matchArgs == MatchArgs.AsSpecifiedInCall ? spec : UpdateCallSpecToMatchAnyArgs(spec); - } + public ICallSpecification FromExistingSpec(ICallSpecification spec, MatchArgs matchArgs) + { + return matchArgs == MatchArgs.AsSpecifiedInCall ? spec : UpdateCallSpecToMatchAnyArgs(spec); + } - private ICallSpecification UpdateCallSpecToMatchAnyArgs(ICallSpecification callSpecification) - { - var anyArgCallSpec = callSpecification.CreateCopyThatMatchesAnyArguments(); - _callActions.MoveActionsForSpecToNewSpec(callSpecification, anyArgCallSpec); - return anyArgCallSpec; - } + private ICallSpecification UpdateCallSpecToMatchAnyArgs(ICallSpecification callSpecification) + { + var anyArgCallSpec = callSpecification.CreateCopyThatMatchesAnyArguments(); + _callActions.MoveActionsForSpecToNewSpec(callSpecification, anyArgCallSpec); + return anyArgCallSpec; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/IArgumentSpecificationDequeue.cs b/src/NSubstitute/Core/IArgumentSpecificationDequeue.cs index 9a20abffc..c7b7ee669 100644 --- a/src/NSubstitute/Core/IArgumentSpecificationDequeue.cs +++ b/src/NSubstitute/Core/IArgumentSpecificationDequeue.cs @@ -1,13 +1,12 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IArgumentSpecificationDequeue { - public interface IArgumentSpecificationDequeue - { - [Obsolete("This method is deprecated and will be removed in future versions of product.")] - IList DequeueAllArgumentSpecificationsForMethod(MethodInfo methodInfo); + [Obsolete("This method is deprecated and will be removed in future versions of product.")] + IList DequeueAllArgumentSpecificationsForMethod(MethodInfo methodInfo); - IList DequeueAllArgumentSpecificationsForMethod(int parametersCount); - } + IList DequeueAllArgumentSpecificationsForMethod(int parametersCount); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICall.cs b/src/NSubstitute/Core/ICall.cs index 75ace00e1..fb2fbc224 100644 --- a/src/NSubstitute/Core/ICall.cs +++ b/src/NSubstitute/Core/ICall.cs @@ -1,20 +1,19 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICall { - public interface ICall - { - Type GetReturnType(); - MethodInfo GetMethodInfo(); - object?[] GetArguments(); - object?[] GetOriginalArguments(); - object Target(); - IParameterInfo[] GetParameterInfos(); - IList GetArgumentSpecifications(); - void AssignSequenceNumber(long number); - long GetSequenceNumber(); - bool CanCallBase { get; } - Maybe TryCallBase(); - } + Type GetReturnType(); + MethodInfo GetMethodInfo(); + object?[] GetArguments(); + object?[] GetOriginalArguments(); + object Target(); + IParameterInfo[] GetParameterInfos(); + IList GetArgumentSpecifications(); + void AssignSequenceNumber(long number); + long GetSequenceNumber(); + bool CanCallBase { get; } + Maybe TryCallBase(); } diff --git a/src/NSubstitute/Core/ICallActions.cs b/src/NSubstitute/Core/ICallActions.cs index 51c158e1c..1fdabad85 100644 --- a/src/NSubstitute/Core/ICallActions.cs +++ b/src/NSubstitute/Core/ICallActions.cs @@ -1,11 +1,10 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallActions { - public interface ICallActions - { - void Add(ICallSpecification callSpecification, Action action); - void Add(ICallSpecification callSpec); - void InvokeMatchingActions(ICall callInfo); - void MoveActionsForSpecToNewSpec(ICallSpecification oldCallSpecification, ICallSpecification newCallSpecification); - void Clear(); - } + void Add(ICallSpecification callSpecification, Action action); + void Add(ICallSpecification callSpec); + void InvokeMatchingActions(ICall callInfo); + void MoveActionsForSpecToNewSpec(ICallSpecification oldCallSpecification, ICallSpecification newCallSpecification); + void Clear(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallBaseConfiguration.cs b/src/NSubstitute/Core/ICallBaseConfiguration.cs index 13037c62d..ef8de7f8f 100644 --- a/src/NSubstitute/Core/ICallBaseConfiguration.cs +++ b/src/NSubstitute/Core/ICallBaseConfiguration.cs @@ -1,27 +1,26 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallBaseConfiguration { - public interface ICallBaseConfiguration - { - /// - /// Gets or sets whether base method should be called by default. - /// - bool CallBaseByDefault { get; set; } + /// + /// Gets or sets whether base method should be called by default. + /// + bool CallBaseByDefault { get; set; } - /// - /// Specifies whether base method should be always ignored for the matching call. - /// If method is both explicitly excluded and included, base method is _not_ called. - /// - void Exclude(ICallSpecification callSpecification); + /// + /// Specifies whether base method should be always ignored for the matching call. + /// If method is both explicitly excluded and included, base method is _not_ called. + /// + void Exclude(ICallSpecification callSpecification); - /// - /// Specifies whether base method should be called for the matching call. - /// If method is both explicitly excluded and included, base method is _not_ called. - /// - void Include(ICallSpecification callSpecification); + /// + /// Specifies whether base method should be called for the matching call. + /// If method is both explicitly excluded and included, base method is _not_ called. + /// + void Include(ICallSpecification callSpecification); - /// - /// Tests whether base method should be called for the call given the existing configuration. - /// - bool ShouldCallBase(ICall call); - } + /// + /// Tests whether base method should be called for the call given the existing configuration. + /// + bool ShouldCallBase(ICall call); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallCollection.cs b/src/NSubstitute/Core/ICallCollection.cs index 6140249dd..93f63bd92 100644 --- a/src/NSubstitute/Core/ICallCollection.cs +++ b/src/NSubstitute/Core/ICallCollection.cs @@ -1,10 +1,9 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallCollection { - public interface ICallCollection - { - void Add(ICall call); - void Delete(ICall call); - IEnumerable AllCalls(); - void Clear(); - } + void Add(ICall call); + void Delete(ICall call); + IEnumerable AllCalls(); + void Clear(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallFactory.cs b/src/NSubstitute/Core/ICallFactory.cs index 4db0eee80..757e6a62f 100644 --- a/src/NSubstitute/Core/ICallFactory.cs +++ b/src/NSubstitute/Core/ICallFactory.cs @@ -1,11 +1,10 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallFactory { - public interface ICallFactory - { - ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications, Func? baseMethod); - ICall Create(MethodInfo methodInfo, object?[] getterArgs, object target, IList getArgumentSpecifications); - } + ICall Create(MethodInfo methodInfo, object?[] arguments, object target, IList argumentSpecifications, Func? baseMethod); + ICall Create(MethodInfo methodInfo, object?[] getterArgs, object target, IList getArgumentSpecifications); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallHandler.cs b/src/NSubstitute/Core/ICallHandler.cs index 4052d5a23..fd7edafa2 100644 --- a/src/NSubstitute/Core/ICallHandler.cs +++ b/src/NSubstitute/Core/ICallHandler.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallHandler { - public interface ICallHandler - { - RouteAction Handle(ICall call); - } + RouteAction Handle(ICall call); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallInfoFactory.cs b/src/NSubstitute/Core/ICallInfoFactory.cs index 664cf1dd7..59de68c78 100644 --- a/src/NSubstitute/Core/ICallInfoFactory.cs +++ b/src/NSubstitute/Core/ICallInfoFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallInfoFactory { - public interface ICallInfoFactory - { - CallInfo Create(ICall call); - } + CallInfo Create(ICall call); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallResults.cs b/src/NSubstitute/Core/ICallResults.cs index 723469155..15c532115 100644 --- a/src/NSubstitute/Core/ICallResults.cs +++ b/src/NSubstitute/Core/ICallResults.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallResults { - public interface ICallResults - { - void SetResult(ICallSpecification callSpecification, IReturn result); - bool TryGetResult(ICall call, out object? result); - void Clear(); - } + void SetResult(ICallSpecification callSpecification, IReturn result); + bool TryGetResult(ICall call, out object? result); + void Clear(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallRouter.cs b/src/NSubstitute/Core/ICallRouter.cs index baa630e6e..22aa5e1c2 100644 --- a/src/NSubstitute/Core/ICallRouter.cs +++ b/src/NSubstitute/Core/ICallRouter.cs @@ -1,25 +1,24 @@ using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallRouter { - public interface ICallRouter - { - /// - /// Specifies whether base method should be called by default. - /// - /// - /// This configuration is considered only when base method exists (e.g. you created a substitute for - /// the AbstractType with method implementation). - /// - bool CallBaseByDefault { get; set; } - ConfiguredCall LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo); - object? Route(ICall call); - IEnumerable ReceivedCalls(); - [Obsolete("This method is deprecated and will be removed in future versions of the product. " + - "Please use " + nameof(IThreadLocalContext) + "." + nameof(IThreadLocalContext.SetNextRoute) + " method instead.")] - void SetRoute(Func getRoute); - void SetReturnForType(Type type, IReturn returnValue); - void RegisterCustomCallHandlerFactory(CallHandlerFactory factory); - void Clear(ClearOptions clear); - } + /// + /// Specifies whether base method should be called by default. + /// + /// + /// This configuration is considered only when base method exists (e.g. you created a substitute for + /// the AbstractType with method implementation). + /// + bool CallBaseByDefault { get; set; } + ConfiguredCall LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo); + object? Route(ICall call); + IEnumerable ReceivedCalls(); + [Obsolete("This method is deprecated and will be removed in future versions of the product. " + + "Please use " + nameof(IThreadLocalContext) + "." + nameof(IThreadLocalContext.SetNextRoute) + " method instead.")] + void SetRoute(Func getRoute); + void SetReturnForType(Type type, IReturn returnValue); + void RegisterCustomCallHandlerFactory(CallHandlerFactory factory); + void Clear(ClearOptions clear); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallRouterFactory.cs b/src/NSubstitute/Core/ICallRouterFactory.cs index da9bfa663..764ba6c5f 100644 --- a/src/NSubstitute/Core/ICallRouterFactory.cs +++ b/src/NSubstitute/Core/ICallRouterFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallRouterFactory { - public interface ICallRouterFactory - { - ICallRouter Create(ISubstituteState substituteState, bool canConfigureBaseCalls); - } + ICallRouter Create(ISubstituteState substituteState, bool canConfigureBaseCalls); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallRouterProvider.cs b/src/NSubstitute/Core/ICallRouterProvider.cs index addacd3ef..03e2528b9 100644 --- a/src/NSubstitute/Core/ICallRouterProvider.cs +++ b/src/NSubstitute/Core/ICallRouterProvider.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallRouterProvider { - public interface ICallRouterProvider - { - ICallRouter GetCallRouter(); - } + ICallRouter GetCallRouter(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallRouterResolver.cs b/src/NSubstitute/Core/ICallRouterResolver.cs index 45919f558..476f1b1d6 100644 --- a/src/NSubstitute/Core/ICallRouterResolver.cs +++ b/src/NSubstitute/Core/ICallRouterResolver.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallRouterResolver { - public interface ICallRouterResolver - { - ICallRouter ResolveFor(object substitute); - } + ICallRouter ResolveFor(object substitute); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallSpecification.cs b/src/NSubstitute/Core/ICallSpecification.cs index 000e60a51..64375ce11 100644 --- a/src/NSubstitute/Core/ICallSpecification.cs +++ b/src/NSubstitute/Core/ICallSpecification.cs @@ -1,16 +1,15 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallSpecification { - public interface ICallSpecification - { - bool IsSatisfiedBy(ICall call); - string Format(ICall call); - ICallSpecification CreateCopyThatMatchesAnyArguments(); - void InvokePerArgumentActions(CallInfo callInfo); - IEnumerable NonMatchingArguments(ICall call); - MethodInfo GetMethodInfo(); - Type ReturnType(); - } + bool IsSatisfiedBy(ICall call); + string Format(ICall call); + ICallSpecification CreateCopyThatMatchesAnyArguments(); + void InvokePerArgumentActions(CallInfo callInfo); + IEnumerable NonMatchingArguments(ICall call); + MethodInfo GetMethodInfo(); + Type ReturnType(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICallSpecificationFactory.cs b/src/NSubstitute/Core/ICallSpecificationFactory.cs index a92998375..252bebef9 100644 --- a/src/NSubstitute/Core/ICallSpecificationFactory.cs +++ b/src/NSubstitute/Core/ICallSpecificationFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ICallSpecificationFactory { - public interface ICallSpecificationFactory - { - ICallSpecification CreateFrom(ICall call, MatchArgs matchArgs); - } + ICallSpecification CreateFrom(ICall call, MatchArgs matchArgs); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IConfigureCall.cs b/src/NSubstitute/Core/IConfigureCall.cs index d696db3a1..bcd5d3c96 100644 --- a/src/NSubstitute/Core/IConfigureCall.cs +++ b/src/NSubstitute/Core/IConfigureCall.cs @@ -1,8 +1,7 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IConfigureCall { - public interface IConfigureCall - { - ConfiguredCall SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo); - void SetResultForCall(ICall call, IReturn valueToReturn, MatchArgs matchArgs); - } + ConfiguredCall SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo); + void SetResultForCall(ICall call, IReturn valueToReturn, MatchArgs matchArgs); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ICustomHandlers.cs b/src/NSubstitute/Core/ICustomHandlers.cs index f8ab94603..cff25a039 100644 --- a/src/NSubstitute/Core/ICustomHandlers.cs +++ b/src/NSubstitute/Core/ICustomHandlers.cs @@ -1,14 +1,13 @@ -namespace NSubstitute.Core -{ - /// - /// Factory method which creates from the . - /// - public delegate ICallHandler CallHandlerFactory(ISubstituteState substituteState); +namespace NSubstitute.Core; + +/// +/// Factory method which creates from the . +/// +public delegate ICallHandler CallHandlerFactory(ISubstituteState substituteState); - public interface ICustomHandlers - { - IReadOnlyCollection Handlers { get; } +public interface ICustomHandlers +{ + IReadOnlyCollection Handlers { get; } - void AddCustomHandlerFactory(CallHandlerFactory factory); - } + void AddCustomHandlerFactory(CallHandlerFactory factory); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IDefaultForType.cs b/src/NSubstitute/Core/IDefaultForType.cs index 945c7b71b..173da0456 100644 --- a/src/NSubstitute/Core/IDefaultForType.cs +++ b/src/NSubstitute/Core/IDefaultForType.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IDefaultForType { - public interface IDefaultForType - { - object? GetDefaultFor(Type type); - } + object? GetDefaultFor(Type type); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IDescribeNonMatches.cs b/src/NSubstitute/Core/IDescribeNonMatches.cs index e3da272d5..d8ba00aa4 100644 --- a/src/NSubstitute/Core/IDescribeNonMatches.cs +++ b/src/NSubstitute/Core/IDescribeNonMatches.cs @@ -1,13 +1,12 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IDescribeNonMatches { - public interface IDescribeNonMatches - { - /// - /// Describes how the does not match the condition specified by this class, or - /// if a detailed description can not be provided for the argument. - /// - /// - /// Description of the non-match, or if no description can be provided. - string DescribeFor(object? argument); - } + /// + /// Describes how the does not match the condition specified by this class, or + /// if a detailed description can not be provided for the argument. + /// + /// + /// Description of the non-match, or if no description can be provided. + string DescribeFor(object? argument); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IEventHandlerRegistry.cs b/src/NSubstitute/Core/IEventHandlerRegistry.cs index 973635c71..6c234158c 100644 --- a/src/NSubstitute/Core/IEventHandlerRegistry.cs +++ b/src/NSubstitute/Core/IEventHandlerRegistry.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IEventHandlerRegistry { - public interface IEventHandlerRegistry - { - void Add(string eventName, object handler); - void Remove(string eventName, object handler); - IEnumerable GetHandlers(string eventName); - } + void Add(string eventName, object handler); + void Remove(string eventName, object handler); + IEnumerable GetHandlers(string eventName); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IGetCallSpec.cs b/src/NSubstitute/Core/IGetCallSpec.cs index 1375eda45..7253546ce 100644 --- a/src/NSubstitute/Core/IGetCallSpec.cs +++ b/src/NSubstitute/Core/IGetCallSpec.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IGetCallSpec { - public interface IGetCallSpec - { - ICallSpecification FromPendingSpecification(MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo); - ICallSpecification FromExistingSpec(ICallSpecification spec, MatchArgs matchArgs); - ICallSpecification FromCall(ICall call, MatchArgs matchArgs); - } + ICallSpecification FromPendingSpecification(MatchArgs matchArgs, PendingSpecificationInfo pendingSpecInfo); + ICallSpecification FromExistingSpec(ICallSpecification spec, MatchArgs matchArgs); + ICallSpecification FromCall(ICall call, MatchArgs matchArgs); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IMethodInfoFormatter.cs b/src/NSubstitute/Core/IMethodInfoFormatter.cs index d9028a141..55f54dcff 100644 --- a/src/NSubstitute/Core/IMethodInfoFormatter.cs +++ b/src/NSubstitute/Core/IMethodInfoFormatter.cs @@ -1,10 +1,9 @@ using System.Reflection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IMethodInfoFormatter { - public interface IMethodInfoFormatter - { - bool CanFormat(MethodInfo methodInfo); - string Format(MethodInfo methodInfo, IEnumerable formattedArguments); - } + bool CanFormat(MethodInfo methodInfo); + string Format(MethodInfo methodInfo, IEnumerable formattedArguments); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IParameterInfo.cs b/src/NSubstitute/Core/IParameterInfo.cs index b00da0aa3..c7fc759b3 100644 --- a/src/NSubstitute/Core/IParameterInfo.cs +++ b/src/NSubstitute/Core/IParameterInfo.cs @@ -1,10 +1,9 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IParameterInfo { - public interface IParameterInfo - { - Type ParameterType { get; } - bool IsParams { get; } - bool IsOptional { get; } - bool IsOut { get; } - } + Type ParameterType { get; } + bool IsParams { get; } + bool IsOptional { get; } + bool IsOut { get; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/IPendingSpecification.cs b/src/NSubstitute/Core/IPendingSpecification.cs index 3a026de8a..c10c5bc0b 100644 --- a/src/NSubstitute/Core/IPendingSpecification.cs +++ b/src/NSubstitute/Core/IPendingSpecification.cs @@ -1,11 +1,10 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IPendingSpecification { - public interface IPendingSpecification - { - bool HasPendingCallSpecInfo(); - PendingSpecificationInfo? UseCallSpecInfo(); - void SetCallSpecification(ICallSpecification callSpecification); - void SetLastCall(ICall lastCall); - void Clear(); - } + bool HasPendingCallSpecInfo(); + PendingSpecificationInfo? UseCallSpecInfo(); + void SetCallSpecification(ICallSpecification callSpecification); + void SetLastCall(ICall lastCall); + void Clear(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IPropertyHelper.cs b/src/NSubstitute/Core/IPropertyHelper.cs index 9266a8c66..168347d7b 100644 --- a/src/NSubstitute/Core/IPropertyHelper.cs +++ b/src/NSubstitute/Core/IPropertyHelper.cs @@ -1,8 +1,7 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IPropertyHelper { - public interface IPropertyHelper - { - bool IsCallToSetAReadWriteProperty(ICall call); - ICall CreateCallToPropertyGetterFromSetterCall(ICall callToSetter); - } + bool IsCallToSetAReadWriteProperty(ICall call); + ICall CreateCallToPropertyGetterFromSetterCall(ICall callToSetter); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IProxyFactory.cs b/src/NSubstitute/Core/IProxyFactory.cs index c03708151..541aad909 100644 --- a/src/NSubstitute/Core/IProxyFactory.cs +++ b/src/NSubstitute/Core/IProxyFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IProxyFactory { - public interface IProxyFactory - { - object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments); - } + object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IQuery.cs b/src/NSubstitute/Core/IQuery.cs index 12b1ce587..5bc377ea6 100644 --- a/src/NSubstitute/Core/IQuery.cs +++ b/src/NSubstitute/Core/IQuery.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IQuery { - public interface IQuery - { - void RegisterCall(ICall call); - } + void RegisterCall(ICall call); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IQueryResults.cs b/src/NSubstitute/Core/IQueryResults.cs index 55f74bf76..5ecce2075 100644 --- a/src/NSubstitute/Core/IQueryResults.cs +++ b/src/NSubstitute/Core/IQueryResults.cs @@ -1,8 +1,7 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IQueryResults { - public interface IQueryResults - { - IEnumerable MatchingCallsInOrder(); - IEnumerable QuerySpecification(); - } + IEnumerable MatchingCallsInOrder(); + IEnumerable QuerySpecification(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IReceivedCallsExceptionThrower.cs b/src/NSubstitute/Core/IReceivedCallsExceptionThrower.cs index e06d42629..a712907f7 100644 --- a/src/NSubstitute/Core/IReceivedCallsExceptionThrower.cs +++ b/src/NSubstitute/Core/IReceivedCallsExceptionThrower.cs @@ -1,9 +1,8 @@ using NSubstitute.ReceivedExtensions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IReceivedCallsExceptionThrower { - public interface IReceivedCallsExceptionThrower - { - void Throw(ICallSpecification callSpecification, IEnumerable matchingCalls, IEnumerable nonMatchingCalls, Quantity requiredQuantity); - } + void Throw(ICallSpecification callSpecification, IEnumerable matchingCalls, IEnumerable nonMatchingCalls, Quantity requiredQuantity); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IResultsForType.cs b/src/NSubstitute/Core/IResultsForType.cs index ceebb4f7f..720b59288 100644 --- a/src/NSubstitute/Core/IResultsForType.cs +++ b/src/NSubstitute/Core/IResultsForType.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IResultsForType { - public interface IResultsForType - { - void SetResult(Type type, IReturn resultToReturn); - bool TryGetResult(ICall call, out object? result); - void Clear(); - } + void SetResult(Type type, IReturn resultToReturn); + bool TryGetResult(ICall call, out object? result); + void Clear(); } \ No newline at end of file diff --git a/src/NSubstitute/Core/IReturn.cs b/src/NSubstitute/Core/IReturn.cs index aefb6d676..8d60c9e11 100644 --- a/src/NSubstitute/Core/IReturn.cs +++ b/src/NSubstitute/Core/IReturn.cs @@ -2,92 +2,91 @@ using System.Reflection; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IReturn { - public interface IReturn - { - object? ReturnFor(CallInfo info); - Type? TypeOrNull(); - bool CanBeAssignedTo(Type t); - } + object? ReturnFor(CallInfo info); + Type? TypeOrNull(); + bool CanBeAssignedTo(Type t); +} + +/// +/// Performance optimization. Allows to not construct if configured result doesn't depend on it. +/// +internal interface ICallIndependentReturn +{ + object? GetReturnValue(); +} - /// - /// Performance optimization. Allows to not construct if configured result doesn't depend on it. - /// - internal interface ICallIndependentReturn +public class ReturnValue : IReturn, ICallIndependentReturn +{ + private readonly object? _value; + + public ReturnValue(object? value) { - object? GetReturnValue(); + _value = value; } - public class ReturnValue : IReturn, ICallIndependentReturn - { - private readonly object? _value; + public object? GetReturnValue() => _value; + public object? ReturnFor(CallInfo info) => GetReturnValue(); + public Type? TypeOrNull() => _value?.GetType(); + public bool CanBeAssignedTo(Type t) => _value.IsCompatibleWith(t); +} - public ReturnValue(object? value) - { - _value = value; - } +public class ReturnValueFromFunc : IReturn +{ + private readonly Func _funcToReturnValue; - public object? GetReturnValue() => _value; - public object? ReturnFor(CallInfo info) => GetReturnValue(); - public Type? TypeOrNull() => _value?.GetType(); - public bool CanBeAssignedTo(Type t) => _value.IsCompatibleWith(t); + public ReturnValueFromFunc(Func? funcToReturnValue) + { + _funcToReturnValue = funcToReturnValue ?? ReturnNull(); } - public class ReturnValueFromFunc : IReturn + public object? ReturnFor(CallInfo info) => _funcToReturnValue(info); + public Type TypeOrNull() => typeof(T); + public bool CanBeAssignedTo(Type t) => typeof(T).IsAssignableFrom(t); + + private static Func ReturnNull() { - private readonly Func _funcToReturnValue; - - public ReturnValueFromFunc(Func? funcToReturnValue) - { - _funcToReturnValue = funcToReturnValue ?? ReturnNull(); - } - - public object? ReturnFor(CallInfo info) => _funcToReturnValue(info); - public Type TypeOrNull() => typeof(T); - public bool CanBeAssignedTo(Type t) => typeof(T).IsAssignableFrom(t); - - private static Func ReturnNull() - { - if (typeof(T).GetTypeInfo().IsValueType) throw new CannotReturnNullForValueType(typeof(T)); - return x => default(T); - } + if (typeof(T).GetTypeInfo().IsValueType) throw new CannotReturnNullForValueType(typeof(T)); + return x => default(T); } +} + +public class ReturnMultipleValues : IReturn, ICallIndependentReturn +{ + private readonly ConcurrentQueue _valuesToReturn; + private readonly T? _lastValue; - public class ReturnMultipleValues : IReturn, ICallIndependentReturn + public ReturnMultipleValues(T?[] values) { - private readonly ConcurrentQueue _valuesToReturn; - private readonly T? _lastValue; + _valuesToReturn = new ConcurrentQueue(values); + _lastValue = values.Last(); + } - public ReturnMultipleValues(T?[] values) - { - _valuesToReturn = new ConcurrentQueue(values); - _lastValue = values.Last(); - } + public object? GetReturnValue() => GetNext(); + public object? ReturnFor(CallInfo info) => GetReturnValue(); + public Type TypeOrNull() => typeof(T); + public bool CanBeAssignedTo(Type t) => typeof(T).IsAssignableFrom(t); - public object? GetReturnValue() => GetNext(); - public object? ReturnFor(CallInfo info) => GetReturnValue(); - public Type TypeOrNull() => typeof(T); - public bool CanBeAssignedTo(Type t) => typeof(T).IsAssignableFrom(t); + private T? GetNext() => _valuesToReturn.TryDequeue(out var nextResult) ? nextResult : _lastValue; +} - private T? GetNext() => _valuesToReturn.TryDequeue(out var nextResult) ? nextResult : _lastValue; - } +public class ReturnMultipleFuncsValues : IReturn +{ + private readonly ConcurrentQueue> _funcsToReturn; + private readonly Func _lastFunc; - public class ReturnMultipleFuncsValues : IReturn + public ReturnMultipleFuncsValues(Func[] funcs) { - private readonly ConcurrentQueue> _funcsToReturn; - private readonly Func _lastFunc; - - public ReturnMultipleFuncsValues(Func[] funcs) - { - _funcsToReturn = new ConcurrentQueue>(funcs); - _lastFunc = funcs.Last(); - } + _funcsToReturn = new ConcurrentQueue>(funcs); + _lastFunc = funcs.Last(); + } - public object? ReturnFor(CallInfo info) => GetNext(info); - public Type TypeOrNull() => typeof(T); - public bool CanBeAssignedTo(Type t) => typeof(T).IsAssignableFrom(t); + public object? ReturnFor(CallInfo info) => GetNext(info); + public Type TypeOrNull() => typeof(T); + public bool CanBeAssignedTo(Type t) => typeof(T).IsAssignableFrom(t); - private T? GetNext(CallInfo info) => _funcsToReturn.TryDequeue(out var nextFunc) ? nextFunc(info) : _lastFunc(info); - } + private T? GetNext(CallInfo info) => _funcsToReturn.TryDequeue(out var nextFunc) ? nextFunc(info) : _lastFunc(info); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ISubstituteFactory.cs b/src/NSubstitute/Core/ISubstituteFactory.cs index eb8c08cd1..8c237f690 100644 --- a/src/NSubstitute/Core/ISubstituteFactory.cs +++ b/src/NSubstitute/Core/ISubstituteFactory.cs @@ -1,8 +1,7 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ISubstituteFactory { - public interface ISubstituteFactory - { - object Create(Type[] typesToProxy, object[] constructorArguments); - object CreatePartial(Type[] typesToProxy, object[] constructorArguments); - } + object Create(Type[] typesToProxy, object[] constructorArguments); + object CreatePartial(Type[] typesToProxy, object[] constructorArguments); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ISubstituteState.cs b/src/NSubstitute/Core/ISubstituteState.cs index 5fc6ed12a..4910bb5b0 100644 --- a/src/NSubstitute/Core/ISubstituteState.cs +++ b/src/NSubstitute/Core/ISubstituteState.cs @@ -1,18 +1,17 @@ using NSubstitute.Routing.AutoValues; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ISubstituteState { - public interface ISubstituteState - { - ICallBaseConfiguration CallBaseConfiguration { get; } - ICallCollection ReceivedCalls { get; } - ICallResults CallResults { get; } - ICallActions CallActions { get; } - IConfigureCall ConfigureCall { get; } - IEventHandlerRegistry EventHandlerRegistry { get; } - IReadOnlyCollection AutoValueProviders { get; } - ICallResults AutoValuesCallResults { get; } - IResultsForType ResultsForType { get; } - ICustomHandlers CustomHandlers { get; } - } + ICallBaseConfiguration CallBaseConfiguration { get; } + ICallCollection ReceivedCalls { get; } + ICallResults CallResults { get; } + ICallActions CallActions { get; } + IConfigureCall ConfigureCall { get; } + IEventHandlerRegistry EventHandlerRegistry { get; } + IReadOnlyCollection AutoValueProviders { get; } + ICallResults AutoValuesCallResults { get; } + IResultsForType ResultsForType { get; } + ICustomHandlers CustomHandlers { get; } } diff --git a/src/NSubstitute/Core/ISubstituteStateFactory.cs b/src/NSubstitute/Core/ISubstituteStateFactory.cs index 586ad1de4..0fd32afe5 100644 --- a/src/NSubstitute/Core/ISubstituteStateFactory.cs +++ b/src/NSubstitute/Core/ISubstituteStateFactory.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ISubstituteStateFactory { - public interface ISubstituteStateFactory - { - ISubstituteState Create(ISubstituteFactory substituteFactory); - } + ISubstituteState Create(ISubstituteFactory substituteFactory); } \ No newline at end of file diff --git a/src/NSubstitute/Core/ISubstitutionContext.cs b/src/NSubstitute/Core/ISubstitutionContext.cs index 0f1294e2d..de5609d5d 100644 --- a/src/NSubstitute/Core/ISubstitutionContext.cs +++ b/src/NSubstitute/Core/ISubstitutionContext.cs @@ -1,83 +1,82 @@ using NSubstitute.Core.Arguments; using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface ISubstitutionContext { - public interface ISubstitutionContext - { - ISubstituteFactory SubstituteFactory { get; } - IRouteFactory RouteFactory { get; } - ICallSpecificationFactory CallSpecificationFactory { get; } - - /// - /// A thread bound state of the NSubstitute context. Usually this API is used to provide the fluent - /// features of the NSubstitute. - /// - IThreadLocalContext ThreadContext { get; } - - ICallRouter GetCallRouterFor(object substitute); - - [Obsolete("This property is obsolete and will be removed in a future version of the product.")] - SequenceNumberGenerator SequenceNumberGenerator { get; } - - [Obsolete("This property is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.PendingSpecification) + " property instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.PendingSpecification) + ".")] - PendingSpecificationInfo? PendingSpecificationInfo { get; set; } - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.LastCallShouldReturn) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.LastCallShouldReturn) + "(...).")] - ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetLastCallRouter) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetLastCallRouter) + "(...).")] - void LastCallRouter(ICallRouter callRouter); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "(...).")] - void EnqueueArgumentSpecification(IArgumentSpecification spec); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "().")] - IList DequeueAllArgumentSpecifications(); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "(...).")] - void RaiseEventForNextCall(Func getArguments); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "().")] - Func? DequeuePendingRaisingEventArguments(); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RunInQueryContext) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RunInQueryContext) + "(...).")] - IQueryResults RunQuery(Action calls); - - [Obsolete("This property is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.IsQuerying) + " property instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.IsQuerying) + ".")] - bool IsQuerying { get; } - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RegisterInContextQuery) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RegisterInContextQuery) + "().", - error: true)] - void AddToQuery(object target, ICallSpecification callSpecification); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.ClearLastCallRouter) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.ClearLastCallRouter) + "().")] - void ClearLastCallRouter(); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(RouteFactory) + " property instead.")] - IRouteFactory GetRouteFactory(); - } + ISubstituteFactory SubstituteFactory { get; } + IRouteFactory RouteFactory { get; } + ICallSpecificationFactory CallSpecificationFactory { get; } + + /// + /// A thread bound state of the NSubstitute context. Usually this API is used to provide the fluent + /// features of the NSubstitute. + /// + IThreadLocalContext ThreadContext { get; } + + ICallRouter GetCallRouterFor(object substitute); + + [Obsolete("This property is obsolete and will be removed in a future version of the product.")] + SequenceNumberGenerator SequenceNumberGenerator { get; } + + [Obsolete("This property is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.PendingSpecification) + " property instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.PendingSpecification) + ".")] + PendingSpecificationInfo? PendingSpecificationInfo { get; set; } + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.LastCallShouldReturn) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.LastCallShouldReturn) + "(...).")] + ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetLastCallRouter) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetLastCallRouter) + "(...).")] + void LastCallRouter(ICallRouter callRouter); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "(...).")] + void EnqueueArgumentSpecification(IArgumentSpecification spec); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "().")] + IList DequeueAllArgumentSpecifications(); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "(...).")] + void RaiseEventForNextCall(Func getArguments); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "().")] + Func? DequeuePendingRaisingEventArguments(); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RunInQueryContext) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RunInQueryContext) + "(...).")] + IQueryResults RunQuery(Action calls); + + [Obsolete("This property is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.IsQuerying) + " property instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.IsQuerying) + ".")] + bool IsQuerying { get; } + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RegisterInContextQuery) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RegisterInContextQuery) + "().", + error: true)] + void AddToQuery(object target, ICallSpecification callSpecification); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.ClearLastCallRouter) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.ClearLastCallRouter) + "().")] + void ClearLastCallRouter(); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(RouteFactory) + " property instead.")] + IRouteFactory GetRouteFactory(); } diff --git a/src/NSubstitute/Core/IThreadLocalContext.cs b/src/NSubstitute/Core/IThreadLocalContext.cs index 23ef8b4a5..5f1354d02 100644 --- a/src/NSubstitute/Core/IThreadLocalContext.cs +++ b/src/NSubstitute/Core/IThreadLocalContext.cs @@ -1,40 +1,39 @@ using NSubstitute.Core.Arguments; using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public interface IThreadLocalContext { - public interface IThreadLocalContext - { - IPendingSpecification PendingSpecification { get; } + IPendingSpecification PendingSpecification { get; } - void SetLastCallRouter(ICallRouter callRouter); - void ClearLastCallRouter(); - ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs); + void SetLastCallRouter(ICallRouter callRouter); + void ClearLastCallRouter(); + ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs); - /// - /// Sets the route to use for the next call dispatch on the current thread for the specified . - /// - void SetNextRoute(ICallRouter callRouter, Func nextRouteFactory); - /// - /// Returns the previously configured next route and resets the stored value. - /// If route was configured for the different router, returns and persist the route info. - /// - Func? UseNextRoute(ICallRouter callRouter); + /// + /// Sets the route to use for the next call dispatch on the current thread for the specified . + /// + void SetNextRoute(ICallRouter callRouter, Func nextRouteFactory); + /// + /// Returns the previously configured next route and resets the stored value. + /// If route was configured for the different router, returns and persist the route info. + /// + Func? UseNextRoute(ICallRouter callRouter); - void EnqueueArgumentSpecification(IArgumentSpecification spec); - IList DequeueAllArgumentSpecifications(); + void EnqueueArgumentSpecification(IArgumentSpecification spec); + IList DequeueAllArgumentSpecifications(); - void SetPendingRaisingEventArgumentsFactory(Func getArguments); - /// - /// Returns the previously set arguments factory and resets the stored value. - /// - Func? UsePendingRaisingEventArgumentsFactory(); + void SetPendingRaisingEventArgumentsFactory(Func getArguments); + /// + /// Returns the previously set arguments factory and resets the stored value. + /// + Func? UsePendingRaisingEventArgumentsFactory(); - bool IsQuerying { get; } - /// - /// Invokes the passed callback in a context of the specified query. - /// - void RunInQueryContext(Action calls, IQuery query); - void RegisterInContextQuery(ICall call); - } + bool IsQuerying { get; } + /// + /// Invokes the passed callback in a context of the specified query. + /// + void RunInQueryContext(Action calls, IQuery query); + void RegisterInContextQuery(ICall call); } \ No newline at end of file diff --git a/src/NSubstitute/Core/MatchArgs.cs b/src/NSubstitute/Core/MatchArgs.cs index 64e84c4b3..661d34250 100644 --- a/src/NSubstitute/Core/MatchArgs.cs +++ b/src/NSubstitute/Core/MatchArgs.cs @@ -1,18 +1,17 @@ using System.Diagnostics; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +[DebuggerDisplay("{" + nameof(_name) + "}")] +public class MatchArgs { - [DebuggerDisplay("{" + nameof(_name) + "}")] - public class MatchArgs - { - private readonly string _name; + private readonly string _name; - public static readonly MatchArgs AsSpecifiedInCall = new(nameof(AsSpecifiedInCall)); - public static readonly MatchArgs Any = new(nameof(Any)); + public static readonly MatchArgs AsSpecifiedInCall = new(nameof(AsSpecifiedInCall)); + public static readonly MatchArgs Any = new(nameof(Any)); - private MatchArgs(string name) - { - _name = name; - } + private MatchArgs(string name) + { + _name = name; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/Maybe.cs b/src/NSubstitute/Core/Maybe.cs index 71329cd3f..b1f6de5d7 100644 --- a/src/NSubstitute/Core/Maybe.cs +++ b/src/NSubstitute/Core/Maybe.cs @@ -1,54 +1,53 @@ using System.Collections; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +/// +/// Particularly poor implementation of Maybe/Option type. +/// This is just filling an immediate need; use FSharpOption or XSharpx or similar for a +/// real implementation. +/// +/// +public struct Maybe : IEnumerable { - /// - /// Particularly poor implementation of Maybe/Option type. - /// This is just filling an immediate need; use FSharpOption or XSharpx or similar for a - /// real implementation. - /// - /// - public struct Maybe : IEnumerable - { - private readonly bool hasValue; - private readonly T value; - - public Maybe(T value) : this() - { - this.value = value; - hasValue = true; - } + private readonly bool hasValue; + private readonly T value; - public bool HasValue() { return hasValue; } + public Maybe(T value) : this() + { + this.value = value; + hasValue = true; + } - public Maybe OrElse(Func> other) { var current = this; return Fold(other, _ => current); } - public Maybe OrElse(Maybe other) { return OrElse(() => other); } - public T ValueOr(Func other) { return Fold(other, x => x); } - public T ValueOr(T other) { return ValueOr(() => other); } - public T? ValueOrDefault() { return ValueOr(default(T)!); } + public bool HasValue() { return hasValue; } - public TResult Fold(Func handleNoValue, Func handleValue) - { - return HasValue() ? handleValue(value) : handleNoValue(); - } + public Maybe OrElse(Func> other) { var current = this; return Fold(other, _ => current); } + public Maybe OrElse(Maybe other) { return OrElse(() => other); } + public T ValueOr(Func other) { return Fold(other, x => x); } + public T ValueOr(T other) { return ValueOr(() => other); } + public T? ValueOrDefault() { return ValueOr(default(T)!); } - IEnumerator IEnumerable.GetEnumerator() - { - if (hasValue) - { - yield return value; - } - } + public TResult Fold(Func handleNoValue, Func handleValue) + { + return HasValue() ? handleValue(value) : handleNoValue(); + } - IEnumerator IEnumerable.GetEnumerator() + IEnumerator IEnumerable.GetEnumerator() + { + if (hasValue) { - return ((IEnumerable)this).GetEnumerator(); + yield return value; } } - public static class Maybe + IEnumerator IEnumerable.GetEnumerator() { - public static Maybe Just(T value) { return new Maybe(value); } - public static Maybe Nothing() { return new Maybe(); } + return ((IEnumerable)this).GetEnumerator(); } +} + +public static class Maybe +{ + public static Maybe Just(T value) { return new Maybe(value); } + public static Maybe Nothing() { return new Maybe(); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/MethodFormatter.cs b/src/NSubstitute/Core/MethodFormatter.cs index 9aff844e6..4f2a1b026 100644 --- a/src/NSubstitute/Core/MethodFormatter.cs +++ b/src/NSubstitute/Core/MethodFormatter.cs @@ -1,29 +1,28 @@ using System.Reflection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class MethodFormatter : IMethodInfoFormatter { - public class MethodFormatter : IMethodInfoFormatter + public bool CanFormat(MethodInfo methodInfo) { - public bool CanFormat(MethodInfo methodInfo) - { - return true; - } + return true; + } - public string Format(MethodInfo methodInfo, IEnumerable arguments) - { - var args = string.Join(", ", arguments); - return $"{methodInfo.Name}{FormatGenericType(methodInfo)}({args})"; - } + public string Format(MethodInfo methodInfo, IEnumerable arguments) + { + var args = string.Join(", ", arguments); + return $"{methodInfo.Name}{FormatGenericType(methodInfo)}({args})"; + } - private static string FormatGenericType(MethodInfo methodInfoOfCall) + private static string FormatGenericType(MethodInfo methodInfoOfCall) + { + if (!methodInfoOfCall.IsGenericMethod) { - if (!methodInfoOfCall.IsGenericMethod) - { - return string.Empty; - } - - var genericArgs = methodInfoOfCall.GetGenericArguments(); - return $"<{string.Join(", ", genericArgs.Select(x => x.GetNonMangledTypeName()))}>"; + return string.Empty; } + + var genericArgs = methodInfoOfCall.GetGenericArguments(); + return $"<{string.Join(", ", genericArgs.Select(x => x.GetNonMangledTypeName()))}>"; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/ParameterInfoWrapper.cs b/src/NSubstitute/Core/ParameterInfoWrapper.cs index 2e45106f9..a6857a17a 100644 --- a/src/NSubstitute/Core/ParameterInfoWrapper.cs +++ b/src/NSubstitute/Core/ParameterInfoWrapper.cs @@ -1,22 +1,21 @@ using System.Reflection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +internal class ParameterInfoWrapper : IParameterInfo { - internal class ParameterInfoWrapper : IParameterInfo - { - private readonly ParameterInfo _parameterInfo; + private readonly ParameterInfo _parameterInfo; - public ParameterInfoWrapper(ParameterInfo parameterInfo) - { - _parameterInfo = parameterInfo; - } + public ParameterInfoWrapper(ParameterInfo parameterInfo) + { + _parameterInfo = parameterInfo; + } - public Type ParameterType => _parameterInfo.ParameterType; + public Type ParameterType => _parameterInfo.ParameterType; - public bool IsParams => _parameterInfo.IsParams(); + public bool IsParams => _parameterInfo.IsParams(); - public bool IsOptional => _parameterInfo.IsOptional; + public bool IsOptional => _parameterInfo.IsOptional; - public bool IsOut => _parameterInfo.IsOut; - } + public bool IsOut => _parameterInfo.IsOut; } \ No newline at end of file diff --git a/src/NSubstitute/Core/PendingSpecificationInfo.cs b/src/NSubstitute/Core/PendingSpecificationInfo.cs index bca46498d..63eefed08 100644 --- a/src/NSubstitute/Core/PendingSpecificationInfo.cs +++ b/src/NSubstitute/Core/PendingSpecificationInfo.cs @@ -1,29 +1,28 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class PendingSpecificationInfo { - public class PendingSpecificationInfo - { - private readonly ICallSpecification? _callSpecification; - private readonly ICall? _lastCall; + private readonly ICallSpecification? _callSpecification; + private readonly ICall? _lastCall; - private PendingSpecificationInfo(ICallSpecification? callSpecification, ICall? lastCall) - { - _callSpecification = callSpecification; - _lastCall = lastCall; - } + private PendingSpecificationInfo(ICallSpecification? callSpecification, ICall? lastCall) + { + _callSpecification = callSpecification; + _lastCall = lastCall; + } - public T Handle(Func onCallSpec, Func onLastCall) - { - return _callSpecification != null ? onCallSpec(_callSpecification) : onLastCall(_lastCall!); - } + public T Handle(Func onCallSpec, Func onLastCall) + { + return _callSpecification != null ? onCallSpec(_callSpecification) : onLastCall(_lastCall!); + } - public static PendingSpecificationInfo FromLastCall(ICall lastCall) - { - return new PendingSpecificationInfo(null, lastCall); - } + public static PendingSpecificationInfo FromLastCall(ICall lastCall) + { + return new PendingSpecificationInfo(null, lastCall); + } - public static PendingSpecificationInfo FromCallSpecification(ICallSpecification callSpecification) - { - return new PendingSpecificationInfo(callSpecification, null); - } + public static PendingSpecificationInfo FromCallSpecification(ICallSpecification callSpecification) + { + return new PendingSpecificationInfo(callSpecification, null); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/PropertyCallFormatter.cs b/src/NSubstitute/Core/PropertyCallFormatter.cs index 885194483..19df03aa8 100644 --- a/src/NSubstitute/Core/PropertyCallFormatter.cs +++ b/src/NSubstitute/Core/PropertyCallFormatter.cs @@ -1,45 +1,44 @@ using System.Reflection; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class PropertyCallFormatter : IMethodInfoFormatter { - public class PropertyCallFormatter : IMethodInfoFormatter + public bool CanFormat(MethodInfo methodInfo) => + GetPropertyFromGetterOrSetterCall(methodInfo) != null; + + public string Format(MethodInfo methodInfo, IEnumerable arguments) + { + var propertyInfo = GetPropertyFromGetterOrSetterCall(methodInfo) + ?? throw new SubstituteInternalException("The 'CanFormat' method should have guarded it."); + + var numberOfIndexParams = propertyInfo.GetIndexParameters().Length; + var propertyName = numberOfIndexParams == 0 + ? propertyInfo.Name + : FormatPropertyIndexer(numberOfIndexParams, arguments); + + return propertyName + FormatArgsAfterIndexParamsAsSetterArgs(numberOfIndexParams, arguments); + } + + private PropertyInfo? GetPropertyFromGetterOrSetterCall(MethodInfo methodInfoOfCall) + { + return methodInfoOfCall.GetPropertyFromSetterCallOrNull() ?? methodInfoOfCall.GetPropertyFromGetterCallOrNull(); + } + + private string FormatPropertyIndexer(int numberOfIndexParameters, IEnumerable arguments) + { + return $"this[{arguments.Take(numberOfIndexParameters).Join(", ")}]"; + } + + private bool OnlyHasIndexParameterArgs(int numberOfIndexParameters, IEnumerable arguments) + { + return numberOfIndexParameters >= arguments.Count(); + } + + private string FormatArgsAfterIndexParamsAsSetterArgs(int numberOfIndexParameters, IEnumerable arguments) { - public bool CanFormat(MethodInfo methodInfo) => - GetPropertyFromGetterOrSetterCall(methodInfo) != null; - - public string Format(MethodInfo methodInfo, IEnumerable arguments) - { - var propertyInfo = GetPropertyFromGetterOrSetterCall(methodInfo) - ?? throw new SubstituteInternalException("The 'CanFormat' method should have guarded it."); - - var numberOfIndexParams = propertyInfo.GetIndexParameters().Length; - var propertyName = numberOfIndexParams == 0 - ? propertyInfo.Name - : FormatPropertyIndexer(numberOfIndexParams, arguments); - - return propertyName + FormatArgsAfterIndexParamsAsSetterArgs(numberOfIndexParams, arguments); - } - - private PropertyInfo? GetPropertyFromGetterOrSetterCall(MethodInfo methodInfoOfCall) - { - return methodInfoOfCall.GetPropertyFromSetterCallOrNull() ?? methodInfoOfCall.GetPropertyFromGetterCallOrNull(); - } - - private string FormatPropertyIndexer(int numberOfIndexParameters, IEnumerable arguments) - { - return $"this[{arguments.Take(numberOfIndexParameters).Join(", ")}]"; - } - - private bool OnlyHasIndexParameterArgs(int numberOfIndexParameters, IEnumerable arguments) - { - return numberOfIndexParameters >= arguments.Count(); - } - - private string FormatArgsAfterIndexParamsAsSetterArgs(int numberOfIndexParameters, IEnumerable arguments) - { - if (OnlyHasIndexParameterArgs(numberOfIndexParameters, arguments)) return string.Empty; - return " = " + arguments.Skip(numberOfIndexParameters).Join(", "); - } + if (OnlyHasIndexParameterArgs(numberOfIndexParameters, arguments)) return string.Empty; + return " = " + arguments.Skip(numberOfIndexParameters).Join(", "); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/PropertyHelper.cs b/src/NSubstitute/Core/PropertyHelper.cs index 25ffc2a6b..44f701d48 100644 --- a/src/NSubstitute/Core/PropertyHelper.cs +++ b/src/NSubstitute/Core/PropertyHelper.cs @@ -3,76 +3,75 @@ using NSubstitute.Core.Arguments; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class PropertyHelper : IPropertyHelper { - public class PropertyHelper : IPropertyHelper + private readonly ICallFactory _callFactory; + private readonly IArgumentSpecificationCompatibilityTester _argSpecCompatTester; + + public PropertyHelper(ICallFactory callFactory, IArgumentSpecificationCompatibilityTester argSpecCompatTester) { - private readonly ICallFactory _callFactory; - private readonly IArgumentSpecificationCompatibilityTester _argSpecCompatTester; + _callFactory = callFactory; + _argSpecCompatTester = argSpecCompatTester; + } - public PropertyHelper(ICallFactory callFactory, IArgumentSpecificationCompatibilityTester argSpecCompatTester) - { - _callFactory = callFactory; - _argSpecCompatTester = argSpecCompatTester; - } + public bool IsCallToSetAReadWriteProperty(ICall call) + { + var propertySetter = GetPropertyFromSetterCall(call); + return PropertySetterExistsAndHasAGetMethod(propertySetter); + } - public bool IsCallToSetAReadWriteProperty(ICall call) - { - var propertySetter = GetPropertyFromSetterCall(call); - return PropertySetterExistsAndHasAGetMethod(propertySetter); - } + private bool PropertySetterExistsAndHasAGetMethod([NotNullWhen(true)] PropertyInfo? propertySetter) + { + return propertySetter != null && propertySetter.GetGetMethod(nonPublic: true) != null; + } - private bool PropertySetterExistsAndHasAGetMethod([NotNullWhen(true)] PropertyInfo? propertySetter) - { - return propertySetter != null && propertySetter.GetGetMethod(nonPublic: true) != null; - } + private PropertyInfo? GetPropertyFromSetterCall(ICall call) + { + return call.GetMethodInfo().GetPropertyFromSetterCallOrNull(); + } - private PropertyInfo? GetPropertyFromSetterCall(ICall call) + public ICall CreateCallToPropertyGetterFromSetterCall(ICall callToSetter) + { + var propertyInfo = GetPropertyFromSetterCall(callToSetter); + if (!PropertySetterExistsAndHasAGetMethod(propertyInfo)) { - return call.GetMethodInfo().GetPropertyFromSetterCallOrNull(); + throw new InvalidOperationException("Could not find a GetMethod for \"" + callToSetter.GetMethodInfo() + "\""); } - public ICall CreateCallToPropertyGetterFromSetterCall(ICall callToSetter) - { - var propertyInfo = GetPropertyFromSetterCall(callToSetter); - if (!PropertySetterExistsAndHasAGetMethod(propertyInfo)) - { - throw new InvalidOperationException("Could not find a GetMethod for \"" + callToSetter.GetMethodInfo() + "\""); - } - - var getter = propertyInfo.GetGetMethod(nonPublic: true); - if (getter is null) throw new SubstituteInternalException("A property with a getter expected."); - - var getterArgs = SkipLast(callToSetter.GetOriginalArguments()); - var getterArgumentSpecifications = GetGetterCallSpecificationsFromSetterCall(callToSetter); + var getter = propertyInfo.GetGetMethod(nonPublic: true); + if (getter is null) throw new SubstituteInternalException("A property with a getter expected."); - return _callFactory.Create(getter, getterArgs, callToSetter.Target(), getterArgumentSpecifications); - } - - private IList GetGetterCallSpecificationsFromSetterCall(ICall callToSetter) - { - var lastSetterArg = callToSetter.GetOriginalArguments().Last(); - var lastSetterArgType = callToSetter.GetParameterInfos().Last().ParameterType; + var getterArgs = SkipLast(callToSetter.GetOriginalArguments()); + var getterArgumentSpecifications = GetGetterCallSpecificationsFromSetterCall(callToSetter); - var argumentSpecifications = callToSetter.GetArgumentSpecifications(); - if (argumentSpecifications.Count == 0) - return argumentSpecifications; + return _callFactory.Create(getter, getterArgs, callToSetter.Target(), getterArgumentSpecifications); + } - // Getter call has one less argument than the setter call (the last arg is trimmed). - // Therefore, we need to remove the last argument specification if it's for the trimmed arg. - // Otherwise, NSubstitute might find that the redundant argument specification is present and the - // validation logic might trigger an exception. - if (_argSpecCompatTester.IsSpecificationCompatible(argumentSpecifications.Last(), lastSetterArg, lastSetterArgType)) - { - argumentSpecifications = SkipLast(argumentSpecifications); - } + private IList GetGetterCallSpecificationsFromSetterCall(ICall callToSetter) + { + var lastSetterArg = callToSetter.GetOriginalArguments().Last(); + var lastSetterArgType = callToSetter.GetParameterInfos().Last().ParameterType; + var argumentSpecifications = callToSetter.GetArgumentSpecifications(); + if (argumentSpecifications.Count == 0) return argumentSpecifications; - } - private static T[] SkipLast(ICollection collection) + // Getter call has one less argument than the setter call (the last arg is trimmed). + // Therefore, we need to remove the last argument specification if it's for the trimmed arg. + // Otherwise, NSubstitute might find that the redundant argument specification is present and the + // validation logic might trigger an exception. + if (_argSpecCompatTester.IsSpecificationCompatible(argumentSpecifications.Last(), lastSetterArg, lastSetterArgType)) { - return collection.Take(collection.Count - 1).ToArray(); + argumentSpecifications = SkipLast(argumentSpecifications); } + + return argumentSpecifications; + } + + private static T[] SkipLast(ICollection collection) + { + return collection.Take(collection.Count - 1).ToArray(); } } diff --git a/src/NSubstitute/Core/Query.cs b/src/NSubstitute/Core/Query.cs index c2848fd76..81b76a57b 100644 --- a/src/NSubstitute/Core/Query.cs +++ b/src/NSubstitute/Core/Query.cs @@ -1,38 +1,37 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class Query : IQuery, IQueryResults { - public class Query : IQuery, IQueryResults - { - private readonly List _querySpec = new(); - private readonly HashSet _matchingCalls = new(new CallSequenceNumberComparer()); - private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly List _querySpec = new(); + private readonly HashSet _matchingCalls = new(new CallSequenceNumberComparer()); + private readonly ICallSpecificationFactory _callSpecificationFactory; - public Query(ICallSpecificationFactory callSpecificationFactory) - { - _callSpecificationFactory = callSpecificationFactory; - } + public Query(ICallSpecificationFactory callSpecificationFactory) + { + _callSpecificationFactory = callSpecificationFactory; + } - public void RegisterCall(ICall call) - { - var target = call.Target(); - var callSpecification = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall); + public void RegisterCall(ICall call) + { + var target = call.Target(); + var callSpecification = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall); - _querySpec.Add(new CallSpecAndTarget(callSpecification, target)); + _querySpec.Add(new CallSpecAndTarget(callSpecification, target)); - var allMatchingCallsOnTarget = target.ReceivedCalls().Where(callSpecification.IsSatisfiedBy); - _matchingCalls.UnionWith(allMatchingCallsOnTarget); - } + var allMatchingCallsOnTarget = target.ReceivedCalls().Where(callSpecification.IsSatisfiedBy); + _matchingCalls.UnionWith(allMatchingCallsOnTarget); + } - public IQueryResults Result() => this; + public IQueryResults Result() => this; - IEnumerable IQueryResults.MatchingCallsInOrder() => _matchingCalls.OrderBy(x => x.GetSequenceNumber()); + IEnumerable IQueryResults.MatchingCallsInOrder() => _matchingCalls.OrderBy(x => x.GetSequenceNumber()); - IEnumerable IQueryResults.QuerySpecification() => _querySpec.Select(x => x); + IEnumerable IQueryResults.QuerySpecification() => _querySpec.Select(x => x); - private class CallSequenceNumberComparer : IEqualityComparer - { - public bool Equals(ICall? x, ICall? y) => x?.GetSequenceNumber() == y?.GetSequenceNumber(); + private class CallSequenceNumberComparer : IEqualityComparer + { + public bool Equals(ICall? x, ICall? y) => x?.GetSequenceNumber() == y?.GetSequenceNumber(); - public int GetHashCode(ICall obj) => obj.GetSequenceNumber().GetHashCode(); - } + public int GetHashCode(ICall obj) => obj.GetSequenceNumber().GetHashCode(); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/ReceivedCallsExceptionThrower.cs b/src/NSubstitute/Core/ReceivedCallsExceptionThrower.cs index 2d7d33479..974bc6185 100644 --- a/src/NSubstitute/Core/ReceivedCallsExceptionThrower.cs +++ b/src/NSubstitute/Core/ReceivedCallsExceptionThrower.cs @@ -2,74 +2,73 @@ using NSubstitute.Exceptions; using NSubstitute.ReceivedExtensions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class ReceivedCallsExceptionThrower : IReceivedCallsExceptionThrower { - public class ReceivedCallsExceptionThrower : IReceivedCallsExceptionThrower + public void Throw(ICallSpecification callSpecification, IEnumerable matchingCalls, IEnumerable nonMatchingCalls, Quantity requiredQuantity) { - public void Throw(ICallSpecification callSpecification, IEnumerable matchingCalls, IEnumerable nonMatchingCalls, Quantity requiredQuantity) - { - var builder = new StringBuilder(); - builder.AppendLine(string.Format("Expected to receive {0} matching:\n\t{1}", requiredQuantity.Describe("call", "calls"), callSpecification)); + var builder = new StringBuilder(); + builder.AppendLine(string.Format("Expected to receive {0} matching:\n\t{1}", requiredQuantity.Describe("call", "calls"), callSpecification)); - AppendMatchingCalls(callSpecification, matchingCalls, builder); + AppendMatchingCalls(callSpecification, matchingCalls, builder); - if (requiredQuantity.RequiresMoreThan(matchingCalls)) - { - AppendNonMatchingCalls(callSpecification, nonMatchingCalls, builder); - } - - throw new ReceivedCallsException(builder.ToString()); + if (requiredQuantity.RequiresMoreThan(matchingCalls)) + { + AppendNonMatchingCalls(callSpecification, nonMatchingCalls, builder); } - private void AppendNonMatchingCalls(ICallSpecification callSpecification, IEnumerable nonMatchingCalls, StringBuilder builder) + throw new ReceivedCallsException(builder.ToString()); + } + + private void AppendNonMatchingCalls(ICallSpecification callSpecification, IEnumerable nonMatchingCalls, StringBuilder builder) + { + if (nonMatchingCalls.Any()) { - if (nonMatchingCalls.Any()) - { - var numberOfRelatedCalls = nonMatchingCalls.Count(); - builder.AppendLine( - string.Format( - "Received {0} non-matching {1} (non-matching arguments indicated with '*' characters):", - numberOfRelatedCalls, - numberOfRelatedCalls == 1 ? "call" : "calls") - ); - WriteCallsWithRespectToCallSpec(callSpecification, nonMatchingCalls, builder); - } + var numberOfRelatedCalls = nonMatchingCalls.Count(); + builder.AppendLine( + string.Format( + "Received {0} non-matching {1} (non-matching arguments indicated with '*' characters):", + numberOfRelatedCalls, + numberOfRelatedCalls == 1 ? "call" : "calls") + ); + WriteCallsWithRespectToCallSpec(callSpecification, nonMatchingCalls, builder); } + } - private void AppendMatchingCalls(ICallSpecification callSpecification, IEnumerable matchingCalls, StringBuilder builder) + private void AppendMatchingCalls(ICallSpecification callSpecification, IEnumerable matchingCalls, StringBuilder builder) + { + var numberOfMatchingCalls = matchingCalls.Count(); + if (numberOfMatchingCalls == 0) { - var numberOfMatchingCalls = matchingCalls.Count(); - if (numberOfMatchingCalls == 0) - { - builder.AppendLine("Actually received no matching calls."); - } - else - { - builder.AppendLine(string.Format("Actually received {0} matching {1}:", numberOfMatchingCalls, numberOfMatchingCalls == 1 ? "call" : "calls")); - WriteCallsWithRespectToCallSpec(callSpecification, matchingCalls, builder); - } + builder.AppendLine("Actually received no matching calls."); + } + else + { + builder.AppendLine(string.Format("Actually received {0} matching {1}:", numberOfMatchingCalls, numberOfMatchingCalls == 1 ? "call" : "calls")); + WriteCallsWithRespectToCallSpec(callSpecification, matchingCalls, builder); } + } - private void WriteCallsWithRespectToCallSpec(ICallSpecification callSpecification, IEnumerable relatedCalls, StringBuilder builder) + private void WriteCallsWithRespectToCallSpec(ICallSpecification callSpecification, IEnumerable relatedCalls, StringBuilder builder) + { + foreach (var call in relatedCalls) { - foreach (var call in relatedCalls) + builder.AppendFormat("\t{0}\n", callSpecification.Format(call)); + var nonMatches = DescribeNonMatches(call, callSpecification).Trim(); + if (!string.IsNullOrEmpty(nonMatches)) { - builder.AppendFormat("\t{0}\n", callSpecification.Format(call)); - var nonMatches = DescribeNonMatches(call, callSpecification).Trim(); - if (!string.IsNullOrEmpty(nonMatches)) - { - builder.AppendFormat("\t\t{0}\n", nonMatches.Replace("\n", "\n\t\t")); - } + builder.AppendFormat("\t\t{0}\n", nonMatches.Replace("\n", "\n\t\t")); } } + } - private string DescribeNonMatches(ICall call, ICallSpecification callSpecification) - { - var nonMatchingArgDescriptions = callSpecification - .NonMatchingArguments(call) - .Select(x => x.DescribeNonMatch()) - .Where(x => !string.IsNullOrEmpty(x)); - return string.Join("\n", nonMatchingArgDescriptions); - } + private string DescribeNonMatches(ICall call, ICallSpecification callSpecification) + { + var nonMatchingArgDescriptions = callSpecification + .NonMatchingArguments(call) + .Select(x => x.DescribeNonMatch()) + .Where(x => !string.IsNullOrEmpty(x)); + return string.Join("\n", nonMatchingArgDescriptions); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/ReflectionExtensions.cs b/src/NSubstitute/Core/ReflectionExtensions.cs index a64c9ac60..962927744 100644 --- a/src/NSubstitute/Core/ReflectionExtensions.cs +++ b/src/NSubstitute/Core/ReflectionExtensions.cs @@ -1,49 +1,48 @@ using System.Reflection; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public static class ReflectionExtensions { - public static class ReflectionExtensions + public static PropertyInfo? GetPropertyFromSetterCallOrNull(this MethodInfo call) { - public static PropertyInfo? GetPropertyFromSetterCallOrNull(this MethodInfo call) - { - if (!CanBePropertySetterCall(call)) return null; - - // Don't use .FirstOrDefault() lambda, as closure leads to allocation even if not reached. - foreach (var property in GetAllProperties(call.DeclaringType)) - { - if (property.GetSetMethod(nonPublic: true) == call) return property; - } + if (!CanBePropertySetterCall(call)) return null; - return null; - } - - public static PropertyInfo? GetPropertyFromGetterCallOrNull(this MethodInfo call) + // Don't use .FirstOrDefault() lambda, as closure leads to allocation even if not reached. + foreach (var property in GetAllProperties(call.DeclaringType)) { - return GetAllProperties(call.DeclaringType) - .FirstOrDefault(x => x.GetGetMethod(nonPublic: true) == call); + if (property.GetSetMethod(nonPublic: true) == call) return property; } - public static bool IsParams(this ParameterInfo parameterInfo) - { - return parameterInfo.IsDefined(typeof(ParamArrayAttribute), inherit: false); - } + return null; + } - private static bool CanBePropertySetterCall(MethodInfo call) - { - // It's safe to verify method prefix and signature as according to the ECMA-335 II.22.28: - // 10. Any setter method for a property whose Name is xxx shall be called set_xxx [CLS] - // 13. Any getter and setter methods shall have Method.Flags.SpecialName = 1 [CLS] - // Notice, even though it's correct to check the SpecialName flag, we don't do that deliberately. - // The reason is that some compilers (e.g. F#) might not emit this attribute and our library - // misbehaves in those cases. We use slightly slower, but robust check. - return call.Name.StartsWith("set_", StringComparison.Ordinal); - } + public static PropertyInfo? GetPropertyFromGetterCallOrNull(this MethodInfo call) + { + return GetAllProperties(call.DeclaringType) + .FirstOrDefault(x => x.GetGetMethod(nonPublic: true) == call); + } - private static PropertyInfo[] GetAllProperties(Type? type) - { - return type != null - ? type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - : new PropertyInfo[0]; - } + public static bool IsParams(this ParameterInfo parameterInfo) + { + return parameterInfo.IsDefined(typeof(ParamArrayAttribute), inherit: false); + } + + private static bool CanBePropertySetterCall(MethodInfo call) + { + // It's safe to verify method prefix and signature as according to the ECMA-335 II.22.28: + // 10. Any setter method for a property whose Name is xxx shall be called set_xxx [CLS] + // 13. Any getter and setter methods shall have Method.Flags.SpecialName = 1 [CLS] + // Notice, even though it's correct to check the SpecialName flag, we don't do that deliberately. + // The reason is that some compilers (e.g. F#) might not emit this attribute and our library + // misbehaves in those cases. We use slightly slower, but robust check. + return call.Name.StartsWith("set_", StringComparison.Ordinal); + } + + private static PropertyInfo[] GetAllProperties(Type? type) + { + return type != null + ? type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + : new PropertyInfo[0]; } } diff --git a/src/NSubstitute/Core/ResultsForType.cs b/src/NSubstitute/Core/ResultsForType.cs index 5a6bf4e2f..63b4aea5c 100644 --- a/src/NSubstitute/Core/ResultsForType.cs +++ b/src/NSubstitute/Core/ResultsForType.cs @@ -1,63 +1,62 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class ResultsForType : IResultsForType { - public class ResultsForType : IResultsForType + private readonly CallResults _results; + + public ResultsForType(ICallInfoFactory callInfoFactory) { - private readonly CallResults _results; + _results = new CallResults(callInfoFactory); + } - public ResultsForType(ICallInfoFactory callInfoFactory) - { - _results = new CallResults(callInfoFactory); - } + public void SetResult(Type type, IReturn resultToReturn) + { + _results.SetResult(new MatchingReturnTypeSpecification(type), resultToReturn); + } - public void SetResult(Type type, IReturn resultToReturn) - { - _results.SetResult(new MatchingReturnTypeSpecification(type), resultToReturn); - } + public bool TryGetResult(ICall call, out object? result) + { + return _results.TryGetResult(call, out result); + } - public bool TryGetResult(ICall call, out object? result) - { - return _results.TryGetResult(call, out result); - } + public void Clear() + { + _results.Clear(); + } - public void Clear() - { - _results.Clear(); - } + private class MatchingReturnTypeSpecification : ICallSpecification + { + private readonly Type _expectedReturnType; - private class MatchingReturnTypeSpecification : ICallSpecification + public MatchingReturnTypeSpecification(Type expectedReturnType) { - private readonly Type _expectedReturnType; - - public MatchingReturnTypeSpecification(Type expectedReturnType) - { - _expectedReturnType = expectedReturnType; - } + _expectedReturnType = expectedReturnType; + } - public bool IsSatisfiedBy(ICall call) - => call.GetReturnType() == _expectedReturnType; + public bool IsSatisfiedBy(ICall call) + => call.GetReturnType() == _expectedReturnType; - // ******* Rest methods are not required ******* + // ******* Rest methods are not required ******* - public string Format(ICall call) - => throw new NotSupportedException(); + public string Format(ICall call) + => throw new NotSupportedException(); - public ICallSpecification CreateCopyThatMatchesAnyArguments() - => throw new NotSupportedException(); + public ICallSpecification CreateCopyThatMatchesAnyArguments() + => throw new NotSupportedException(); - public void InvokePerArgumentActions(CallInfo callInfo) - => throw new NotSupportedException(); + public void InvokePerArgumentActions(CallInfo callInfo) + => throw new NotSupportedException(); - public IEnumerable NonMatchingArguments(ICall call) - => throw new NotSupportedException(); + public IEnumerable NonMatchingArguments(ICall call) + => throw new NotSupportedException(); - public MethodInfo GetMethodInfo() - => throw new NotSupportedException(); + public MethodInfo GetMethodInfo() + => throw new NotSupportedException(); - public Type ReturnType() - => throw new NotSupportedException(); - } + public Type ReturnType() + => throw new NotSupportedException(); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/ReturnObservable.cs b/src/NSubstitute/Core/ReturnObservable.cs index 57f204c2f..ce023e04c 100644 --- a/src/NSubstitute/Core/ReturnObservable.cs +++ b/src/NSubstitute/Core/ReturnObservable.cs @@ -1,29 +1,28 @@ -namespace NSubstitute.Core -{ - internal class ReturnObservable : IObservable - { - private readonly T? _value; +namespace NSubstitute.Core; - public ReturnObservable() : this(default) { } - - public ReturnObservable(T? value) - { - _value = value; - } +internal class ReturnObservable : IObservable +{ + private readonly T? _value; - public IDisposable Subscribe(IObserver observer) - { - observer.OnNext(_value); - observer.OnCompleted(); + public ReturnObservable() : this(default) { } - return EmptyDisposable.Instance; - } + public ReturnObservable(T? value) + { + _value = value; } - internal class EmptyDisposable : IDisposable + public IDisposable Subscribe(IObserver observer) { - public static IDisposable Instance { get; } = new EmptyDisposable(); + observer.OnNext(_value); + observer.OnCompleted(); - public void Dispose() { } + return EmptyDisposable.Instance; } +} + +internal class EmptyDisposable : IDisposable +{ + public static IDisposable Instance { get; } = new EmptyDisposable(); + + public void Dispose() { } } \ No newline at end of file diff --git a/src/NSubstitute/Core/RobustThreadLocal.cs b/src/NSubstitute/Core/RobustThreadLocal.cs index 8e9a0da09..1b6f245ab 100644 --- a/src/NSubstitute/Core/RobustThreadLocal.cs +++ b/src/NSubstitute/Core/RobustThreadLocal.cs @@ -1,50 +1,49 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +/// +/// Delegates to ThreadLocal<T>, but wraps Value property access in try/catch to swallow ObjectDisposedExceptions. +/// These can occur if the Value property is accessed from the finalizer thread. Because we can't detect this, we'll +/// just swallow the exception (the finalizer thread won't be using any of the values from thread local storage anyway). +/// +internal class RobustThreadLocal { - /// - /// Delegates to ThreadLocal<T>, but wraps Value property access in try/catch to swallow ObjectDisposedExceptions. - /// These can occur if the Value property is accessed from the finalizer thread. Because we can't detect this, we'll - /// just swallow the exception (the finalizer thread won't be using any of the values from thread local storage anyway). - /// - internal class RobustThreadLocal + private readonly ThreadLocal _threadLocal; + private readonly Func? _initialValueFactory; + + public RobustThreadLocal() { - private readonly ThreadLocal _threadLocal; - private readonly Func? _initialValueFactory; + _threadLocal = new ThreadLocal(); + } - public RobustThreadLocal() - { - _threadLocal = new ThreadLocal(); - } + public RobustThreadLocal(Func initialValueFactory) + { + _initialValueFactory = initialValueFactory; + _threadLocal = new ThreadLocal(initialValueFactory); + } - public RobustThreadLocal(Func initialValueFactory) + public T Value + { + get { - _initialValueFactory = initialValueFactory; - _threadLocal = new ThreadLocal(initialValueFactory); + // Suppress nullability for result, as we trust type by usage. + // For non-nullable we expect ctor with default to be used. + try + { + return _threadLocal.Value!; + } + catch (ObjectDisposedException) + { + return _initialValueFactory != null ? _initialValueFactory.Invoke() : default!; + } } - - public T Value + set { - get + try { - // Suppress nullability for result, as we trust type by usage. - // For non-nullable we expect ctor with default to be used. - try - { - return _threadLocal.Value!; - } - catch (ObjectDisposedException) - { - return _initialValueFactory != null ? _initialValueFactory.Invoke() : default!; - } + _threadLocal.Value = value; } - set + catch (ObjectDisposedException) { - try - { - _threadLocal.Value = value; - } - catch (ObjectDisposedException) - { - } } } } diff --git a/src/NSubstitute/Core/RouteAction.cs b/src/NSubstitute/Core/RouteAction.cs index 1dd4ad359..409895a1f 100644 --- a/src/NSubstitute/Core/RouteAction.cs +++ b/src/NSubstitute/Core/RouteAction.cs @@ -1,20 +1,19 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class RouteAction { - public class RouteAction - { - private static readonly RouteAction _continue = new(hasReturnValue: false, null); + private static readonly RouteAction _continue = new(hasReturnValue: false, null); - public bool HasReturnValue { get; } + public bool HasReturnValue { get; } - public object? ReturnValue { get; } + public object? ReturnValue { get; } - public static RouteAction Continue() => _continue; - public static RouteAction Return(object? value) => new(hasReturnValue: true, value); + public static RouteAction Continue() => _continue; + public static RouteAction Return(object? value) => new(hasReturnValue: true, value); - private RouteAction(bool hasReturnValue, object? returnValue) - { - HasReturnValue = hasReturnValue; - ReturnValue = returnValue; - } + private RouteAction(bool hasReturnValue, object? returnValue) + { + HasReturnValue = hasReturnValue; + ReturnValue = returnValue; } } diff --git a/src/NSubstitute/Core/RouteFactoryCacheWrapper.cs b/src/NSubstitute/Core/RouteFactoryCacheWrapper.cs index df277e3d2..808958e4c 100644 --- a/src/NSubstitute/Core/RouteFactoryCacheWrapper.cs +++ b/src/NSubstitute/Core/RouteFactoryCacheWrapper.cs @@ -1,70 +1,69 @@ using NSubstitute.ReceivedExtensions; using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class RouteFactoryCacheWrapper : IRouteFactory { - public class RouteFactoryCacheWrapper : IRouteFactory - { - private readonly IRouteFactory _factory; + private readonly IRouteFactory _factory; - private CachedRoute _recordReplayCache; - private CachedRoute _recordCallSpecificationCache; + private CachedRoute _recordReplayCache; + private CachedRoute _recordCallSpecificationCache; - public RouteFactoryCacheWrapper(IRouteFactory factory) + public RouteFactoryCacheWrapper(IRouteFactory factory) + { + _factory = factory; + } + + public IRoute RecordReplay(ISubstituteState state) + { + // Don't care about concurrency - routes are immutable and in worst case we'll simply create a few ones. + if (_recordReplayCache.State != state) { - _factory = factory; + _recordReplayCache = new CachedRoute(_factory.RecordReplay(state), state); } - public IRoute RecordReplay(ISubstituteState state) - { - // Don't care about concurrency - routes are immutable and in worst case we'll simply create a few ones. - if (_recordReplayCache.State != state) - { - _recordReplayCache = new CachedRoute(_factory.RecordReplay(state), state); - } + return _recordReplayCache.Route; + } - return _recordReplayCache.Route; + public IRoute RecordCallSpecification(ISubstituteState state) + { + // Don't care about concurrency - routes are immutable and in worst case we'll simply create a few ones. + if (_recordCallSpecificationCache.State != state) + { + _recordCallSpecificationCache = new CachedRoute(_factory.RecordCallSpecification(state), state); } - public IRoute RecordCallSpecification(ISubstituteState state) - { - // Don't care about concurrency - routes are immutable and in worst case we'll simply create a few ones. - if (_recordCallSpecificationCache.State != state) - { - _recordCallSpecificationCache = new CachedRoute(_factory.RecordCallSpecification(state), state); - } + return _recordCallSpecificationCache.Route; + } - return _recordCallSpecificationCache.Route; - } + public IRoute CallQuery(ISubstituteState state) => + _factory.CallQuery(state); - public IRoute CallQuery(ISubstituteState state) => - _factory.CallQuery(state); + public IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity) => + _factory.CheckReceivedCalls(state, matchArgs, requiredQuantity); - public IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity) => - _factory.CheckReceivedCalls(state, matchArgs, requiredQuantity); + public IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs) => + _factory.DoWhenCalled(state, doAction, matchArgs); - public IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs) => - _factory.DoWhenCalled(state, doAction, matchArgs); + public IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs) => + _factory.DoNotCallBase(state, matchArgs); - public IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs) => - _factory.DoNotCallBase(state, matchArgs); + public IRoute CallBase(ISubstituteState state, MatchArgs matchArgs) => + _factory.CallBase(state, matchArgs); - public IRoute CallBase(ISubstituteState state, MatchArgs matchArgs) => - _factory.CallBase(state, matchArgs); + public IRoute RaiseEvent(ISubstituteState state, Func getEventArguments) => + _factory.RaiseEvent(state, getEventArguments); - public IRoute RaiseEvent(ISubstituteState state, Func getEventArguments) => - _factory.RaiseEvent(state, getEventArguments); + private readonly struct CachedRoute + { + public readonly IRoute Route; + public readonly ISubstituteState State; - private readonly struct CachedRoute + public CachedRoute(IRoute route, ISubstituteState state) { - public readonly IRoute Route; - public readonly ISubstituteState State; - - public CachedRoute(IRoute route, ISubstituteState state) - { - Route = route; - State = state; - } + Route = route; + State = state; } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SequenceChecking/InstanceTracker.cs b/src/NSubstitute/Core/SequenceChecking/InstanceTracker.cs index f62207465..913a65eb7 100644 --- a/src/NSubstitute/Core/SequenceChecking/InstanceTracker.cs +++ b/src/NSubstitute/Core/SequenceChecking/InstanceTracker.cs @@ -1,30 +1,29 @@ using System.Runtime.CompilerServices; -namespace NSubstitute.Core.SequenceChecking +namespace NSubstitute.Core.SequenceChecking; + +public class InstanceTracker { - public class InstanceTracker - { - private readonly Dictionary _instances = new(new ReferenceEqualityComparer()); - private int _counter = 0; + private readonly Dictionary _instances = new(new ReferenceEqualityComparer()); + private int _counter = 0; - public int InstanceNumber(object o) + public int InstanceNumber(object o) + { + if (_instances.TryGetValue(o, out var i)) { - if (_instances.TryGetValue(o, out var i)) - { - return i; - } - - var next = ++_counter; - _instances.Add(o, next); - return next; + return i; } - public int NumberOfInstances() => _counter; + var next = ++_counter; + _instances.Add(o, next); + return next; + } - private class ReferenceEqualityComparer : IEqualityComparer - { - public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); - public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj); - } + public int NumberOfInstances() => _counter; + + private class ReferenceEqualityComparer : IEqualityComparer + { + public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); + public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SequenceChecking/SequenceFormatter.cs b/src/NSubstitute/Core/SequenceChecking/SequenceFormatter.cs index 9bf036629..e407a3342 100644 --- a/src/NSubstitute/Core/SequenceChecking/SequenceFormatter.cs +++ b/src/NSubstitute/Core/SequenceChecking/SequenceFormatter.cs @@ -2,141 +2,140 @@ using System.Reflection; using NSubstitute.Core.Arguments; -namespace NSubstitute.Core.SequenceChecking +namespace NSubstitute.Core.SequenceChecking; + +public class SequenceFormatter { - public class SequenceFormatter - { - private readonly string _delimiter; - private readonly CallData[] _query; - private readonly CallData[] _actualCalls; - private readonly bool _requiresInstanceNumbers; - private readonly bool _hasMultipleInstances; + private readonly string _delimiter; + private readonly CallData[] _query; + private readonly CallData[] _actualCalls; + private readonly bool _requiresInstanceNumbers; + private readonly bool _hasMultipleInstances; - public SequenceFormatter(string delimiter, CallSpecAndTarget[] querySpec, ICall[] matchingCallsInOrder) - { - _delimiter = delimiter; + public SequenceFormatter(string delimiter, CallSpecAndTarget[] querySpec, ICall[] matchingCallsInOrder) + { + _delimiter = delimiter; - var instances = new InstanceTracker(); - _query = querySpec - .Select(x => new CallData(instances.InstanceNumber(x.Target), x)).ToArray(); + var instances = new InstanceTracker(); + _query = querySpec + .Select(x => new CallData(instances.InstanceNumber(x.Target), x)).ToArray(); - _actualCalls = matchingCallsInOrder - .Select(x => new CallData(instances.InstanceNumber(x.Target()), x)).ToArray(); + _actualCalls = matchingCallsInOrder + .Select(x => new CallData(instances.InstanceNumber(x.Target()), x)).ToArray(); - _hasMultipleInstances = instances.NumberOfInstances() > 1; - _requiresInstanceNumbers = HasMultipleCallsOnSameType(); - } + _hasMultipleInstances = instances.NumberOfInstances() > 1; + _requiresInstanceNumbers = HasMultipleCallsOnSameType(); + } - public string FormatQuery() => Format(_query); + public string FormatQuery() => Format(_query); - public string FormatActualCalls() => Format(_actualCalls); + public string FormatActualCalls() => Format(_actualCalls); - private string Format(CallData[] calls) - { - return calls.Select(x => x.Format(_hasMultipleInstances, _requiresInstanceNumbers)).Join(_delimiter); - } + private string Format(CallData[] calls) + { + return calls.Select(x => x.Format(_hasMultipleInstances, _requiresInstanceNumbers)).Join(_delimiter); + } - private bool HasMultipleCallsOnSameType() + private bool HasMultipleCallsOnSameType() + { + var lookup = new Dictionary(); + foreach (var x in _query) { - var lookup = new Dictionary(); - foreach (var x in _query) + if (lookup.TryGetValue(x.DeclaringType, out var instance)) { - if (lookup.TryGetValue(x.DeclaringType, out var instance)) - { - if (!ReferenceEquals(x.Target, instance)) { return true; } - } - else - { - lookup.Add(x.DeclaringType, x.Target); - } + if (!ReferenceEquals(x.Target, instance)) { return true; } } - return false; - } - - private class CallData - { - private readonly int _instanceNumber; - private readonly ICall? _call; - private readonly CallSpecAndTarget? _specAndTarget; - - public CallData(int instanceNumber, CallSpecAndTarget specAndTarget) + else { - _instanceNumber = instanceNumber; - _specAndTarget = specAndTarget; + lookup.Add(x.DeclaringType, x.Target); } + } + return false; + } - public CallData(int instanceNumber, ICall call) - { - _instanceNumber = instanceNumber; - _call = call; - } + private class CallData + { + private readonly int _instanceNumber; + private readonly ICall? _call; + private readonly CallSpecAndTarget? _specAndTarget; - private MethodInfo MethodInfo => - _call != null - ? _call.GetMethodInfo() - : _specAndTarget!.CallSpecification.GetMethodInfo(); + public CallData(int instanceNumber, CallSpecAndTarget specAndTarget) + { + _instanceNumber = instanceNumber; + _specAndTarget = specAndTarget; + } - public object Target => _call != null ? _call.Target() : _specAndTarget!.Target; + public CallData(int instanceNumber, ICall call) + { + _instanceNumber = instanceNumber; + _call = call; + } - public Type DeclaringType => MethodInfo.DeclaringType!; + private MethodInfo MethodInfo => + _call != null + ? _call.GetMethodInfo() + : _specAndTarget!.CallSpecification.GetMethodInfo(); - public string Format(bool multipleInstances, bool includeInstanceNumber) - { - var call = _call != null - ? Format(_call) - : Format(_specAndTarget!); + public object Target => _call != null ? _call.Target() : _specAndTarget!.Target; - if (!multipleInstances) return call; + public Type DeclaringType => MethodInfo.DeclaringType!; - var instanceIdentifier = includeInstanceNumber ? _instanceNumber + "@" : ""; + public string Format(bool multipleInstances, bool includeInstanceNumber) + { + var call = _call != null + ? Format(_call) + : Format(_specAndTarget!); - var declaringTypeName = MethodInfo.DeclaringType!.GetNonMangledTypeName(); - return string.Format("{1}{0}.{2}", declaringTypeName, instanceIdentifier, call); - } + if (!multipleInstances) return call; - private string Format(CallSpecAndTarget x) - { - return x.CallSpecification.ToString() ?? string.Empty; - } + var instanceIdentifier = includeInstanceNumber ? _instanceNumber + "@" : ""; - private string Format(ICall call) - { - var methodInfo = call.GetMethodInfo(); - var args = methodInfo.GetParameters() - .Zip(call.GetOriginalArguments(), (p, a) => new ArgAndParamInfo(p, a)) - .ToArray(); - return CallFormatter.Default.Format(methodInfo, FormatArgs(args)); - } + var declaringTypeName = MethodInfo.DeclaringType!.GetNonMangledTypeName(); + return string.Format("{1}{0}.{2}", declaringTypeName, instanceIdentifier, call); + } - private IEnumerable FormatArgs(ArgAndParamInfo[] arguments) - { - var argsWithParamsExpanded = - arguments - .SelectMany(a => a.ParamInfo.IsParams() - ? ((IEnumerable)a.Argument!).Cast() - : ToEnumerable(a.Argument)) - .Select(x => ArgumentFormatter.Default.Format(x, false)) - .ToArray(); + private string Format(CallSpecAndTarget x) + { + return x.CallSpecification.ToString() ?? string.Empty; + } - return argsWithParamsExpanded; - } + private string Format(ICall call) + { + var methodInfo = call.GetMethodInfo(); + var args = methodInfo.GetParameters() + .Zip(call.GetOriginalArguments(), (p, a) => new ArgAndParamInfo(p, a)) + .ToArray(); + return CallFormatter.Default.Format(methodInfo, FormatArgs(args)); + } - private IEnumerable ToEnumerable(T value) - { - yield return value; - } + private IEnumerable FormatArgs(ArgAndParamInfo[] arguments) + { + var argsWithParamsExpanded = + arguments + .SelectMany(a => a.ParamInfo.IsParams() + ? ((IEnumerable)a.Argument!).Cast() + : ToEnumerable(a.Argument)) + .Select(x => ArgumentFormatter.Default.Format(x, false)) + .ToArray(); + + return argsWithParamsExpanded; } - private class ArgAndParamInfo + private IEnumerable ToEnumerable(T value) { - public ParameterInfo ParamInfo { get; } - public object? Argument { get; } + yield return value; + } + } - public ArgAndParamInfo(ParameterInfo paramInfo, object? argument) - { - ParamInfo = paramInfo; - Argument = argument; - } + private class ArgAndParamInfo + { + public ParameterInfo ParamInfo { get; } + public object? Argument { get; } + + public ArgAndParamInfo(ParameterInfo paramInfo, object? argument) + { + ParamInfo = paramInfo; + Argument = argument; } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SequenceChecking/SequenceInOrderAssertion.cs b/src/NSubstitute/Core/SequenceChecking/SequenceInOrderAssertion.cs index cdf41b05a..d2af50b78 100644 --- a/src/NSubstitute/Core/SequenceChecking/SequenceInOrderAssertion.cs +++ b/src/NSubstitute/Core/SequenceChecking/SequenceInOrderAssertion.cs @@ -1,63 +1,62 @@ using System.Reflection; using NSubstitute.Exceptions; -namespace NSubstitute.Core.SequenceChecking +namespace NSubstitute.Core.SequenceChecking; + +public class SequenceInOrderAssertion { - public class SequenceInOrderAssertion + public void Assert(IQueryResults queryResult) { - public void Assert(IQueryResults queryResult) - { - var matchingCallsInOrder = queryResult - .MatchingCallsInOrder() - .Where(x => IsNotPropertyGetterCall(x.GetMethodInfo())) - .ToArray(); - var querySpec = queryResult - .QuerySpecification() - .Where(x => IsNotPropertyGetterCall(x.CallSpecification.GetMethodInfo())) - .ToArray(); - - if (matchingCallsInOrder.Length != querySpec.Length) - { - throw new CallSequenceNotFoundException(GetExceptionMessage(querySpec, matchingCallsInOrder)); - } - - var callsAndSpecs = matchingCallsInOrder - .Zip(querySpec, (call, specAndTarget) => - new - { - Call = call, - Spec = specAndTarget.CallSpecification, - IsMatch = Matches(call, specAndTarget) - } - ); - - if (callsAndSpecs.Any(x => !x.IsMatch)) - { - throw new CallSequenceNotFoundException(GetExceptionMessage(querySpec, matchingCallsInOrder)); - } - } + var matchingCallsInOrder = queryResult + .MatchingCallsInOrder() + .Where(x => IsNotPropertyGetterCall(x.GetMethodInfo())) + .ToArray(); + var querySpec = queryResult + .QuerySpecification() + .Where(x => IsNotPropertyGetterCall(x.CallSpecification.GetMethodInfo())) + .ToArray(); - private bool Matches(ICall call, CallSpecAndTarget specAndTarget) + if (matchingCallsInOrder.Length != querySpec.Length) { - return ReferenceEquals(call.Target(), specAndTarget.Target) - && specAndTarget.CallSpecification.IsSatisfiedBy(call); + throw new CallSequenceNotFoundException(GetExceptionMessage(querySpec, matchingCallsInOrder)); } - private bool IsNotPropertyGetterCall(MethodInfo methodInfo) - { - return methodInfo.GetPropertyFromGetterCallOrNull() == null; - } + var callsAndSpecs = matchingCallsInOrder + .Zip(querySpec, (call, specAndTarget) => + new + { + Call = call, + Spec = specAndTarget.CallSpecification, + IsMatch = Matches(call, specAndTarget) + } + ); - private string GetExceptionMessage(CallSpecAndTarget[] querySpec, ICall[] matchingCallsInOrder) + if (callsAndSpecs.Any(x => !x.IsMatch)) { - const string callDelimiter = "\n "; - var formatter = new SequenceFormatter(callDelimiter, querySpec, matchingCallsInOrder); - return string.Format("\nExpected to receive these calls in order:\n{0}{1}\n" + - "\nActually received matching calls in this order:\n{0}{2}\n\n{3}", - callDelimiter, - formatter.FormatQuery(), - formatter.FormatActualCalls(), - "*** Note: calls to property getters are not considered part of the query. ***"); + throw new CallSequenceNotFoundException(GetExceptionMessage(querySpec, matchingCallsInOrder)); } } + + private bool Matches(ICall call, CallSpecAndTarget specAndTarget) + { + return ReferenceEquals(call.Target(), specAndTarget.Target) + && specAndTarget.CallSpecification.IsSatisfiedBy(call); + } + + private bool IsNotPropertyGetterCall(MethodInfo methodInfo) + { + return methodInfo.GetPropertyFromGetterCallOrNull() == null; + } + + private string GetExceptionMessage(CallSpecAndTarget[] querySpec, ICall[] matchingCallsInOrder) + { + const string callDelimiter = "\n "; + var formatter = new SequenceFormatter(callDelimiter, querySpec, matchingCallsInOrder); + return string.Format("\nExpected to receive these calls in order:\n{0}{1}\n" + + "\nActually received matching calls in this order:\n{0}{2}\n\n{3}", + callDelimiter, + formatter.FormatQuery(), + formatter.FormatActualCalls(), + "*** Note: calls to property getters are not considered part of the query. ***"); + } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SequenceNumberGenerator.cs b/src/NSubstitute/Core/SequenceNumberGenerator.cs index 6930e595b..9c64b1471 100644 --- a/src/NSubstitute/Core/SequenceNumberGenerator.cs +++ b/src/NSubstitute/Core/SequenceNumberGenerator.cs @@ -1,12 +1,11 @@ -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class SequenceNumberGenerator { - public class SequenceNumberGenerator - { - private long _current = long.MinValue; + private long _current = long.MinValue; - public virtual long Next() - { - return Interlocked.Increment(ref _current); - } + public virtual long Next() + { + return Interlocked.Increment(ref _current); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SubstituteFactory.cs b/src/NSubstitute/Core/SubstituteFactory.cs index c67bb7bdc..27b96e6e5 100644 --- a/src/NSubstitute/Core/SubstituteFactory.cs +++ b/src/NSubstitute/Core/SubstituteFactory.cs @@ -1,78 +1,77 @@ using System.Reflection; using NSubstitute.Exceptions; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class SubstituteFactory : ISubstituteFactory { - public class SubstituteFactory : ISubstituteFactory + private readonly ISubstituteStateFactory _substituteStateFactory; + private readonly ICallRouterFactory _callRouterFactory; + private readonly IProxyFactory _proxyFactory; + + public SubstituteFactory(ISubstituteStateFactory substituteStateFactory, ICallRouterFactory callRouterFactory, IProxyFactory proxyFactory) { - private readonly ISubstituteStateFactory _substituteStateFactory; - private readonly ICallRouterFactory _callRouterFactory; - private readonly IProxyFactory _proxyFactory; + _substituteStateFactory = substituteStateFactory; + _callRouterFactory = callRouterFactory; + _proxyFactory = proxyFactory; + } - public SubstituteFactory(ISubstituteStateFactory substituteStateFactory, ICallRouterFactory callRouterFactory, IProxyFactory proxyFactory) - { - _substituteStateFactory = substituteStateFactory; - _callRouterFactory = callRouterFactory; - _proxyFactory = proxyFactory; - } + /// + /// Create a substitute for the given types. + /// + /// + /// + /// + public object Create(Type[] typesToProxy, object?[] constructorArguments) + { + return Create(typesToProxy, constructorArguments, callBaseByDefault: false); + } - /// - /// Create a substitute for the given types. - /// - /// - /// - /// - public object Create(Type[] typesToProxy, object?[] constructorArguments) + /// + /// Create an instance of the given types, with calls configured to call the base implementation + /// where possible. Parts of the instance can be substituted using + /// Returns(). + /// + /// + /// + /// + public object CreatePartial(Type[] typesToProxy, object?[] constructorArguments) + { + var primaryProxyType = GetPrimaryProxyType(typesToProxy); + if (!CanCallBaseImplementation(primaryProxyType)) { - return Create(typesToProxy, constructorArguments, callBaseByDefault: false); + throw new CanNotPartiallySubForInterfaceOrDelegateException(primaryProxyType); } - /// - /// Create an instance of the given types, with calls configured to call the base implementation - /// where possible. Parts of the instance can be substituted using - /// Returns(). - /// - /// - /// - /// - public object CreatePartial(Type[] typesToProxy, object?[] constructorArguments) - { - var primaryProxyType = GetPrimaryProxyType(typesToProxy); - if (!CanCallBaseImplementation(primaryProxyType)) - { - throw new CanNotPartiallySubForInterfaceOrDelegateException(primaryProxyType); - } - - return Create(typesToProxy, constructorArguments, callBaseByDefault: true); - } + return Create(typesToProxy, constructorArguments, callBaseByDefault: true); + } - private object Create(Type[] typesToProxy, object?[] constructorArguments, bool callBaseByDefault) - { - var substituteState = _substituteStateFactory.Create(this); - substituteState.CallBaseConfiguration.CallBaseByDefault = callBaseByDefault; + private object Create(Type[] typesToProxy, object?[] constructorArguments, bool callBaseByDefault) + { + var substituteState = _substituteStateFactory.Create(this); + substituteState.CallBaseConfiguration.CallBaseByDefault = callBaseByDefault; - var primaryProxyType = GetPrimaryProxyType(typesToProxy); - var canConfigureBaseCalls = callBaseByDefault || CanCallBaseImplementation(primaryProxyType); + var primaryProxyType = GetPrimaryProxyType(typesToProxy); + var canConfigureBaseCalls = callBaseByDefault || CanCallBaseImplementation(primaryProxyType); - var callRouter = _callRouterFactory.Create(substituteState, canConfigureBaseCalls); - var additionalTypes = typesToProxy.Where(x => x != primaryProxyType).ToArray(); - var proxy = _proxyFactory.GenerateProxy(callRouter, primaryProxyType, additionalTypes, constructorArguments); - return proxy; - } + var callRouter = _callRouterFactory.Create(substituteState, canConfigureBaseCalls); + var additionalTypes = typesToProxy.Where(x => x != primaryProxyType).ToArray(); + var proxy = _proxyFactory.GenerateProxy(callRouter, primaryProxyType, additionalTypes, constructorArguments); + return proxy; + } - private static Type GetPrimaryProxyType(Type[] typesToProxy) - { - return typesToProxy.FirstOrDefault(t => t.IsDelegate()) - ?? typesToProxy.FirstOrDefault(t => t.GetTypeInfo().IsClass) - ?? typesToProxy.First(); - } + private static Type GetPrimaryProxyType(Type[] typesToProxy) + { + return typesToProxy.FirstOrDefault(t => t.IsDelegate()) + ?? typesToProxy.FirstOrDefault(t => t.GetTypeInfo().IsClass) + ?? typesToProxy.First(); + } - private static bool CanCallBaseImplementation(Type primaryProxyType) - { - var isDelegate = primaryProxyType.IsDelegate(); - var isClass = primaryProxyType.GetTypeInfo().IsClass; + private static bool CanCallBaseImplementation(Type primaryProxyType) + { + var isDelegate = primaryProxyType.IsDelegate(); + var isClass = primaryProxyType.GetTypeInfo().IsClass; - return isClass && !isDelegate; - } + return isClass && !isDelegate; } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SubstituteState.cs b/src/NSubstitute/Core/SubstituteState.cs index ad4f5ac35..76f3a238c 100644 --- a/src/NSubstitute/Core/SubstituteState.cs +++ b/src/NSubstitute/Core/SubstituteState.cs @@ -1,38 +1,37 @@ using NSubstitute.Routing.AutoValues; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class SubstituteState : ISubstituteState { - public class SubstituteState : ISubstituteState - { - public ICallBaseConfiguration CallBaseConfiguration { get; } - public ICallCollection ReceivedCalls { get; } - public ICallResults CallResults { get; } - public ICallActions CallActions { get; } - public IConfigureCall ConfigureCall { get; } - public IEventHandlerRegistry EventHandlerRegistry { get; } - public IReadOnlyCollection AutoValueProviders { get; } - public ICallResults AutoValuesCallResults { get; } - public IResultsForType ResultsForType { get; } - public ICustomHandlers CustomHandlers { get; } + public ICallBaseConfiguration CallBaseConfiguration { get; } + public ICallCollection ReceivedCalls { get; } + public ICallResults CallResults { get; } + public ICallActions CallActions { get; } + public IConfigureCall ConfigureCall { get; } + public IEventHandlerRegistry EventHandlerRegistry { get; } + public IReadOnlyCollection AutoValueProviders { get; } + public ICallResults AutoValuesCallResults { get; } + public IResultsForType ResultsForType { get; } + public ICustomHandlers CustomHandlers { get; } - public SubstituteState(ICallSpecificationFactory callSpecificationFactory, - ICallInfoFactory callInfoFactory, - IReadOnlyCollection autoValueProviders) - { - AutoValueProviders = autoValueProviders; + public SubstituteState(ICallSpecificationFactory callSpecificationFactory, + ICallInfoFactory callInfoFactory, + IReadOnlyCollection autoValueProviders) + { + AutoValueProviders = autoValueProviders; - var callCollection = new CallCollection(); - ReceivedCalls = callCollection; + var callCollection = new CallCollection(); + ReceivedCalls = callCollection; - CallBaseConfiguration = new CallBaseConfiguration(); - CallResults = new CallResults(callInfoFactory); - AutoValuesCallResults = new CallResults(callInfoFactory); - CallActions = new CallActions(callInfoFactory); - ResultsForType = new ResultsForType(callInfoFactory); - CustomHandlers = new CustomHandlers(this); - var getCallSpec = new GetCallSpec(callCollection, callSpecificationFactory, CallActions); - ConfigureCall = new ConfigureCall(CallResults, CallActions, getCallSpec); - EventHandlerRegistry = new EventHandlerRegistry(); - } + CallBaseConfiguration = new CallBaseConfiguration(); + CallResults = new CallResults(callInfoFactory); + AutoValuesCallResults = new CallResults(callInfoFactory); + CallActions = new CallActions(callInfoFactory); + ResultsForType = new ResultsForType(callInfoFactory); + CustomHandlers = new CustomHandlers(this); + var getCallSpec = new GetCallSpec(callCollection, callSpecificationFactory, CallActions); + ConfigureCall = new ConfigureCall(CallResults, CallActions, getCallSpec); + EventHandlerRegistry = new EventHandlerRegistry(); } } diff --git a/src/NSubstitute/Core/SubstituteStateFactory.cs b/src/NSubstitute/Core/SubstituteStateFactory.cs index b50e717c9..ade9f17cd 100644 --- a/src/NSubstitute/Core/SubstituteStateFactory.cs +++ b/src/NSubstitute/Core/SubstituteStateFactory.cs @@ -1,26 +1,25 @@ using NSubstitute.Routing.AutoValues; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class SubstituteStateFactory : ISubstituteStateFactory { - public class SubstituteStateFactory : ISubstituteStateFactory - { - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly ICallInfoFactory _callInfoFactory; - private readonly IAutoValueProvidersFactory _autoValueProvidersFactory; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly ICallInfoFactory _callInfoFactory; + private readonly IAutoValueProvidersFactory _autoValueProvidersFactory; - public SubstituteStateFactory(ICallSpecificationFactory callSpecificationFactory, - ICallInfoFactory callInfoFactory, - IAutoValueProvidersFactory autoValueProvidersFactory) - { - _callSpecificationFactory = callSpecificationFactory; - _callInfoFactory = callInfoFactory; - _autoValueProvidersFactory = autoValueProvidersFactory; - } + public SubstituteStateFactory(ICallSpecificationFactory callSpecificationFactory, + ICallInfoFactory callInfoFactory, + IAutoValueProvidersFactory autoValueProvidersFactory) + { + _callSpecificationFactory = callSpecificationFactory; + _callInfoFactory = callInfoFactory; + _autoValueProvidersFactory = autoValueProvidersFactory; + } - public ISubstituteState Create(ISubstituteFactory substituteFactory) - { - var autoValueProviders = _autoValueProvidersFactory.CreateProviders(substituteFactory); - return new SubstituteState(_callSpecificationFactory, _callInfoFactory, autoValueProviders); - } + public ISubstituteState Create(ISubstituteFactory substituteFactory) + { + var autoValueProviders = _autoValueProvidersFactory.CreateProviders(substituteFactory); + return new SubstituteState(_callSpecificationFactory, _callInfoFactory, autoValueProviders); } } \ No newline at end of file diff --git a/src/NSubstitute/Core/SubstitutionContext.cs b/src/NSubstitute/Core/SubstitutionContext.cs index 20e40177e..a3a4f1787 100644 --- a/src/NSubstitute/Core/SubstitutionContext.cs +++ b/src/NSubstitute/Core/SubstitutionContext.cs @@ -2,168 +2,167 @@ using NSubstitute.Core.DependencyInjection; using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class SubstitutionContext : ISubstitutionContext { - public class SubstitutionContext : ISubstitutionContext - { - public static ISubstitutionContext Current { get; set; } + public static ISubstitutionContext Current { get; set; } - private readonly ICallRouterResolver _callRouterResolver; - public ISubstituteFactory SubstituteFactory { get; } - public IRouteFactory RouteFactory { get; } - public IThreadLocalContext ThreadContext { get; } - public ICallSpecificationFactory CallSpecificationFactory { get; } + private readonly ICallRouterResolver _callRouterResolver; + public ISubstituteFactory SubstituteFactory { get; } + public IRouteFactory RouteFactory { get; } + public IThreadLocalContext ThreadContext { get; } + public ICallSpecificationFactory CallSpecificationFactory { get; } - static SubstitutionContext() - { - Current = NSubstituteDefaultFactory.CreateSubstitutionContext(); - } + static SubstitutionContext() + { + Current = NSubstituteDefaultFactory.CreateSubstitutionContext(); + } - public SubstitutionContext(ISubstituteFactory substituteFactory, - IRouteFactory routeFactory, - ICallSpecificationFactory callSpecificationFactory, - IThreadLocalContext threadLocalContext, - ICallRouterResolver callRouterResolver, - SequenceNumberGenerator sequenceNumberGenerator) - { - SubstituteFactory = substituteFactory; - RouteFactory = routeFactory; - CallSpecificationFactory = callSpecificationFactory; - ThreadContext = threadLocalContext; - _callRouterResolver = callRouterResolver; + public SubstitutionContext(ISubstituteFactory substituteFactory, + IRouteFactory routeFactory, + ICallSpecificationFactory callSpecificationFactory, + IThreadLocalContext threadLocalContext, + ICallRouterResolver callRouterResolver, + SequenceNumberGenerator sequenceNumberGenerator) + { + SubstituteFactory = substituteFactory; + RouteFactory = routeFactory; + CallSpecificationFactory = callSpecificationFactory; + ThreadContext = threadLocalContext; + _callRouterResolver = callRouterResolver; #pragma warning disable 618 // Obsolete - SequenceNumberGenerator = sequenceNumberGenerator; + SequenceNumberGenerator = sequenceNumberGenerator; #pragma warning restore 618 // Obsolete - } + } - public ICallRouter GetCallRouterFor(object substitute) => - _callRouterResolver.ResolveFor(substitute); + public ICallRouter GetCallRouterFor(object substitute) => + _callRouterResolver.ResolveFor(substitute); - // *********************************************************** - // ********************** OBSOLETE API ********************** - // API below is obsolete and present for the binary compatibility with the previous versions. - // All implementations are relaying to the non-obsolete members. + // *********************************************************** + // ********************** OBSOLETE API ********************** + // API below is obsolete and present for the binary compatibility with the previous versions. + // All implementations are relaying to the non-obsolete members. - [Obsolete("This property is obsolete and will be removed in a future version of the product.")] - public SequenceNumberGenerator SequenceNumberGenerator { get; } + [Obsolete("This property is obsolete and will be removed in a future version of the product.")] + public SequenceNumberGenerator SequenceNumberGenerator { get; } - [Obsolete("This property is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.IsQuerying) + " property instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.IsQuerying) + ".")] - public bool IsQuerying => ThreadContext.IsQuerying; + [Obsolete("This property is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.IsQuerying) + " property instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.IsQuerying) + ".")] + public bool IsQuerying => ThreadContext.IsQuerying; - [Obsolete("This property is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.PendingSpecification) + " property instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.PendingSpecification) + ".")] - public PendingSpecificationInfo? PendingSpecificationInfo + [Obsolete("This property is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.PendingSpecification) + " property instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.PendingSpecification) + ".")] + public PendingSpecificationInfo? PendingSpecificationInfo + { + get { - get + if (!ThreadContext.PendingSpecification.HasPendingCallSpecInfo()) + return null; + + // This removes the pending specification, so we need to restore it back. + var consumedSpecInfo = ThreadContext.PendingSpecification.UseCallSpecInfo(); + PendingSpecificationInfo = consumedSpecInfo; + + return consumedSpecInfo; + } + set + { + if (value == null) { - if (!ThreadContext.PendingSpecification.HasPendingCallSpecInfo()) - return null; + ThreadContext.PendingSpecification.Clear(); + return; + } - // This removes the pending specification, so we need to restore it back. - var consumedSpecInfo = ThreadContext.PendingSpecification.UseCallSpecInfo(); - PendingSpecificationInfo = consumedSpecInfo; + // Emulate the old API. A bit clumsy, however it's here for the backward compatibility only + // and is not expected to be used frequently. + var unwrappedValue = value.Handle( + spec => Tuple.Create(spec, null), + call => Tuple.Create(null, call)); - return consumedSpecInfo; + if (unwrappedValue.Item1 != null) + { + ThreadContext.PendingSpecification.SetCallSpecification(unwrappedValue.Item1); } - set + else { - if (value == null) - { - ThreadContext.PendingSpecification.Clear(); - return; - } - - // Emulate the old API. A bit clumsy, however it's here for the backward compatibility only - // and is not expected to be used frequently. - var unwrappedValue = value.Handle( - spec => Tuple.Create(spec, null), - call => Tuple.Create(null, call)); - - if (unwrappedValue.Item1 != null) - { - ThreadContext.PendingSpecification.SetCallSpecification(unwrappedValue.Item1); - } - else - { - ThreadContext.PendingSpecification.SetLastCall(unwrappedValue.Item2!); - } + ThreadContext.PendingSpecification.SetLastCall(unwrappedValue.Item2!); } } + } - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.LastCallShouldReturn) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.LastCallShouldReturn) + "(...).")] - public ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs) => - ThreadContext.LastCallShouldReturn(value, matchArgs); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.ClearLastCallRouter) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.ClearLastCallRouter) + "().")] - public void ClearLastCallRouter() => - ThreadContext.ClearLastCallRouter(); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(RouteFactory) + " property instead.")] - public IRouteFactory GetRouteFactory() => - RouteFactory; - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetLastCallRouter) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetLastCallRouter) + "(...).")] - public void LastCallRouter(ICallRouter callRouter) => - ThreadContext.SetLastCallRouter(callRouter); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "(...).")] - public void EnqueueArgumentSpecification(IArgumentSpecification spec) => - ThreadContext.EnqueueArgumentSpecification(spec); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "().")] - public IList DequeueAllArgumentSpecifications() => - ThreadContext.DequeueAllArgumentSpecifications(); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "(...).")] - public void RaiseEventForNextCall(Func getArguments) => - ThreadContext.SetPendingRaisingEventArgumentsFactory(getArguments); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "().")] - public Func? DequeuePendingRaisingEventArguments() => - ThreadContext.UsePendingRaisingEventArgumentsFactory(); - - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RegisterInContextQuery) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RegisterInContextQuery) + "().", - error: true)] - public void AddToQuery(object target, ICallSpecification callSpecification) - { - // We cannot simulate the API anymore as it changed drastically. - // That should be fine, as this method was expected to be called from the NSubstitute core only. - throw new NotSupportedException( - "This API was obsolete and is not supported anymore. " + - "Please use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RegisterInContextQuery) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RegisterInContextQuery) + "()."); - } + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.LastCallShouldReturn) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.LastCallShouldReturn) + "(...).")] + public ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs) => + ThreadContext.LastCallShouldReturn(value, matchArgs); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.ClearLastCallRouter) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.ClearLastCallRouter) + "().")] + public void ClearLastCallRouter() => + ThreadContext.ClearLastCallRouter(); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(RouteFactory) + " property instead.")] + public IRouteFactory GetRouteFactory() => + RouteFactory; + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetLastCallRouter) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetLastCallRouter) + "(...).")] + public void LastCallRouter(ICallRouter callRouter) => + ThreadContext.SetLastCallRouter(callRouter); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.EnqueueArgumentSpecification) + "(...).")] + public void EnqueueArgumentSpecification(IArgumentSpecification spec) => + ThreadContext.EnqueueArgumentSpecification(spec); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.DequeueAllArgumentSpecifications) + "().")] + public IList DequeueAllArgumentSpecifications() => + ThreadContext.DequeueAllArgumentSpecifications(); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.SetPendingRaisingEventArgumentsFactory) + "(...).")] + public void RaiseEventForNextCall(Func getArguments) => + ThreadContext.SetPendingRaisingEventArgumentsFactory(getArguments); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.UsePendingRaisingEventArgumentsFactory) + "().")] + public Func? DequeuePendingRaisingEventArguments() => + ThreadContext.UsePendingRaisingEventArgumentsFactory(); + + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RegisterInContextQuery) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RegisterInContextQuery) + "().", + error: true)] + public void AddToQuery(object target, ICallSpecification callSpecification) + { + // We cannot simulate the API anymore as it changed drastically. + // That should be fine, as this method was expected to be called from the NSubstitute core only. + throw new NotSupportedException( + "This API was obsolete and is not supported anymore. " + + "Please use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RegisterInContextQuery) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RegisterInContextQuery) + "()."); + } - [Obsolete("This method is obsolete and will be removed in a future version of the product. " + - "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RunInQueryContext) + "() method instead. " + - "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RunInQueryContext) + "(...).")] - public IQueryResults RunQuery(Action calls) - { - var query = new Query(CallSpecificationFactory); - ThreadContext.RunInQueryContext(calls, query); - return query.Result(); - } + [Obsolete("This method is obsolete and will be removed in a future version of the product. " + + "Use the " + nameof(ThreadContext) + "." + nameof(IThreadLocalContext.RunInQueryContext) + "() method instead. " + + "For example: SubstitutionContext.Current.ThreadContext." + nameof(IThreadLocalContext.RunInQueryContext) + "(...).")] + public IQueryResults RunQuery(Action calls) + { + var query = new Query(CallSpecificationFactory); + ThreadContext.RunInQueryContext(calls, query); + return query.Result(); } } diff --git a/src/NSubstitute/Core/ThreadLocalContext.cs b/src/NSubstitute/Core/ThreadLocalContext.cs index 614a82198..59756f52d 100644 --- a/src/NSubstitute/Core/ThreadLocalContext.cs +++ b/src/NSubstitute/Core/ThreadLocalContext.cs @@ -2,222 +2,221 @@ using NSubstitute.Exceptions; using NSubstitute.Routing; -namespace NSubstitute.Core +namespace NSubstitute.Core; + +public class ThreadLocalContext : IThreadLocalContext { - public class ThreadLocalContext : IThreadLocalContext + private static readonly IArgumentSpecification[] EmptySpecifications = new IArgumentSpecification[0]; + + private readonly RobustThreadLocal _lastCallRouter; + private readonly RobustThreadLocal> _argumentSpecifications; + private readonly RobustThreadLocal?> _getArgumentsForRaisingEvent; + private readonly RobustThreadLocal _currentQuery; + private readonly RobustThreadLocal _pendingSpecificationInfo; + private readonly RobustThreadLocal>?> _nextRouteFactory; + public IPendingSpecification PendingSpecification { get; } + + public ThreadLocalContext() { - private static readonly IArgumentSpecification[] EmptySpecifications = new IArgumentSpecification[0]; + _lastCallRouter = new RobustThreadLocal(); + _argumentSpecifications = new RobustThreadLocal>(() => new List()); + _getArgumentsForRaisingEvent = new RobustThreadLocal?>(); + _currentQuery = new RobustThreadLocal(); + _pendingSpecificationInfo = new RobustThreadLocal(); + _nextRouteFactory = new RobustThreadLocal>?>(); + + PendingSpecification = new PendingSpecificationWrapper(_pendingSpecificationInfo); + } - private readonly RobustThreadLocal _lastCallRouter; - private readonly RobustThreadLocal> _argumentSpecifications; - private readonly RobustThreadLocal?> _getArgumentsForRaisingEvent; - private readonly RobustThreadLocal _currentQuery; - private readonly RobustThreadLocal _pendingSpecificationInfo; - private readonly RobustThreadLocal>?> _nextRouteFactory; - public IPendingSpecification PendingSpecification { get; } + public void SetLastCallRouter(ICallRouter callRouter) + { + _lastCallRouter.Value = callRouter; + } - public ThreadLocalContext() - { - _lastCallRouter = new RobustThreadLocal(); - _argumentSpecifications = new RobustThreadLocal>(() => new List()); - _getArgumentsForRaisingEvent = new RobustThreadLocal?>(); - _currentQuery = new RobustThreadLocal(); - _pendingSpecificationInfo = new RobustThreadLocal(); - _nextRouteFactory = new RobustThreadLocal>?>(); + public ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs) + { + var lastCallRouter = _lastCallRouter.Value; + if (lastCallRouter == null) + throw new CouldNotSetReturnDueToNoLastCallException(); - PendingSpecification = new PendingSpecificationWrapper(_pendingSpecificationInfo); - } + if (!PendingSpecification.HasPendingCallSpecInfo()) + throw new CouldNotSetReturnDueToMissingInfoAboutLastCallException(); - public void SetLastCallRouter(ICallRouter callRouter) + if (_argumentSpecifications.Value.Count > 0) { - _lastCallRouter.Value = callRouter; + // Clear invalid arg specs so they will not affect other tests. + _argumentSpecifications.Value.Clear(); + throw new UnexpectedArgumentMatcherException(); } - public ConfiguredCall LastCallShouldReturn(IReturn value, MatchArgs matchArgs) + var pendingSpecInfo = PendingSpecification.UseCallSpecInfo()!; + var configuredCall = lastCallRouter.LastCallShouldReturn(value, matchArgs, pendingSpecInfo); + ClearLastCallRouter(); + return configuredCall; + } + + public void SetNextRoute(ICallRouter callRouter, Func nextRouteFactory) + { + _nextRouteFactory.Value = Tuple.Create(callRouter, nextRouteFactory); + } + + public Func? UseNextRoute(ICallRouter callRouter) + { + var value = _nextRouteFactory.Value; + if (value != null && ReferenceEquals(callRouter, value.Item1)) { - var lastCallRouter = _lastCallRouter.Value; - if (lastCallRouter == null) - throw new CouldNotSetReturnDueToNoLastCallException(); + _nextRouteFactory.Value = null; + return value.Item2; + } - if (!PendingSpecification.HasPendingCallSpecInfo()) - throw new CouldNotSetReturnDueToMissingInfoAboutLastCallException(); + return null; + } - if (_argumentSpecifications.Value.Count > 0) - { - // Clear invalid arg specs so they will not affect other tests. - _argumentSpecifications.Value.Clear(); - throw new UnexpectedArgumentMatcherException(); - } + public void ClearLastCallRouter() + { + _lastCallRouter.Value = null; + } - var pendingSpecInfo = PendingSpecification.UseCallSpecInfo()!; - var configuredCall = lastCallRouter.LastCallShouldReturn(value, matchArgs, pendingSpecInfo); - ClearLastCallRouter(); - return configuredCall; - } + public void EnqueueArgumentSpecification(IArgumentSpecification spec) + { + var queue = _argumentSpecifications.Value; + if (queue == null) + throw new SubstituteInternalException("Argument specification queue is null."); + + queue.Add(spec); + } + + public IList DequeueAllArgumentSpecifications() + { + var queue = _argumentSpecifications.Value; + if (queue == null) + throw new SubstituteInternalException("Argument specification queue is null."); - public void SetNextRoute(ICallRouter callRouter, Func nextRouteFactory) + if (queue.Count == 0) { - _nextRouteFactory.Value = Tuple.Create(callRouter, nextRouteFactory); + // It's a performance optimization to avoid extra allocation and write access to ThreadLocal variable. + // We violate public contract, as mutable list was expected as result. + // However, in reality we never expect value to be mutated, so this optimization is fine. + // We are not allowed to change public contract due to SemVer, so keeping that as it is. + queue = EmptySpecifications; } - - public Func? UseNextRoute(ICallRouter callRouter) + else { - var value = _nextRouteFactory.Value; - if (value != null && ReferenceEquals(callRouter, value.Item1)) - { - _nextRouteFactory.Value = null; - return value.Item2; - } - - return null; + _argumentSpecifications.Value = new List(); } - public void ClearLastCallRouter() + return queue; + } + + public void SetPendingRaisingEventArgumentsFactory(Func getArguments) + { + _getArgumentsForRaisingEvent.Value = getArguments; + } + + public Func? UsePendingRaisingEventArgumentsFactory() + { + var result = _getArgumentsForRaisingEvent.Value; + if (result != null) { - _lastCallRouter.Value = null; + _getArgumentsForRaisingEvent.Value = null; } - public void EnqueueArgumentSpecification(IArgumentSpecification spec) - { - var queue = _argumentSpecifications.Value; - if (queue == null) - throw new SubstituteInternalException("Argument specification queue is null."); + return result; + } - queue.Add(spec); + public void RunInQueryContext(Action calls, IQuery query) + { + _currentQuery.Value = query; + try + { + calls(); } - - public IList DequeueAllArgumentSpecifications() + finally { - var queue = _argumentSpecifications.Value; - if (queue == null) - throw new SubstituteInternalException("Argument specification queue is null."); + _currentQuery.Value = null; + } + } - if (queue.Count == 0) - { - // It's a performance optimization to avoid extra allocation and write access to ThreadLocal variable. - // We violate public contract, as mutable list was expected as result. - // However, in reality we never expect value to be mutated, so this optimization is fine. - // We are not allowed to change public contract due to SemVer, so keeping that as it is. - queue = EmptySpecifications; - } - else - { - _argumentSpecifications.Value = new List(); - } + public bool IsQuerying => _currentQuery.Value != null; - return queue; - } + public void RegisterInContextQuery(ICall call) + { + var query = _currentQuery.Value; + if (query == null) + throw new NotRunningAQueryException(); + + query.RegisterCall(call); + } + + private class PendingSpecificationWrapper : IPendingSpecification + { + private readonly RobustThreadLocal _valueHolder; - public void SetPendingRaisingEventArgumentsFactory(Func getArguments) + public PendingSpecificationWrapper(RobustThreadLocal valueHolder) { - _getArgumentsForRaisingEvent.Value = getArguments; + _valueHolder = valueHolder; } - public Func? UsePendingRaisingEventArgumentsFactory() + public bool HasPendingCallSpecInfo() { - var result = _getArgumentsForRaisingEvent.Value; - if (result != null) - { - _getArgumentsForRaisingEvent.Value = null; - } - - return result; + return _valueHolder.Value.HasValue; } - public void RunInQueryContext(Action calls, IQuery query) + public PendingSpecificationInfo? UseCallSpecInfo() { - _currentQuery.Value = query; - try - { - calls(); - } - finally - { - _currentQuery.Value = null; - } + var info = _valueHolder.Value; + Clear(); + return info.ToPendingSpecificationInfo(); } - public bool IsQuerying => _currentQuery.Value != null; - - public void RegisterInContextQuery(ICall call) + public void SetCallSpecification(ICallSpecification callSpecification) { - var query = _currentQuery.Value; - if (query == null) - throw new NotRunningAQueryException(); - - query.RegisterCall(call); + _valueHolder.Value = PendingSpecInfoData.FromCallSpecification(callSpecification); } - private class PendingSpecificationWrapper : IPendingSpecification + public void SetLastCall(ICall lastCall) { - private readonly RobustThreadLocal _valueHolder; - - public PendingSpecificationWrapper(RobustThreadLocal valueHolder) - { - _valueHolder = valueHolder; - } - - public bool HasPendingCallSpecInfo() - { - return _valueHolder.Value.HasValue; - } + _valueHolder.Value = PendingSpecInfoData.FromLastCall(lastCall); + } - public PendingSpecificationInfo? UseCallSpecInfo() - { - var info = _valueHolder.Value; - Clear(); - return info.ToPendingSpecificationInfo(); - } + public void Clear() + { + _valueHolder.Value = default; + } + } - public void SetCallSpecification(ICallSpecification callSpecification) - { - _valueHolder.Value = PendingSpecInfoData.FromCallSpecification(callSpecification); - } + private readonly struct PendingSpecInfoData + { + private readonly ICallSpecification? _callSpecification; + private readonly ICall? _lastCall; - public void SetLastCall(ICall lastCall) - { - _valueHolder.Value = PendingSpecInfoData.FromLastCall(lastCall); - } + public bool HasValue => _lastCall != null || _callSpecification != null; - public void Clear() - { - _valueHolder.Value = default; - } + private PendingSpecInfoData(ICallSpecification? callSpecification, ICall? lastCall) + { + _callSpecification = callSpecification; + _lastCall = lastCall; } - private readonly struct PendingSpecInfoData + public PendingSpecificationInfo? ToPendingSpecificationInfo() { - private readonly ICallSpecification? _callSpecification; - private readonly ICall? _lastCall; + if (_callSpecification != null) + return PendingSpecificationInfo.FromCallSpecification(_callSpecification); - public bool HasValue => _lastCall != null || _callSpecification != null; + if (_lastCall != null) + return PendingSpecificationInfo.FromLastCall(_lastCall); - private PendingSpecInfoData(ICallSpecification? callSpecification, ICall? lastCall) - { - _callSpecification = callSpecification; - _lastCall = lastCall; - } - - public PendingSpecificationInfo? ToPendingSpecificationInfo() - { - if (_callSpecification != null) - return PendingSpecificationInfo.FromCallSpecification(_callSpecification); - - if (_lastCall != null) - return PendingSpecificationInfo.FromLastCall(_lastCall); - - return null; - } + return null; + } - public static PendingSpecInfoData FromLastCall(ICall lastCall) - { - return new PendingSpecInfoData(null, lastCall); - } + public static PendingSpecInfoData FromLastCall(ICall lastCall) + { + return new PendingSpecInfoData(null, lastCall); + } - public static PendingSpecInfoData FromCallSpecification(ICallSpecification callSpecification) - { - return new PendingSpecInfoData(callSpecification, null); - } + public static PendingSpecInfoData FromCallSpecification(ICallSpecification callSpecification) + { + return new PendingSpecInfoData(callSpecification, null); } } } \ No newline at end of file diff --git a/src/NSubstitute/Core/WhenCalled.cs b/src/NSubstitute/Core/WhenCalled.cs index 38c2f6020..c15b96912 100644 --- a/src/NSubstitute/Core/WhenCalled.cs +++ b/src/NSubstitute/Core/WhenCalled.cs @@ -3,85 +3,84 @@ // Disable nullability for entry-point API #nullable disable annotations -namespace NSubstitute.Core -{ - public class WhenCalled - { - private readonly T _substitute; - private readonly Action _call; - private readonly MatchArgs _matchArgs; - private readonly ICallRouter _callRouter; - private readonly IThreadLocalContext _threadContext; - private readonly IRouteFactory _routeFactory; +namespace NSubstitute.Core; - public WhenCalled(ISubstitutionContext context, T substitute, Action call, MatchArgs matchArgs) - { - _substitute = substitute; - _call = call; - _matchArgs = matchArgs; - _callRouter = context.GetCallRouterFor(substitute!); - _routeFactory = context.RouteFactory; - _threadContext = context.ThreadContext; - } +public class WhenCalled +{ + private readonly T _substitute; + private readonly Action _call; + private readonly MatchArgs _matchArgs; + private readonly ICallRouter _callRouter; + private readonly IThreadLocalContext _threadContext; + private readonly IRouteFactory _routeFactory; - /// - /// Perform this action when called. - /// - /// - public void Do(Action callbackWithArguments) - { - _threadContext.SetNextRoute(_callRouter, x => _routeFactory.DoWhenCalled(x, callbackWithArguments, _matchArgs)); - _call(_substitute); - } + public WhenCalled(ISubstitutionContext context, T substitute, Action call, MatchArgs matchArgs) + { + _substitute = substitute; + _call = call; + _matchArgs = matchArgs; + _callRouter = context.GetCallRouterFor(substitute!); + _routeFactory = context.RouteFactory; + _threadContext = context.ThreadContext; + } - /// - /// Perform this configured callback when called. - /// - /// - public void Do(Callback callback) - { - _threadContext.SetNextRoute(_callRouter, x => _routeFactory.DoWhenCalled(x, callback.Call, _matchArgs)); - _call(_substitute); - } + /// + /// Perform this action when called. + /// + /// + public void Do(Action callbackWithArguments) + { + _threadContext.SetNextRoute(_callRouter, x => _routeFactory.DoWhenCalled(x, callbackWithArguments, _matchArgs)); + _call(_substitute); + } - /// - /// Do not call the base implementation on future calls. For use with partial substitutes. - /// - public void DoNotCallBase() - { - _threadContext.SetNextRoute(_callRouter, x => _routeFactory.DoNotCallBase(x, _matchArgs)); - _call(_substitute); - } + /// + /// Perform this configured callback when called. + /// + /// + public void Do(Callback callback) + { + _threadContext.SetNextRoute(_callRouter, x => _routeFactory.DoWhenCalled(x, callback.Call, _matchArgs)); + _call(_substitute); + } - /// - /// Call the base implementation of future calls. For use with non-partial class substitutes. - /// - public void CallBase() - { - _threadContext.SetNextRoute(_callRouter, x => _routeFactory.CallBase(x, _matchArgs)); - _call(_substitute); - } + /// + /// Do not call the base implementation on future calls. For use with partial substitutes. + /// + public void DoNotCallBase() + { + _threadContext.SetNextRoute(_callRouter, x => _routeFactory.DoNotCallBase(x, _matchArgs)); + _call(_substitute); + } - /// - /// Throw the specified exception when called. - /// - public void Throw(Exception exception) => - Do(ci => throw exception); + /// + /// Call the base implementation of future calls. For use with non-partial class substitutes. + /// + public void CallBase() + { + _threadContext.SetNextRoute(_callRouter, x => _routeFactory.CallBase(x, _matchArgs)); + _call(_substitute); + } - /// - /// Throw an exception of the given type when called. - /// - public TException Throw() where TException : Exception, new() - { - var exception = new TException(); - Do(_ => throw exception!); - return exception; - } + /// + /// Throw the specified exception when called. + /// + public void Throw(Exception exception) => + Do(ci => throw exception); - /// - /// Throw an exception generated by the specified function when called. - /// - public void Throw(Func createException) => - Do(ci => throw createException(ci)); + /// + /// Throw an exception of the given type when called. + /// + public TException Throw() where TException : Exception, new() + { + var exception = new TException(); + Do(_ => throw exception!); + return exception; } + + /// + /// Throw an exception generated by the specified function when called. + /// + public void Throw(Func createException) => + Do(ci => throw createException(ci)); } \ No newline at end of file diff --git a/src/NSubstitute/Exceptions/AmbiguousArgumentsException.cs b/src/NSubstitute/Exceptions/AmbiguousArgumentsException.cs index 12b16e154..51625d858 100644 --- a/src/NSubstitute/Exceptions/AmbiguousArgumentsException.cs +++ b/src/NSubstitute/Exceptions/AmbiguousArgumentsException.cs @@ -5,142 +5,141 @@ using NSubstitute.Core.Arguments; using static System.Environment; -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class AmbiguousArgumentsException : SubstituteException { - public class AmbiguousArgumentsException : SubstituteException - { - internal const string NonReportedResolvedSpecificationsKey = "NON_REPORTED_RESOLVED_SPECIFICATIONS"; - private const string DefaultErrorMessage = - "Cannot determine argument specifications to use. Please use specifications for all arguments of the same type."; + internal const string NonReportedResolvedSpecificationsKey = "NON_REPORTED_RESOLVED_SPECIFICATIONS"; + private const string DefaultErrorMessage = + "Cannot determine argument specifications to use. Please use specifications for all arguments of the same type."; - private const string TabPadding = " "; + private const string TabPadding = " "; - internal bool ContainsDefaultMessage { get; } + internal bool ContainsDefaultMessage { get; } - public AmbiguousArgumentsException() : base(DefaultErrorMessage) - { - ContainsDefaultMessage = true; - } + public AmbiguousArgumentsException() : base(DefaultErrorMessage) + { + ContainsDefaultMessage = true; + } - public AmbiguousArgumentsException(string message) : base(message) - { - } + public AmbiguousArgumentsException(string message) : base(message) + { + } - public AmbiguousArgumentsException(MethodInfo method, - IEnumerable invocationArguments, - IEnumerable matchedSpecifications, - IEnumerable allSpecifications) - : this(BuildExceptionMessage(method, invocationArguments, matchedSpecifications, allSpecifications)) - { - } + public AmbiguousArgumentsException(MethodInfo method, + IEnumerable invocationArguments, + IEnumerable matchedSpecifications, + IEnumerable allSpecifications) + : this(BuildExceptionMessage(method, invocationArguments, matchedSpecifications, allSpecifications)) + { + } - private static string BuildExceptionMessage(MethodInfo method, - IEnumerable invocationArguments, - IEnumerable matchedSpecifications, - IEnumerable allSpecifications) + private static string BuildExceptionMessage(MethodInfo method, + IEnumerable invocationArguments, + IEnumerable matchedSpecifications, + IEnumerable allSpecifications) + { + string? methodSignature = null; + string? methodArgsWithHighlightedPossibleArgSpecs = null; + string? matchedSpecificationsInfo = null; + if (CallFormatter.Default.CanFormat(method)) { - string? methodSignature = null; - string? methodArgsWithHighlightedPossibleArgSpecs = null; - string? matchedSpecificationsInfo = null; - if (CallFormatter.Default.CanFormat(method)) + var argsWithInlinedParamsArray = invocationArguments.ToArray(); + // If last argument is `params`, we inline the value. + if (method.GetParameters().Last().IsParams() + && argsWithInlinedParamsArray.Last() is IEnumerable paramsArray) { - var argsWithInlinedParamsArray = invocationArguments.ToArray(); - // If last argument is `params`, we inline the value. - if (method.GetParameters().Last().IsParams() - && argsWithInlinedParamsArray.Last() is IEnumerable paramsArray) - { - argsWithInlinedParamsArray = argsWithInlinedParamsArray - .Take(argsWithInlinedParamsArray.Length - 1) - .Concat(paramsArray.Cast()) - .ToArray(); - } - - methodSignature = CallFormatter.Default.Format( - method, - FormatMethodParameterTypes(method.GetParameters())); - - methodArgsWithHighlightedPossibleArgSpecs = CallFormatter.Default.Format( - method, - FormatMethodArguments(argsWithInlinedParamsArray)); - - matchedSpecificationsInfo = CallFormatter.Default.Format( - method, - PadNonMatchedSpecifications(matchedSpecifications, argsWithInlinedParamsArray)); + argsWithInlinedParamsArray = argsWithInlinedParamsArray + .Take(argsWithInlinedParamsArray.Length - 1) + .Concat(paramsArray.Cast()) + .ToArray(); } - var message = new StringBuilder(); - message.AppendLine(DefaultErrorMessage); + methodSignature = CallFormatter.Default.Format( + method, + FormatMethodParameterTypes(method.GetParameters())); - if (methodSignature != null) - { - message.AppendLine("Method signature:"); - message.Append(TabPadding); - message.AppendLine(methodSignature); - } + methodArgsWithHighlightedPossibleArgSpecs = CallFormatter.Default.Format( + method, + FormatMethodArguments(argsWithInlinedParamsArray)); - if (methodArgsWithHighlightedPossibleArgSpecs != null) - { - message.AppendLine("Method arguments (possible arg matchers are indicated with '*'):"); - message.Append(TabPadding); - message.AppendLine(methodArgsWithHighlightedPossibleArgSpecs); - } + matchedSpecificationsInfo = CallFormatter.Default.Format( + method, + PadNonMatchedSpecifications(matchedSpecifications, argsWithInlinedParamsArray)); + } - message.AppendLine("All queued specifications:"); - message.AppendLine(FormatSpecifications(allSpecifications)); + var message = new StringBuilder(); + message.AppendLine(DefaultErrorMessage); - if (matchedSpecificationsInfo != null) - { - message.AppendLine("Matched argument specifications:"); - message.Append(TabPadding); - message.AppendLine(matchedSpecificationsInfo); - } + if (methodSignature != null) + { + message.AppendLine("Method signature:"); + message.Append(TabPadding); + message.AppendLine(methodSignature); + } - return message.ToString(); + if (methodArgsWithHighlightedPossibleArgSpecs != null) + { + message.AppendLine("Method arguments (possible arg matchers are indicated with '*'):"); + message.Append(TabPadding); + message.AppendLine(methodArgsWithHighlightedPossibleArgSpecs); } - private static IEnumerable FormatMethodParameterTypes(IEnumerable parameters) + message.AppendLine("All queued specifications:"); + message.AppendLine(FormatSpecifications(allSpecifications)); + + if (matchedSpecificationsInfo != null) { - return parameters.Select(p => - { - var type = p.ParameterType; + message.AppendLine("Matched argument specifications:"); + message.Append(TabPadding); + message.AppendLine(matchedSpecificationsInfo); + } - if (p.IsOut) - return "out " + type.GetElementType()!.GetNonMangledTypeName(); + return message.ToString(); + } - if (type.IsByRef) - return "ref " + type.GetElementType()!.GetNonMangledTypeName(); + private static IEnumerable FormatMethodParameterTypes(IEnumerable parameters) + { + return parameters.Select(p => + { + var type = p.ParameterType; - if (p.IsParams()) - return "params " + type.GetNonMangledTypeName(); + if (p.IsOut) + return "out " + type.GetElementType()!.GetNonMangledTypeName(); - return type.GetNonMangledTypeName(); - }); - } + if (type.IsByRef) + return "ref " + type.GetElementType()!.GetNonMangledTypeName(); - private static IEnumerable FormatMethodArguments(IEnumerable arguments) - { - var defaultChecker = new DefaultChecker(new DefaultForType()); + if (p.IsParams()) + return "params " + type.GetNonMangledTypeName(); - return arguments.Select(arg => - { - var isPotentialArgSpec = arg == null || defaultChecker.IsDefault(arg, arg.GetType()); - return ArgumentFormatter.Default.Format(arg, highlight: isPotentialArgSpec); - }); - } + return type.GetNonMangledTypeName(); + }); + } + + private static IEnumerable FormatMethodArguments(IEnumerable arguments) + { + var defaultChecker = new DefaultChecker(new DefaultForType()); - private static IEnumerable PadNonMatchedSpecifications(IEnumerable matchedSpecifications, IEnumerable allArguments) + return arguments.Select(arg => { - var allMatchedSpecs = matchedSpecifications.Select(x => x.ToString() ?? string.Empty).ToArray(); + var isPotentialArgSpec = arg == null || defaultChecker.IsDefault(arg, arg.GetType()); + return ArgumentFormatter.Default.Format(arg, highlight: isPotentialArgSpec); + }); + } - int nonResolvedArgumentsCount = allArguments.Count() - allMatchedSpecs.Length; - var nonResolvedArgsPlaceholders = Enumerable.Repeat("???", nonResolvedArgumentsCount); + private static IEnumerable PadNonMatchedSpecifications(IEnumerable matchedSpecifications, IEnumerable allArguments) + { + var allMatchedSpecs = matchedSpecifications.Select(x => x.ToString() ?? string.Empty).ToArray(); - return allMatchedSpecs.Concat(nonResolvedArgsPlaceholders); - } + int nonResolvedArgumentsCount = allArguments.Count() - allMatchedSpecs.Length; + var nonResolvedArgsPlaceholders = Enumerable.Repeat("???", nonResolvedArgumentsCount); - private static string FormatSpecifications(IEnumerable specifications) - { - return string.Join(NewLine, specifications.Select(spec => TabPadding + spec.ToString())); - } + return allMatchedSpecs.Concat(nonResolvedArgsPlaceholders); + } + + private static string FormatSpecifications(IEnumerable specifications) + { + return string.Join(NewLine, specifications.Select(spec => TabPadding + spec.ToString())); } } diff --git a/src/NSubstitute/Exceptions/ArgumentIsNotOutOrRefException.cs b/src/NSubstitute/Exceptions/ArgumentIsNotOutOrRefException.cs index 5e41c9b07..3d33144a9 100644 --- a/src/NSubstitute/Exceptions/ArgumentIsNotOutOrRefException.cs +++ b/src/NSubstitute/Exceptions/ArgumentIsNotOutOrRefException.cs @@ -1,12 +1,11 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class ArgumentIsNotOutOrRefException : SubstituteException { - public class ArgumentIsNotOutOrRefException : SubstituteException - { - private const string WhatProbablyWentWrong = "Could not set argument {0} ({1}) as it is not an out or ref argument."; + private const string WhatProbablyWentWrong = "Could not set argument {0} ({1}) as it is not an out or ref argument."; - public ArgumentIsNotOutOrRefException(int argumentIndex, Type argumentType) - : base(string.Format(WhatProbablyWentWrong, argumentIndex, argumentType.Name)) - { - } + public ArgumentIsNotOutOrRefException(int argumentIndex, Type argumentType) + : base(string.Format(WhatProbablyWentWrong, argumentIndex, argumentType.Name)) + { } } diff --git a/src/NSubstitute/Exceptions/ArgumentNotFoundException.cs b/src/NSubstitute/Exceptions/ArgumentNotFoundException.cs index 2e2c09c3b..c34c9a52a 100644 --- a/src/NSubstitute/Exceptions/ArgumentNotFoundException.cs +++ b/src/NSubstitute/Exceptions/ArgumentNotFoundException.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class ArgumentNotFoundException : SubstituteException { - public class ArgumentNotFoundException : SubstituteException - { - public ArgumentNotFoundException(string message) : base(message) { } - } + public ArgumentNotFoundException(string message) : base(message) { } } diff --git a/src/NSubstitute/Exceptions/ArgumentSetWithIncompatibleValueException.cs b/src/NSubstitute/Exceptions/ArgumentSetWithIncompatibleValueException.cs index f09974c47..505ee7532 100644 --- a/src/NSubstitute/Exceptions/ArgumentSetWithIncompatibleValueException.cs +++ b/src/NSubstitute/Exceptions/ArgumentSetWithIncompatibleValueException.cs @@ -1,11 +1,10 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class ArgumentSetWithIncompatibleValueException : SubstituteException { - public class ArgumentSetWithIncompatibleValueException : SubstituteException - { - private const string WhatProbablyWentWrong = - "Could not set value of type {2} to argument {0} ({1}) because the types are incompatible."; + private const string WhatProbablyWentWrong = + "Could not set value of type {2} to argument {0} ({1}) because the types are incompatible."; - public ArgumentSetWithIncompatibleValueException(int argumentIndex, Type argumentType, Type typeOfValueWeTriedToAssign) - : base(string.Format(WhatProbablyWentWrong, argumentIndex, argumentType.Name, typeOfValueWeTriedToAssign.Name)) { } - } + public ArgumentSetWithIncompatibleValueException(int argumentIndex, Type argumentType, Type typeOfValueWeTriedToAssign) + : base(string.Format(WhatProbablyWentWrong, argumentIndex, argumentType.Name, typeOfValueWeTriedToAssign.Name)) { } } diff --git a/src/NSubstitute/Exceptions/CallSequenceNotFoundException.cs b/src/NSubstitute/Exceptions/CallSequenceNotFoundException.cs index c56582f5d..30e478d50 100644 --- a/src/NSubstitute/Exceptions/CallSequenceNotFoundException.cs +++ b/src/NSubstitute/Exceptions/CallSequenceNotFoundException.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class CallSequenceNotFoundException : SubstituteException { - public class CallSequenceNotFoundException : SubstituteException - { - public CallSequenceNotFoundException(string message) : base(message) { } - } + public CallSequenceNotFoundException(string message) : base(message) { } } diff --git a/src/NSubstitute/Exceptions/CanNotPartiallySubForInterfaceOrDelegateException.cs b/src/NSubstitute/Exceptions/CanNotPartiallySubForInterfaceOrDelegateException.cs index 2494c8b5b..112e325b9 100644 --- a/src/NSubstitute/Exceptions/CanNotPartiallySubForInterfaceOrDelegateException.cs +++ b/src/NSubstitute/Exceptions/CanNotPartiallySubForInterfaceOrDelegateException.cs @@ -1,12 +1,11 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class CanNotPartiallySubForInterfaceOrDelegateException : SubstituteException { - public class CanNotPartiallySubForInterfaceOrDelegateException : SubstituteException + public CanNotPartiallySubForInterfaceOrDelegateException(Type type) : base(DescribeProblem(type)) { } + private static string DescribeProblem(Type type) { - public CanNotPartiallySubForInterfaceOrDelegateException(Type type) : base(DescribeProblem(type)) { } - private static string DescribeProblem(Type type) - { - return string.Format("Can only substitute for parts of classes, not interfaces or delegates. " - + "Try `Substitute.For<{0}> instead.", type.Name); - } + return string.Format("Can only substitute for parts of classes, not interfaces or delegates. " + + "Try `Substitute.For<{0}> instead.", type.Name); } } diff --git a/src/NSubstitute/Exceptions/CannotCreateEventArgsException.cs b/src/NSubstitute/Exceptions/CannotCreateEventArgsException.cs index d0bc9cfd9..b03028c54 100644 --- a/src/NSubstitute/Exceptions/CannotCreateEventArgsException.cs +++ b/src/NSubstitute/Exceptions/CannotCreateEventArgsException.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class CannotCreateEventArgsException : SubstituteException { - public class CannotCreateEventArgsException : SubstituteException - { - public CannotCreateEventArgsException() { } - public CannotCreateEventArgsException(string message) : base(message) { } - public CannotCreateEventArgsException(string message, Exception innerException) : base(message, innerException) { } - } + public CannotCreateEventArgsException() { } + public CannotCreateEventArgsException(string message) : base(message) { } + public CannotCreateEventArgsException(string message, Exception innerException) : base(message, innerException) { } } diff --git a/src/NSubstitute/Exceptions/CannotReturnNullforValueType.cs b/src/NSubstitute/Exceptions/CannotReturnNullforValueType.cs index 370d8b2b1..ddfffdb75 100644 --- a/src/NSubstitute/Exceptions/CannotReturnNullforValueType.cs +++ b/src/NSubstitute/Exceptions/CannotReturnNullforValueType.cs @@ -1,11 +1,10 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class CannotReturnNullForValueType : SubstituteException { - public class CannotReturnNullForValueType : SubstituteException - { - private const string Description = - "Cannot return null for {0} because it is a value type. " + - "If you want to return the default value for this type use \"default({0})\"."; + private const string Description = + "Cannot return null for {0} because it is a value type. " + + "If you want to return the default value for this type use \"default({0})\"."; - public CannotReturnNullForValueType(Type valueType) : base(string.Format(Description, valueType.Name)) { } - } + public CannotReturnNullForValueType(Type valueType) : base(string.Format(Description, valueType.Name)) { } } diff --git a/src/NSubstitute/Exceptions/CouldNotConfigureBaseMethodException.cs b/src/NSubstitute/Exceptions/CouldNotConfigureBaseMethodException.cs index 24f7fb873..839e005db 100644 --- a/src/NSubstitute/Exceptions/CouldNotConfigureBaseMethodException.cs +++ b/src/NSubstitute/Exceptions/CouldNotConfigureBaseMethodException.cs @@ -1,23 +1,22 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class CouldNotConfigureCallBaseException : SubstituteException { - public class CouldNotConfigureCallBaseException : SubstituteException - { - private const string CannotConfigureSingleCallMessage = - "Cannot configure the base method call as base method implementation is missing. " + - "You can call base method only if you create a class substitute and the method is not abstract."; + private const string CannotConfigureSingleCallMessage = + "Cannot configure the base method call as base method implementation is missing. " + + "You can call base method only if you create a class substitute and the method is not abstract."; - private const string CannotConfigureAllCallsMessage = - "Base method calls can be configured for a class substitute only, " + - "as otherwise base implementation does not exist."; + private const string CannotConfigureAllCallsMessage = + "Base method calls can be configured for a class substitute only, " + + "as otherwise base implementation does not exist."; - internal static CouldNotConfigureCallBaseException ForSingleCall() => - new CouldNotConfigureCallBaseException(CannotConfigureSingleCallMessage); + internal static CouldNotConfigureCallBaseException ForSingleCall() => + new CouldNotConfigureCallBaseException(CannotConfigureSingleCallMessage); - internal static CouldNotConfigureCallBaseException ForAllCalls() => - new CouldNotConfigureCallBaseException(CannotConfigureAllCallsMessage); + internal static CouldNotConfigureCallBaseException ForAllCalls() => + new CouldNotConfigureCallBaseException(CannotConfigureAllCallsMessage); - public CouldNotConfigureCallBaseException(string message) : base(message) - { - } + public CouldNotConfigureCallBaseException(string message) : base(message) + { } } \ No newline at end of file diff --git a/src/NSubstitute/Exceptions/CouldNotRaiseEventException.cs b/src/NSubstitute/Exceptions/CouldNotRaiseEventException.cs index 479ae6a42..cb0bf4543 100644 --- a/src/NSubstitute/Exceptions/CouldNotRaiseEventException.cs +++ b/src/NSubstitute/Exceptions/CouldNotRaiseEventException.cs @@ -1,22 +1,21 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class CouldNotRaiseEventException : SubstituteException { - public class CouldNotRaiseEventException : SubstituteException - { - protected const string WhatProbablyWentWrong = - "Make sure you are using Raise.Event() as part of an event subscription on a substitute.\n" + - "For example:\n" + - "\tmySub.Clicked += Raise.Event();\n" + - "\n" + - "If you substituted for a class rather than an interface, check that the event on your substitute is virtual/abstract.\n" + - "Events on classes cannot be raised if they are not declared virtual or abstract.\n" + - "\n" + - "Note that the source of the problem may be prior to where this exception was thrown (possibly in a previous test!).\n" + - "For example:\n" + - "\tvar notASub = new Button();\n" + - "\tnotASub.Clicked += Raise.Event(); // <-- Problem here. This is not a substitute.\n" + - "\tvar sub = Substitute.For();\n" + - "\tsub.Load(); // <-- Exception thrown here. NSubstitute thinks the earlier Raise.Event() was meant for this call."; + protected const string WhatProbablyWentWrong = + "Make sure you are using Raise.Event() as part of an event subscription on a substitute.\n" + + "For example:\n" + + "\tmySub.Clicked += Raise.Event();\n" + + "\n" + + "If you substituted for a class rather than an interface, check that the event on your substitute is virtual/abstract.\n" + + "Events on classes cannot be raised if they are not declared virtual or abstract.\n" + + "\n" + + "Note that the source of the problem may be prior to where this exception was thrown (possibly in a previous test!).\n" + + "For example:\n" + + "\tvar notASub = new Button();\n" + + "\tnotASub.Clicked += Raise.Event(); // <-- Problem here. This is not a substitute.\n" + + "\tvar sub = Substitute.For();\n" + + "\tsub.Load(); // <-- Exception thrown here. NSubstitute thinks the earlier Raise.Event() was meant for this call."; - public CouldNotRaiseEventException() : base(WhatProbablyWentWrong) { } - } + public CouldNotRaiseEventException() : base(WhatProbablyWentWrong) { } } diff --git a/src/NSubstitute/Exceptions/CouldNotSetReturnException.cs b/src/NSubstitute/Exceptions/CouldNotSetReturnException.cs index 35db62e7e..f050b23c9 100644 --- a/src/NSubstitute/Exceptions/CouldNotSetReturnException.cs +++ b/src/NSubstitute/Exceptions/CouldNotSetReturnException.cs @@ -1,51 +1,50 @@ using System.Reflection; -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public abstract class CouldNotSetReturnException : SubstituteException { - public abstract class CouldNotSetReturnException : SubstituteException - { - protected const string WhatProbablyWentWrong = - "Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),\n" + - "and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).\n" + - "\n" + - "If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.\n" + - "Return values cannot be configured for non-virtual/non-abstract members.\n" + - "\n" + - "Correct use:\n" + - "\tmySub.SomeMethod().Returns(returnValue);\n" + - "\n" + - "Potentially problematic use:\n" + - "\tmySub.SomeMethod().Returns(ConfigOtherSub());\n" + - "Instead try:\n" + - "\tvar returnValue = ConfigOtherSub();\n" + - "\tmySub.SomeMethod().Returns(returnValue);\n" + - ""; - - protected CouldNotSetReturnException(string s) : base(s + "\n\n" + WhatProbablyWentWrong) { } - } + protected const string WhatProbablyWentWrong = + "Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),\n" + + "and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).\n" + + "\n" + + "If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.\n" + + "Return values cannot be configured for non-virtual/non-abstract members.\n" + + "\n" + + "Correct use:\n" + + "\tmySub.SomeMethod().Returns(returnValue);\n" + + "\n" + + "Potentially problematic use:\n" + + "\tmySub.SomeMethod().Returns(ConfigOtherSub());\n" + + "Instead try:\n" + + "\tvar returnValue = ConfigOtherSub();\n" + + "\tmySub.SomeMethod().Returns(returnValue);\n" + + ""; - public class CouldNotSetReturnDueToNoLastCallException : CouldNotSetReturnException + protected CouldNotSetReturnException(string s) : base(s + "\n\n" + WhatProbablyWentWrong) { } +} + +public class CouldNotSetReturnDueToNoLastCallException : CouldNotSetReturnException +{ + public CouldNotSetReturnDueToNoLastCallException() : base("Could not find a call to return from.") { } +} + +public class CouldNotSetReturnDueToMissingInfoAboutLastCallException : CouldNotSetReturnException +{ + public CouldNotSetReturnDueToMissingInfoAboutLastCallException() : base("Could not find information about the last call to return from.") { - public CouldNotSetReturnDueToNoLastCallException() : base("Could not find a call to return from.") { } } - public class CouldNotSetReturnDueToMissingInfoAboutLastCallException : CouldNotSetReturnException - { - public CouldNotSetReturnDueToMissingInfoAboutLastCallException() : base("Could not find information about the last call to return from.") - { - } +} - } +public class CouldNotSetReturnDueToTypeMismatchException : CouldNotSetReturnException +{ + public CouldNotSetReturnDueToTypeMismatchException(Type? returnType, MethodInfo member) : base(DescribeProblem(returnType, member)) { } - public class CouldNotSetReturnDueToTypeMismatchException : CouldNotSetReturnException + private static string DescribeProblem(Type? typeOfReturnValue, MethodInfo member) { - public CouldNotSetReturnDueToTypeMismatchException(Type? returnType, MethodInfo member) : base(DescribeProblem(returnType, member)) { } - - private static string DescribeProblem(Type? typeOfReturnValue, MethodInfo member) - { - return typeOfReturnValue == null - ? string.Format("Can not return null for {0}.{1} (expected type {2}).", member.DeclaringType!.Name, member.Name, member.ReturnType.Name) - : string.Format("Can not return value of type {0} for {1}.{2} (expected type {3}).", typeOfReturnValue.Name, member.DeclaringType!.Name, member.Name, member.ReturnType.Name); - } + return typeOfReturnValue == null + ? string.Format("Can not return null for {0}.{1} (expected type {2}).", member.DeclaringType!.Name, member.Name, member.ReturnType.Name) + : string.Format("Can not return value of type {0} for {1}.{2} (expected type {3}).", typeOfReturnValue.Name, member.DeclaringType!.Name, member.Name, member.ReturnType.Name); } } diff --git a/src/NSubstitute/Exceptions/MissingSequenceNumberException.cs b/src/NSubstitute/Exceptions/MissingSequenceNumberException.cs index d81955339..770421b4f 100644 --- a/src/NSubstitute/Exceptions/MissingSequenceNumberException.cs +++ b/src/NSubstitute/Exceptions/MissingSequenceNumberException.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class MissingSequenceNumberException : SubstituteException { - public class MissingSequenceNumberException : SubstituteException - { - public MissingSequenceNumberException() { } - } + public MissingSequenceNumberException() { } } diff --git a/src/NSubstitute/Exceptions/NotASubstituteException.cs b/src/NSubstitute/Exceptions/NotASubstituteException.cs index 1828c0a94..d89bace95 100644 --- a/src/NSubstitute/Exceptions/NotASubstituteException.cs +++ b/src/NSubstitute/Exceptions/NotASubstituteException.cs @@ -1,11 +1,10 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class NotASubstituteException : SubstituteException { - public class NotASubstituteException : SubstituteException - { - private const string Explanation = - "NSubstitute extension methods like .Received() can only be called " + - "on objects created using Substitute.For() and related methods."; + private const string Explanation = + "NSubstitute extension methods like .Received() can only be called " + + "on objects created using Substitute.For() and related methods."; - public NotASubstituteException() : base(Explanation) { } - } + public NotASubstituteException() : base(Explanation) { } } diff --git a/src/NSubstitute/Exceptions/NotRunningAQueryException.cs b/src/NSubstitute/Exceptions/NotRunningAQueryException.cs index 85fc05622..ca3116046 100644 --- a/src/NSubstitute/Exceptions/NotRunningAQueryException.cs +++ b/src/NSubstitute/Exceptions/NotRunningAQueryException.cs @@ -1,7 +1,6 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class NotRunningAQueryException : SubstituteException { - public class NotRunningAQueryException : SubstituteException - { - public NotRunningAQueryException() { } - } + public NotRunningAQueryException() { } } diff --git a/src/NSubstitute/Exceptions/NullSubstituteReferenceException.cs b/src/NSubstitute/Exceptions/NullSubstituteReferenceException.cs index b82dab76b..4c4d60e43 100644 --- a/src/NSubstitute/Exceptions/NullSubstituteReferenceException.cs +++ b/src/NSubstitute/Exceptions/NullSubstituteReferenceException.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class NullSubstituteReferenceException : SubstituteException { - public class NullSubstituteReferenceException : SubstituteException - { - private const string Explanation = "NSubstitute extension methods like .Received() can only be called on non-null objects."; + private const string Explanation = "NSubstitute extension methods like .Received() can only be called on non-null objects."; - public NullSubstituteReferenceException() : base(Explanation) { } - } + public NullSubstituteReferenceException() : base(Explanation) { } } diff --git a/src/NSubstitute/Exceptions/ReceivedCallsException.cs b/src/NSubstitute/Exceptions/ReceivedCallsException.cs index 17503d539..be310492f 100644 --- a/src/NSubstitute/Exceptions/ReceivedCallsException.cs +++ b/src/NSubstitute/Exceptions/ReceivedCallsException.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class ReceivedCallsException : SubstituteException { - public class ReceivedCallsException : SubstituteException - { - public ReceivedCallsException() { } - public ReceivedCallsException(string message) : base(message) { } - public ReceivedCallsException(string message, Exception innerException) : base(message, innerException) { } - } + public ReceivedCallsException() { } + public ReceivedCallsException(string message) : base(message) { } + public ReceivedCallsException(string message, Exception innerException) : base(message, innerException) { } } diff --git a/src/NSubstitute/Exceptions/RedundantArgumentMatcherException.cs b/src/NSubstitute/Exceptions/RedundantArgumentMatcherException.cs index 5f2304c62..a70290624 100644 --- a/src/NSubstitute/Exceptions/RedundantArgumentMatcherException.cs +++ b/src/NSubstitute/Exceptions/RedundantArgumentMatcherException.cs @@ -1,63 +1,62 @@ using NSubstitute.Core.Arguments; using static System.Environment; -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class RedundantArgumentMatcherException : SubstituteException { - public class RedundantArgumentMatcherException : SubstituteException + public RedundantArgumentMatcherException(IEnumerable remainingSpecifications, + IEnumerable allSpecifications) + : this(FormatErrorMessage(remainingSpecifications, allSpecifications)) { - public RedundantArgumentMatcherException(IEnumerable remainingSpecifications, - IEnumerable allSpecifications) - : this(FormatErrorMessage(remainingSpecifications, allSpecifications)) - { - } + } - public RedundantArgumentMatcherException(string message) : base(message) - { - } + public RedundantArgumentMatcherException(string message) : base(message) + { + } - private static string FormatErrorMessage(IEnumerable remainingSpecifications, - IEnumerable allSpecifications) - { - return - $"Some argument specifications (e.g. Arg.Is, Arg.Any) were left over after the last call.{NewLine}" + - NewLine + - $"This is often caused by using an argument spec with a call to a member NSubstitute does not handle" + - $" (such as a non-virtual member or a call to an instance which is not a substitute), or for a purpose" + - $" other than specifying a call (such as using an arg spec as a return value). For example:{NewLine}" + - NewLine + - $" var sub = Substitute.For();{NewLine}" + - $" var realType = new MyRealType(sub);{NewLine}" + - $" // INCORRECT, arg spec used on realType, not a substitute:{NewLine}" + - $" realType.SomeMethod(Arg.Any()).Returns(2);{NewLine}" + - $" // INCORRECT, arg spec used as a return value, not to specify a call:{NewLine}" + - $" sub.VirtualMethod(2).Returns(Arg.Any());{NewLine}" + - $" // INCORRECT, arg spec used with a non-virtual method:{NewLine}" + - $" sub.NonVirtualMethod(Arg.Any()).Returns(2);{NewLine}" + - $" // CORRECT, arg spec used to specify virtual call on a substitute:{NewLine}" + - $" sub.VirtualMethod(Arg.Any()).Returns(2);{NewLine}" + - NewLine + - $"To fix this make sure you only use argument specifications with calls to substitutes." + - $" If your substitute is a class, make sure the member is virtual.{NewLine}" + - NewLine + - $"Another possible cause is that the argument spec type does not match the actual argument type," + - $" but code compiles due to an implicit cast. For example, Arg.Any() was used," + - $" but Arg.Any() was required.{NewLine}" + - NewLine + - $"NOTE: the cause of this exception can be in a previously executed test. Use the diagnostics below" + - $" to see the types of any redundant arg specs, then work out where they are being created.{NewLine}" + - NewLine + - $"Diagnostic information:{NewLine}" + - NewLine + - $"Remaining (non-bound) argument specifications:{NewLine}" + - $"{FormatSpecifications(remainingSpecifications)}{NewLine}" + - $"{NewLine}" + - $"All argument specifications:{NewLine}" + - $"{FormatSpecifications(allSpecifications)}{NewLine}"; - } + private static string FormatErrorMessage(IEnumerable remainingSpecifications, + IEnumerable allSpecifications) + { + return + $"Some argument specifications (e.g. Arg.Is, Arg.Any) were left over after the last call.{NewLine}" + + NewLine + + $"This is often caused by using an argument spec with a call to a member NSubstitute does not handle" + + $" (such as a non-virtual member or a call to an instance which is not a substitute), or for a purpose" + + $" other than specifying a call (such as using an arg spec as a return value). For example:{NewLine}" + + NewLine + + $" var sub = Substitute.For();{NewLine}" + + $" var realType = new MyRealType(sub);{NewLine}" + + $" // INCORRECT, arg spec used on realType, not a substitute:{NewLine}" + + $" realType.SomeMethod(Arg.Any()).Returns(2);{NewLine}" + + $" // INCORRECT, arg spec used as a return value, not to specify a call:{NewLine}" + + $" sub.VirtualMethod(2).Returns(Arg.Any());{NewLine}" + + $" // INCORRECT, arg spec used with a non-virtual method:{NewLine}" + + $" sub.NonVirtualMethod(Arg.Any()).Returns(2);{NewLine}" + + $" // CORRECT, arg spec used to specify virtual call on a substitute:{NewLine}" + + $" sub.VirtualMethod(Arg.Any()).Returns(2);{NewLine}" + + NewLine + + $"To fix this make sure you only use argument specifications with calls to substitutes." + + $" If your substitute is a class, make sure the member is virtual.{NewLine}" + + NewLine + + $"Another possible cause is that the argument spec type does not match the actual argument type," + + $" but code compiles due to an implicit cast. For example, Arg.Any() was used," + + $" but Arg.Any() was required.{NewLine}" + + NewLine + + $"NOTE: the cause of this exception can be in a previously executed test. Use the diagnostics below" + + $" to see the types of any redundant arg specs, then work out where they are being created.{NewLine}" + + NewLine + + $"Diagnostic information:{NewLine}" + + NewLine + + $"Remaining (non-bound) argument specifications:{NewLine}" + + $"{FormatSpecifications(remainingSpecifications)}{NewLine}" + + $"{NewLine}" + + $"All argument specifications:{NewLine}" + + $"{FormatSpecifications(allSpecifications)}{NewLine}"; + } - private static string FormatSpecifications(IEnumerable specifications) - { - return string.Join(NewLine, specifications.Select(spec => " " + spec.ToString())); - } + private static string FormatSpecifications(IEnumerable specifications) + { + return string.Join(NewLine, specifications.Select(spec => " " + spec.ToString())); } } \ No newline at end of file diff --git a/src/NSubstitute/Exceptions/SubstituteException.cs b/src/NSubstitute/Exceptions/SubstituteException.cs index 61b9f00fe..53ff063fe 100644 --- a/src/NSubstitute/Exceptions/SubstituteException.cs +++ b/src/NSubstitute/Exceptions/SubstituteException.cs @@ -1,9 +1,8 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class SubstituteException : Exception { - public class SubstituteException : Exception - { - public SubstituteException() : this("") { } - public SubstituteException(string message) : this(message, null) { } - public SubstituteException(string message, Exception? innerException) : base(message, innerException) { } - } + public SubstituteException() : this("") { } + public SubstituteException(string message) : this(message, null) { } + public SubstituteException(string message, Exception? innerException) : base(message, innerException) { } } diff --git a/src/NSubstitute/Exceptions/SubstituteInternalException.cs b/src/NSubstitute/Exceptions/SubstituteInternalException.cs index 4c35d2344..6616725dd 100644 --- a/src/NSubstitute/Exceptions/SubstituteInternalException.cs +++ b/src/NSubstitute/Exceptions/SubstituteInternalException.cs @@ -1,13 +1,12 @@ -namespace NSubstitute.Exceptions -{ +namespace NSubstitute.Exceptions; + - public class SubstituteInternalException : SubstituteException - { - public SubstituteInternalException() : this("") { } - public SubstituteInternalException(string message) : this(message, null) { } - public SubstituteInternalException(string message, Exception? innerException) - : base("Please report this exception at https://github.com/nsubstitute/NSubstitute/issues: \n\n" + message, - innerException) - { } - } +public class SubstituteInternalException : SubstituteException +{ + public SubstituteInternalException() : this("") { } + public SubstituteInternalException(string message) : this(message, null) { } + public SubstituteInternalException(string message, Exception? innerException) + : base("Please report this exception at https://github.com/nsubstitute/NSubstitute/issues: \n\n" + message, + innerException) + { } } \ No newline at end of file diff --git a/src/NSubstitute/Exceptions/UnexpectedArgumentMatcherException.cs b/src/NSubstitute/Exceptions/UnexpectedArgumentMatcherException.cs index 3b89541e4..8b4200d18 100644 --- a/src/NSubstitute/Exceptions/UnexpectedArgumentMatcherException.cs +++ b/src/NSubstitute/Exceptions/UnexpectedArgumentMatcherException.cs @@ -1,15 +1,14 @@ -namespace NSubstitute.Exceptions +namespace NSubstitute.Exceptions; + +public class UnexpectedArgumentMatcherException : SubstituteException { - public class UnexpectedArgumentMatcherException : SubstituteException - { - public static readonly string WhatProbablyWentWrong = - "Argument matchers (Arg.Is, Arg.Any) should only be used in place of member arguments. " + - "Do not use in a Returns() statement or anywhere else outside of a member call." + Environment.NewLine + - "Correct use:" + Environment.NewLine + - " sub.MyMethod(Arg.Any()).Returns(\"hi\")" + Environment.NewLine + - "Incorrect use:" + Environment.NewLine + - " sub.MyMethod(\"hi\").Returns(Arg.Any())"; - public UnexpectedArgumentMatcherException() : this(WhatProbablyWentWrong) { } - public UnexpectedArgumentMatcherException(string message) : base(message) { } - } + public static readonly string WhatProbablyWentWrong = + "Argument matchers (Arg.Is, Arg.Any) should only be used in place of member arguments. " + + "Do not use in a Returns() statement or anywhere else outside of a member call." + Environment.NewLine + + "Correct use:" + Environment.NewLine + + " sub.MyMethod(Arg.Any()).Returns(\"hi\")" + Environment.NewLine + + "Incorrect use:" + Environment.NewLine + + " sub.MyMethod(\"hi\").Returns(Arg.Any())"; + public UnexpectedArgumentMatcherException() : this(WhatProbablyWentWrong) { } + public UnexpectedArgumentMatcherException(string message) : base(message) { } } diff --git a/src/NSubstitute/Extensions/ClearExtensions.cs b/src/NSubstitute/Extensions/ClearExtensions.cs index f86755bf8..3d8d9ecd9 100644 --- a/src/NSubstitute/Extensions/ClearExtensions.cs +++ b/src/NSubstitute/Extensions/ClearExtensions.cs @@ -4,26 +4,25 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.ClearExtensions +namespace NSubstitute.ClearExtensions; + +public static class ClearExtensions { - public static class ClearExtensions + /// + /// Clears received calls, configured return values and/or call actions for this substitute. + /// + /// + /// + /// Specifies what to clear on the substitute. Can be combined with | to + /// clear multiple aspects at once. + /// + /// + public static void ClearSubstitute(this T substitute, ClearOptions options = ClearOptions.All) where T : class { - /// - /// Clears received calls, configured return values and/or call actions for this substitute. - /// - /// - /// - /// Specifies what to clear on the substitute. Can be combined with | to - /// clear multiple aspects at once. - /// - /// - public static void ClearSubstitute(this T substitute, ClearOptions options = ClearOptions.All) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); + if (substitute == null) throw new NullSubstituteReferenceException(); - var context = SubstitutionContext.Current; - var router = context.GetCallRouterFor(substitute!); - router.Clear(options); - } + var context = SubstitutionContext.Current; + var router = context.GetCallRouterFor(substitute!); + router.Clear(options); } } \ No newline at end of file diff --git a/src/NSubstitute/Extensions/ConfigurationExtensions.cs b/src/NSubstitute/Extensions/ConfigurationExtensions.cs index 1680e83cf..23ca685a0 100644 --- a/src/NSubstitute/Extensions/ConfigurationExtensions.cs +++ b/src/NSubstitute/Extensions/ConfigurationExtensions.cs @@ -4,34 +4,33 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.Extensions +namespace NSubstitute.Extensions; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + /// + /// A hint for the NSubstitute that the subsequent method/property call is about to be configured. + /// For example: substitute.Configure().GetValue().Returns(1,2,3); + /// + /// NOTICE, you _don't need_ to invoke this method for the basic configuration scenarios. + /// Ensure you don't overuse this method and it is applied only if strictly required. + /// + /// + /// Due to the NSubstitute configuration syntax it is often impossible to recognise during the method call + /// dispatch whether this is a setup phase or a regular method call. + /// Usually it doesn't matter, however sometimes method invocation could lead to undesired side effects + /// (e.g. the previously configured value is returned, base method is invoked). In that case you might want to + /// provide NSubstitute with a hint that you are configuring a method, so it handles the call in configuration mode. + /// + /// + public static T Configure(this T substitute) where T : class { - /// - /// A hint for the NSubstitute that the subsequent method/property call is about to be configured. - /// For example: substitute.Configure().GetValue().Returns(1,2,3); - /// - /// NOTICE, you _don't need_ to invoke this method for the basic configuration scenarios. - /// Ensure you don't overuse this method and it is applied only if strictly required. - /// - /// - /// Due to the NSubstitute configuration syntax it is often impossible to recognise during the method call - /// dispatch whether this is a setup phase or a regular method call. - /// Usually it doesn't matter, however sometimes method invocation could lead to undesired side effects - /// (e.g. the previously configured value is returned, base method is invoked). In that case you might want to - /// provide NSubstitute with a hint that you are configuring a method, so it handles the call in configuration mode. - /// - /// - public static T Configure(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); + if (substitute == null) throw new NullSubstituteReferenceException(); - var context = SubstitutionContext.Current; - var callRouter = context.GetCallRouterFor(substitute!); - context.ThreadContext.SetNextRoute(callRouter, context.RouteFactory.RecordCallSpecification); + var context = SubstitutionContext.Current; + var callRouter = context.GetCallRouterFor(substitute!); + context.ThreadContext.SetNextRoute(callRouter, context.RouteFactory.RecordCallSpecification); - return substitute; - } + return substitute; } } \ No newline at end of file diff --git a/src/NSubstitute/Extensions/ExceptionExtensions.cs b/src/NSubstitute/Extensions/ExceptionExtensions.cs index 46cf03e9e..ced667693 100644 --- a/src/NSubstitute/Extensions/ExceptionExtensions.cs +++ b/src/NSubstitute/Extensions/ExceptionExtensions.cs @@ -4,242 +4,241 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.ExceptionExtensions +namespace NSubstitute.ExceptionExtensions; + +public static class ExceptionExtensions { - public static class ExceptionExtensions + /// + /// Throw an exception for this call. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall Throws(this object value, Exception ex) => + value.Returns(_ => throw ex); + + /// + /// Throw an exception of the given type for this call. + /// + /// Type of exception to throw + /// + /// + public static ConfiguredCall Throws(this object value) + where TException : notnull, Exception, new() { - /// - /// Throw an exception for this call. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall Throws(this object value, Exception ex) => - value.Returns(_ => throw ex); - - /// - /// Throw an exception of the given type for this call. - /// - /// Type of exception to throw - /// - /// - public static ConfiguredCall Throws(this object value) - where TException : notnull, Exception, new() - { - return value.Returns(_ => throw new TException()); - } + return value.Returns(_ => throw new TException()); + } - /// - /// Throw an exception for this call, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall Throws(this object value, Func createException) => - value.Returns(ci => throw createException(ci)); - - /// - /// Throw an exception for this call made with any arguments. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsForAnyArgs(this object value, Exception ex) => - value.ReturnsForAnyArgs(_ => throw ex); - - /// - /// Throws an exception of the given type for this call made with any arguments. - /// - /// Type of exception to throw - /// - /// - public static ConfiguredCall ThrowsForAnyArgs(this object value) - where TException : notnull, Exception, new() - { - return value.ReturnsForAnyArgs(_ => throw new TException()); - } + /// + /// Throw an exception for this call, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall Throws(this object value, Func createException) => + value.Returns(ci => throw createException(ci)); + + /// + /// Throw an exception for this call made with any arguments. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsForAnyArgs(this object value, Exception ex) => + value.ReturnsForAnyArgs(_ => throw ex); + + /// + /// Throws an exception of the given type for this call made with any arguments. + /// + /// Type of exception to throw + /// + /// + public static ConfiguredCall ThrowsForAnyArgs(this object value) + where TException : notnull, Exception, new() + { + return value.ReturnsForAnyArgs(_ => throw new TException()); + } - /// - /// Throws an exception for this call made with any arguments, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsForAnyArgs(this object value, Func createException) => - value.ReturnsForAnyArgs(ci => throw createException(ci)); - - /// - /// Throw an exception for this call. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsAsync(this Task value, Exception ex) => - value.Returns(_ => Task.FromException(ex)); - - /// - /// Throw an exception for this call. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsAsync(this Task value, Exception ex) => - value.Returns(_ => Task.FromException(ex)); - - /// - /// Throw an exception of the given type for this call. - /// - /// Type of exception to throw - /// - /// - public static ConfiguredCall ThrowsAsync(this Task value) - where TException : notnull, Exception, new() - { - return value.Returns(_ => FromException(value, new TException())); - } + /// + /// Throws an exception for this call made with any arguments, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsForAnyArgs(this object value, Func createException) => + value.ReturnsForAnyArgs(ci => throw createException(ci)); + + /// + /// Throw an exception for this call. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsAsync(this Task value, Exception ex) => + value.Returns(_ => Task.FromException(ex)); + + /// + /// Throw an exception for this call. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsAsync(this Task value, Exception ex) => + value.Returns(_ => Task.FromException(ex)); + + /// + /// Throw an exception of the given type for this call. + /// + /// Type of exception to throw + /// + /// + public static ConfiguredCall ThrowsAsync(this Task value) + where TException : notnull, Exception, new() + { + return value.Returns(_ => FromException(value, new TException())); + } - /// - /// Throw an exception for this call, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsAsync(this Task value, Func createException) => - value.Returns(ci => Task.FromException(createException(ci))); - - /// - /// Throw an exception for this call, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsAsync(this Task value, Func createException) => - value.Returns(ci => Task.FromException(createException(ci))); - - /// - /// Throw an exception for this call made with any arguments. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Exception ex) => - value.ReturnsForAnyArgs(_ => Task.FromException(ex)); - - /// - /// Throw an exception for this call made with any arguments. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Exception ex) => - value.ReturnsForAnyArgs(_ => Task.FromException(ex)); - - /// - /// Throws an exception of the given type for this call made with any arguments. - /// - /// Type of exception to throw - /// - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value) - where TException : notnull, Exception, new() - { - return value.ReturnsForAnyArgs(_ => FromException(value, new TException())); - } + /// + /// Throw an exception for this call, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsAsync(this Task value, Func createException) => + value.Returns(ci => Task.FromException(createException(ci))); + + /// + /// Throw an exception for this call, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsAsync(this Task value, Func createException) => + value.Returns(ci => Task.FromException(createException(ci))); + + /// + /// Throw an exception for this call made with any arguments. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Exception ex) => + value.ReturnsForAnyArgs(_ => Task.FromException(ex)); + + /// + /// Throw an exception for this call made with any arguments. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Exception ex) => + value.ReturnsForAnyArgs(_ => Task.FromException(ex)); + + /// + /// Throws an exception of the given type for this call made with any arguments. + /// + /// Type of exception to throw + /// + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value) + where TException : notnull, Exception, new() + { + return value.ReturnsForAnyArgs(_ => FromException(value, new TException())); + } - /// - /// Throws an exception for this call made with any arguments, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Func createException) => - value.ReturnsForAnyArgs(ci => Task.FromException(createException(ci))); - - /// - /// Throws an exception for this call made with any arguments, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Func createException) => - value.ReturnsForAnyArgs(ci => Task.FromException(createException(ci))); + /// + /// Throws an exception for this call made with any arguments, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Func createException) => + value.ReturnsForAnyArgs(ci => Task.FromException(createException(ci))); + + /// + /// Throws an exception for this call made with any arguments, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this Task value, Func createException) => + value.ReturnsForAnyArgs(ci => Task.FromException(createException(ci))); #if NET5_0_OR_GREATER - /// - /// Throw an exception for this call. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsAsync(this ValueTask value, Exception ex) => - value.Returns(_ => ValueTask.FromException(ex)); - - /// - /// Throw an exception of the given type for this call. - /// - /// Type of exception to throw - /// Type of exception to throw - /// - /// - public static ConfiguredCall ThrowsAsync(this ValueTask value) - where TException : notnull, Exception, new() - { - return value.Returns(_ => ValueTask.FromException(new TException())); - } + /// + /// Throw an exception for this call. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsAsync(this ValueTask value, Exception ex) => + value.Returns(_ => ValueTask.FromException(ex)); + + /// + /// Throw an exception of the given type for this call. + /// + /// Type of exception to throw + /// Type of exception to throw + /// + /// + public static ConfiguredCall ThrowsAsync(this ValueTask value) + where TException : notnull, Exception, new() + { + return value.Returns(_ => ValueTask.FromException(new TException())); + } - /// - /// Throw an exception for this call, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsAsync(this ValueTask value, Func createException) => - value.Returns(ci => ValueTask.FromException(createException(ci))); - - /// - /// Throws an exception of the given type for this call made with any arguments. - /// - /// - /// Type of exception to throw - /// - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this ValueTask value) - where TException : notnull, Exception, new() - { - return value.ReturnsForAnyArgs(_ => ValueTask.FromException(new TException())); - } + /// + /// Throw an exception for this call, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsAsync(this ValueTask value, Func createException) => + value.Returns(ci => ValueTask.FromException(createException(ci))); + + /// + /// Throws an exception of the given type for this call made with any arguments. + /// + /// + /// Type of exception to throw + /// + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this ValueTask value) + where TException : notnull, Exception, new() + { + return value.ReturnsForAnyArgs(_ => ValueTask.FromException(new TException())); + } - /// - /// Throw an exception for this call made with any arguments. - /// - /// - /// Exception to throw - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this ValueTask value, Exception ex) => - value.ReturnsForAnyArgs(_ => ValueTask.FromException(ex)); - - /// - /// Throws an exception for this call made with any arguments, as generated by the specified function. - /// - /// - /// Func creating exception object - /// - public static ConfiguredCall ThrowsAsyncForAnyArgs(this ValueTask value, Func createException) => - value.ReturnsForAnyArgs(ci => ValueTask.FromException(createException(ci))); + /// + /// Throw an exception for this call made with any arguments. + /// + /// + /// Exception to throw + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this ValueTask value, Exception ex) => + value.ReturnsForAnyArgs(_ => ValueTask.FromException(ex)); + + /// + /// Throws an exception for this call made with any arguments, as generated by the specified function. + /// + /// + /// Func creating exception object + /// + public static ConfiguredCall ThrowsAsyncForAnyArgs(this ValueTask value, Func createException) => + value.ReturnsForAnyArgs(ci => ValueTask.FromException(createException(ci))); #endif - private static object FromException(object value, Exception exception) + private static object FromException(object value, Exception exception) + { + // Handle Task + var valueType = value.GetType(); + if (valueType.IsConstructedGenericType) { - // Handle Task - var valueType = value.GetType(); - if (valueType.IsConstructedGenericType) - { - var fromExceptionMethodInfo = typeof(Task).GetMethods(BindingFlags.Static | BindingFlags.Public).Single(m => m.Name == "FromException" && m.ContainsGenericParameters); - var specificFromExceptionMethod = fromExceptionMethodInfo.MakeGenericMethod(valueType.GenericTypeArguments); - return specificFromExceptionMethod.Invoke(null, new object[] { exception }); - } - - return Task.FromException(exception); + var fromExceptionMethodInfo = typeof(Task).GetMethods(BindingFlags.Static | BindingFlags.Public).Single(m => m.Name == "FromException" && m.ContainsGenericParameters); + var specificFromExceptionMethod = fromExceptionMethodInfo.MakeGenericMethod(valueType.GenericTypeArguments); + return specificFromExceptionMethod.Invoke(null, new object[] { exception }); } + + return Task.FromException(exception); } } diff --git a/src/NSubstitute/Extensions/ReceivedExtensions.cs b/src/NSubstitute/Extensions/ReceivedExtensions.cs index 96c7f0bb2..a79ce0f85 100644 --- a/src/NSubstitute/Extensions/ReceivedExtensions.cs +++ b/src/NSubstitute/Extensions/ReceivedExtensions.cs @@ -4,201 +4,200 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.ReceivedExtensions +namespace NSubstitute.ReceivedExtensions; + +public static class ReceivedExtensions { - public static class ReceivedExtensions + /// + /// Checks this substitute has received the following call the required number of times. + /// + /// + /// + /// + /// + public static T Received(this T substitute, Quantity requiredQuantity) { - /// - /// Checks this substitute has received the following call the required number of times. - /// - /// - /// - /// - /// - public static T Received(this T substitute, Quantity requiredQuantity) - { - if (substitute == null) throw new NullSubstituteReferenceException(); + if (substitute == null) throw new NullSubstituteReferenceException(); - var context = SubstitutionContext.Current; - var callRouter = context.GetCallRouterFor(substitute); + var context = SubstitutionContext.Current; + var callRouter = context.GetCallRouterFor(substitute); - context.ThreadContext.SetNextRoute(callRouter, x => context.RouteFactory.CheckReceivedCalls(x, MatchArgs.AsSpecifiedInCall, requiredQuantity)); - return substitute; - } + context.ThreadContext.SetNextRoute(callRouter, x => context.RouteFactory.CheckReceivedCalls(x, MatchArgs.AsSpecifiedInCall, requiredQuantity)); + return substitute; + } - /// - /// Checks this substitute has received the following call with any arguments the required number of times. - /// - /// - /// - /// - /// - public static T ReceivedWithAnyArgs(this T substitute, Quantity requiredQuantity) - { - if (substitute == null) throw new NullSubstituteReferenceException(); + /// + /// Checks this substitute has received the following call with any arguments the required number of times. + /// + /// + /// + /// + /// + public static T ReceivedWithAnyArgs(this T substitute, Quantity requiredQuantity) + { + if (substitute == null) throw new NullSubstituteReferenceException(); - var context = SubstitutionContext.Current; - var callRouter = context.GetCallRouterFor(substitute); + var context = SubstitutionContext.Current; + var callRouter = context.GetCallRouterFor(substitute); - context.ThreadContext.SetNextRoute(callRouter, x => context.RouteFactory.CheckReceivedCalls(x, MatchArgs.Any, requiredQuantity)); - return substitute; - } + context.ThreadContext.SetNextRoute(callRouter, x => context.RouteFactory.CheckReceivedCalls(x, MatchArgs.Any, requiredQuantity)); + return substitute; } +} +/// +/// Represents a quantity. Primarily used for specifying a required amount of calls to a member. +/// +public abstract class Quantity +{ + public static Quantity Exactly(int number) { return number == 0 ? None() : new ExactQuantity(number); } + public static Quantity AtLeastOne() { return new AnyNonZeroQuantity(); } + public static Quantity None() { return new NoneQuantity(); } /// - /// Represents a quantity. Primarily used for specifying a required amount of calls to a member. + /// A non-zero quantity between the given minimum and maximum numbers (inclusive). /// - public abstract class Quantity - { - public static Quantity Exactly(int number) { return number == 0 ? None() : new ExactQuantity(number); } - public static Quantity AtLeastOne() { return new AnyNonZeroQuantity(); } - public static Quantity None() { return new NoneQuantity(); } - /// - /// A non-zero quantity between the given minimum and maximum numbers (inclusive). - /// - /// Minimum quantity (inclusive). Must be greater than or equal to 0. - /// Maximum quantity (inclusive). Must be greater than minInclusive. - /// - public static Quantity Within(int minInclusive, int maxInclusive) { return new RangeQuantity(minInclusive, maxInclusive); } - - /// - /// Returns whether the given collection contains the required quantity of items. - /// - /// - /// - /// true if the collection has the required quantity; otherwise false. - public abstract bool Matches(IEnumerable items); - - /// - /// Returns whether the given collections needs more items to satisfy the required quantity. - /// - /// - /// - /// true if the collection needs more items to match this quantity; otherwise false. - public abstract bool RequiresMoreThan(IEnumerable items); - - /// - /// Describe this quantity using the given noun variants. - /// For example, `Describe("item", "items")` could return the description: - /// "more than 1 item, but less than 10 items". - /// - /// - /// - /// A string describing the required quantity of items identified by the provided noun forms. - public abstract string Describe(string singularNoun, string pluralNoun); - - private class ExactQuantity : Quantity - { - private readonly int _number; - public ExactQuantity(int number) { _number = number; } - public override bool Matches(IEnumerable items) { return _number == items.Count(); } - public override bool RequiresMoreThan(IEnumerable items) { return _number > items.Count(); } - public override string Describe(string singularNoun, string pluralNoun) - { - return string.Format("exactly {0} {1}", _number, _number == 1 ? singularNoun : pluralNoun); - } + /// Minimum quantity (inclusive). Must be greater than or equal to 0. + /// Maximum quantity (inclusive). Must be greater than minInclusive. + /// + public static Quantity Within(int minInclusive, int maxInclusive) { return new RangeQuantity(minInclusive, maxInclusive); } - public bool Equals(ExactQuantity other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other._number == _number; - } + /// + /// Returns whether the given collection contains the required quantity of items. + /// + /// + /// + /// true if the collection has the required quantity; otherwise false. + public abstract bool Matches(IEnumerable items); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof(ExactQuantity)) return false; - return Equals((ExactQuantity)obj); - } + /// + /// Returns whether the given collections needs more items to satisfy the required quantity. + /// + /// + /// + /// true if the collection needs more items to match this quantity; otherwise false. + public abstract bool RequiresMoreThan(IEnumerable items); + + /// + /// Describe this quantity using the given noun variants. + /// For example, `Describe("item", "items")` could return the description: + /// "more than 1 item, but less than 10 items". + /// + /// + /// + /// A string describing the required quantity of items identified by the provided noun forms. + public abstract string Describe(string singularNoun, string pluralNoun); - public override int GetHashCode() { return _number; } + private class ExactQuantity : Quantity + { + private readonly int _number; + public ExactQuantity(int number) { _number = number; } + public override bool Matches(IEnumerable items) { return _number == items.Count(); } + public override bool RequiresMoreThan(IEnumerable items) { return _number > items.Count(); } + public override string Describe(string singularNoun, string pluralNoun) + { + return string.Format("exactly {0} {1}", _number, _number == 1 ? singularNoun : pluralNoun); } - private class AnyNonZeroQuantity : Quantity + public bool Equals(ExactQuantity other) { - public override bool Matches(IEnumerable items) { return items.Any(); } - public override bool RequiresMoreThan(IEnumerable items) { return !items.Any(); } + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other._number == _number; + } - public override string Describe(string singularNoun, string pluralNoun) - { - return string.Format("a {0}", singularNoun); - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(ExactQuantity)) return false; + return Equals((ExactQuantity)obj); + } - public bool Equals(AnyNonZeroQuantity other) - { - return !ReferenceEquals(null, other); - } + public override int GetHashCode() { return _number; } + } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof(AnyNonZeroQuantity)) return false; - return Equals((AnyNonZeroQuantity)obj); - } + private class AnyNonZeroQuantity : Quantity + { + public override bool Matches(IEnumerable items) { return items.Any(); } + public override bool RequiresMoreThan(IEnumerable items) { return !items.Any(); } - public override int GetHashCode() - { - return 0; - } + public override string Describe(string singularNoun, string pluralNoun) + { + return string.Format("a {0}", singularNoun); } - private class NoneQuantity : Quantity + public bool Equals(AnyNonZeroQuantity other) { - public override bool Matches(IEnumerable items) { return !items.Any(); } - public override bool RequiresMoreThan(IEnumerable items) { return false; } - public override string Describe(string singularNoun, string pluralNoun) - { - return "no " + pluralNoun; - } + return !ReferenceEquals(null, other); + } - public bool Equals(NoneQuantity other) - { - return !ReferenceEquals(null, other); - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(AnyNonZeroQuantity)) return false; + return Equals((AnyNonZeroQuantity)obj); + } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof(NoneQuantity)) return false; - return Equals((NoneQuantity)obj); - } + public override int GetHashCode() + { + return 0; + } + } - public override int GetHashCode() { return 0; } + private class NoneQuantity : Quantity + { + public override bool Matches(IEnumerable items) { return !items.Any(); } + public override bool RequiresMoreThan(IEnumerable items) { return false; } + public override string Describe(string singularNoun, string pluralNoun) + { + return "no " + pluralNoun; } - private class RangeQuantity : Quantity + public bool Equals(NoneQuantity other) { - private readonly int minInclusive; - private readonly int maxInclusive; - public RangeQuantity(int minInclusive, int maxInclusive) + return !ReferenceEquals(null, other); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(NoneQuantity)) return false; + return Equals((NoneQuantity)obj); + } + + public override int GetHashCode() { return 0; } + } + + private class RangeQuantity : Quantity + { + private readonly int minInclusive; + private readonly int maxInclusive; + public RangeQuantity(int minInclusive, int maxInclusive) + { + if (minInclusive < 0) { - if (minInclusive < 0) - { - throw new ArgumentOutOfRangeException(nameof(minInclusive), - $"{nameof(minInclusive)} must be >= 0, but was {minInclusive}."); - } - if (maxInclusive <= minInclusive) - { - throw new ArgumentOutOfRangeException(nameof(maxInclusive), - $"{nameof(maxInclusive)} must be greater than {nameof(minInclusive)} (was {maxInclusive}, required > {minInclusive})."); - } - this.minInclusive = minInclusive; - this.maxInclusive = maxInclusive; + throw new ArgumentOutOfRangeException(nameof(minInclusive), + $"{nameof(minInclusive)} must be >= 0, but was {minInclusive}."); } - public override string Describe(string singularNoun, string pluralNoun) => - $"between {minInclusive} and {maxInclusive} (inclusive) {((maxInclusive == 1) ? singularNoun : pluralNoun)}"; - - public override bool Matches(IEnumerable items) + if (maxInclusive <= minInclusive) { - var count = items.Count(); - return count >= minInclusive && count <= maxInclusive; + throw new ArgumentOutOfRangeException(nameof(maxInclusive), + $"{nameof(maxInclusive)} must be greater than {nameof(minInclusive)} (was {maxInclusive}, required > {minInclusive})."); } + this.minInclusive = minInclusive; + this.maxInclusive = maxInclusive; + } + public override string Describe(string singularNoun, string pluralNoun) => + $"between {minInclusive} and {maxInclusive} (inclusive) {((maxInclusive == 1) ? singularNoun : pluralNoun)}"; - public override bool RequiresMoreThan(IEnumerable items) => items.Count() < minInclusive; + public override bool Matches(IEnumerable items) + { + var count = items.Count(); + return count >= minInclusive && count <= maxInclusive; } + + public override bool RequiresMoreThan(IEnumerable items) => items.Count() < minInclusive; } } \ No newline at end of file diff --git a/src/NSubstitute/Extensions/ReturnsExtensions.cs b/src/NSubstitute/Extensions/ReturnsExtensions.cs index d56214916..414f449f7 100644 --- a/src/NSubstitute/Extensions/ReturnsExtensions.cs +++ b/src/NSubstitute/Extensions/ReturnsExtensions.cs @@ -3,83 +3,82 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.ReturnsExtensions +namespace NSubstitute.ReturnsExtensions; + +public static class ReturnsExtensions { - public static class ReturnsExtensions - { - /// - /// Set null as returned value for this call. - /// - public static ConfiguredCall ReturnsNull(this T value) where T : class => - value.Returns(default(T)); + /// + /// Set null as returned value for this call. + /// + public static ConfiguredCall ReturnsNull(this T value) where T : class => + value.Returns(default(T)); - /// - /// Set null as returned value for this call made with any arguments. - /// - public static ConfiguredCall ReturnsNullForAnyArgs(this T value) where T : class => - value.ReturnsForAnyArgs(default(T)); + /// + /// Set null as returned value for this call made with any arguments. + /// + public static ConfiguredCall ReturnsNullForAnyArgs(this T value) where T : class => + value.ReturnsForAnyArgs(default(T)); - /// - /// Set null as returned value for this call. - /// - public static ConfiguredCall ReturnsNull(this T? value) where T : struct => - value.Returns(default(T?)); + /// + /// Set null as returned value for this call. + /// + public static ConfiguredCall ReturnsNull(this T? value) where T : struct => + value.Returns(default(T?)); - /// - /// Set null as returned value for this call made with any arguments. - /// - public static ConfiguredCall ReturnsNullForAnyArgs(this T? value) where T : struct => - value.ReturnsForAnyArgs(default(T?)); + /// + /// Set null as returned value for this call made with any arguments. + /// + public static ConfiguredCall ReturnsNullForAnyArgs(this T? value) where T : struct => + value.ReturnsForAnyArgs(default(T?)); - /// - /// Set null as returned value for this call. - /// - public static ConfiguredCall ReturnsNull(this Task value) where T : class => - value.Returns(default(T)); + /// + /// Set null as returned value for this call. + /// + public static ConfiguredCall ReturnsNull(this Task value) where T : class => + value.Returns(default(T)); - /// - /// Set null as returned value for this call. - /// - public static ConfiguredCall ReturnsNull(this ValueTask value) where T : class => - value.Returns(default(T)); + /// + /// Set null as returned value for this call. + /// + public static ConfiguredCall ReturnsNull(this ValueTask value) where T : class => + value.Returns(default(T)); - /// - /// Set null as returned value for this call made with any arguments. - /// - public static ConfiguredCall ReturnsNullForAnyArgs(this Task value) where T : class => - value.ReturnsForAnyArgs(default(T)); + /// + /// Set null as returned value for this call made with any arguments. + /// + public static ConfiguredCall ReturnsNullForAnyArgs(this Task value) where T : class => + value.ReturnsForAnyArgs(default(T)); - /// - /// Set null as returned value for this call made with any arguments. - /// - /// - /// - /// - public static ConfiguredCall ReturnsNullForAnyArgs(this ValueTask value) where T : class => - value.ReturnsForAnyArgs(default(T)); + /// + /// Set null as returned value for this call made with any arguments. + /// + /// + /// + /// + public static ConfiguredCall ReturnsNullForAnyArgs(this ValueTask value) where T : class => + value.ReturnsForAnyArgs(default(T)); - /// - /// Set null as returned value for this call. - /// - public static ConfiguredCall ReturnsNull(this Task value) where T : struct => - value.Returns(default(T?)); + /// + /// Set null as returned value for this call. + /// + public static ConfiguredCall ReturnsNull(this Task value) where T : struct => + value.Returns(default(T?)); - /// - /// Set null as returned value for this call made with any arguments. - /// - public static ConfiguredCall ReturnsNullForAnyArgs(this Task value) where T : struct => - value.ReturnsForAnyArgs(default(T?)); + /// + /// Set null as returned value for this call made with any arguments. + /// + public static ConfiguredCall ReturnsNullForAnyArgs(this Task value) where T : struct => + value.ReturnsForAnyArgs(default(T?)); - /// - /// Set null as returned value for this call. - /// - public static ConfiguredCall ReturnsNull(this ValueTask value) where T : struct => - value.Returns(default(T?)); + /// + /// Set null as returned value for this call. + /// + public static ConfiguredCall ReturnsNull(this ValueTask value) where T : struct => + value.Returns(default(T?)); - /// - /// Set null as returned value for this call made with any arguments. - /// - public static ConfiguredCall ReturnsNullForAnyArgs(this ValueTask value) where T : struct => - value.ReturnsForAnyArgs(default(T?)); - } + /// + /// Set null as returned value for this call made with any arguments. + /// + public static ConfiguredCall ReturnsNullForAnyArgs(this ValueTask value) where T : struct => + value.ReturnsForAnyArgs(default(T?)); } diff --git a/src/NSubstitute/Extensions/ReturnsForAllExtensions.cs b/src/NSubstitute/Extensions/ReturnsForAllExtensions.cs index 546c92bcf..5e8267b22 100644 --- a/src/NSubstitute/Extensions/ReturnsForAllExtensions.cs +++ b/src/NSubstitute/Extensions/ReturnsForAllExtensions.cs @@ -4,38 +4,37 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute.Extensions +namespace NSubstitute.Extensions; + +public static class ReturnsForAllExtensions { - public static class ReturnsForAllExtensions + /// + /// Configure default return value for all methods that return the specified type + /// + /// + /// + /// + /// + public static void ReturnsForAll(this object substitute, T returnThis) { - /// - /// Configure default return value for all methods that return the specified type - /// - /// - /// - /// - /// - public static void ReturnsForAll(this object substitute, T returnThis) - { - if (substitute == null) throw new NullSubstituteReferenceException(); + if (substitute == null) throw new NullSubstituteReferenceException(); - var callRouter = SubstitutionContext.Current.GetCallRouterFor(substitute); - callRouter.SetReturnForType(typeof(T), new ReturnValue(returnThis)); - } + var callRouter = SubstitutionContext.Current.GetCallRouterFor(substitute); + callRouter.SetReturnForType(typeof(T), new ReturnValue(returnThis)); + } - /// - /// Configure default return value for all methods that return the specified type, calculated by a function - /// - /// - /// - /// - /// - public static void ReturnsForAll(this object substitute, Func returnThis) - { - if (substitute == null) throw new NullSubstituteReferenceException(); + /// + /// Configure default return value for all methods that return the specified type, calculated by a function + /// + /// + /// + /// + /// + public static void ReturnsForAll(this object substitute, Func returnThis) + { + if (substitute == null) throw new NullSubstituteReferenceException(); - var callRouter = SubstitutionContext.Current.GetCallRouterFor(substitute); - callRouter.SetReturnForType(typeof(T), new ReturnValueFromFunc(returnThis)); - } + var callRouter = SubstitutionContext.Current.GetCallRouterFor(substitute); + callRouter.SetReturnForType(typeof(T), new ReturnValueFromFunc(returnThis)); } } \ No newline at end of file diff --git a/src/NSubstitute/Proxies/CastleDynamicProxy/CastleDynamicProxyFactory.cs b/src/NSubstitute/Proxies/CastleDynamicProxy/CastleDynamicProxyFactory.cs index ce93ea0d3..dab852004 100644 --- a/src/NSubstitute/Proxies/CastleDynamicProxy/CastleDynamicProxyFactory.cs +++ b/src/NSubstitute/Proxies/CastleDynamicProxy/CastleDynamicProxyFactory.cs @@ -3,197 +3,196 @@ using NSubstitute.Core; using NSubstitute.Exceptions; -namespace NSubstitute.Proxies.CastleDynamicProxy +namespace NSubstitute.Proxies.CastleDynamicProxy; + +public class CastleDynamicProxyFactory : IProxyFactory { - public class CastleDynamicProxyFactory : IProxyFactory - { - private readonly ICallFactory _callFactory; - private readonly IArgumentSpecificationDequeue _argSpecificationDequeue; - private readonly ProxyGenerator _proxyGenerator; - private readonly AllMethodsExceptCallRouterCallsHook _allMethodsExceptCallRouterCallsHook; + private readonly ICallFactory _callFactory; + private readonly IArgumentSpecificationDequeue _argSpecificationDequeue; + private readonly ProxyGenerator _proxyGenerator; + private readonly AllMethodsExceptCallRouterCallsHook _allMethodsExceptCallRouterCallsHook; - public CastleDynamicProxyFactory(ICallFactory callFactory, IArgumentSpecificationDequeue argSpecificationDequeue) - { - _callFactory = callFactory; - _argSpecificationDequeue = argSpecificationDequeue; - _proxyGenerator = new ProxyGenerator(); - _allMethodsExceptCallRouterCallsHook = new AllMethodsExceptCallRouterCallsHook(); - } + public CastleDynamicProxyFactory(ICallFactory callFactory, IArgumentSpecificationDequeue argSpecificationDequeue) + { + _callFactory = callFactory; + _argSpecificationDequeue = argSpecificationDequeue; + _proxyGenerator = new ProxyGenerator(); + _allMethodsExceptCallRouterCallsHook = new AllMethodsExceptCallRouterCallsHook(); + } - public object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) - { - return typeToProxy.IsDelegate() - ? GenerateDelegateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments) - : GenerateTypeProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments); - } + public object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) + { + return typeToProxy.IsDelegate() + ? GenerateDelegateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments) + : GenerateTypeProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments); + } - private object GenerateTypeProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) - { - VerifyClassHasNotBeenPassedAsAnAdditionalInterface(additionalInterfaces); + private object GenerateTypeProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) + { + VerifyClassHasNotBeenPassedAsAnAdditionalInterface(additionalInterfaces); - var proxyIdInterceptor = new ProxyIdInterceptor(typeToProxy); - var forwardingInterceptor = CreateForwardingInterceptor(callRouter); + var proxyIdInterceptor = new ProxyIdInterceptor(typeToProxy); + var forwardingInterceptor = CreateForwardingInterceptor(callRouter); - var proxyGenerationOptions = GetOptionsToMixinCallRouterProvider(callRouter); + var proxyGenerationOptions = GetOptionsToMixinCallRouterProvider(callRouter); - var proxy = CreateProxyUsingCastleProxyGenerator( - typeToProxy, - additionalInterfaces, - constructorArguments, - new IInterceptor[] { proxyIdInterceptor, forwardingInterceptor }, - proxyGenerationOptions); + var proxy = CreateProxyUsingCastleProxyGenerator( + typeToProxy, + additionalInterfaces, + constructorArguments, + new IInterceptor[] { proxyIdInterceptor, forwardingInterceptor }, + proxyGenerationOptions); - forwardingInterceptor.SwitchToFullDispatchMode(); - return proxy; - } + forwardingInterceptor.SwitchToFullDispatchMode(); + return proxy; + } - private object GenerateDelegateProxy(ICallRouter callRouter, Type delegateType, Type[]? additionalInterfaces, object?[]? constructorArguments) - { - VerifyNoAdditionalInterfacesGivenForDelegate(additionalInterfaces); - VerifyNoConstructorArgumentsGivenForDelegate(constructorArguments); + private object GenerateDelegateProxy(ICallRouter callRouter, Type delegateType, Type[]? additionalInterfaces, object?[]? constructorArguments) + { + VerifyNoAdditionalInterfacesGivenForDelegate(additionalInterfaces); + VerifyNoConstructorArgumentsGivenForDelegate(constructorArguments); - var forwardingInterceptor = CreateForwardingInterceptor(callRouter); - // Keep this interceptor, so that real proxy ID can be retrieved by proxy.Target.ToString(). - var proxyIdInterceptor = new ProxyIdInterceptor(delegateType); + var forwardingInterceptor = CreateForwardingInterceptor(callRouter); + // Keep this interceptor, so that real proxy ID can be retrieved by proxy.Target.ToString(). + var proxyIdInterceptor = new ProxyIdInterceptor(delegateType); - var proxyGenerationOptions = GetOptionsToMixinCallRouterProvider(callRouter); - proxyGenerationOptions.AddDelegateTypeMixin(delegateType); + var proxyGenerationOptions = GetOptionsToMixinCallRouterProvider(callRouter); + proxyGenerationOptions.AddDelegateTypeMixin(delegateType); - var proxy = CreateProxyUsingCastleProxyGenerator( - typeToProxy: typeof(object), - additionalInterfaces: null, - constructorArguments: null, - interceptors: new IInterceptor[] { proxyIdInterceptor, forwardingInterceptor }, - proxyGenerationOptions); + var proxy = CreateProxyUsingCastleProxyGenerator( + typeToProxy: typeof(object), + additionalInterfaces: null, + constructorArguments: null, + interceptors: new IInterceptor[] { proxyIdInterceptor, forwardingInterceptor }, + proxyGenerationOptions); - forwardingInterceptor.SwitchToFullDispatchMode(); + forwardingInterceptor.SwitchToFullDispatchMode(); - // Ideally we should use ProxyUtil.CreateDelegateToMixin(proxy, delegateType). - // But it's slower than code below due to extra checks it performs. - return proxy.GetType().GetInvokeMethod().CreateDelegate(delegateType, proxy); - } + // Ideally we should use ProxyUtil.CreateDelegateToMixin(proxy, delegateType). + // But it's slower than code below due to extra checks it performs. + return proxy.GetType().GetInvokeMethod().CreateDelegate(delegateType, proxy); + } - private CastleForwardingInterceptor CreateForwardingInterceptor(ICallRouter callRouter) - { - return new CastleForwardingInterceptor( - new CastleInvocationMapper( - _callFactory, - _argSpecificationDequeue), - callRouter); - } + private CastleForwardingInterceptor CreateForwardingInterceptor(ICallRouter callRouter) + { + return new CastleForwardingInterceptor( + new CastleInvocationMapper( + _callFactory, + _argSpecificationDequeue), + callRouter); + } - private object CreateProxyUsingCastleProxyGenerator(Type typeToProxy, Type[]? additionalInterfaces, - object?[]? constructorArguments, - IInterceptor[] interceptors, - ProxyGenerationOptions proxyGenerationOptions) + private object CreateProxyUsingCastleProxyGenerator(Type typeToProxy, Type[]? additionalInterfaces, + object?[]? constructorArguments, + IInterceptor[] interceptors, + ProxyGenerationOptions proxyGenerationOptions) + { + if (typeToProxy.GetTypeInfo().IsInterface) { - if (typeToProxy.GetTypeInfo().IsInterface) - { - VerifyNoConstructorArgumentsGivenForInterface(constructorArguments); + VerifyNoConstructorArgumentsGivenForInterface(constructorArguments); - var interfacesArrayLength = additionalInterfaces != null ? additionalInterfaces.Length + 1 : 1; - var interfaces = new Type[interfacesArrayLength]; + var interfacesArrayLength = additionalInterfaces != null ? additionalInterfaces.Length + 1 : 1; + var interfaces = new Type[interfacesArrayLength]; - interfaces[0] = typeToProxy; - if (additionalInterfaces != null) - { - Array.Copy(additionalInterfaces, 0, interfaces, 1, additionalInterfaces.Length); - } - - // We need to create a proxy for the object type, so we can intercept the ToString() method. - // Therefore, we put the desired primary interface to the secondary list. - typeToProxy = typeof(object); - additionalInterfaces = interfaces; + interfaces[0] = typeToProxy; + if (additionalInterfaces != null) + { + Array.Copy(additionalInterfaces, 0, interfaces, 1, additionalInterfaces.Length); } - return _proxyGenerator.CreateClassProxy(typeToProxy, - additionalInterfaces, - proxyGenerationOptions, - constructorArguments, - interceptors); + // We need to create a proxy for the object type, so we can intercept the ToString() method. + // Therefore, we put the desired primary interface to the secondary list. + typeToProxy = typeof(object); + additionalInterfaces = interfaces; } - private ProxyGenerationOptions GetOptionsToMixinCallRouterProvider(ICallRouter callRouter) - { - var options = new ProxyGenerationOptions(_allMethodsExceptCallRouterCallsHook); + return _proxyGenerator.CreateClassProxy(typeToProxy, + additionalInterfaces, + proxyGenerationOptions, + constructorArguments, + interceptors); + } - // Previously we mixed in the callRouter instance directly, and now we create a wrapper around it. - // The reason is that we want SubstitutionContext.GetCallRouterFor(substitute) to return us the - // original callRouter object, rather than the substitute object (as it implemented the ICallRouter interface directly). - // That need appeared due to the ThreadLocalContext.SetNextRoute() API, which compares the passed callRouter instance by reference. - options.AddMixinInstance(new StaticCallRouterProvider(callRouter)); + private ProxyGenerationOptions GetOptionsToMixinCallRouterProvider(ICallRouter callRouter) + { + var options = new ProxyGenerationOptions(_allMethodsExceptCallRouterCallsHook); - return options; - } + // Previously we mixed in the callRouter instance directly, and now we create a wrapper around it. + // The reason is that we want SubstitutionContext.GetCallRouterFor(substitute) to return us the + // original callRouter object, rather than the substitute object (as it implemented the ICallRouter interface directly). + // That need appeared due to the ThreadLocalContext.SetNextRoute() API, which compares the passed callRouter instance by reference. + options.AddMixinInstance(new StaticCallRouterProvider(callRouter)); - private static void VerifyNoConstructorArgumentsGivenForInterface(object?[]? constructorArguments) + return options; + } + + private static void VerifyNoConstructorArgumentsGivenForInterface(object?[]? constructorArguments) + { + if (HasItems(constructorArguments)) { - if (HasItems(constructorArguments)) - { - throw new SubstituteException("Can not provide constructor arguments when substituting for an interface."); - } + throw new SubstituteException("Can not provide constructor arguments when substituting for an interface."); } + } - private static void VerifyNoConstructorArgumentsGivenForDelegate(object?[]? constructorArguments) + private static void VerifyNoConstructorArgumentsGivenForDelegate(object?[]? constructorArguments) + { + if (HasItems(constructorArguments)) { - if (HasItems(constructorArguments)) - { - throw new SubstituteException("Can not provide constructor arguments when substituting for a delegate."); - } + throw new SubstituteException("Can not provide constructor arguments when substituting for a delegate."); } + } - private static void VerifyNoAdditionalInterfacesGivenForDelegate(Type[]? constructorArguments) + private static void VerifyNoAdditionalInterfacesGivenForDelegate(Type[]? constructorArguments) + { + if (HasItems(constructorArguments)) { - if (HasItems(constructorArguments)) - { - throw new SubstituteException( - "Can not specify additional interfaces when substituting for a delegate. " + - "You must specify only a single delegate type if you need to substitute for a delegate."); - } + throw new SubstituteException( + "Can not specify additional interfaces when substituting for a delegate. " + + "You must specify only a single delegate type if you need to substitute for a delegate."); } + } - private static void VerifyClassHasNotBeenPassedAsAnAdditionalInterface(Type[]? additionalInterfaces) + private static void VerifyClassHasNotBeenPassedAsAnAdditionalInterface(Type[]? additionalInterfaces) + { + if (additionalInterfaces != null && additionalInterfaces.Any(x => x.GetTypeInfo().IsClass)) { - if (additionalInterfaces != null && additionalInterfaces.Any(x => x.GetTypeInfo().IsClass)) - { - throw new SubstituteException( - "Can not substitute for multiple classes. " + - "To substitute for multiple types only one type can be a concrete class; other types can only be interfaces."); - } + throw new SubstituteException( + "Can not substitute for multiple classes. " + + "To substitute for multiple types only one type can be a concrete class; other types can only be interfaces."); } + } - private static bool HasItems(T[]? array) => array?.Length > 0; + private static bool HasItems(T[]? array) => array?.Length > 0; - private class AllMethodsExceptCallRouterCallsHook : AllMethodsHook + private class AllMethodsExceptCallRouterCallsHook : AllMethodsHook + { + public override bool ShouldInterceptMethod(Type type, MethodInfo methodInfo) { - public override bool ShouldInterceptMethod(Type type, MethodInfo methodInfo) - { - // Always intercept object.ToString() as we would like to return proxy id as a result. - if (ProxyIdInterceptor.IsDefaultToStringMethod(methodInfo)) - return true; + // Always intercept object.ToString() as we would like to return proxy id as a result. + if (ProxyIdInterceptor.IsDefaultToStringMethod(methodInfo)) + return true; - return IsNotCallRouterProviderMethod(methodInfo) - && IsNotBaseObjectMethod(methodInfo) - && base.ShouldInterceptMethod(type, methodInfo); - } - - private static bool IsNotCallRouterProviderMethod(MethodInfo methodInfo) => - methodInfo.DeclaringType != typeof(ICallRouterProvider); - - private static bool IsNotBaseObjectMethod(MethodInfo methodInfo) => - methodInfo.GetBaseDefinition().DeclaringType != typeof(object); + return IsNotCallRouterProviderMethod(methodInfo) + && IsNotBaseObjectMethod(methodInfo) + && base.ShouldInterceptMethod(type, methodInfo); } - private class StaticCallRouterProvider : ICallRouterProvider - { - private readonly ICallRouter _callRouter; + private static bool IsNotCallRouterProviderMethod(MethodInfo methodInfo) => + methodInfo.DeclaringType != typeof(ICallRouterProvider); - public StaticCallRouterProvider(ICallRouter callRouter) - { - _callRouter = callRouter; - } + private static bool IsNotBaseObjectMethod(MethodInfo methodInfo) => + methodInfo.GetBaseDefinition().DeclaringType != typeof(object); + } - public ICallRouter GetCallRouter() => _callRouter; + private class StaticCallRouterProvider : ICallRouterProvider + { + private readonly ICallRouter _callRouter; + + public StaticCallRouterProvider(ICallRouter callRouter) + { + _callRouter = callRouter; } + + public ICallRouter GetCallRouter() => _callRouter; } } \ No newline at end of file diff --git a/src/NSubstitute/Proxies/CastleDynamicProxy/CastleForwardingInterceptor.cs b/src/NSubstitute/Proxies/CastleDynamicProxy/CastleForwardingInterceptor.cs index fe3e926de..d818da07c 100644 --- a/src/NSubstitute/Proxies/CastleDynamicProxy/CastleForwardingInterceptor.cs +++ b/src/NSubstitute/Proxies/CastleDynamicProxy/CastleForwardingInterceptor.cs @@ -1,44 +1,43 @@ using Castle.DynamicProxy; using NSubstitute.Core; -namespace NSubstitute.Proxies.CastleDynamicProxy +namespace NSubstitute.Proxies.CastleDynamicProxy; + +public class CastleForwardingInterceptor : IInterceptor { - public class CastleForwardingInterceptor : IInterceptor + private readonly CastleInvocationMapper _invocationMapper; + private readonly ICallRouter _callRouter; + private bool _fullDispatchMode; + + public CastleForwardingInterceptor(CastleInvocationMapper invocationMapper, ICallRouter callRouter) { - private readonly CastleInvocationMapper _invocationMapper; - private readonly ICallRouter _callRouter; - private bool _fullDispatchMode; + _invocationMapper = invocationMapper; + _callRouter = callRouter; + } - public CastleForwardingInterceptor(CastleInvocationMapper invocationMapper, ICallRouter callRouter) - { - _invocationMapper = invocationMapper; - _callRouter = callRouter; - } + public void Intercept(IInvocation invocation) + { + ICall mappedInvocation = _invocationMapper.Map(invocation); - public void Intercept(IInvocation invocation) + if (_fullDispatchMode) { - ICall mappedInvocation = _invocationMapper.Map(invocation); - - if (_fullDispatchMode) - { - invocation.ReturnValue = _callRouter.Route(mappedInvocation); - return; - } - - // Fallback to the base value until the full dispatch mode is activated. - // Useful to ensure that object is initialized properly. - if (_callRouter.CallBaseByDefault) - { - invocation.ReturnValue = mappedInvocation.TryCallBase().ValueOrDefault(); - } + invocation.ReturnValue = _callRouter.Route(mappedInvocation); + return; } - /// - /// Switches interceptor to dispatch calls via the full pipeline. - /// - public void SwitchToFullDispatchMode() + // Fallback to the base value until the full dispatch mode is activated. + // Useful to ensure that object is initialized properly. + if (_callRouter.CallBaseByDefault) { - _fullDispatchMode = true; + invocation.ReturnValue = mappedInvocation.TryCallBase().ValueOrDefault(); } } + + /// + /// Switches interceptor to dispatch calls via the full pipeline. + /// + public void SwitchToFullDispatchMode() + { + _fullDispatchMode = true; + } } \ No newline at end of file diff --git a/src/NSubstitute/Proxies/CastleDynamicProxy/CastleInvocationMapper.cs b/src/NSubstitute/Proxies/CastleDynamicProxy/CastleInvocationMapper.cs index 27550118e..8b48a50f7 100644 --- a/src/NSubstitute/Proxies/CastleDynamicProxy/CastleInvocationMapper.cs +++ b/src/NSubstitute/Proxies/CastleDynamicProxy/CastleInvocationMapper.cs @@ -1,42 +1,41 @@ using Castle.DynamicProxy; using NSubstitute.Core; -namespace NSubstitute.Proxies.CastleDynamicProxy +namespace NSubstitute.Proxies.CastleDynamicProxy; + +public class CastleInvocationMapper { - public class CastleInvocationMapper + private readonly ICallFactory _callFactory; + private readonly IArgumentSpecificationDequeue _argSpecificationDequeue; + + public CastleInvocationMapper(ICallFactory callFactory, IArgumentSpecificationDequeue argSpecificationDequeue) { - private readonly ICallFactory _callFactory; - private readonly IArgumentSpecificationDequeue _argSpecificationDequeue; + _callFactory = callFactory; + _argSpecificationDequeue = argSpecificationDequeue; + } - public CastleInvocationMapper(ICallFactory callFactory, IArgumentSpecificationDequeue argSpecificationDequeue) + public virtual ICall Map(IInvocation castleInvocation) + { + Func? baseMethod = null; + if (castleInvocation.InvocationTarget != null && + castleInvocation.MethodInvocationTarget.IsVirtual && + !castleInvocation.MethodInvocationTarget.IsAbstract && + !castleInvocation.MethodInvocationTarget.IsFinal) { - _callFactory = callFactory; - _argSpecificationDequeue = argSpecificationDequeue; + baseMethod = CreateBaseResultInvocation(castleInvocation); } - public virtual ICall Map(IInvocation castleInvocation) - { - Func? baseMethod = null; - if (castleInvocation.InvocationTarget != null && - castleInvocation.MethodInvocationTarget.IsVirtual && - !castleInvocation.MethodInvocationTarget.IsAbstract && - !castleInvocation.MethodInvocationTarget.IsFinal) - { - baseMethod = CreateBaseResultInvocation(castleInvocation); - } - - var queuedArgSpecifications = _argSpecificationDequeue.DequeueAllArgumentSpecificationsForMethod(castleInvocation.Arguments.Length); - return _callFactory.Create(castleInvocation.Method, castleInvocation.Arguments, castleInvocation.Proxy, queuedArgSpecifications, baseMethod); - } + var queuedArgSpecifications = _argSpecificationDequeue.DequeueAllArgumentSpecificationsForMethod(castleInvocation.Arguments.Length); + return _callFactory.Create(castleInvocation.Method, castleInvocation.Arguments, castleInvocation.Proxy, queuedArgSpecifications, baseMethod); + } - private static Func CreateBaseResultInvocation(IInvocation invocation) - { - // Notice, it's important to keep this as a separate method, as methods with lambda closures - // always allocate, even if delegate is not actually constructed. - // This way we make allocation only if indeed required. - Func baseResult = () => { invocation.Proceed(); return invocation.ReturnValue; }; - var result = new Lazy(baseResult); - return () => result.Value; - } + private static Func CreateBaseResultInvocation(IInvocation invocation) + { + // Notice, it's important to keep this as a separate method, as methods with lambda closures + // always allocate, even if delegate is not actually constructed. + // This way we make allocation only if indeed required. + Func baseResult = () => { invocation.Proceed(); return invocation.ReturnValue; }; + var result = new Lazy(baseResult); + return () => result.Value; } } diff --git a/src/NSubstitute/Proxies/CastleDynamicProxy/ProxyIdInterceptor.cs b/src/NSubstitute/Proxies/CastleDynamicProxy/ProxyIdInterceptor.cs index a90b5ac75..19c244fc3 100644 --- a/src/NSubstitute/Proxies/CastleDynamicProxy/ProxyIdInterceptor.cs +++ b/src/NSubstitute/Proxies/CastleDynamicProxy/ProxyIdInterceptor.cs @@ -3,44 +3,43 @@ using Castle.DynamicProxy; using NSubstitute.Core; -namespace NSubstitute.Proxies.CastleDynamicProxy +namespace NSubstitute.Proxies.CastleDynamicProxy; + +public class ProxyIdInterceptor : IInterceptor { - public class ProxyIdInterceptor : IInterceptor + private readonly Type _primaryProxyType; + private string? _cachedProxyId; + + public ProxyIdInterceptor(Type primaryProxyType) { - private readonly Type _primaryProxyType; - private string? _cachedProxyId; + _primaryProxyType = primaryProxyType; + } - public ProxyIdInterceptor(Type primaryProxyType) + public void Intercept(IInvocation invocation) + { + if (IsDefaultToStringMethod(invocation.Method)) { - _primaryProxyType = primaryProxyType; + invocation.ReturnValue = _cachedProxyId ??= GenerateId(invocation); + return; } - public void Intercept(IInvocation invocation) - { - if (IsDefaultToStringMethod(invocation.Method)) - { - invocation.ReturnValue = _cachedProxyId ??= GenerateId(invocation); - return; - } - - invocation.Proceed(); - } + invocation.Proceed(); + } - private string GenerateId(IInvocation invocation) - { - var proxy = invocation.InvocationTarget; + private string GenerateId(IInvocation invocation) + { + var proxy = invocation.InvocationTarget; - var shortTypeName = _primaryProxyType.GetNonMangledTypeName(); - var proxyHashCode = proxy.GetHashCode(); + var shortTypeName = _primaryProxyType.GetNonMangledTypeName(); + var proxyHashCode = proxy.GetHashCode(); - return string.Format(CultureInfo.InvariantCulture, "Substitute.{0}|{1:x8}", shortTypeName, proxyHashCode); - } + return string.Format(CultureInfo.InvariantCulture, "Substitute.{0}|{1:x8}", shortTypeName, proxyHashCode); + } - public static bool IsDefaultToStringMethod(MethodInfo methodInfo) - { - return methodInfo.DeclaringType == typeof(object) - && string.Equals(methodInfo.Name, nameof(ToString), StringComparison.Ordinal) - && methodInfo.GetParameters().Length == 0; - } + public static bool IsDefaultToStringMethod(MethodInfo methodInfo) + { + return methodInfo.DeclaringType == typeof(object) + && string.Equals(methodInfo.Name, nameof(ToString), StringComparison.Ordinal) + && methodInfo.GetParameters().Length == 0; } } \ No newline at end of file diff --git a/src/NSubstitute/Proxies/DelegateProxy/DelegateProxyFactory.cs b/src/NSubstitute/Proxies/DelegateProxy/DelegateProxyFactory.cs index a6fbcf05e..6b81f51d3 100644 --- a/src/NSubstitute/Proxies/DelegateProxy/DelegateProxyFactory.cs +++ b/src/NSubstitute/Proxies/DelegateProxy/DelegateProxyFactory.cs @@ -1,22 +1,21 @@ using NSubstitute.Core; using NSubstitute.Proxies.CastleDynamicProxy; -namespace NSubstitute.Proxies.DelegateProxy +namespace NSubstitute.Proxies.DelegateProxy; + +[Obsolete("This class is deprecated and will be removed in future versions of the product.")] +public class DelegateProxyFactory : IProxyFactory { - [Obsolete("This class is deprecated and will be removed in future versions of the product.")] - public class DelegateProxyFactory : IProxyFactory - { - private readonly CastleDynamicProxyFactory _castleObjectProxyFactory; + private readonly CastleDynamicProxyFactory _castleObjectProxyFactory; - public DelegateProxyFactory(CastleDynamicProxyFactory objectProxyFactory) - { - _castleObjectProxyFactory = objectProxyFactory ?? throw new ArgumentNullException(nameof(objectProxyFactory)); - } + public DelegateProxyFactory(CastleDynamicProxyFactory objectProxyFactory) + { + _castleObjectProxyFactory = objectProxyFactory ?? throw new ArgumentNullException(nameof(objectProxyFactory)); + } - public object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) - { - // Castle factory can now resolve delegate proxies as well. - return _castleObjectProxyFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments); - } + public object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) + { + // Castle factory can now resolve delegate proxies as well. + return _castleObjectProxyFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments); } } \ No newline at end of file diff --git a/src/NSubstitute/Proxies/DelegateProxy/ProxiedDelegateTypeAttribute.cs b/src/NSubstitute/Proxies/DelegateProxy/ProxiedDelegateTypeAttribute.cs index b966bf484..26f5cb105 100644 --- a/src/NSubstitute/Proxies/DelegateProxy/ProxiedDelegateTypeAttribute.cs +++ b/src/NSubstitute/Proxies/DelegateProxy/ProxiedDelegateTypeAttribute.cs @@ -1,14 +1,13 @@ -namespace NSubstitute.Proxies.DelegateProxy +namespace NSubstitute.Proxies.DelegateProxy; + +[Obsolete("This class is deprecated and will be removed in future versions of the product.")] +[AttributeUsage(AttributeTargets.Method)] +public class ProxiedDelegateTypeAttribute : Attribute { - [Obsolete("This class is deprecated and will be removed in future versions of the product.")] - [AttributeUsage(AttributeTargets.Method)] - public class ProxiedDelegateTypeAttribute : Attribute - { - public Type DelegateType { get; } + public Type DelegateType { get; } - public ProxiedDelegateTypeAttribute(Type delegateType) - { - DelegateType = delegateType; - } + public ProxiedDelegateTypeAttribute(Type delegateType) + { + DelegateType = delegateType; } } \ No newline at end of file diff --git a/src/NSubstitute/Proxies/ProxyFactory.cs b/src/NSubstitute/Proxies/ProxyFactory.cs index 5ccb21a8e..3833fce55 100644 --- a/src/NSubstitute/Proxies/ProxyFactory.cs +++ b/src/NSubstitute/Proxies/ProxyFactory.cs @@ -1,25 +1,24 @@ using NSubstitute.Core; -namespace NSubstitute.Proxies +namespace NSubstitute.Proxies; + +[Obsolete("This class is deprecated and will be removed in future versions of the product.")] +public class ProxyFactory : IProxyFactory { - [Obsolete("This class is deprecated and will be removed in future versions of the product.")] - public class ProxyFactory : IProxyFactory - { - private readonly IProxyFactory _delegateFactory; - private readonly IProxyFactory _dynamicProxyFactory; + private readonly IProxyFactory _delegateFactory; + private readonly IProxyFactory _dynamicProxyFactory; - public ProxyFactory(IProxyFactory delegateFactory, IProxyFactory dynamicProxyFactory) - { - _delegateFactory = delegateFactory; - _dynamicProxyFactory = dynamicProxyFactory; - } + public ProxyFactory(IProxyFactory delegateFactory, IProxyFactory dynamicProxyFactory) + { + _delegateFactory = delegateFactory; + _dynamicProxyFactory = dynamicProxyFactory; + } - public object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) - { - var isDelegate = typeToProxy.IsDelegate(); - return isDelegate - ? _delegateFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments) - : _dynamicProxyFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments); - } + public object GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[]? additionalInterfaces, object?[]? constructorArguments) + { + var isDelegate = typeToProxy.IsDelegate(); + return isDelegate + ? _delegateFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments) + : _dynamicProxyFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments); } } \ No newline at end of file diff --git a/src/NSubstitute/Raise.cs b/src/NSubstitute/Raise.cs index b4312466b..f0fc2580f 100644 --- a/src/NSubstitute/Raise.cs +++ b/src/NSubstitute/Raise.cs @@ -5,86 +5,85 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static class Raise { - public static class Raise + /// + /// Raise an event for an EventHandler<TEventArgs> event with the provided and . + /// + public static EventHandlerWrapper EventWith(object sender, TEventArgs eventArgs) where TEventArgs : EventArgs { - /// - /// Raise an event for an EventHandler<TEventArgs> event with the provided and . - /// - public static EventHandlerWrapper EventWith(object sender, TEventArgs eventArgs) where TEventArgs : EventArgs - { - return new EventHandlerWrapper(sender, eventArgs); - } + return new EventHandlerWrapper(sender, eventArgs); + } - /// - /// Raise an event for an EventHandler<TEventArgs> event with the substitute as the sender and the provided . - /// - public static EventHandlerWrapper EventWith(TEventArgs eventArgs) where TEventArgs : EventArgs - { - return new EventHandlerWrapper(eventArgs); - } + /// + /// Raise an event for an EventHandler<TEventArgs> event with the substitute as the sender and the provided . + /// + public static EventHandlerWrapper EventWith(TEventArgs eventArgs) where TEventArgs : EventArgs + { + return new EventHandlerWrapper(eventArgs); + } + + /// + /// Raise an event for an EventHandler<EventArgsT> event with the substitute as the sender + /// and with a default instance of . + /// + public static EventHandlerWrapper EventWith() where TEventArgs : EventArgs + { + return new EventHandlerWrapper(); + } + + /// + /// Raise an event for an EventHandler or EventHandler<EventArgs> event with the substitute + /// as the sender and with empty EventArgs. + /// + public static EventHandlerWrapper Event() + { + return new EventHandlerWrapper(); + } - /// - /// Raise an event for an EventHandler<EventArgsT> event with the substitute as the sender - /// and with a default instance of . - /// - public static EventHandlerWrapper EventWith() where TEventArgs : EventArgs + /// + /// Raise an event of type with the provided arguments. If no arguments are provided + /// NSubstitute will try to provide reasonable defaults. + /// + public static DelegateEventWrapper Event(params object[] arguments) + { + var normalizedArgs = FixParamsArrayAmbiguity(arguments, typeof(THandler)); + return new DelegateEventWrapper(normalizedArgs); + } + + /// + /// If delegate takes single parameter of array type, it's impossible to distinguish + /// whether input array represents all arguments, or the first argument only. + /// If we find that ambiguity might happen, we wrap user input in an extra array. + /// + private static object[] FixParamsArrayAmbiguity(object[] arguments, Type delegateType) + { + ParameterInfo[] invokeMethodParameters = delegateType.GetInvokeMethod().GetParameters(); + if (invokeMethodParameters.Length != 1) { - return new EventHandlerWrapper(); + return arguments; } - /// - /// Raise an event for an EventHandler or EventHandler<EventArgs> event with the substitute - /// as the sender and with empty EventArgs. - /// - public static EventHandlerWrapper Event() + Type singleParameterType = invokeMethodParameters[0].ParameterType; + if (!singleParameterType.IsArray) { - return new EventHandlerWrapper(); + return arguments; } - /// - /// Raise an event of type with the provided arguments. If no arguments are provided - /// NSubstitute will try to provide reasonable defaults. - /// - public static DelegateEventWrapper Event(params object[] arguments) + // Check if native non-params syntax was used. + // This way actual value is already wrapped in array and we don't need to extra-wrap it. + if (arguments.Length == 1 && singleParameterType.IsInstanceOfType(arguments[0])) { - var normalizedArgs = FixParamsArrayAmbiguity(arguments, typeof(THandler)); - return new DelegateEventWrapper(normalizedArgs); + return arguments; } - /// - /// If delegate takes single parameter of array type, it's impossible to distinguish - /// whether input array represents all arguments, or the first argument only. - /// If we find that ambiguity might happen, we wrap user input in an extra array. - /// - private static object[] FixParamsArrayAmbiguity(object[] arguments, Type delegateType) + if (singleParameterType.IsInstanceOfType(arguments)) { - ParameterInfo[] invokeMethodParameters = delegateType.GetInvokeMethod().GetParameters(); - if (invokeMethodParameters.Length != 1) - { - return arguments; - } - - Type singleParameterType = invokeMethodParameters[0].ParameterType; - if (!singleParameterType.IsArray) - { - return arguments; - } - - // Check if native non-params syntax was used. - // This way actual value is already wrapped in array and we don't need to extra-wrap it. - if (arguments.Length == 1 && singleParameterType.IsInstanceOfType(arguments[0])) - { - return arguments; - } - - if (singleParameterType.IsInstanceOfType(arguments)) - { - return new object[] { arguments }; - } - - return arguments; + return new object[] { arguments }; } + + return arguments; } } diff --git a/src/NSubstitute/Received.cs b/src/NSubstitute/Received.cs index 213a0304d..3e397d154 100644 --- a/src/NSubstitute/Received.cs +++ b/src/NSubstitute/Received.cs @@ -4,21 +4,20 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public class Received { - public class Received + /// + /// Asserts the calls to the substitutes contained in the given Action were + /// received by these substitutes in the same order. Calls to property getters are not included + /// in the assertion. + /// + /// Action containing calls to substitutes in the expected order + public static void InOrder(Action calls) { - /// - /// Asserts the calls to the substitutes contained in the given Action were - /// received by these substitutes in the same order. Calls to property getters are not included - /// in the assertion. - /// - /// Action containing calls to substitutes in the expected order - public static void InOrder(Action calls) - { - var query = new Query(SubstitutionContext.Current.CallSpecificationFactory); - SubstitutionContext.Current.ThreadContext.RunInQueryContext(calls, query); - new SequenceInOrderAssertion().Assert(query.Result()); - } + var query = new Query(SubstitutionContext.Current.CallSpecificationFactory); + SubstitutionContext.Current.ThreadContext.RunInQueryContext(calls, query); + new SequenceInOrderAssertion().Assert(query.Result()); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/AutoValues/AutoArrayProvider.cs b/src/NSubstitute/Routing/AutoValues/AutoArrayProvider.cs index 5dd77fa5d..fd3f4cb00 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoArrayProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoArrayProvider.cs @@ -1,15 +1,14 @@ -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoArrayProvider : IAutoValueProvider { - public class AutoArrayProvider : IAutoValueProvider - { - public bool CanProvideValueFor(Type type) => - type.IsArray; + public bool CanProvideValueFor(Type type) => + type.IsArray; - public object GetValue(Type type) - { - var rank = type.GetArrayRank(); - var dimensionLengths = new int[rank]; - return Array.CreateInstance(type.GetElementType()!, dimensionLengths); - } + public object GetValue(Type type) + { + var rank = type.GetArrayRank(); + var dimensionLengths = new int[rank]; + return Array.CreateInstance(type.GetElementType()!, dimensionLengths); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/AutoValues/AutoObservableProvider.cs b/src/NSubstitute/Routing/AutoValues/AutoObservableProvider.cs index ac81abc8f..bdf1ecd01 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoObservableProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoObservableProvider.cs @@ -1,36 +1,35 @@ using System.Reflection; using NSubstitute.Core; -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoObservableProvider : IAutoValueProvider { - public class AutoObservableProvider : IAutoValueProvider - { - private readonly Lazy> _autoValueProviders; + private readonly Lazy> _autoValueProviders; - public AutoObservableProvider(Lazy> autoValueProviders) - { - _autoValueProviders = autoValueProviders; - } + public AutoObservableProvider(Lazy> autoValueProviders) + { + _autoValueProviders = autoValueProviders; + } - public bool CanProvideValueFor(Type type) => - type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IObservable<>); + public bool CanProvideValueFor(Type type) => + type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IObservable<>); - public object? GetValue(Type type) - { - if (!CanProvideValueFor(type)) - throw new InvalidOperationException(); + public object? GetValue(Type type) + { + if (!CanProvideValueFor(type)) + throw new InvalidOperationException(); - Type innerType = type.GetGenericArguments()[0]; - var valueProvider = _autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(innerType)); - var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(innerType); - return Activator.CreateInstance( - typeof(ReturnObservable<>).MakeGenericType(innerType) - , new object?[] { value }); - } + Type innerType = type.GetGenericArguments()[0]; + var valueProvider = _autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(innerType)); + var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(innerType); + return Activator.CreateInstance( + typeof(ReturnObservable<>).MakeGenericType(innerType) + , new object?[] { value }); + } - private static object? GetDefault(Type type) - { - return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null; - } + private static object? GetDefault(Type type) + { + return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null; } } diff --git a/src/NSubstitute/Routing/AutoValues/AutoQueryableProvider.cs b/src/NSubstitute/Routing/AutoValues/AutoQueryableProvider.cs index f6082a837..2496b8a33 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoQueryableProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoQueryableProvider.cs @@ -1,20 +1,19 @@ using System.Reflection; -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoQueryableProvider : IAutoValueProvider { - public class AutoQueryableProvider : IAutoValueProvider - { - public bool CanProvideValueFor(Type type) => - type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IQueryable<>); + public bool CanProvideValueFor(Type type) => + type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IQueryable<>); - public object GetValue(Type type) - { - if (!CanProvideValueFor(type)) - throw new InvalidOperationException(); + public object GetValue(Type type) + { + if (!CanProvideValueFor(type)) + throw new InvalidOperationException(); - Type innerType = type.GetGenericArguments()[0]; + Type innerType = type.GetGenericArguments()[0]; - return Array.CreateInstance(innerType, 0).AsQueryable(); - } + return Array.CreateInstance(innerType, 0).AsQueryable(); } } diff --git a/src/NSubstitute/Routing/AutoValues/AutoStringProvider.cs b/src/NSubstitute/Routing/AutoValues/AutoStringProvider.cs index 16d611e2b..d886d9fdc 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoStringProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoStringProvider.cs @@ -1,12 +1,11 @@ -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoStringProvider : IAutoValueProvider { - public class AutoStringProvider : IAutoValueProvider - { - public bool CanProvideValueFor(Type type) => type == typeof(string); + public bool CanProvideValueFor(Type type) => type == typeof(string); - public object GetValue(Type type) - { - return string.Empty; - } + public object GetValue(Type type) + { + return string.Empty; } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/AutoValues/AutoSubstituteProvider.cs b/src/NSubstitute/Routing/AutoValues/AutoSubstituteProvider.cs index 8052443cf..e3806e1da 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoSubstituteProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoSubstituteProvider.cs @@ -1,71 +1,70 @@ using System.Reflection; using NSubstitute.Core; -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoSubstituteProvider : IAutoValueProvider { - public class AutoSubstituteProvider : IAutoValueProvider - { - private readonly ISubstituteFactory _substituteFactory; + private readonly ISubstituteFactory _substituteFactory; - public AutoSubstituteProvider(ISubstituteFactory substituteFactory) - { - _substituteFactory = substituteFactory; - } + public AutoSubstituteProvider(ISubstituteFactory substituteFactory) + { + _substituteFactory = substituteFactory; + } - public bool CanProvideValueFor(Type type) - { - return type.GetTypeInfo().IsInterface - || type.IsDelegate() - || IsPureVirtualClassWithParameterlessConstructor(type); - } + public bool CanProvideValueFor(Type type) + { + return type.GetTypeInfo().IsInterface + || type.IsDelegate() + || IsPureVirtualClassWithParameterlessConstructor(type); + } - public object GetValue(Type type) - { - return _substituteFactory.Create(new[] { type }, new object[0]); - } + public object GetValue(Type type) + { + return _substituteFactory.Create(new[] { type }, new object[0]); + } - private bool IsPureVirtualClassWithParameterlessConstructor(Type type) - { - if (type == typeof(object)) return false; - if (!type.GetTypeInfo().IsClass) return false; - if (!IsPureVirtualType(type)) return false; - if (!HasParameterlessConstructor(type)) return false; - return true; - } + private bool IsPureVirtualClassWithParameterlessConstructor(Type type) + { + if (type == typeof(object)) return false; + if (!type.GetTypeInfo().IsClass) return false; + if (!IsPureVirtualType(type)) return false; + if (!HasParameterlessConstructor(type)) return false; + return true; + } - private bool HasParameterlessConstructor(Type type) - { - var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - var parameterlessConstructors = constructors.Where(x => IsCallableFromProxy(x) && x.GetParameters().Length == 0); - if (!parameterlessConstructors.Any()) return false; - return true; - } + private bool HasParameterlessConstructor(Type type) + { + var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + var parameterlessConstructors = constructors.Where(x => IsCallableFromProxy(x) && x.GetParameters().Length == 0); + if (!parameterlessConstructors.Any()) return false; + return true; + } - private bool IsPureVirtualType(Type type) - { - if (type.GetTypeInfo().IsSealed) return false; - var methods = type.GetMethods().Where(NotMethodFromObject).Where(NotStaticMethod); - return methods.All(IsOverridable); - } + private bool IsPureVirtualType(Type type) + { + if (type.GetTypeInfo().IsSealed) return false; + var methods = type.GetMethods().Where(NotMethodFromObject).Where(NotStaticMethod); + return methods.All(IsOverridable); + } - private bool IsCallableFromProxy(MethodBase constructor) - { - return constructor.IsPublic || constructor.IsFamily || constructor.IsFamilyOrAssembly; - } + private bool IsCallableFromProxy(MethodBase constructor) + { + return constructor.IsPublic || constructor.IsFamily || constructor.IsFamilyOrAssembly; + } - private bool IsOverridable(MethodInfo methodInfo) - { - return methodInfo.IsVirtual && !methodInfo.IsFinal; - } + private bool IsOverridable(MethodInfo methodInfo) + { + return methodInfo.IsVirtual && !methodInfo.IsFinal; + } - private bool NotMethodFromObject(MethodInfo methodInfo) - { - return methodInfo.DeclaringType != typeof(object); - } + private bool NotMethodFromObject(MethodInfo methodInfo) + { + return methodInfo.DeclaringType != typeof(object); + } - private bool NotStaticMethod(MethodInfo methodInfo) - { - return !methodInfo.IsStatic; - } + private bool NotStaticMethod(MethodInfo methodInfo) + { + return !methodInfo.IsStatic; } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/AutoValues/AutoTaskProvider.cs b/src/NSubstitute/Routing/AutoValues/AutoTaskProvider.cs index 4d1dd2c88..239b65066 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoTaskProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoTaskProvider.cs @@ -1,45 +1,44 @@ using System.Reflection; -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoTaskProvider : IAutoValueProvider { - public class AutoTaskProvider : IAutoValueProvider + private readonly Lazy> _autoValueProviders; + + public AutoTaskProvider(Lazy> autoValueProviders) { - private readonly Lazy> _autoValueProviders; + _autoValueProviders = autoValueProviders; + } - public AutoTaskProvider(Lazy> autoValueProviders) - { - _autoValueProviders = autoValueProviders; - } + public bool CanProvideValueFor(Type type) => typeof(Task).IsAssignableFrom(type); - public bool CanProvideValueFor(Type type) => typeof(Task).IsAssignableFrom(type); + public object GetValue(Type type) + { + if (!CanProvideValueFor(type)) + throw new InvalidOperationException(); - public object GetValue(Type type) + if (type.GetTypeInfo().IsGenericType) { - if (!CanProvideValueFor(type)) - throw new InvalidOperationException(); - - if (type.GetTypeInfo().IsGenericType) - { - var taskType = type.GetGenericArguments()[0]; - var valueProvider = _autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(taskType)); - - var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(taskType); - var taskCompletionSourceType = typeof(TaskCompletionSource<>).MakeGenericType(taskType); - var taskCompletionSource = Activator.CreateInstance(taskCompletionSourceType); - taskCompletionSourceType.GetMethod(nameof(TaskCompletionSource.SetResult))!.Invoke(taskCompletionSource, new[] { value }); - return taskCompletionSourceType.GetProperty(nameof(TaskCompletionSource.Task))!.GetValue(taskCompletionSource, null)!; - } - else - { - var taskCompletionSource = new TaskCompletionSource(); - taskCompletionSource.SetResult(null); - return taskCompletionSource.Task; - } - } + var taskType = type.GetGenericArguments()[0]; + var valueProvider = _autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(taskType)); - private static object? GetDefault(Type type) + var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(taskType); + var taskCompletionSourceType = typeof(TaskCompletionSource<>).MakeGenericType(taskType); + var taskCompletionSource = Activator.CreateInstance(taskCompletionSourceType); + taskCompletionSourceType.GetMethod(nameof(TaskCompletionSource.SetResult))!.Invoke(taskCompletionSource, new[] { value }); + return taskCompletionSourceType.GetProperty(nameof(TaskCompletionSource.Task))!.GetValue(taskCompletionSource, null)!; + } + else { - return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null; + var taskCompletionSource = new TaskCompletionSource(); + taskCompletionSource.SetResult(null); + return taskCompletionSource.Task; } } + + private static object? GetDefault(Type type) + { + return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null; + } } diff --git a/src/NSubstitute/Routing/AutoValues/AutoValueProvidersFactory.cs b/src/NSubstitute/Routing/AutoValues/AutoValueProvidersFactory.cs index 8a39c91b7..815c41c0b 100644 --- a/src/NSubstitute/Routing/AutoValues/AutoValueProvidersFactory.cs +++ b/src/NSubstitute/Routing/AutoValues/AutoValueProvidersFactory.cs @@ -1,28 +1,27 @@ using NSubstitute.Core; using NSubstitute.Exceptions; -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public class AutoValueProvidersFactory : IAutoValueProvidersFactory { - public class AutoValueProvidersFactory : IAutoValueProvidersFactory + public IReadOnlyCollection CreateProviders(ISubstituteFactory substituteFactory) { - public IReadOnlyCollection CreateProviders(ISubstituteFactory substituteFactory) - { - IAutoValueProvider[]? result = null; - var lazyResult = new Lazy>( - () => result ?? throw new SubstituteInternalException("Value was not constructed yet."), - LazyThreadSafetyMode.PublicationOnly); + IAutoValueProvider[]? result = null; + var lazyResult = new Lazy>( + () => result ?? throw new SubstituteInternalException("Value was not constructed yet."), + LazyThreadSafetyMode.PublicationOnly); - result = new IAutoValueProvider[] - { - new AutoObservableProvider(lazyResult), - new AutoQueryableProvider(), - new AutoSubstituteProvider(substituteFactory), - new AutoStringProvider(), - new AutoArrayProvider(), - new AutoTaskProvider(lazyResult) - }; + result = new IAutoValueProvider[] + { + new AutoObservableProvider(lazyResult), + new AutoQueryableProvider(), + new AutoSubstituteProvider(substituteFactory), + new AutoStringProvider(), + new AutoArrayProvider(), + new AutoTaskProvider(lazyResult) + }; - return result; - } + return result; } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/AutoValues/IAutoValueProvider.cs b/src/NSubstitute/Routing/AutoValues/IAutoValueProvider.cs index 676561f5b..47f10eb78 100644 --- a/src/NSubstitute/Routing/AutoValues/IAutoValueProvider.cs +++ b/src/NSubstitute/Routing/AutoValues/IAutoValueProvider.cs @@ -1,8 +1,7 @@ -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public interface IAutoValueProvider { - public interface IAutoValueProvider - { - bool CanProvideValueFor(Type type); - object? GetValue(Type type); - } + bool CanProvideValueFor(Type type); + object? GetValue(Type type); } \ No newline at end of file diff --git a/src/NSubstitute/Routing/AutoValues/IAutoValueProvidersFactory.cs b/src/NSubstitute/Routing/AutoValues/IAutoValueProvidersFactory.cs index ee13a60f6..0c5da4a97 100644 --- a/src/NSubstitute/Routing/AutoValues/IAutoValueProvidersFactory.cs +++ b/src/NSubstitute/Routing/AutoValues/IAutoValueProvidersFactory.cs @@ -1,9 +1,8 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.AutoValues +namespace NSubstitute.Routing.AutoValues; + +public interface IAutoValueProvidersFactory { - public interface IAutoValueProvidersFactory - { - IReadOnlyCollection CreateProviders(ISubstituteFactory substituteFactory); - } + IReadOnlyCollection CreateProviders(ISubstituteFactory substituteFactory); } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/AddCallToQueryResultHandler.cs b/src/NSubstitute/Routing/Handlers/AddCallToQueryResultHandler.cs index 0fb572e0e..5b276285f 100644 --- a/src/NSubstitute/Routing/Handlers/AddCallToQueryResultHandler.cs +++ b/src/NSubstitute/Routing/Handlers/AddCallToQueryResultHandler.cs @@ -1,21 +1,20 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class AddCallToQueryResultHandler : ICallHandler { - public class AddCallToQueryResultHandler : ICallHandler - { - private readonly IThreadLocalContext _threadContext; + private readonly IThreadLocalContext _threadContext; - public AddCallToQueryResultHandler(IThreadLocalContext threadContext) - { - _threadContext = threadContext; - } + public AddCallToQueryResultHandler(IThreadLocalContext threadContext) + { + _threadContext = threadContext; + } - public RouteAction Handle(ICall call) - { - _threadContext.RegisterInContextQuery(call); + public RouteAction Handle(ICall call) + { + _threadContext.RegisterInContextQuery(call); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/CallBaseForCallHandler.cs b/src/NSubstitute/Routing/Handlers/CallBaseForCallHandler.cs index dca7c9561..749a54cc0 100644 --- a/src/NSubstitute/Routing/Handlers/CallBaseForCallHandler.cs +++ b/src/NSubstitute/Routing/Handlers/CallBaseForCallHandler.cs @@ -1,29 +1,28 @@ using NSubstitute.Core; using NSubstitute.Exceptions; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class CallBaseForCallHandler : ICallHandler { - public class CallBaseForCallHandler : ICallHandler - { - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly ICallBaseConfiguration _callBaseConfig; - private readonly MatchArgs _matchArgs; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly ICallBaseConfiguration _callBaseConfig; + private readonly MatchArgs _matchArgs; - public CallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseConfiguration callBaseConfig, MatchArgs matchArgs) - { - _callSpecificationFactory = callSpecificationFactory; - _callBaseConfig = callBaseConfig; - _matchArgs = matchArgs; - } + public CallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseConfiguration callBaseConfig, MatchArgs matchArgs) + { + _callSpecificationFactory = callSpecificationFactory; + _callBaseConfig = callBaseConfig; + _matchArgs = matchArgs; + } - public RouteAction Handle(ICall call) - { - if (!call.CanCallBase) throw CouldNotConfigureCallBaseException.ForSingleCall(); + public RouteAction Handle(ICall call) + { + if (!call.CanCallBase) throw CouldNotConfigureCallBaseException.ForSingleCall(); - var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs); - _callBaseConfig.Include(callSpec); + var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs); + _callBaseConfig.Include(callSpec); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/CheckReceivedCallsHandler.cs b/src/NSubstitute/Routing/Handlers/CheckReceivedCallsHandler.cs index e9051bd1a..de7c5816f 100644 --- a/src/NSubstitute/Routing/Handlers/CheckReceivedCallsHandler.cs +++ b/src/NSubstitute/Routing/Handlers/CheckReceivedCallsHandler.cs @@ -1,40 +1,39 @@ using NSubstitute.Core; using NSubstitute.ReceivedExtensions; -namespace NSubstitute.Routing.Handlers -{ - public class CheckReceivedCallsHandler : ICallHandler - { - private readonly ICallCollection _receivedCalls; - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly IReceivedCallsExceptionThrower _exceptionThrower; - private readonly MatchArgs _matchArgs; - private readonly Quantity _requiredQuantity; +namespace NSubstitute.Routing.Handlers; - public CheckReceivedCallsHandler(ICallCollection receivedCalls, ICallSpecificationFactory callSpecificationFactory, IReceivedCallsExceptionThrower exceptionThrower, MatchArgs matchArgs, Quantity requiredQuantity) - { - _receivedCalls = receivedCalls; - _callSpecificationFactory = callSpecificationFactory; - _exceptionThrower = exceptionThrower; - _matchArgs = matchArgs; - _requiredQuantity = requiredQuantity; - } +public class CheckReceivedCallsHandler : ICallHandler +{ + private readonly ICallCollection _receivedCalls; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly IReceivedCallsExceptionThrower _exceptionThrower; + private readonly MatchArgs _matchArgs; + private readonly Quantity _requiredQuantity; - public RouteAction Handle(ICall call) - { - var callSpecification = _callSpecificationFactory.CreateFrom(call, _matchArgs); - var allCallsToMethodSpec = _callSpecificationFactory.CreateFrom(call, MatchArgs.Any); + public CheckReceivedCallsHandler(ICallCollection receivedCalls, ICallSpecificationFactory callSpecificationFactory, IReceivedCallsExceptionThrower exceptionThrower, MatchArgs matchArgs, Quantity requiredQuantity) + { + _receivedCalls = receivedCalls; + _callSpecificationFactory = callSpecificationFactory; + _exceptionThrower = exceptionThrower; + _matchArgs = matchArgs; + _requiredQuantity = requiredQuantity; + } - var allCalls = _receivedCalls.AllCalls().ToList(); - var matchingCalls = allCalls.Where(callSpecification.IsSatisfiedBy).ToList(); + public RouteAction Handle(ICall call) + { + var callSpecification = _callSpecificationFactory.CreateFrom(call, _matchArgs); + var allCallsToMethodSpec = _callSpecificationFactory.CreateFrom(call, MatchArgs.Any); - if (!_requiredQuantity.Matches(matchingCalls)) - { - var relatedCalls = allCalls.Where(allCallsToMethodSpec.IsSatisfiedBy).Except(matchingCalls); - _exceptionThrower.Throw(callSpecification, matchingCalls, relatedCalls, _requiredQuantity); - } + var allCalls = _receivedCalls.AllCalls().ToList(); + var matchingCalls = allCalls.Where(callSpecification.IsSatisfiedBy).ToList(); - return RouteAction.Continue(); + if (!_requiredQuantity.Matches(matchingCalls)) + { + var relatedCalls = allCalls.Where(allCallsToMethodSpec.IsSatisfiedBy).Except(matchingCalls); + _exceptionThrower.Throw(callSpecification, matchingCalls, relatedCalls, _requiredQuantity); } + + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ClearLastCallRouterHandler.cs b/src/NSubstitute/Routing/Handlers/ClearLastCallRouterHandler.cs index a73d3ade5..793ff6258 100644 --- a/src/NSubstitute/Routing/Handlers/ClearLastCallRouterHandler.cs +++ b/src/NSubstitute/Routing/Handlers/ClearLastCallRouterHandler.cs @@ -1,27 +1,26 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +/// +/// Clears last call router on SubstitutionContext for routes that do not require it. +/// +/// +/// This is to help prevent static state bleeding over into future calls. +/// +public class ClearLastCallRouterHandler : ICallHandler { - /// - /// Clears last call router on SubstitutionContext for routes that do not require it. - /// - /// - /// This is to help prevent static state bleeding over into future calls. - /// - public class ClearLastCallRouterHandler : ICallHandler - { - private readonly IThreadLocalContext _threadContext; + private readonly IThreadLocalContext _threadContext; - public ClearLastCallRouterHandler(IThreadLocalContext threadContext) - { - _threadContext = threadContext; - } + public ClearLastCallRouterHandler(IThreadLocalContext threadContext) + { + _threadContext = threadContext; + } - public RouteAction Handle(ICall call) - { - _threadContext.ClearLastCallRouter(); + public RouteAction Handle(ICall call) + { + _threadContext.ClearLastCallRouter(); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ClearUnusedCallSpecHandler.cs b/src/NSubstitute/Routing/Handlers/ClearUnusedCallSpecHandler.cs index b5bab33d8..9154a9609 100644 --- a/src/NSubstitute/Routing/Handlers/ClearUnusedCallSpecHandler.cs +++ b/src/NSubstitute/Routing/Handlers/ClearUnusedCallSpecHandler.cs @@ -1,21 +1,20 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ClearUnusedCallSpecHandler : ICallHandler { - public class ClearUnusedCallSpecHandler : ICallHandler - { - private readonly IPendingSpecification _pendingSpecification; + private readonly IPendingSpecification _pendingSpecification; - public ClearUnusedCallSpecHandler(IPendingSpecification pendingSpecification) - { - _pendingSpecification = pendingSpecification; - } + public ClearUnusedCallSpecHandler(IPendingSpecification pendingSpecification) + { + _pendingSpecification = pendingSpecification; + } - public RouteAction Handle(ICall call) - { - _pendingSpecification.Clear(); + public RouteAction Handle(ICall call) + { + _pendingSpecification.Clear(); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/DoActionsCallHandler.cs b/src/NSubstitute/Routing/Handlers/DoActionsCallHandler.cs index 0eceaf3c0..bd3fa4fd9 100644 --- a/src/NSubstitute/Routing/Handlers/DoActionsCallHandler.cs +++ b/src/NSubstitute/Routing/Handlers/DoActionsCallHandler.cs @@ -1,21 +1,20 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class DoActionsCallHandler : ICallHandler { - public class DoActionsCallHandler : ICallHandler - { - private readonly ICallActions _callActions; + private readonly ICallActions _callActions; - public DoActionsCallHandler(ICallActions callActions) - { - _callActions = callActions; - } + public DoActionsCallHandler(ICallActions callActions) + { + _callActions = callActions; + } - public RouteAction Handle(ICall call) - { - _callActions.InvokeMatchingActions(call); + public RouteAction Handle(ICall call) + { + _callActions.InvokeMatchingActions(call); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/DoNotCallBaseForCallHandler.cs b/src/NSubstitute/Routing/Handlers/DoNotCallBaseForCallHandler.cs index c685990fb..78fce8814 100644 --- a/src/NSubstitute/Routing/Handlers/DoNotCallBaseForCallHandler.cs +++ b/src/NSubstitute/Routing/Handlers/DoNotCallBaseForCallHandler.cs @@ -1,29 +1,28 @@ using NSubstitute.Core; using NSubstitute.Exceptions; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class DoNotCallBaseForCallHandler : ICallHandler { - public class DoNotCallBaseForCallHandler : ICallHandler - { - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly ICallBaseConfiguration _callBaseConfig; - private readonly MatchArgs _matchArgs; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly ICallBaseConfiguration _callBaseConfig; + private readonly MatchArgs _matchArgs; - public DoNotCallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseConfiguration callBaseConfig, MatchArgs matchArgs) - { - _callSpecificationFactory = callSpecificationFactory; - _callBaseConfig = callBaseConfig; - _matchArgs = matchArgs; - } + public DoNotCallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseConfiguration callBaseConfig, MatchArgs matchArgs) + { + _callSpecificationFactory = callSpecificationFactory; + _callBaseConfig = callBaseConfig; + _matchArgs = matchArgs; + } - public RouteAction Handle(ICall call) - { - if (!call.CanCallBase) throw CouldNotConfigureCallBaseException.ForSingleCall(); + public RouteAction Handle(ICall call) + { + if (!call.CanCallBase) throw CouldNotConfigureCallBaseException.ForSingleCall(); - var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs); - _callBaseConfig.Exclude(callSpec); + var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs); + _callBaseConfig.Exclude(callSpec); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/EventSubscriptionHandler.cs b/src/NSubstitute/Routing/Handlers/EventSubscriptionHandler.cs index ecc6825e1..5ce3bdc2c 100644 --- a/src/NSubstitute/Routing/Handlers/EventSubscriptionHandler.cs +++ b/src/NSubstitute/Routing/Handlers/EventSubscriptionHandler.cs @@ -1,65 +1,64 @@ using System.Reflection; using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class EventSubscriptionHandler : ICallHandler { - public class EventSubscriptionHandler : ICallHandler + private readonly IEventHandlerRegistry _eventHandlerRegistry; + + public EventSubscriptionHandler(IEventHandlerRegistry eventHandlerRegistry) { - private readonly IEventHandlerRegistry _eventHandlerRegistry; + _eventHandlerRegistry = eventHandlerRegistry; + } - public EventSubscriptionHandler(IEventHandlerRegistry eventHandlerRegistry) + public RouteAction Handle(ICall call) + { + if (CanBeSubscribeUnsubscribeCall(call)) { - _eventHandlerRegistry = eventHandlerRegistry; + If(call, IsEventSubscription, _eventHandlerRegistry.Add); + If(call, IsEventUnsubscription, _eventHandlerRegistry.Remove); } - public RouteAction Handle(ICall call) - { - if (CanBeSubscribeUnsubscribeCall(call)) - { - If(call, IsEventSubscription, _eventHandlerRegistry.Add); - If(call, IsEventUnsubscription, _eventHandlerRegistry.Remove); - } - - return RouteAction.Continue(); - } + return RouteAction.Continue(); + } - private static bool CanBeSubscribeUnsubscribeCall(ICall call) - { - var methodInfo = call.GetMethodInfo(); + private static bool CanBeSubscribeUnsubscribeCall(ICall call) + { + var methodInfo = call.GetMethodInfo(); - // It's safe to verify method prefix and signature as according to the ECMA-335 II.22.28: - // 18. Any AddOn method for an event whose Name is xxx shall have the signature: void add_xxx ( handler) (§I.10.4) [CLS] - // 19. Any RemoveOn method for an event whose Name is xxx shall have the signature: void remove_xxx( handler) (§I.10.4) [CLS] - // Notice, even though it's correct to check the SpecialName flag, we don't do that deliberately. - // The reason is that some compilers (e.g. F#) might not emit this attribute and our library - // misbehaves in those cases. We use slightly slower, but robust check. - return methodInfo.ReturnType == typeof(void) && - (methodInfo.Name.StartsWith("add_", StringComparison.Ordinal) || - methodInfo.Name.StartsWith("remove_", StringComparison.Ordinal)); - } + // It's safe to verify method prefix and signature as according to the ECMA-335 II.22.28: + // 18. Any AddOn method for an event whose Name is xxx shall have the signature: void add_xxx ( handler) (§I.10.4) [CLS] + // 19. Any RemoveOn method for an event whose Name is xxx shall have the signature: void remove_xxx( handler) (§I.10.4) [CLS] + // Notice, even though it's correct to check the SpecialName flag, we don't do that deliberately. + // The reason is that some compilers (e.g. F#) might not emit this attribute and our library + // misbehaves in those cases. We use slightly slower, but robust check. + return methodInfo.ReturnType == typeof(void) && + (methodInfo.Name.StartsWith("add_", StringComparison.Ordinal) || + methodInfo.Name.StartsWith("remove_", StringComparison.Ordinal)); + } - private static void If(ICall call, Func> meetsThisSpecification, Action takeThisAction) + private static void If(ICall call, Func> meetsThisSpecification, Action takeThisAction) + { + var matchingEvent = GetEvents(call, meetsThisSpecification).FirstOrDefault(); + if (matchingEvent != null) { - var matchingEvent = GetEvents(call, meetsThisSpecification).FirstOrDefault(); - if (matchingEvent != null) - { - // It's important to use original arguments, as it provides better performance. - // It's safe to use original arguments here, as only by-ref arguments might be modified, - // which should never happen for this case. - takeThisAction(matchingEvent.Name, call.GetOriginalArguments()[0]!); - } + // It's important to use original arguments, as it provides better performance. + // It's safe to use original arguments here, as only by-ref arguments might be modified, + // which should never happen for this case. + takeThisAction(matchingEvent.Name, call.GetOriginalArguments()[0]!); } + } - private static Predicate IsEventSubscription(ICall call) => - x => call.GetMethodInfo() == x.GetAddMethod(); + private static Predicate IsEventSubscription(ICall call) => + x => call.GetMethodInfo() == x.GetAddMethod(); - private static Predicate IsEventUnsubscription(ICall call) => - x => call.GetMethodInfo() == x.GetRemoveMethod(); + private static Predicate IsEventUnsubscription(ICall call) => + x => call.GetMethodInfo() == x.GetRemoveMethod(); - private static IEnumerable GetEvents(ICall call, Func> createPredicate) - { - var predicate = createPredicate(call); - return call.GetMethodInfo().DeclaringType!.GetEvents().Where(x => predicate(x)); - } + private static IEnumerable GetEvents(ICall call, Func> createPredicate) + { + var predicate = createPredicate(call); + return call.GetMethodInfo().DeclaringType!.GetEvents().Where(x => predicate(x)); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/PropertySetterHandler.cs b/src/NSubstitute/Routing/Handlers/PropertySetterHandler.cs index c351711e2..7319d7487 100644 --- a/src/NSubstitute/Routing/Handlers/PropertySetterHandler.cs +++ b/src/NSubstitute/Routing/Handlers/PropertySetterHandler.cs @@ -1,31 +1,30 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class PropertySetterHandler : ICallHandler { - public class PropertySetterHandler : ICallHandler + private readonly IPropertyHelper _propertyHelper; + private readonly IConfigureCall _configureCall; + + public PropertySetterHandler(IPropertyHelper propertyHelper, IConfigureCall configureCall) { - private readonly IPropertyHelper _propertyHelper; - private readonly IConfigureCall _configureCall; + _propertyHelper = propertyHelper; + _configureCall = configureCall; + } - public PropertySetterHandler(IPropertyHelper propertyHelper, IConfigureCall configureCall) + public RouteAction Handle(ICall call) + { + if (_propertyHelper.IsCallToSetAReadWriteProperty(call)) { - _propertyHelper = propertyHelper; - _configureCall = configureCall; + var callToPropertyGetter = _propertyHelper.CreateCallToPropertyGetterFromSetterCall(call); + // It's important to use original arguments, as it provides better performance. + // It's safe to use original arguments here, as only by-ref arguments might be modified, + // which should never happen for this case. + var valueBeingSetOnProperty = call.GetOriginalArguments().Last(); + _configureCall.SetResultForCall(callToPropertyGetter, new ReturnValue(valueBeingSetOnProperty), MatchArgs.AsSpecifiedInCall); } - public RouteAction Handle(ICall call) - { - if (_propertyHelper.IsCallToSetAReadWriteProperty(call)) - { - var callToPropertyGetter = _propertyHelper.CreateCallToPropertyGetterFromSetterCall(call); - // It's important to use original arguments, as it provides better performance. - // It's safe to use original arguments here, as only by-ref arguments might be modified, - // which should never happen for this case. - var valueBeingSetOnProperty = call.GetOriginalArguments().Last(); - _configureCall.SetResultForCall(callToPropertyGetter, new ReturnValue(valueBeingSetOnProperty), MatchArgs.AsSpecifiedInCall); - } - - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/RaiseEventHandler.cs b/src/NSubstitute/Routing/Handlers/RaiseEventHandler.cs index 97badfa6b..bf668083f 100644 --- a/src/NSubstitute/Routing/Handlers/RaiseEventHandler.cs +++ b/src/NSubstitute/Routing/Handlers/RaiseEventHandler.cs @@ -2,54 +2,53 @@ using NSubstitute.Core; using NSubstitute.Exceptions; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class RaiseEventHandler : ICallHandler { - public class RaiseEventHandler : ICallHandler + private readonly IEventHandlerRegistry _eventHandlerRegistry; + private readonly Func _getEventArguments; + + public RaiseEventHandler(IEventHandlerRegistry eventHandlerRegistry, Func getEventArguments) { - private readonly IEventHandlerRegistry _eventHandlerRegistry; - private readonly Func _getEventArguments; + _eventHandlerRegistry = eventHandlerRegistry; + _getEventArguments = getEventArguments; + } - public RaiseEventHandler(IEventHandlerRegistry eventHandlerRegistry, Func getEventArguments) + public RouteAction Handle(ICall call) + { + var methodInfo = call.GetMethodInfo(); + var eventInfo = FindEventInfo(methodInfo); + if (eventInfo == null) { - _eventHandlerRegistry = eventHandlerRegistry; - _getEventArguments = getEventArguments; + throw new CouldNotRaiseEventException(); } - public RouteAction Handle(ICall call) + object?[] eventArguments = _getEventArguments(call); + var handlers = _eventHandlerRegistry.GetHandlers(eventInfo.Name); + foreach (Delegate handler in handlers) { - var methodInfo = call.GetMethodInfo(); - var eventInfo = FindEventInfo(methodInfo); - if (eventInfo == null) + if (handler == null) { - throw new CouldNotRaiseEventException(); + continue; } - object?[] eventArguments = _getEventArguments(call); - var handlers = _eventHandlerRegistry.GetHandlers(eventInfo.Name); - foreach (Delegate handler in handlers) + try { - if (handler == null) - { - continue; - } - - try - { - handler.DynamicInvoke(eventArguments); - } - catch (TargetInvocationException e) - { - throw e.InnerException!; - } + handler.DynamicInvoke(eventArguments); } - - return RouteAction.Continue(); - - static EventInfo? FindEventInfo(MethodInfo mi) + catch (TargetInvocationException e) { - return mi.DeclaringType!.GetEvents().FirstOrDefault( - e => e.GetAddMethod() == mi || e.GetRemoveMethod() == mi); + throw e.InnerException!; } } + + return RouteAction.Continue(); + + static EventInfo? FindEventInfo(MethodInfo mi) + { + return mi.DeclaringType!.GetEvents().FirstOrDefault( + e => e.GetAddMethod() == mi || e.GetRemoveMethod() == mi); + } } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/RecordCallHandler.cs b/src/NSubstitute/Routing/Handlers/RecordCallHandler.cs index 0af1cb01f..828d641a7 100644 --- a/src/NSubstitute/Routing/Handlers/RecordCallHandler.cs +++ b/src/NSubstitute/Routing/Handlers/RecordCallHandler.cs @@ -1,24 +1,23 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class RecordCallHandler : ICallHandler { - public class RecordCallHandler : ICallHandler - { - private readonly ICallCollection _callCollection; - private readonly SequenceNumberGenerator _generator; + private readonly ICallCollection _callCollection; + private readonly SequenceNumberGenerator _generator; - public RecordCallHandler(ICallCollection callCollection, SequenceNumberGenerator generator) - { - _callCollection = callCollection; - _generator = generator; - } + public RecordCallHandler(ICallCollection callCollection, SequenceNumberGenerator generator) + { + _callCollection = callCollection; + _generator = generator; + } - public RouteAction Handle(ICall call) - { - call.AssignSequenceNumber(_generator.Next()); - _callCollection.Add(call); + public RouteAction Handle(ICall call) + { + call.AssignSequenceNumber(_generator.Next()); + _callCollection.Add(call); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/RecordCallSpecificationHandler.cs b/src/NSubstitute/Routing/Handlers/RecordCallSpecificationHandler.cs index 4b4b3b2af..654ba5ca4 100644 --- a/src/NSubstitute/Routing/Handlers/RecordCallSpecificationHandler.cs +++ b/src/NSubstitute/Routing/Handlers/RecordCallSpecificationHandler.cs @@ -1,33 +1,32 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class RecordCallSpecificationHandler : ICallHandler { - public class RecordCallSpecificationHandler : ICallHandler + private readonly IPendingSpecification _pendingCallSpecification; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly ICallActions _callActions; + + public RecordCallSpecificationHandler(IPendingSpecification pendingCallSpecification, ICallSpecificationFactory callSpecificationFactory, ICallActions callActions) { - private readonly IPendingSpecification _pendingCallSpecification; - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly ICallActions _callActions; + _pendingCallSpecification = pendingCallSpecification; + _callSpecificationFactory = callSpecificationFactory; + _callActions = callActions; + } - public RecordCallSpecificationHandler(IPendingSpecification pendingCallSpecification, ICallSpecificationFactory callSpecificationFactory, ICallActions callActions) - { - _pendingCallSpecification = pendingCallSpecification; - _callSpecificationFactory = callSpecificationFactory; - _callActions = callActions; - } + public RouteAction Handle(ICall call) + { + var callSpec = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall); + _pendingCallSpecification.SetCallSpecification(callSpec); - public RouteAction Handle(ICall call) + // Performance optimization - don't register call actions if current argument matchers + // don't have any callbacks. + if (call.GetArgumentSpecifications().Any(x => x.HasAction)) { - var callSpec = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall); - _pendingCallSpecification.SetCallSpecification(callSpec); - - // Performance optimization - don't register call actions if current argument matchers - // don't have any callbacks. - if (call.GetArgumentSpecifications().Any(x => x.HasAction)) - { - _callActions.Add(callSpec); - } - - return RouteAction.Continue(); + _callActions.Add(callSpec); } + + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ReturnAutoValue.cs b/src/NSubstitute/Routing/Handlers/ReturnAutoValue.cs index abf760d17..0c3257664 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnAutoValue.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnAutoValue.cs @@ -1,60 +1,59 @@ using NSubstitute.Core; using NSubstitute.Routing.AutoValues; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public enum AutoValueBehaviour +{ + UseValueForSubsequentCalls, + ReturnAndForgetValue +} +public class ReturnAutoValue : ICallHandler { - public enum AutoValueBehaviour + private readonly IAutoValueProvider[] _autoValueProviders; + private readonly ICallResults _callResults; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly AutoValueBehaviour _autoValueBehaviour; + + public ReturnAutoValue(AutoValueBehaviour autoValueBehaviour, IEnumerable autoValueProviders, ICallResults callResults, ICallSpecificationFactory callSpecificationFactory) { - UseValueForSubsequentCalls, - ReturnAndForgetValue + _autoValueProviders = autoValueProviders.AsArray(); + _callResults = callResults; + _callSpecificationFactory = callSpecificationFactory; + _autoValueBehaviour = autoValueBehaviour; } - public class ReturnAutoValue : ICallHandler - { - private readonly IAutoValueProvider[] _autoValueProviders; - private readonly ICallResults _callResults; - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly AutoValueBehaviour _autoValueBehaviour; - public ReturnAutoValue(AutoValueBehaviour autoValueBehaviour, IEnumerable autoValueProviders, ICallResults callResults, ICallSpecificationFactory callSpecificationFactory) + public RouteAction Handle(ICall call) + { + if (_callResults.TryGetResult(call, out var cachedResult)) { - _autoValueProviders = autoValueProviders.AsArray(); - _callResults = callResults; - _callSpecificationFactory = callSpecificationFactory; - _autoValueBehaviour = autoValueBehaviour; + return RouteAction.Return(cachedResult); } - public RouteAction Handle(ICall call) - { - if (_callResults.TryGetResult(call, out var cachedResult)) - { - return RouteAction.Return(cachedResult); - } - - var type = call.GetReturnType(); + var type = call.GetReturnType(); - // This is a hot method which is invoked frequently and has major impact on performance. - // Therefore, the LINQ cycle was unwinded to loop. - foreach (var autoValueProvider in _autoValueProviders) + // This is a hot method which is invoked frequently and has major impact on performance. + // Therefore, the LINQ cycle was unwinded to loop. + foreach (var autoValueProvider in _autoValueProviders) + { + if (autoValueProvider.CanProvideValueFor(type)) { - if (autoValueProvider.CanProvideValueFor(type)) - { - return RouteAction.Return(GetResultValueUsingProvider(call, type, autoValueProvider)); - } + return RouteAction.Return(GetResultValueUsingProvider(call, type, autoValueProvider)); } - - return RouteAction.Continue(); } - private object? GetResultValueUsingProvider(ICall call, Type type, IAutoValueProvider provider) - { - var valueToReturn = provider.GetValue(type); - if (_autoValueBehaviour == AutoValueBehaviour.UseValueForSubsequentCalls) - { - var spec = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall); - _callResults.SetResult(spec, new ReturnValue(valueToReturn)); - } + return RouteAction.Continue(); + } - return valueToReturn; + private object? GetResultValueUsingProvider(ICall call, Type type, IAutoValueProvider provider) + { + var valueToReturn = provider.GetValue(type); + if (_autoValueBehaviour == AutoValueBehaviour.UseValueForSubsequentCalls) + { + var spec = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall); + _callResults.SetResult(spec, new ReturnValue(valueToReturn)); } + + return valueToReturn; } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ReturnConfiguredResultHandler.cs b/src/NSubstitute/Routing/Handlers/ReturnConfiguredResultHandler.cs index c82e9c495..244e57138 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnConfiguredResultHandler.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnConfiguredResultHandler.cs @@ -1,24 +1,23 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ReturnConfiguredResultHandler : ICallHandler { - public class ReturnConfiguredResultHandler : ICallHandler + private readonly ICallResults _callResults; + + public ReturnConfiguredResultHandler(ICallResults callResults) { - private readonly ICallResults _callResults; + _callResults = callResults; + } - public ReturnConfiguredResultHandler(ICallResults callResults) + public RouteAction Handle(ICall call) + { + if (_callResults.TryGetResult(call, out var configuredResult)) { - _callResults = callResults; + return RouteAction.Return(configuredResult); } - public RouteAction Handle(ICall call) - { - if (_callResults.TryGetResult(call, out var configuredResult)) - { - return RouteAction.Return(configuredResult); - } - - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ReturnDefaultForReturnTypeHandler.cs b/src/NSubstitute/Routing/Handlers/ReturnDefaultForReturnTypeHandler.cs index 6a8ea5dec..ff0b9170a 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnDefaultForReturnTypeHandler.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnDefaultForReturnTypeHandler.cs @@ -1,20 +1,19 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ReturnDefaultForReturnTypeHandler : ICallHandler { - public class ReturnDefaultForReturnTypeHandler : ICallHandler - { - private readonly IDefaultForType _defaultForType; + private readonly IDefaultForType _defaultForType; - public ReturnDefaultForReturnTypeHandler(IDefaultForType defaultForType) - { - _defaultForType = defaultForType; - } + public ReturnDefaultForReturnTypeHandler(IDefaultForType defaultForType) + { + _defaultForType = defaultForType; + } - public RouteAction Handle(ICall call) - { - var returnValue = _defaultForType.GetDefaultFor(call.GetMethodInfo().ReturnType); - return RouteAction.Return(returnValue); - } + public RouteAction Handle(ICall call) + { + var returnValue = _defaultForType.GetDefaultFor(call.GetMethodInfo().ReturnType); + return RouteAction.Return(returnValue); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ReturnFromAndConfigureDynamicCall.cs b/src/NSubstitute/Routing/Handlers/ReturnFromAndConfigureDynamicCall.cs index 49778a76c..976e1b28c 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnFromAndConfigureDynamicCall.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnFromAndConfigureDynamicCall.cs @@ -1,66 +1,65 @@ using NSubstitute.Core; using System.Runtime.CompilerServices; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ReturnFromAndConfigureDynamicCall : ICallHandler { - public class ReturnFromAndConfigureDynamicCall : ICallHandler + private static readonly Type DynamicAttributeType = typeof(DynamicAttribute); + private readonly IConfigureCall _configureCall; + + public ReturnFromAndConfigureDynamicCall(IConfigureCall configureCall) { - private static readonly Type DynamicAttributeType = typeof(DynamicAttribute); - private readonly IConfigureCall _configureCall; + _configureCall = configureCall; + } - public ReturnFromAndConfigureDynamicCall(IConfigureCall configureCall) + public RouteAction Handle(ICall call) + { + if (ReturnsDynamic(call)) { - _configureCall = configureCall; + var stubToReturn = new DynamicStub(); + _configureCall.SetResultForCall(call, new ReturnValue(stubToReturn), MatchArgs.AsSpecifiedInCall); + return RouteAction.Return(new DynamicStub()); } - - public RouteAction Handle(ICall call) + else { - if (ReturnsDynamic(call)) - { - var stubToReturn = new DynamicStub(); - _configureCall.SetResultForCall(call, new ReturnValue(stubToReturn), MatchArgs.AsSpecifiedInCall); - return RouteAction.Return(new DynamicStub()); - } - else - { - return RouteAction.Continue(); - } + return RouteAction.Continue(); } + } - private bool ReturnsDynamic(ICall call) + private bool ReturnsDynamic(ICall call) + { + var returnParameter = call.GetMethodInfo().ReturnParameter; + if (returnParameter == null) { - var returnParameter = call.GetMethodInfo().ReturnParameter; - if (returnParameter == null) - { - return false; - } - - bool isDynamic; - isDynamic = returnParameter.GetCustomAttributes(DynamicAttributeType, inherit: false).Length != 0; - return isDynamic; + return false; } - public class DynamicStub + bool isDynamic; + isDynamic = returnParameter.GetCustomAttributes(DynamicAttributeType, inherit: false).Length != 0; + return isDynamic; + } + + public class DynamicStub + { + public ConfiguredCall Returns(T? returnThis, params T?[] returnThese) { - public ConfiguredCall Returns(T? returnThis, params T?[] returnThese) - { - return default(T).Returns(returnThis, returnThese); - } + return default(T).Returns(returnThis, returnThese); + } - public ConfiguredCall Returns(Func returnThis, params Func[] returnThese) - { - return default(T).Returns(returnThis, returnThese); - } + public ConfiguredCall Returns(Func returnThis, params Func[] returnThese) + { + return default(T).Returns(returnThis, returnThese); + } - public ConfiguredCall ReturnsForAnyArgs(T? returnThis, params T?[] returnThese) - { - return default(T).ReturnsForAnyArgs(returnThis, returnThese); - } + public ConfiguredCall ReturnsForAnyArgs(T? returnThis, params T?[] returnThese) + { + return default(T).ReturnsForAnyArgs(returnThis, returnThese); + } - public ConfiguredCall ReturnsForAnyArgs(Func returnThis, params Func[] returnThese) - { - return default(T).ReturnsForAnyArgs(returnThis, returnThese); - } + public ConfiguredCall ReturnsForAnyArgs(Func returnThis, params Func[] returnThese) + { + return default(T).ReturnsForAnyArgs(returnThis, returnThese); } } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ReturnFromBaseIfRequired.cs b/src/NSubstitute/Routing/Handlers/ReturnFromBaseIfRequired.cs index 2fc74666e..457bce15d 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnFromBaseIfRequired.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnFromBaseIfRequired.cs @@ -1,26 +1,25 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ReturnFromBaseIfRequired : ICallHandler { - public class ReturnFromBaseIfRequired : ICallHandler + private readonly ICallBaseConfiguration _config; + + public ReturnFromBaseIfRequired(ICallBaseConfiguration config) { - private readonly ICallBaseConfiguration _config; + _config = config; + } - public ReturnFromBaseIfRequired(ICallBaseConfiguration config) + public RouteAction Handle(ICall call) + { + if (_config.ShouldCallBase(call)) { - _config = config; + return call + .TryCallBase() + .Fold(RouteAction.Continue, RouteAction.Return); } - public RouteAction Handle(ICall call) - { - if (_config.ShouldCallBase(call)) - { - return call - .TryCallBase() - .Fold(RouteAction.Continue, RouteAction.Return); - } - - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/ReturnFromCustomHandlers.cs b/src/NSubstitute/Routing/Handlers/ReturnFromCustomHandlers.cs index 151ffa4bd..85d935944 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnFromCustomHandlers.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnFromCustomHandlers.cs @@ -1,34 +1,33 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ReturnFromCustomHandlers : ICallHandler { - public class ReturnFromCustomHandlers : ICallHandler + private readonly ICustomHandlers _customHandlers; + + public ReturnFromCustomHandlers(ICustomHandlers customHandlers) { - private readonly ICustomHandlers _customHandlers; + _customHandlers = customHandlers; + } - public ReturnFromCustomHandlers(ICustomHandlers customHandlers) + public RouteAction Handle(ICall call) + { + // Performance optimization, as enumerator retrieval allocates. + if (_customHandlers.Handlers.Count == 0) { - _customHandlers = customHandlers; + return RouteAction.Continue(); } - public RouteAction Handle(ICall call) + foreach (var handler in _customHandlers.Handlers) { - // Performance optimization, as enumerator retrieval allocates. - if (_customHandlers.Handlers.Count == 0) + var result = handler.Handle(call); + if (result.HasReturnValue) { - return RouteAction.Continue(); + return result; } - - foreach (var handler in _customHandlers.Handlers) - { - var result = handler.Handle(call); - if (result.HasReturnValue) - { - return result; - } - } - - return RouteAction.Continue(); } + + return RouteAction.Continue(); } } diff --git a/src/NSubstitute/Routing/Handlers/ReturnResultForTypeHandler.cs b/src/NSubstitute/Routing/Handlers/ReturnResultForTypeHandler.cs index 8dcfbb7c4..ab445ce82 100644 --- a/src/NSubstitute/Routing/Handlers/ReturnResultForTypeHandler.cs +++ b/src/NSubstitute/Routing/Handlers/ReturnResultForTypeHandler.cs @@ -1,24 +1,23 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class ReturnResultForTypeHandler : ICallHandler { - public class ReturnResultForTypeHandler : ICallHandler + private readonly IResultsForType _resultsForType; + + public ReturnResultForTypeHandler(IResultsForType resultsForType) { - private readonly IResultsForType _resultsForType; + _resultsForType = resultsForType; + } - public ReturnResultForTypeHandler(IResultsForType resultsForType) + public RouteAction Handle(ICall call) + { + if (_resultsForType.TryGetResult(call, out var result)) { - _resultsForType = resultsForType; + return RouteAction.Return(result); } - public RouteAction Handle(ICall call) - { - if (_resultsForType.TryGetResult(call, out var result)) - { - return RouteAction.Return(result); - } - - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/SetActionForCallHandler.cs b/src/NSubstitute/Routing/Handlers/SetActionForCallHandler.cs index 8fa336a34..89cdb945d 100644 --- a/src/NSubstitute/Routing/Handlers/SetActionForCallHandler.cs +++ b/src/NSubstitute/Routing/Handlers/SetActionForCallHandler.cs @@ -1,28 +1,27 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class SetActionForCallHandler : ICallHandler { - public class SetActionForCallHandler : ICallHandler - { - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly ICallActions _callActions; - private readonly Action _action; - private readonly MatchArgs _matchArgs; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly ICallActions _callActions; + private readonly Action _action; + private readonly MatchArgs _matchArgs; - public SetActionForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallActions callActions, Action action, MatchArgs matchArgs) - { - _callSpecificationFactory = callSpecificationFactory; - _callActions = callActions; - _action = action; - _matchArgs = matchArgs; - } + public SetActionForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallActions callActions, Action action, MatchArgs matchArgs) + { + _callSpecificationFactory = callSpecificationFactory; + _callActions = callActions; + _action = action; + _matchArgs = matchArgs; + } - public RouteAction Handle(ICall call) - { - var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs); - _callActions.Add(callSpec, _action); + public RouteAction Handle(ICall call) + { + var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs); + _callActions.Add(callSpec, _action); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Handlers/TrackLastCallHandler.cs b/src/NSubstitute/Routing/Handlers/TrackLastCallHandler.cs index 6eccc7ad2..3afa6358f 100644 --- a/src/NSubstitute/Routing/Handlers/TrackLastCallHandler.cs +++ b/src/NSubstitute/Routing/Handlers/TrackLastCallHandler.cs @@ -1,21 +1,20 @@ using NSubstitute.Core; -namespace NSubstitute.Routing.Handlers +namespace NSubstitute.Routing.Handlers; + +public class TrackLastCallHandler : ICallHandler { - public class TrackLastCallHandler : ICallHandler - { - private readonly IPendingSpecification _pendingSpecification; + private readonly IPendingSpecification _pendingSpecification; - public TrackLastCallHandler(IPendingSpecification pendingSpecification) - { - _pendingSpecification = pendingSpecification; - } + public TrackLastCallHandler(IPendingSpecification pendingSpecification) + { + _pendingSpecification = pendingSpecification; + } - public RouteAction Handle(ICall call) - { - _pendingSpecification.SetLastCall(call); + public RouteAction Handle(ICall call) + { + _pendingSpecification.SetLastCall(call); - return RouteAction.Continue(); - } + return RouteAction.Continue(); } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/IRoute.cs b/src/NSubstitute/Routing/IRoute.cs index ec6fa819b..f67fc20be 100644 --- a/src/NSubstitute/Routing/IRoute.cs +++ b/src/NSubstitute/Routing/IRoute.cs @@ -1,9 +1,8 @@ using NSubstitute.Core; -namespace NSubstitute.Routing +namespace NSubstitute.Routing; + +public interface IRoute { - public interface IRoute - { - object? Handle(ICall call); - } + object? Handle(ICall call); } \ No newline at end of file diff --git a/src/NSubstitute/Routing/IRouteFactory.cs b/src/NSubstitute/Routing/IRouteFactory.cs index 9f81cb0ec..5f60a84e1 100644 --- a/src/NSubstitute/Routing/IRouteFactory.cs +++ b/src/NSubstitute/Routing/IRouteFactory.cs @@ -1,17 +1,16 @@ using NSubstitute.Core; using NSubstitute.ReceivedExtensions; -namespace NSubstitute.Routing +namespace NSubstitute.Routing; + +public interface IRouteFactory { - public interface IRouteFactory - { - IRoute CallQuery(ISubstituteState state); - IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity); - IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs); - IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs); - IRoute CallBase(ISubstituteState state, MatchArgs matchArgs); - IRoute RaiseEvent(ISubstituteState state, Func getEventArguments); - IRoute RecordCallSpecification(ISubstituteState state); - IRoute RecordReplay(ISubstituteState state); - } + IRoute CallQuery(ISubstituteState state); + IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity); + IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs); + IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs); + IRoute CallBase(ISubstituteState state, MatchArgs matchArgs); + IRoute RaiseEvent(ISubstituteState state, Func getEventArguments); + IRoute RecordCallSpecification(ISubstituteState state); + IRoute RecordReplay(ISubstituteState state); } \ No newline at end of file diff --git a/src/NSubstitute/Routing/Route.cs b/src/NSubstitute/Routing/Route.cs index 93020f7b9..4e3e8bfff 100644 --- a/src/NSubstitute/Routing/Route.cs +++ b/src/NSubstitute/Routing/Route.cs @@ -1,32 +1,31 @@ using NSubstitute.Core; -namespace NSubstitute.Routing +namespace NSubstitute.Routing; + +public class Route : IRoute { - public class Route : IRoute - { - private readonly ICallHandler[] _handlers; + private readonly ICallHandler[] _handlers; - public Route(ICallHandler[] handlers) - { - _handlers = handlers; - } + public Route(ICallHandler[] handlers) + { + _handlers = handlers; + } - public IEnumerable Handlers => _handlers; + public IEnumerable Handlers => _handlers; - public object? Handle(ICall call) + public object? Handle(ICall call) + { + // This is a hot method which is invoked frequently and has major impact on performance. + // Therefore, the LINQ cycle was unwinded to for loop. + for (int i = 0; i < _handlers.Length; i++) { - // This is a hot method which is invoked frequently and has major impact on performance. - // Therefore, the LINQ cycle was unwinded to for loop. - for (int i = 0; i < _handlers.Length; i++) + var result = _handlers[i].Handle(call); + if (result.HasReturnValue) { - var result = _handlers[i].Handle(call); - if (result.HasReturnValue) - { - return result.ReturnValue; - } + return result.ReturnValue; } - - return null; } + + return null; } } \ No newline at end of file diff --git a/src/NSubstitute/Routing/RouteFactory.cs b/src/NSubstitute/Routing/RouteFactory.cs index aed113612..ac84ed24e 100644 --- a/src/NSubstitute/Routing/RouteFactory.cs +++ b/src/NSubstitute/Routing/RouteFactory.cs @@ -2,115 +2,114 @@ using NSubstitute.ReceivedExtensions; using NSubstitute.Routing.Handlers; -namespace NSubstitute.Routing -{ - public class RouteFactory : IRouteFactory - { - private readonly SequenceNumberGenerator _sequenceNumberGenerator; - private readonly IThreadLocalContext _threadLocalContext; - private readonly ICallSpecificationFactory _callSpecificationFactory; - private readonly IReceivedCallsExceptionThrower _receivedCallsExceptionThrower; - private readonly IPropertyHelper _propertyHelper; - private readonly IDefaultForType _defaultForType; +namespace NSubstitute.Routing; - public RouteFactory(SequenceNumberGenerator sequenceNumberGenerator, - IThreadLocalContext threadLocalContext, - ICallSpecificationFactory callSpecificationFactory, - IReceivedCallsExceptionThrower receivedCallsExceptionThrower, - IPropertyHelper propertyHelper, - IDefaultForType defaultForType) - { - _sequenceNumberGenerator = sequenceNumberGenerator; - _threadLocalContext = threadLocalContext; - _callSpecificationFactory = callSpecificationFactory; - _receivedCallsExceptionThrower = receivedCallsExceptionThrower; - _propertyHelper = propertyHelper; - _defaultForType = defaultForType; - } +public class RouteFactory : IRouteFactory +{ + private readonly SequenceNumberGenerator _sequenceNumberGenerator; + private readonly IThreadLocalContext _threadLocalContext; + private readonly ICallSpecificationFactory _callSpecificationFactory; + private readonly IReceivedCallsExceptionThrower _receivedCallsExceptionThrower; + private readonly IPropertyHelper _propertyHelper; + private readonly IDefaultForType _defaultForType; - public IRoute CallQuery(ISubstituteState state) - { - return new Route(new ICallHandler[] { - new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) - , new AddCallToQueryResultHandler(_threadLocalContext) - , new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity) - { - return new Route(new ICallHandler[] { - new ClearLastCallRouterHandler(_threadLocalContext) - , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) - , new CheckReceivedCallsHandler(state.ReceivedCalls, _callSpecificationFactory, _receivedCallsExceptionThrower, matchArgs, requiredQuantity) - , new ReturnAutoValue(AutoValueBehaviour.ReturnAndForgetValue, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs) - { - return new Route(new ICallHandler[] { - new ClearLastCallRouterHandler(_threadLocalContext) - , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) - , new SetActionForCallHandler(_callSpecificationFactory, state.CallActions, doAction, matchArgs) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs) - { - return new Route(new ICallHandler[] { - new ClearLastCallRouterHandler(_threadLocalContext) - , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) - , new DoNotCallBaseForCallHandler(_callSpecificationFactory, state.CallBaseConfiguration, matchArgs) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute CallBase(ISubstituteState state, MatchArgs matchArgs) - { - return new Route(new ICallHandler[] { - new ClearLastCallRouterHandler(_threadLocalContext) - , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) - , new CallBaseForCallHandler(_callSpecificationFactory, state.CallBaseConfiguration, matchArgs) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute RaiseEvent(ISubstituteState state, Func getEventArguments) - { - return new Route(new ICallHandler[] { - new ClearLastCallRouterHandler(_threadLocalContext) - , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) - , new RaiseEventHandler(state.EventHandlerRegistry, getEventArguments) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute RecordCallSpecification(ISubstituteState state) - { - return new Route(new ICallHandler[] { - new RecordCallSpecificationHandler(_threadLocalContext.PendingSpecification, _callSpecificationFactory, state.CallActions) - , new PropertySetterHandler(_propertyHelper, state.ConfigureCall) - , new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) - , new ReturnFromAndConfigureDynamicCall(state.ConfigureCall) - , ReturnDefaultForReturnTypeHandler() - }); - } - public IRoute RecordReplay(ISubstituteState state) - { - return new Route(new ICallHandler[] { - new TrackLastCallHandler(_threadLocalContext.PendingSpecification) - , new RecordCallHandler(state.ReceivedCalls, _sequenceNumberGenerator) - , new EventSubscriptionHandler(state.EventHandlerRegistry) - , new PropertySetterHandler(_propertyHelper, state.ConfigureCall) - , new DoActionsCallHandler(state.CallActions) - , new ReturnConfiguredResultHandler(state.CallResults) - , new ReturnResultForTypeHandler(state.ResultsForType) - , new ReturnFromBaseIfRequired(state.CallBaseConfiguration) - , new ReturnFromCustomHandlers(state.CustomHandlers) - , new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) - , new ReturnFromAndConfigureDynamicCall(state.ConfigureCall) - , ReturnDefaultForReturnTypeHandler() - }); - } + public RouteFactory(SequenceNumberGenerator sequenceNumberGenerator, + IThreadLocalContext threadLocalContext, + ICallSpecificationFactory callSpecificationFactory, + IReceivedCallsExceptionThrower receivedCallsExceptionThrower, + IPropertyHelper propertyHelper, + IDefaultForType defaultForType) + { + _sequenceNumberGenerator = sequenceNumberGenerator; + _threadLocalContext = threadLocalContext; + _callSpecificationFactory = callSpecificationFactory; + _receivedCallsExceptionThrower = receivedCallsExceptionThrower; + _propertyHelper = propertyHelper; + _defaultForType = defaultForType; + } - private ReturnDefaultForReturnTypeHandler ReturnDefaultForReturnTypeHandler() => new(_defaultForType); + public IRoute CallQuery(ISubstituteState state) + { + return new Route(new ICallHandler[] { + new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) + , new AddCallToQueryResultHandler(_threadLocalContext) + , new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) + , ReturnDefaultForReturnTypeHandler() + }); } + public IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity) + { + return new Route(new ICallHandler[] { + new ClearLastCallRouterHandler(_threadLocalContext) + , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) + , new CheckReceivedCallsHandler(state.ReceivedCalls, _callSpecificationFactory, _receivedCallsExceptionThrower, matchArgs, requiredQuantity) + , new ReturnAutoValue(AutoValueBehaviour.ReturnAndForgetValue, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) + , ReturnDefaultForReturnTypeHandler() + }); + } + public IRoute DoWhenCalled(ISubstituteState state, Action doAction, MatchArgs matchArgs) + { + return new Route(new ICallHandler[] { + new ClearLastCallRouterHandler(_threadLocalContext) + , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) + , new SetActionForCallHandler(_callSpecificationFactory, state.CallActions, doAction, matchArgs) + , ReturnDefaultForReturnTypeHandler() + }); + } + public IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs) + { + return new Route(new ICallHandler[] { + new ClearLastCallRouterHandler(_threadLocalContext) + , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) + , new DoNotCallBaseForCallHandler(_callSpecificationFactory, state.CallBaseConfiguration, matchArgs) + , ReturnDefaultForReturnTypeHandler() + }); + } + public IRoute CallBase(ISubstituteState state, MatchArgs matchArgs) + { + return new Route(new ICallHandler[] { + new ClearLastCallRouterHandler(_threadLocalContext) + , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) + , new CallBaseForCallHandler(_callSpecificationFactory, state.CallBaseConfiguration, matchArgs) + , ReturnDefaultForReturnTypeHandler() + }); + } + public IRoute RaiseEvent(ISubstituteState state, Func getEventArguments) + { + return new Route(new ICallHandler[] { + new ClearLastCallRouterHandler(_threadLocalContext) + , new ClearUnusedCallSpecHandler(_threadLocalContext.PendingSpecification) + , new RaiseEventHandler(state.EventHandlerRegistry, getEventArguments) + , ReturnDefaultForReturnTypeHandler() + }); + } + public IRoute RecordCallSpecification(ISubstituteState state) + { + return new Route(new ICallHandler[] { + new RecordCallSpecificationHandler(_threadLocalContext.PendingSpecification, _callSpecificationFactory, state.CallActions) + , new PropertySetterHandler(_propertyHelper, state.ConfigureCall) + , new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) + , new ReturnFromAndConfigureDynamicCall(state.ConfigureCall) + , ReturnDefaultForReturnTypeHandler() + }); + } + public IRoute RecordReplay(ISubstituteState state) + { + return new Route(new ICallHandler[] { + new TrackLastCallHandler(_threadLocalContext.PendingSpecification) + , new RecordCallHandler(state.ReceivedCalls, _sequenceNumberGenerator) + , new EventSubscriptionHandler(state.EventHandlerRegistry) + , new PropertySetterHandler(_propertyHelper, state.ConfigureCall) + , new DoActionsCallHandler(state.CallActions) + , new ReturnConfiguredResultHandler(state.CallResults) + , new ReturnResultForTypeHandler(state.ResultsForType) + , new ReturnFromBaseIfRequired(state.CallBaseConfiguration) + , new ReturnFromCustomHandlers(state.CustomHandlers) + , new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, _callSpecificationFactory) + , new ReturnFromAndConfigureDynamicCall(state.ConfigureCall) + , ReturnDefaultForReturnTypeHandler() + }); + } + + private ReturnDefaultForReturnTypeHandler ReturnDefaultForReturnTypeHandler() => new(_defaultForType); } \ No newline at end of file diff --git a/src/NSubstitute/Substitute.cs b/src/NSubstitute/Substitute.cs index 966e701f8..9efd22233 100644 --- a/src/NSubstitute/Substitute.cs +++ b/src/NSubstitute/Substitute.cs @@ -3,91 +3,90 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +/// +/// Create a substitute for one or more types. For example: Substitute.For<ISomeType>() +/// +public static class Substitute { /// - /// Create a substitute for one or more types. For example: Substitute.For<ISomeType>() + /// Substitute for an interface or class. + /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members + /// can be recorded or have return values specified. /// - public static class Substitute + /// The type of interface or class to substitute. + /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. + /// A substitute for the interface or class. + public static T For(params object[] constructorArguments) + where T : class { - /// - /// Substitute for an interface or class. - /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members - /// can be recorded or have return values specified. - /// - /// The type of interface or class to substitute. - /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. - /// A substitute for the interface or class. - public static T For(params object[] constructorArguments) - where T : class - { - return (T)For(new[] { typeof(T) }, constructorArguments); - } + return (T)For(new[] { typeof(T) }, constructorArguments); + } - /// - /// Substitute for multiple interfaces or a class that implements an interface. At most one class can be specified. - /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members - /// can be recorded or have return values specified. - /// - /// The type of interface or class to substitute. - /// An additional interface or class (maximum of one class) the substitute should implement. - /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. - /// A substitute of type T1, that also implements T2. - public static T1 For(params object[] constructorArguments) - where T1 : class - where T2 : class - { - return (T1)For(new[] { typeof(T1), typeof(T2) }, constructorArguments); - } + /// + /// Substitute for multiple interfaces or a class that implements an interface. At most one class can be specified. + /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members + /// can be recorded or have return values specified. + /// + /// The type of interface or class to substitute. + /// An additional interface or class (maximum of one class) the substitute should implement. + /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. + /// A substitute of type T1, that also implements T2. + public static T1 For(params object[] constructorArguments) + where T1 : class + where T2 : class + { + return (T1)For(new[] { typeof(T1), typeof(T2) }, constructorArguments); + } - /// - /// Substitute for multiple interfaces or a class that implements multiple interfaces. At most one class can be specified. - /// If additional interfaces are required use the overload. - /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members - /// can be recorded or have return values specified. - /// - /// The type of interface or class to substitute. - /// An additional interface or class (maximum of one class) the substitute should implement. - /// An additional interface or class (maximum of one class) the substitute should implement. - /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. - /// A substitute of type T1, that also implements T2 and T3. - public static T1 For(params object[] constructorArguments) - where T1 : class - where T2 : class - where T3 : class - { - return (T1)For(new[] { typeof(T1), typeof(T2), typeof(T3) }, constructorArguments); - } + /// + /// Substitute for multiple interfaces or a class that implements multiple interfaces. At most one class can be specified. + /// If additional interfaces are required use the overload. + /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members + /// can be recorded or have return values specified. + /// + /// The type of interface or class to substitute. + /// An additional interface or class (maximum of one class) the substitute should implement. + /// An additional interface or class (maximum of one class) the substitute should implement. + /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. + /// A substitute of type T1, that also implements T2 and T3. + public static T1 For(params object[] constructorArguments) + where T1 : class + where T2 : class + where T3 : class + { + return (T1)For(new[] { typeof(T1), typeof(T2), typeof(T3) }, constructorArguments); + } - /// - /// Substitute for multiple interfaces or a class that implements multiple interfaces. At most one class can be specified. - /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members - /// can be recorded or have return values specified. - /// - /// The types of interfaces or a type of class and multiple interfaces the substitute should implement. - /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. - /// A substitute implementing the specified types. - public static object For(Type[] typesToProxy, object[] constructorArguments) - { - var substituteFactory = SubstitutionContext.Current.SubstituteFactory; - return substituteFactory.Create(typesToProxy, constructorArguments); - } + /// + /// Substitute for multiple interfaces or a class that implements multiple interfaces. At most one class can be specified. + /// Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members + /// can be recorded or have return values specified. + /// + /// The types of interfaces or a type of class and multiple interfaces the substitute should implement. + /// Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors. + /// A substitute implementing the specified types. + public static object For(Type[] typesToProxy, object[] constructorArguments) + { + var substituteFactory = SubstitutionContext.Current.SubstituteFactory; + return substituteFactory.Create(typesToProxy, constructorArguments); + } - /// - /// Create a substitute for a class that behaves just like a real instance of the class, but also - /// records calls made to its virtual members and allows for specific members to be substituted - /// by using When(() => call).DoNotCallBase() or by - /// setting a value to return value for that member. - /// - /// The type to substitute for parts of. Must be a class; not a delegate or interface. - /// - /// An instance of the class that will execute real methods when called, but allows parts to be selectively - /// overridden via `Returns` and `When..DoNotCallBase`. - public static T ForPartsOf(params object[] constructorArguments) - where T : class - { - var substituteFactory = SubstitutionContext.Current.SubstituteFactory; - return (T)substituteFactory.CreatePartial(new[] { typeof(T) }, constructorArguments); - } + /// + /// Create a substitute for a class that behaves just like a real instance of the class, but also + /// records calls made to its virtual members and allows for specific members to be substituted + /// by using When(() => call).DoNotCallBase() or by + /// setting a value to return value for that member. + /// + /// The type to substitute for parts of. Must be a class; not a delegate or interface. + /// + /// An instance of the class that will execute real methods when called, but allows parts to be selectively + /// overridden via `Returns` and `When..DoNotCallBase`. + public static T ForPartsOf(params object[] constructorArguments) + where T : class + { + var substituteFactory = SubstitutionContext.Current.SubstituteFactory; + return (T)substituteFactory.CreatePartial(new[] { typeof(T) }, constructorArguments); } } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.Received.cs b/src/NSubstitute/SubstituteExtensions.Received.cs index db0c1a390..f0d5d8b56 100644 --- a/src/NSubstitute/SubstituteExtensions.Received.cs +++ b/src/NSubstitute/SubstituteExtensions.Received.cs @@ -7,96 +7,95 @@ #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions + /// + /// Checks this substitute has received the following call. + /// + public static T Received(this T substitute) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + return substitute.Received(Quantity.AtLeastOne()); + } + + /// + /// Checks this substitute has received the following call the required number of times. + /// + public static T Received(this T substitute, int requiredNumberOfCalls) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + return substitute.Received(Quantity.Exactly(requiredNumberOfCalls)); + } + + /// + /// Checks this substitute has not received the following call. + /// + public static T DidNotReceive(this T substitute) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + return substitute.Received(Quantity.None()); + } + + /// + /// Checks this substitute has received the following call with any arguments. + /// + public static T ReceivedWithAnyArgs(this T substitute) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + return substitute.ReceivedWithAnyArgs(Quantity.AtLeastOne()); + } + + /// + /// Checks this substitute has received the following call with any arguments the required number of times. + /// + public static T ReceivedWithAnyArgs(this T substitute, int requiredNumberOfCalls) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + return substitute.ReceivedWithAnyArgs(Quantity.Exactly(requiredNumberOfCalls)); + } + + /// + /// Checks this substitute has not received the following call with any arguments. + /// + public static T DidNotReceiveWithAnyArgs(this T substitute) where T : class { - /// - /// Checks this substitute has received the following call. - /// - public static T Received(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return substitute.Received(Quantity.AtLeastOne()); - } - - /// - /// Checks this substitute has received the following call the required number of times. - /// - public static T Received(this T substitute, int requiredNumberOfCalls) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return substitute.Received(Quantity.Exactly(requiredNumberOfCalls)); - } - - /// - /// Checks this substitute has not received the following call. - /// - public static T DidNotReceive(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return substitute.Received(Quantity.None()); - } - - /// - /// Checks this substitute has received the following call with any arguments. - /// - public static T ReceivedWithAnyArgs(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return substitute.ReceivedWithAnyArgs(Quantity.AtLeastOne()); - } - - /// - /// Checks this substitute has received the following call with any arguments the required number of times. - /// - public static T ReceivedWithAnyArgs(this T substitute, int requiredNumberOfCalls) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return substitute.ReceivedWithAnyArgs(Quantity.Exactly(requiredNumberOfCalls)); - } - - /// - /// Checks this substitute has not received the following call with any arguments. - /// - public static T DidNotReceiveWithAnyArgs(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return substitute.ReceivedWithAnyArgs(Quantity.None()); - } - - /// - /// Returns the calls received by this substitute. - /// - public static IEnumerable ReceivedCalls(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - return SubstitutionContext - .Current - .GetCallRouterFor(substitute!) - .ReceivedCalls(); - } - - /// - /// Forget all the calls this substitute has received. - /// - /// - /// Note that this will not clear any results set up for the substitute using Returns(). - /// See for more options with resetting - /// a substitute. - /// - public static void ClearReceivedCalls(this T substitute) where T : class - { - if (substitute == null) throw new NullSubstituteReferenceException(); - - substitute.ClearSubstitute(ClearOptions.ReceivedCalls); - } + if (substitute == null) throw new NullSubstituteReferenceException(); + + return substitute.ReceivedWithAnyArgs(Quantity.None()); + } + + /// + /// Returns the calls received by this substitute. + /// + public static IEnumerable ReceivedCalls(this T substitute) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + return SubstitutionContext + .Current + .GetCallRouterFor(substitute!) + .ReceivedCalls(); + } + + /// + /// Forget all the calls this substitute has received. + /// + /// + /// Note that this will not clear any results set up for the substitute using Returns(). + /// See for more options with resetting + /// a substitute. + /// + public static void ClearReceivedCalls(this T substitute) where T : class + { + if (substitute == null) throw new NullSubstituteReferenceException(); + + substitute.ClearSubstitute(ClearOptions.ReceivedCalls); } } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.Returns.Task.cs b/src/NSubstitute/SubstituteExtensions.Returns.Task.cs index 49f4b9240..0b894f3c4 100644 --- a/src/NSubstitute/SubstituteExtensions.Returns.Task.cs +++ b/src/NSubstitute/SubstituteExtensions.Returns.Task.cs @@ -4,86 +4,85 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions + /// + /// Set a return value for this call. The value(s) to be returned will be wrapped in Tasks. + /// + /// + /// Value to return. Will be wrapped in a Task + /// Optionally use these values next + public static ConfiguredCall Returns(this Task value, T returnThis, params T[] returnThese) { - /// - /// Set a return value for this call. The value(s) to be returned will be wrapped in Tasks. - /// - /// - /// Value to return. Will be wrapped in a Task - /// Optionally use these values next - public static ConfiguredCall Returns(this Task value, T returnThis, params T[] returnThese) - { - ReThrowOnNSubstituteFault(value); + ReThrowOnNSubstituteFault(value); - var wrappedReturnValue = CompletedTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedTask).ToArray() : null; + var wrappedReturnValue = CompletedTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedTask).ToArray() : null; - return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedReturnValue, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedReturnValue, wrappedReturnThese); + } - /// - /// Set a return value for this call, calculated by the provided function. The value(s) to be returned will be wrapped in Tasks. - /// - /// - /// Function to calculate the return value - /// Optionally use these functions next - public static ConfiguredCall Returns(this Task value, Func returnThis, params Func[] returnThese) - { - ReThrowOnNSubstituteFault(value); + /// + /// Set a return value for this call, calculated by the provided function. The value(s) to be returned will be wrapped in Tasks. + /// + /// + /// Function to calculate the return value + /// Optionally use these functions next + public static ConfiguredCall Returns(this Task value, Func returnThis, params Func[] returnThese) + { + ReThrowOnNSubstituteFault(value); - var wrappedFunc = WrapFuncInTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInTask).ToArray() : null; + var wrappedFunc = WrapFuncInTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInTask).ToArray() : null; - return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedFunc, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedFunc, wrappedReturnThese); + } - /// - /// Set a return value for this call made with any arguments. The value(s) to be returned will be wrapped in Tasks. - /// - /// - /// Value to return - /// Optionally return these values next - public static ConfiguredCall ReturnsForAnyArgs(this Task value, T returnThis, params T[] returnThese) - { - ReThrowOnNSubstituteFault(value); + /// + /// Set a return value for this call made with any arguments. The value(s) to be returned will be wrapped in Tasks. + /// + /// + /// Value to return + /// Optionally return these values next + public static ConfiguredCall ReturnsForAnyArgs(this Task value, T returnThis, params T[] returnThese) + { + ReThrowOnNSubstituteFault(value); - var wrappedReturnValue = CompletedTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedTask).ToArray() : null; + var wrappedReturnValue = CompletedTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedTask).ToArray() : null; - return ConfigureReturn(MatchArgs.Any, wrappedReturnValue, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.Any, wrappedReturnValue, wrappedReturnThese); + } - /// - /// Set a return value for this call made with any arguments, calculated by the provided function. The value(s) to be returned will be wrapped in Tasks. - /// - /// - /// Function to calculate the return value - /// Optionally use these functions next - public static ConfiguredCall ReturnsForAnyArgs(this Task value, Func returnThis, params Func[] returnThese) - { - ReThrowOnNSubstituteFault(value); + /// + /// Set a return value for this call made with any arguments, calculated by the provided function. The value(s) to be returned will be wrapped in Tasks. + /// + /// + /// Function to calculate the return value + /// Optionally use these functions next + public static ConfiguredCall ReturnsForAnyArgs(this Task value, Func returnThis, params Func[] returnThese) + { + ReThrowOnNSubstituteFault(value); - var wrappedFunc = WrapFuncInTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInTask).ToArray() : null; + var wrappedFunc = WrapFuncInTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInTask).ToArray() : null; - return ConfigureReturn(MatchArgs.Any, wrappedFunc, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.Any, wrappedFunc, wrappedReturnThese); + } #nullable restore - private static void ReThrowOnNSubstituteFault(Task task) + private static void ReThrowOnNSubstituteFault(Task task) + { + if (task.IsFaulted && task.Exception!.InnerExceptions.FirstOrDefault() is SubstituteException) { - if (task.IsFaulted && task.Exception!.InnerExceptions.FirstOrDefault() is SubstituteException) - { - task.GetAwaiter().GetResult(); - } + task.GetAwaiter().GetResult(); } + } - private static Task CompletedTask(T? result) => Task.FromResult(result); + private static Task CompletedTask(T? result) => Task.FromResult(result); - private static Func> WrapFuncInTask(Func returnThis) => - x => CompletedTask(returnThis(x)); - } + private static Func> WrapFuncInTask(Func returnThis) => + x => CompletedTask(returnThis(x)); } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.Returns.ValueTask.cs b/src/NSubstitute/SubstituteExtensions.Returns.ValueTask.cs index f684b324d..ea1efb454 100644 --- a/src/NSubstitute/SubstituteExtensions.Returns.ValueTask.cs +++ b/src/NSubstitute/SubstituteExtensions.Returns.ValueTask.cs @@ -4,86 +4,85 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions + /// + /// Set a return value for this call. The value(s) to be returned will be wrapped in ValueTasks. + /// + /// + /// Value to return. Will be wrapped in a ValueTask + /// Optionally use these values next + public static ConfiguredCall Returns(this ValueTask value, T returnThis, params T[] returnThese) { - /// - /// Set a return value for this call. The value(s) to be returned will be wrapped in ValueTasks. - /// - /// - /// Value to return. Will be wrapped in a ValueTask - /// Optionally use these values next - public static ConfiguredCall Returns(this ValueTask value, T returnThis, params T[] returnThese) - { - ReThrowOnNSubstituteFault(value); + ReThrowOnNSubstituteFault(value); - var wrappedReturnValue = CompletedValueTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedValueTask).ToArray() : null; + var wrappedReturnValue = CompletedValueTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedValueTask).ToArray() : null; - return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedReturnValue, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedReturnValue, wrappedReturnThese); + } - /// - /// Set a return value for this call, calculated by the provided function. The value(s) to be returned will be wrapped in ValueTasks. - /// - /// - /// Function to calculate the return value - /// Optionally use these functions next - public static ConfiguredCall Returns(this ValueTask value, Func returnThis, params Func[] returnThese) - { - ReThrowOnNSubstituteFault(value); + /// + /// Set a return value for this call, calculated by the provided function. The value(s) to be returned will be wrapped in ValueTasks. + /// + /// + /// Function to calculate the return value + /// Optionally use these functions next + public static ConfiguredCall Returns(this ValueTask value, Func returnThis, params Func[] returnThese) + { + ReThrowOnNSubstituteFault(value); - var wrappedFunc = WrapFuncInValueTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInValueTask).ToArray() : null; + var wrappedFunc = WrapFuncInValueTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInValueTask).ToArray() : null; - return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedFunc, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.AsSpecifiedInCall, wrappedFunc, wrappedReturnThese); + } - /// - /// Set a return value for this call made with any arguments. The value(s) to be returned will be wrapped in ValueTasks. - /// - /// - /// Value to return - /// Optionally return these values next - public static ConfiguredCall ReturnsForAnyArgs(this ValueTask value, T returnThis, params T[] returnThese) - { - ReThrowOnNSubstituteFault(value); + /// + /// Set a return value for this call made with any arguments. The value(s) to be returned will be wrapped in ValueTasks. + /// + /// + /// Value to return + /// Optionally return these values next + public static ConfiguredCall ReturnsForAnyArgs(this ValueTask value, T returnThis, params T[] returnThese) + { + ReThrowOnNSubstituteFault(value); - var wrappedReturnValue = CompletedValueTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedValueTask).ToArray() : null; + var wrappedReturnValue = CompletedValueTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(CompletedValueTask).ToArray() : null; - return ConfigureReturn(MatchArgs.Any, wrappedReturnValue, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.Any, wrappedReturnValue, wrappedReturnThese); + } - /// - /// Set a return value for this call made with any arguments, calculated by the provided function. The value(s) to be returned will be wrapped in ValueTasks. - /// - /// - /// Function to calculate the return value - /// Optionally use these functions next - public static ConfiguredCall ReturnsForAnyArgs(this ValueTask value, Func returnThis, params Func[] returnThese) - { - ReThrowOnNSubstituteFault(value); + /// + /// Set a return value for this call made with any arguments, calculated by the provided function. The value(s) to be returned will be wrapped in ValueTasks. + /// + /// + /// Function to calculate the return value + /// Optionally use these functions next + public static ConfiguredCall ReturnsForAnyArgs(this ValueTask value, Func returnThis, params Func[] returnThese) + { + ReThrowOnNSubstituteFault(value); - var wrappedFunc = WrapFuncInValueTask(returnThis); - var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInValueTask).ToArray() : null; + var wrappedFunc = WrapFuncInValueTask(returnThis); + var wrappedReturnThese = returnThese.Length > 0 ? returnThese.Select(WrapFuncInValueTask).ToArray() : null; - return ConfigureReturn(MatchArgs.Any, wrappedFunc, wrappedReturnThese); - } + return ConfigureReturn(MatchArgs.Any, wrappedFunc, wrappedReturnThese); + } #nullable restore - private static void ReThrowOnNSubstituteFault(ValueTask task) + private static void ReThrowOnNSubstituteFault(ValueTask task) + { + if (task.IsFaulted && task.AsTask().Exception!.InnerExceptions.FirstOrDefault() is SubstituteException) { - if (task.IsFaulted && task.AsTask().Exception!.InnerExceptions.FirstOrDefault() is SubstituteException) - { - task.GetAwaiter().GetResult(); - } + task.GetAwaiter().GetResult(); } + } - private static ValueTask CompletedValueTask(T? result) => new(result); + private static ValueTask CompletedValueTask(T? result) => new(result); - private static Func> WrapFuncInValueTask(Func returnThis) => - x => CompletedValueTask(returnThis(x)); - } + private static Func> WrapFuncInValueTask(Func returnThis) => + x => CompletedValueTask(returnThis(x)); } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.Returns.cs b/src/NSubstitute/SubstituteExtensions.Returns.cs index d118f9d58..e63b673d0 100644 --- a/src/NSubstitute/SubstituteExtensions.Returns.cs +++ b/src/NSubstitute/SubstituteExtensions.Returns.cs @@ -3,81 +3,80 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions - { - /// - /// Set a return value for this call. - /// - /// - /// Value to return - /// Optionally return these values next - public static ConfiguredCall Returns(this T value, T returnThis, params T[] returnThese) => - ConfigureReturn(MatchArgs.AsSpecifiedInCall, returnThis, returnThese); + /// + /// Set a return value for this call. + /// + /// + /// Value to return + /// Optionally return these values next + public static ConfiguredCall Returns(this T value, T returnThis, params T[] returnThese) => + ConfigureReturn(MatchArgs.AsSpecifiedInCall, returnThis, returnThese); - /// - /// Set a return value for this call, calculated by the provided function. - /// - /// - /// Function to calculate the return value - /// Optionally use these functions next - public static ConfiguredCall Returns(this T value, Func returnThis, params Func[] returnThese) => - ConfigureReturn(MatchArgs.AsSpecifiedInCall, returnThis, returnThese); + /// + /// Set a return value for this call, calculated by the provided function. + /// + /// + /// Function to calculate the return value + /// Optionally use these functions next + public static ConfiguredCall Returns(this T value, Func returnThis, params Func[] returnThese) => + ConfigureReturn(MatchArgs.AsSpecifiedInCall, returnThis, returnThese); - /// - /// Set a return value for this call made with any arguments. - /// - /// - /// Value to return - /// Optionally return these values next - public static ConfiguredCall ReturnsForAnyArgs(this T value, T returnThis, params T[] returnThese) => - ConfigureReturn(MatchArgs.Any, returnThis, returnThese); + /// + /// Set a return value for this call made with any arguments. + /// + /// + /// Value to return + /// Optionally return these values next + public static ConfiguredCall ReturnsForAnyArgs(this T value, T returnThis, params T[] returnThese) => + ConfigureReturn(MatchArgs.Any, returnThis, returnThese); - /// - /// Set a return value for this call made with any arguments, calculated by the provided function. - /// - /// - /// Function to calculate the return value - /// Optionally use these functions next - /// - public static ConfiguredCall ReturnsForAnyArgs(this T value, Func returnThis, params Func[] returnThese) => - ConfigureReturn(MatchArgs.Any, returnThis, returnThese); + /// + /// Set a return value for this call made with any arguments, calculated by the provided function. + /// + /// + /// Function to calculate the return value + /// Optionally use these functions next + /// + public static ConfiguredCall ReturnsForAnyArgs(this T value, Func returnThis, params Func[] returnThese) => + ConfigureReturn(MatchArgs.Any, returnThis, returnThese); #nullable restore - private static ConfiguredCall ConfigureReturn(MatchArgs matchArgs, T? returnThis, T?[]? returnThese) + private static ConfiguredCall ConfigureReturn(MatchArgs matchArgs, T? returnThis, T?[]? returnThese) + { + IReturn returnValue; + if (returnThese == null || returnThese.Length == 0) { - IReturn returnValue; - if (returnThese == null || returnThese.Length == 0) - { - returnValue = new ReturnValue(returnThis); - } - else - { - returnValue = new ReturnMultipleValues(new[] { returnThis }.Concat(returnThese).ToArray()); - } - return SubstitutionContext - .Current - .ThreadContext - .LastCallShouldReturn(returnValue, matchArgs); + returnValue = new ReturnValue(returnThis); } - - private static ConfiguredCall ConfigureReturn(MatchArgs matchArgs, Func returnThis, Func[]? returnThese) + else { - IReturn returnValue; - if (returnThese == null || returnThese.Length == 0) - { - returnValue = new ReturnValueFromFunc(returnThis); - } - else - { - returnValue = new ReturnMultipleFuncsValues(new[] { returnThis }.Concat(returnThese).ToArray()); - } + returnValue = new ReturnMultipleValues(new[] { returnThis }.Concat(returnThese).ToArray()); + } + return SubstitutionContext + .Current + .ThreadContext + .LastCallShouldReturn(returnValue, matchArgs); + } - return SubstitutionContext - .Current - .ThreadContext - .LastCallShouldReturn(returnValue, matchArgs); + private static ConfiguredCall ConfigureReturn(MatchArgs matchArgs, Func returnThis, Func[]? returnThese) + { + IReturn returnValue; + if (returnThese == null || returnThese.Length == 0) + { + returnValue = new ReturnValueFromFunc(returnThis); } + else + { + returnValue = new ReturnMultipleFuncsValues(new[] { returnThis }.Concat(returnThese).ToArray()); + } + + return SubstitutionContext + .Current + .ThreadContext + .LastCallShouldReturn(returnValue, matchArgs); } } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.When.Task.cs b/src/NSubstitute/SubstituteExtensions.When.Task.cs index f64f71734..4f1780b06 100644 --- a/src/NSubstitute/SubstituteExtensions.When.Task.cs +++ b/src/NSubstitute/SubstituteExtensions.When.Task.cs @@ -3,26 +3,25 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions + /// + /// Perform an action when this member is called. + /// Must be followed by to provide the callback. + /// + public static WhenCalled When(this T substitute, Func substituteCall) where T : class { - /// - /// Perform an action when this member is called. - /// Must be followed by to provide the callback. - /// - public static WhenCalled When(this T substitute, Func substituteCall) where T : class - { - return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.AsSpecifiedInCall); - } + return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.AsSpecifiedInCall); + } - /// - /// Perform an action when this member is called with any arguments. - /// Must be followed by to provide the callback. - /// - public static WhenCalled WhenForAnyArgs(this T substitute, Func substituteCall) where T : class - { - return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.Any); - } + /// + /// Perform an action when this member is called with any arguments. + /// Must be followed by to provide the callback. + /// + public static WhenCalled WhenForAnyArgs(this T substitute, Func substituteCall) where T : class + { + return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.Any); } } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.When.ValueTask.cs b/src/NSubstitute/SubstituteExtensions.When.ValueTask.cs index 4756f6f38..a89d24a3f 100644 --- a/src/NSubstitute/SubstituteExtensions.When.ValueTask.cs +++ b/src/NSubstitute/SubstituteExtensions.When.ValueTask.cs @@ -3,28 +3,27 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions + /// + /// Perform an action when this member is called. + /// Must be followed by to provide the callback. + /// + public static WhenCalled When(this TSubstitute substitute, + Func> substituteCall) where TSubstitute : class { - /// - /// Perform an action when this member is called. - /// Must be followed by to provide the callback. - /// - public static WhenCalled When(this TSubstitute substitute, - Func> substituteCall) where TSubstitute : class - { - return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.AsSpecifiedInCall); - } + return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.AsSpecifiedInCall); + } - /// - /// Perform an action when this member is called with any arguments. - /// Must be followed by to provide the callback. - /// - public static WhenCalled WhenForAnyArgs(this TSubstitute substitute, - Func> substituteCall) where TSubstitute : class - { - return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.Any); - } + /// + /// Perform an action when this member is called with any arguments. + /// Must be followed by to provide the callback. + /// + public static WhenCalled WhenForAnyArgs(this TSubstitute substitute, + Func> substituteCall) where TSubstitute : class + { + return MakeWhenCalled(substitute, x => substituteCall(x), MatchArgs.Any); } } \ No newline at end of file diff --git a/src/NSubstitute/SubstituteExtensions.When.cs b/src/NSubstitute/SubstituteExtensions.When.cs index dfb730477..eb59779a6 100644 --- a/src/NSubstitute/SubstituteExtensions.When.cs +++ b/src/NSubstitute/SubstituteExtensions.When.cs @@ -4,36 +4,35 @@ // Disable nullability for client API, so it does not affect clients. #nullable disable annotations -namespace NSubstitute +namespace NSubstitute; + +public static partial class SubstituteExtensions { - public static partial class SubstituteExtensions + /// + /// Perform an action when this member is called. + /// Must be followed by to provide the callback. + /// + public static WhenCalled When(this T substitute, Action substituteCall) where T : class { - /// - /// Perform an action when this member is called. - /// Must be followed by to provide the callback. - /// - public static WhenCalled When(this T substitute, Action substituteCall) where T : class - { - return MakeWhenCalled(substitute, substituteCall, MatchArgs.AsSpecifiedInCall); - } + return MakeWhenCalled(substitute, substituteCall, MatchArgs.AsSpecifiedInCall); + } - /// - /// Perform an action when this member is called with any arguments. - /// Must be followed by to provide the callback. - /// - public static WhenCalled WhenForAnyArgs(this T substitute, Action substituteCall) where T : class - { - return MakeWhenCalled(substitute, substituteCall, MatchArgs.Any); - } + /// + /// Perform an action when this member is called with any arguments. + /// Must be followed by to provide the callback. + /// + public static WhenCalled WhenForAnyArgs(this T substitute, Action substituteCall) where T : class + { + return MakeWhenCalled(substitute, substituteCall, MatchArgs.Any); + } #nullable restore - private static WhenCalled MakeWhenCalled(TSubstitute? substitute, - Action action, MatchArgs matchArgs) - { - if (substitute == null) throw new NullSubstituteReferenceException(); + private static WhenCalled MakeWhenCalled(TSubstitute? substitute, + Action action, MatchArgs matchArgs) + { + if (substitute == null) throw new NullSubstituteReferenceException(); - var context = SubstitutionContext.Current; - return new WhenCalled(context, substitute, action, matchArgs); - } + var context = SubstitutionContext.Current; + return new WhenCalled(context, substitute, action, matchArgs); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ArgDoFromMatcher.cs b/tests/NSubstitute.Acceptance.Specs/ArgDoFromMatcher.cs index e62b9a5a6..cd49cc265 100644 --- a/tests/NSubstitute.Acceptance.Specs/ArgDoFromMatcher.cs +++ b/tests/NSubstitute.Acceptance.Specs/ArgDoFromMatcher.cs @@ -1,140 +1,139 @@ using NSubstitute.ClearExtensions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class ArgDoFromMatcher { - public class ArgDoFromMatcher + private readonly object _someObject = new object(); + private IFoo _sub; + + public interface IFoo + { + void Bar(string a, int b, object c); + int Zap(object c); + void MethodWithRef(ref int arg); + void MethodWithOut(out int arg); + } + + [SetUp] + public void SetUp() + { + _sub = Substitute.For(); + } + + [Test] + public void Should_do_with_argument_as_directed_and_if_pain_persists_see_your_coder() + { + string stringArg = null; + _sub.Bar(Arg.Do(x => stringArg = x), 1, _someObject); + + _sub.Bar("hello world", 1, _someObject); + + Assert.That(stringArg, Is.EqualTo("hello world")); + } + + [Test] + public void Setting_an_argument_do_should_not_count_as_a_call() { - private readonly object _someObject = new object(); - private IFoo _sub; - - public interface IFoo - { - void Bar(string a, int b, object c); - int Zap(object c); - void MethodWithRef(ref int arg); - void MethodWithOut(out int arg); - } - - [SetUp] - public void SetUp() - { - _sub = Substitute.For(); - } - - [Test] - public void Should_do_with_argument_as_directed_and_if_pain_persists_see_your_coder() - { - string stringArg = null; - _sub.Bar(Arg.Do(x => stringArg = x), 1, _someObject); - - _sub.Bar("hello world", 1, _someObject); - - Assert.That(stringArg, Is.EqualTo("hello world")); - } - - [Test] - public void Setting_an_argument_do_should_not_count_as_a_call() - { - string stringArg = null; - _sub.Bar(Arg.Do(x => stringArg = x), 1, _someObject); - - _sub.DidNotReceiveWithAnyArgs().Bar(null, 0, null); - Assert.That(stringArg, Is.Null); - } - - [Test] - public void Should_call_action_with_each_matching_call() - { - var stringArgs = new List(); - _sub.Bar(Arg.Do(x => stringArgs.Add(x)), 1, _someObject); - - _sub.Bar("hello", 1, _someObject); - _sub.Bar("world", 1, _someObject); - _sub.Bar("don't use this because call doesn't match", -123, _someObject); - - Assert.That(stringArgs, Is.EqualTo(new[] { "hello", "world" })); - } - - [Test] - public void Arg_do_with_when_for_any_args() - { - string stringArg = null; - _sub.WhenForAnyArgs(x => x.Bar(Arg.Do(arg => stringArg = arg), 1, _someObject)).Do(x => { }); - - _sub.Bar("hello world", 42, null); - - Assert.That(stringArg, Is.EqualTo("hello world")); - } - - [Test] - public void Arg_do_when_action_requires_more_specific_type_should_only_run_action_when_arg_is_of_compatible_type() - { - string stringArg = null; - _sub.Zap(Arg.Do(arg => stringArg = arg)); - - _sub.Zap("hello world"); - _sub.Zap(new object()); - - Assert.That(stringArg, Is.EqualTo("hello world")); - } - - [Test] - public void Arg_do_with_returns_for_any_args() - { - var stringArgLength = 0; - _sub.Zap(Arg.Do(arg => stringArgLength = arg.Length)).ReturnsForAnyArgs(1); - - _sub.Zap(new object()); - Assert.That(stringArgLength, Is.EqualTo(0)); - - _sub.Zap("hello"); - Assert.That(stringArgLength, Is.EqualTo("hello".Length)); - } - - [Test] - public void Override_arg_do_subclass_with_returns_for_any_args() - { - var stringArgLength = 0; - _sub.Zap(Arg.Do(arg => stringArgLength = arg.Length)).ReturnsForAnyArgs(1); - - var result = _sub.Zap(new object()); - Assert.That(stringArgLength, Is.EqualTo(0)); - Assert.That(result, Is.EqualTo(1)); - } - - [Test] - public void Should_be_cleared_on_ClearCallActions() - { - var count = 0; - _sub.Zap(Arg.Do(arg => count++)); - _sub.ClearSubstitute(ClearOptions.CallActions); - _sub.Zap(""); - Assert.That(count, Is.EqualTo(0)); - } - - [Test] - public void Should_run_action_with_ref_argument() - { - int captured = 0; - _sub.MethodWithRef(ref Arg.Do(x => captured = x)); - - int arg = 42; - _sub.MethodWithRef(ref arg); - - Assert.That(captured, Is.EqualTo(42)); - } - - [Test] - public void Should_run_action_with_out_argument() - { - int captured = 0; - _sub.MethodWithOut(out Arg.Do(x => captured = x)); - - int arg = 42; - _sub.MethodWithOut(out arg); - - Assert.That(captured, Is.EqualTo(42)); - } + string stringArg = null; + _sub.Bar(Arg.Do(x => stringArg = x), 1, _someObject); + + _sub.DidNotReceiveWithAnyArgs().Bar(null, 0, null); + Assert.That(stringArg, Is.Null); + } + + [Test] + public void Should_call_action_with_each_matching_call() + { + var stringArgs = new List(); + _sub.Bar(Arg.Do(x => stringArgs.Add(x)), 1, _someObject); + + _sub.Bar("hello", 1, _someObject); + _sub.Bar("world", 1, _someObject); + _sub.Bar("don't use this because call doesn't match", -123, _someObject); + + Assert.That(stringArgs, Is.EqualTo(new[] { "hello", "world" })); + } + + [Test] + public void Arg_do_with_when_for_any_args() + { + string stringArg = null; + _sub.WhenForAnyArgs(x => x.Bar(Arg.Do(arg => stringArg = arg), 1, _someObject)).Do(x => { }); + + _sub.Bar("hello world", 42, null); + + Assert.That(stringArg, Is.EqualTo("hello world")); + } + + [Test] + public void Arg_do_when_action_requires_more_specific_type_should_only_run_action_when_arg_is_of_compatible_type() + { + string stringArg = null; + _sub.Zap(Arg.Do(arg => stringArg = arg)); + + _sub.Zap("hello world"); + _sub.Zap(new object()); + + Assert.That(stringArg, Is.EqualTo("hello world")); + } + + [Test] + public void Arg_do_with_returns_for_any_args() + { + var stringArgLength = 0; + _sub.Zap(Arg.Do(arg => stringArgLength = arg.Length)).ReturnsForAnyArgs(1); + + _sub.Zap(new object()); + Assert.That(stringArgLength, Is.EqualTo(0)); + + _sub.Zap("hello"); + Assert.That(stringArgLength, Is.EqualTo("hello".Length)); + } + + [Test] + public void Override_arg_do_subclass_with_returns_for_any_args() + { + var stringArgLength = 0; + _sub.Zap(Arg.Do(arg => stringArgLength = arg.Length)).ReturnsForAnyArgs(1); + + var result = _sub.Zap(new object()); + Assert.That(stringArgLength, Is.EqualTo(0)); + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void Should_be_cleared_on_ClearCallActions() + { + var count = 0; + _sub.Zap(Arg.Do(arg => count++)); + _sub.ClearSubstitute(ClearOptions.CallActions); + _sub.Zap(""); + Assert.That(count, Is.EqualTo(0)); + } + + [Test] + public void Should_run_action_with_ref_argument() + { + int captured = 0; + _sub.MethodWithRef(ref Arg.Do(x => captured = x)); + + int arg = 42; + _sub.MethodWithRef(ref arg); + + Assert.That(captured, Is.EqualTo(42)); + } + + [Test] + public void Should_run_action_with_out_argument() + { + int captured = 0; + _sub.MethodWithOut(out Arg.Do(x => captured = x)); + + int arg = 42; + _sub.MethodWithOut(out arg); + + Assert.That(captured, Is.EqualTo(42)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ArgumentInvocationFromMatchers.cs b/tests/NSubstitute.Acceptance.Specs/ArgumentInvocationFromMatchers.cs index 996db2b95..372a450e8 100644 --- a/tests/NSubstitute.Acceptance.Specs/ArgumentInvocationFromMatchers.cs +++ b/tests/NSubstitute.Acceptance.Specs/ArgumentInvocationFromMatchers.cs @@ -1,273 +1,272 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class ArgumentInvocationFromMatchers { - public class ArgumentInvocationFromMatchers + public delegate void ActionCompatibleDelegate(int i); + public interface IFoo + { + void MethodWithCallback(string something, Action callback); + void MethodWithCallbackWithArguments(string something, Action callback); + void MethodWithCallbackWithArguments(string something, Action callback); + void MethodWithCallbackWithArguments(string something, Action callback); + void MethodWithCallbackWithArguments(string something, Action callback); + void MethodWithDelegateCallback(string something, ActionCompatibleDelegate callback); + int MethodWithCallbackWithArgumentsAndReturnValue(string something, Action callback); + void MethodWithRefCallback(string something, ref Action callback); + void MethodWithRefCallbackWithArguments(string something, ref Action callback); + void MethodWithRefDelegateCallback(string something, ref ActionCompatibleDelegate callback); + } + + [Test] + public void Invoke_callback_from_matcher() + { + var action = Substitute.For(); + var sub = Substitute.For(); + sub.MethodWithCallback("test", Arg.Invoke()); + + sub.MethodWithCallback("test", action); + + action.Received().Invoke(); + sub.Received().MethodWithCallback("test", action); + } + + [Test] + public void Invoke_ref_callback_from_matcher() + { + var action = Substitute.For(); + var sub = Substitute.For(); + sub.MethodWithRefCallback("test", ref Arg.Invoke()); + + sub.MethodWithRefCallback("test", ref action); + + action.Received().Invoke(); + sub.Received().MethodWithRefCallback("test", ref action); + } + + [Test] + public void Invoke_callback_with_arguments() + { + var sub = Substitute.For(); + + var action1 = Substitute.For>(); + sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1)); + sub.MethodWithCallbackWithArguments("test", action1); + action1.Received().Invoke(1); + sub.Received().MethodWithCallbackWithArguments("test", action1); + } + + [Test] + public void Invoke_ref_callback_with_arguments() + { + var sub = Substitute.For(); + + var action1 = Substitute.For>(); + sub.MethodWithRefCallbackWithArguments("test", ref Arg.Invoke(1)); + sub.MethodWithRefCallbackWithArguments("test", ref action1); + action1.Received().Invoke(1); + sub.Received().MethodWithRefCallbackWithArguments("test", ref action1); + } + [Test] + public void Invoke_callback_with_two_arguments() + { + var sub = Substitute.For(); + var action2 = Substitute.For>(); + sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello")); + sub.MethodWithCallbackWithArguments("test", action2); + action2.Received().Invoke(1, "hello"); + sub.Received().MethodWithCallbackWithArguments("test", action2); + } + + [Test] + public void Invoke_callback_with_three_arguments() + { + var sub = Substitute.For(); + var action3 = Substitute.For>(); + sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello", 3.14)); + sub.MethodWithCallbackWithArguments("test", action3); + action3.Received().Invoke(1, "hello", 3.14); + sub.Received().MethodWithCallbackWithArguments("test", action3); + } + + [Test] + public void Invoke_callback_with_four_arguments() + { + var sub = Substitute.For(); + var action4 = Substitute.For>(); + sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello", 3.14, '!')); + sub.MethodWithCallbackWithArguments("test", action4); + action4.Received().Invoke(1, "hello", 3.14, '!'); + sub.Received().MethodWithCallbackWithArguments("test", action4); + } + + [Test] + public void Invoke_callback_with_argument_using_specific_delegate_type() + { + var action = Substitute.For>(); + var sub = Substitute.For(); + sub.MethodWithCallbackWithArguments("test", Arg.InvokeDelegate>(1, "hello")); + + sub.MethodWithCallbackWithArguments("test", action); + + action.Received().Invoke(1, "hello"); + sub.Received().MethodWithCallbackWithArguments("test", action); + } + + [Test] + public void Invoke_delegate_callback() + { + var action = Substitute.For>(); + ActionCompatibleDelegate @delegate = x => action(x); + var sub = Substitute.For(); + sub.MethodWithDelegateCallback("test", Arg.InvokeDelegate(1)); + + sub.MethodWithDelegateCallback("test", @delegate); + + action.Received().Invoke(1); + sub.Received().MethodWithDelegateCallback("test", @delegate); + } + + [Test] + public void Invoke_ref_delegate_callback() + { + var action = Substitute.For>(); + ActionCompatibleDelegate @delegate = x => action(x); + var sub = Substitute.For(); + sub.MethodWithRefDelegateCallback("test", ref Arg.InvokeDelegate(1)); + + sub.MethodWithRefDelegateCallback("test", ref @delegate); + + action.Received().Invoke(1); + sub.Received().MethodWithRefDelegateCallback("test", ref @delegate); + } + + [Test] + public void Call_with_invoke_matcher_should_not_count_as_a_received_call() + { + var sub = Substitute.For(); + + sub.MethodWithCallback("test", Arg.Invoke()); + + sub.DidNotReceiveWithAnyArgs().MethodWithCallback(null, null); + } + + [Test] + public void Invoke_callback_as_well_as_return_a_value_for_call() + { + const int expectedReturnValue = 42; + var sub = Substitute.For(); + var action = Substitute.For>(); + sub.MethodWithCallbackWithArgumentsAndReturnValue("test", Arg.Invoke(1, "hello")).Returns(expectedReturnValue); + + var result = sub.MethodWithCallbackWithArgumentsAndReturnValue("test", action); + + action.Received().Invoke(1, "hello"); + Assert.That(result, Is.EqualTo(expectedReturnValue)); + } + + [Test] + public void Set_return_for_any_args_should_invoke_callback_when_args_do_not_match() + { + const int expectedReturnValue = 42; + var sub = Substitute.For(); + var action = Substitute.For>(); + sub + .MethodWithCallbackWithArgumentsAndReturnValue("test", Arg.Invoke(1, "hello")) + .ReturnsForAnyArgs(expectedReturnValue); + + var result = sub.MethodWithCallbackWithArgumentsAndReturnValue("different arg", action); + + action.Received().Invoke(1, "hello"); + Assert.That(result, Is.EqualTo(expectedReturnValue)); + } + + [Test] + public void Invoke_callback_and_set_return_for_any_arguments() + { + const int expectedReturnValue = 42; + var sub = Substitute.For(); + var action = Substitute.For>(); + sub + .MethodWithCallbackWithArgumentsAndReturnValue("test", Arg.Invoke(1, "hello")) + .ReturnsForAnyArgs(expectedReturnValue); + + var result = sub.MethodWithCallbackWithArgumentsAndReturnValue("test", action); + + action.Received().Invoke(1, "hello"); + Assert.That(result, Is.EqualTo(expectedReturnValue)); + } + + [Test] + public void Invoke_callback_using_when_do() + { + var sub = Substitute.For(); + var action = Substitute.For>(); + sub.When(x => x.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello"))).Do(x => { }); + + sub.MethodWithCallbackWithArguments("test", action); + + action.Received().Invoke(1, "hello"); + } + + [Test] + public void Invoke_callback_using_when_for_any_args_do() + { + var sub = Substitute.For(); + var action = Substitute.For>(); + sub.WhenForAnyArgs(x => x.MethodWithCallbackWithArguments(null, Arg.Invoke(1, "hello"))).Do(x => { }); + + sub.MethodWithCallbackWithArguments("something else", action); + action.Received().Invoke(1, "hello"); + } + + [Test] + public void Invoke_multiple_callbacks() + { + var action = Substitute.For>(); + var sub = Substitute.For(); + sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello")); + sub.MethodWithCallbackWithArguments("test", Arg.Invoke(2, "bye")); + + sub.MethodWithCallbackWithArguments("test", action); + + action.Received().Invoke(1, "hello"); + action.Received().Invoke(2, "bye"); + Assert.That(action.ReceivedCalls().Count(), Is.EqualTo(2)); + sub.Received().MethodWithCallbackWithArguments("test", action); + Assert.That(sub.ReceivedCalls().Count(), Is.EqualTo(1)); + } + + [Test] + public void Insanity_test() + { + var result = -1; + var sub = Substitute.For(); + var actions = new[] { Substitute.For>(), Substitute.For>(), Substitute.For>() }; + + sub.WhenForAnyArgs(x => x.MethodWithCallbackWithArgumentsAndReturnValue(null, Arg.Invoke(1, "que?"))).Do(x => { }); + sub.MethodWithCallbackWithArgumentsAndReturnValue("hello", Arg.Invoke(2, "hello")).ReturnsForAnyArgs(2); + sub.MethodWithCallbackWithArgumentsAndReturnValue("bye", Arg.Invoke(3, "bye")).Returns(3); + sub.MethodWithCallbackWithArgumentsAndReturnValue("hmm", Arg.Any>()).Returns(4); + + result = sub.MethodWithCallbackWithArgumentsAndReturnValue("something else", actions[0]); + Assert.That(result, Is.EqualTo(2)); + actions[0].Received().Invoke(1, "que?"); + actions[0].Received().Invoke(2, "hello"); + Assert.That(actions[0].ReceivedCalls().Count(), Is.EqualTo(2)); + ClearAllCalls(actions); + + result = sub.MethodWithCallbackWithArgumentsAndReturnValue("bye", actions[0]); + Assert.That(result, Is.EqualTo(3)); + actions[0].Received().Invoke(1, "que?"); + actions[0].Received().Invoke(2, "hello"); + actions[0].Received().Invoke(3, "bye"); + ClearAllCalls(actions); + } + + private void ClearAllCalls(IEnumerable subs) { - public delegate void ActionCompatibleDelegate(int i); - public interface IFoo - { - void MethodWithCallback(string something, Action callback); - void MethodWithCallbackWithArguments(string something, Action callback); - void MethodWithCallbackWithArguments(string something, Action callback); - void MethodWithCallbackWithArguments(string something, Action callback); - void MethodWithCallbackWithArguments(string something, Action callback); - void MethodWithDelegateCallback(string something, ActionCompatibleDelegate callback); - int MethodWithCallbackWithArgumentsAndReturnValue(string something, Action callback); - void MethodWithRefCallback(string something, ref Action callback); - void MethodWithRefCallbackWithArguments(string something, ref Action callback); - void MethodWithRefDelegateCallback(string something, ref ActionCompatibleDelegate callback); - } - - [Test] - public void Invoke_callback_from_matcher() - { - var action = Substitute.For(); - var sub = Substitute.For(); - sub.MethodWithCallback("test", Arg.Invoke()); - - sub.MethodWithCallback("test", action); - - action.Received().Invoke(); - sub.Received().MethodWithCallback("test", action); - } - - [Test] - public void Invoke_ref_callback_from_matcher() - { - var action = Substitute.For(); - var sub = Substitute.For(); - sub.MethodWithRefCallback("test", ref Arg.Invoke()); - - sub.MethodWithRefCallback("test", ref action); - - action.Received().Invoke(); - sub.Received().MethodWithRefCallback("test", ref action); - } - - [Test] - public void Invoke_callback_with_arguments() - { - var sub = Substitute.For(); - - var action1 = Substitute.For>(); - sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1)); - sub.MethodWithCallbackWithArguments("test", action1); - action1.Received().Invoke(1); - sub.Received().MethodWithCallbackWithArguments("test", action1); - } - - [Test] - public void Invoke_ref_callback_with_arguments() - { - var sub = Substitute.For(); - - var action1 = Substitute.For>(); - sub.MethodWithRefCallbackWithArguments("test", ref Arg.Invoke(1)); - sub.MethodWithRefCallbackWithArguments("test", ref action1); - action1.Received().Invoke(1); - sub.Received().MethodWithRefCallbackWithArguments("test", ref action1); - } - [Test] - public void Invoke_callback_with_two_arguments() - { - var sub = Substitute.For(); - var action2 = Substitute.For>(); - sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello")); - sub.MethodWithCallbackWithArguments("test", action2); - action2.Received().Invoke(1, "hello"); - sub.Received().MethodWithCallbackWithArguments("test", action2); - } - - [Test] - public void Invoke_callback_with_three_arguments() - { - var sub = Substitute.For(); - var action3 = Substitute.For>(); - sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello", 3.14)); - sub.MethodWithCallbackWithArguments("test", action3); - action3.Received().Invoke(1, "hello", 3.14); - sub.Received().MethodWithCallbackWithArguments("test", action3); - } - - [Test] - public void Invoke_callback_with_four_arguments() - { - var sub = Substitute.For(); - var action4 = Substitute.For>(); - sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello", 3.14, '!')); - sub.MethodWithCallbackWithArguments("test", action4); - action4.Received().Invoke(1, "hello", 3.14, '!'); - sub.Received().MethodWithCallbackWithArguments("test", action4); - } - - [Test] - public void Invoke_callback_with_argument_using_specific_delegate_type() - { - var action = Substitute.For>(); - var sub = Substitute.For(); - sub.MethodWithCallbackWithArguments("test", Arg.InvokeDelegate>(1, "hello")); - - sub.MethodWithCallbackWithArguments("test", action); - - action.Received().Invoke(1, "hello"); - sub.Received().MethodWithCallbackWithArguments("test", action); - } - - [Test] - public void Invoke_delegate_callback() - { - var action = Substitute.For>(); - ActionCompatibleDelegate @delegate = x => action(x); - var sub = Substitute.For(); - sub.MethodWithDelegateCallback("test", Arg.InvokeDelegate(1)); - - sub.MethodWithDelegateCallback("test", @delegate); - - action.Received().Invoke(1); - sub.Received().MethodWithDelegateCallback("test", @delegate); - } - - [Test] - public void Invoke_ref_delegate_callback() - { - var action = Substitute.For>(); - ActionCompatibleDelegate @delegate = x => action(x); - var sub = Substitute.For(); - sub.MethodWithRefDelegateCallback("test", ref Arg.InvokeDelegate(1)); - - sub.MethodWithRefDelegateCallback("test", ref @delegate); - - action.Received().Invoke(1); - sub.Received().MethodWithRefDelegateCallback("test", ref @delegate); - } - - [Test] - public void Call_with_invoke_matcher_should_not_count_as_a_received_call() - { - var sub = Substitute.For(); - - sub.MethodWithCallback("test", Arg.Invoke()); - - sub.DidNotReceiveWithAnyArgs().MethodWithCallback(null, null); - } - - [Test] - public void Invoke_callback_as_well_as_return_a_value_for_call() - { - const int expectedReturnValue = 42; - var sub = Substitute.For(); - var action = Substitute.For>(); - sub.MethodWithCallbackWithArgumentsAndReturnValue("test", Arg.Invoke(1, "hello")).Returns(expectedReturnValue); - - var result = sub.MethodWithCallbackWithArgumentsAndReturnValue("test", action); - - action.Received().Invoke(1, "hello"); - Assert.That(result, Is.EqualTo(expectedReturnValue)); - } - - [Test] - public void Set_return_for_any_args_should_invoke_callback_when_args_do_not_match() - { - const int expectedReturnValue = 42; - var sub = Substitute.For(); - var action = Substitute.For>(); - sub - .MethodWithCallbackWithArgumentsAndReturnValue("test", Arg.Invoke(1, "hello")) - .ReturnsForAnyArgs(expectedReturnValue); - - var result = sub.MethodWithCallbackWithArgumentsAndReturnValue("different arg", action); - - action.Received().Invoke(1, "hello"); - Assert.That(result, Is.EqualTo(expectedReturnValue)); - } - - [Test] - public void Invoke_callback_and_set_return_for_any_arguments() - { - const int expectedReturnValue = 42; - var sub = Substitute.For(); - var action = Substitute.For>(); - sub - .MethodWithCallbackWithArgumentsAndReturnValue("test", Arg.Invoke(1, "hello")) - .ReturnsForAnyArgs(expectedReturnValue); - - var result = sub.MethodWithCallbackWithArgumentsAndReturnValue("test", action); - - action.Received().Invoke(1, "hello"); - Assert.That(result, Is.EqualTo(expectedReturnValue)); - } - - [Test] - public void Invoke_callback_using_when_do() - { - var sub = Substitute.For(); - var action = Substitute.For>(); - sub.When(x => x.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello"))).Do(x => { }); - - sub.MethodWithCallbackWithArguments("test", action); - - action.Received().Invoke(1, "hello"); - } - - [Test] - public void Invoke_callback_using_when_for_any_args_do() - { - var sub = Substitute.For(); - var action = Substitute.For>(); - sub.WhenForAnyArgs(x => x.MethodWithCallbackWithArguments(null, Arg.Invoke(1, "hello"))).Do(x => { }); - - sub.MethodWithCallbackWithArguments("something else", action); - action.Received().Invoke(1, "hello"); - } - - [Test] - public void Invoke_multiple_callbacks() - { - var action = Substitute.For>(); - var sub = Substitute.For(); - sub.MethodWithCallbackWithArguments("test", Arg.Invoke(1, "hello")); - sub.MethodWithCallbackWithArguments("test", Arg.Invoke(2, "bye")); - - sub.MethodWithCallbackWithArguments("test", action); - - action.Received().Invoke(1, "hello"); - action.Received().Invoke(2, "bye"); - Assert.That(action.ReceivedCalls().Count(), Is.EqualTo(2)); - sub.Received().MethodWithCallbackWithArguments("test", action); - Assert.That(sub.ReceivedCalls().Count(), Is.EqualTo(1)); - } - - [Test] - public void Insanity_test() - { - var result = -1; - var sub = Substitute.For(); - var actions = new[] { Substitute.For>(), Substitute.For>(), Substitute.For>() }; - - sub.WhenForAnyArgs(x => x.MethodWithCallbackWithArgumentsAndReturnValue(null, Arg.Invoke(1, "que?"))).Do(x => { }); - sub.MethodWithCallbackWithArgumentsAndReturnValue("hello", Arg.Invoke(2, "hello")).ReturnsForAnyArgs(2); - sub.MethodWithCallbackWithArgumentsAndReturnValue("bye", Arg.Invoke(3, "bye")).Returns(3); - sub.MethodWithCallbackWithArgumentsAndReturnValue("hmm", Arg.Any>()).Returns(4); - - result = sub.MethodWithCallbackWithArgumentsAndReturnValue("something else", actions[0]); - Assert.That(result, Is.EqualTo(2)); - actions[0].Received().Invoke(1, "que?"); - actions[0].Received().Invoke(2, "hello"); - Assert.That(actions[0].ReceivedCalls().Count(), Is.EqualTo(2)); - ClearAllCalls(actions); - - result = sub.MethodWithCallbackWithArgumentsAndReturnValue("bye", actions[0]); - Assert.That(result, Is.EqualTo(3)); - actions[0].Received().Invoke(1, "que?"); - actions[0].Received().Invoke(2, "hello"); - actions[0].Received().Invoke(3, "bye"); - ClearAllCalls(actions); - } - - private void ClearAllCalls(IEnumerable subs) - { - foreach (var sub in subs) { sub.ClearReceivedCalls(); } - } + foreach (var sub in subs) { sub.ClearReceivedCalls(); } } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ArgumentMatching.cs b/tests/NSubstitute.Acceptance.Specs/ArgumentMatching.cs index 7e4f29b44..63468c3d1 100644 --- a/tests/NSubstitute.Acceptance.Specs/ArgumentMatching.cs +++ b/tests/NSubstitute.Acceptance.Specs/ArgumentMatching.cs @@ -4,746 +4,745 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +[TestFixture] +public class ArgumentMatching { - [TestFixture] - public class ArgumentMatching - { - private ISomething _something; + private ISomething _something; - [Test] - public void Return_result_for_any_argument() - { - _something.Echo(Arg.Any()).Returns("anything"); + [Test] + public void Return_result_for_any_argument() + { + _something.Echo(Arg.Any()).Returns("anything"); - Assert.That(_something.Echo(1), Is.EqualTo("anything"), "First return"); - Assert.That(_something.Echo(2), Is.EqualTo("anything"), "Second return"); - } + Assert.That(_something.Echo(1), Is.EqualTo("anything"), "First return"); + Assert.That(_something.Echo(2), Is.EqualTo("anything"), "Second return"); + } - [Test] - public void Return_result_for_specific_argument() - { - _something.Echo(Arg.Is(3)).Returns("three"); - _something.Echo(4).Returns("four"); + [Test] + public void Return_result_for_specific_argument() + { + _something.Echo(Arg.Is(3)).Returns("three"); + _something.Echo(4).Returns("four"); - Assert.That(_something.Echo(3), Is.EqualTo("three"), "First return"); - Assert.That(_something.Echo(4), Is.EqualTo("four"), "Second return"); - } + Assert.That(_something.Echo(3), Is.EqualTo("three"), "First return"); + Assert.That(_something.Echo(4), Is.EqualTo("four"), "Second return"); + } - [Test] - public void Return_result_for_argument_matching_predicate() - { - _something.Echo(Arg.Is(x => x <= 3)).Returns("small"); - _something.Echo(Arg.Is(x => x > 3)).Returns("big"); + [Test] + public void Return_result_for_argument_matching_predicate() + { + _something.Echo(Arg.Is(x => x <= 3)).Returns("small"); + _something.Echo(Arg.Is(x => x > 3)).Returns("big"); - Assert.That(_something.Echo(1), Is.EqualTo("small"), "First return"); - Assert.That(_something.Echo(4), Is.EqualTo("big"), "Second return"); - } + Assert.That(_something.Echo(1), Is.EqualTo("small"), "First return"); + Assert.That(_something.Echo(4), Is.EqualTo("big"), "Second return"); + } - [Test] - public void Should_not_match_when_arg_matcher_throws() - { - _something.Say(Arg.Is(x => x.Length < 2)).Returns("?"); + [Test] + public void Should_not_match_when_arg_matcher_throws() + { + _something.Say(Arg.Is(x => x.Length < 2)).Returns("?"); - Assert.That(_something.Say("e"), Is.EqualTo("?")); - Assert.That(_something.Say("eh"), Is.EqualTo(string.Empty)); - Assert.That(_something.Say(null), Is.EqualTo(string.Empty)); - } + Assert.That(_something.Say("e"), Is.EqualTo("?")); + Assert.That(_something.Say("eh"), Is.EqualTo(string.Empty)); + Assert.That(_something.Say(null), Is.EqualTo(string.Empty)); + } - [Test] - public void Should_match_value_types_by_content() - { - const int intToMatch = 123; - const int identicalInt = 123; - _something.Echo(Arg.Is(intToMatch)).Returns("matching int"); + [Test] + public void Should_match_value_types_by_content() + { + const int intToMatch = 123; + const int identicalInt = 123; + _something.Echo(Arg.Is(intToMatch)).Returns("matching int"); - Assert.That(_something.Echo(intToMatch), Is.EqualTo("matching int")); - Assert.That(_something.Echo(identicalInt), Is.EqualTo("matching int")); + Assert.That(_something.Echo(intToMatch), Is.EqualTo("matching int")); + Assert.That(_something.Echo(identicalInt), Is.EqualTo("matching int")); - var dateToMatch = new DateTime(2021, 10, 22); - var identicalDate = new DateTime(2021, 10, 22); - _something.Anything(dateToMatch).Returns(20211022); + var dateToMatch = new DateTime(2021, 10, 22); + var identicalDate = new DateTime(2021, 10, 22); + _something.Anything(dateToMatch).Returns(20211022); - Assert.That(_something.Anything(dateToMatch), Is.EqualTo(20211022)); - Assert.That(_something.Anything(identicalDate), Is.EqualTo(20211022)); - } + Assert.That(_something.Anything(dateToMatch), Is.EqualTo(20211022)); + Assert.That(_something.Anything(identicalDate), Is.EqualTo(20211022)); + } - [Test] - public void Should_match_strings_by_content() - { - const string stringToMatch = "hello"; - _something.Say(Arg.Is(stringToMatch)).Returns("hi"); + [Test] + public void Should_match_strings_by_content() + { + const string stringToMatch = "hello"; + _something.Say(Arg.Is(stringToMatch)).Returns("hi"); - Assert.That(_something.Say(stringToMatch), Is.EqualTo("hi")); - Assert.That(_something.Say("hello"), Is.EqualTo("hi")); - } + Assert.That(_something.Say(stringToMatch), Is.EqualTo("hi")); + Assert.That(_something.Say("hello"), Is.EqualTo("hi")); + } - [Test] - public void Should_match_nullable_ref_types_by_content() - { + [Test] + public void Should_match_nullable_ref_types_by_content() + { #nullable enable - SomeClass? nullClassToMatch = null; - List? nullList = null; - _something.Anything(Arg.Is(nullClassToMatch)).Returns(456); + SomeClass? nullClassToMatch = null; + List? nullList = null; + _something.Anything(Arg.Is(nullClassToMatch)).Returns(456); - Assert.That(_something.Anything(nullClassToMatch), Is.EqualTo(456)); - Assert.That(_something.Anything(nullList), Is.EqualTo(456)); + Assert.That(_something.Anything(nullClassToMatch), Is.EqualTo(456)); + Assert.That(_something.Anything(nullList), Is.EqualTo(456)); #nullable disable - } + } - [Test] - public void Should_match_non_string_non_record_ref_types_by_reference() - { - var listToMatch = new List { 1, 2 }; - _something.Anything(Arg.Is(listToMatch)).Returns(123); + [Test] + public void Should_match_non_string_non_record_ref_types_by_reference() + { + var listToMatch = new List { 1, 2 }; + _something.Anything(Arg.Is(listToMatch)).Returns(123); - Assert.That(_something.Anything(listToMatch), Is.EqualTo(123)); - Assert.That(_something.Anything(new List { 1, 2 }), Is.EqualTo(0)); + Assert.That(_something.Anything(listToMatch), Is.EqualTo(123)); + Assert.That(_something.Anything(new List { 1, 2 }), Is.EqualTo(0)); - var classToMatch = new SomeClass(); - _something.Anything(Arg.Is(classToMatch)).Returns(456); + var classToMatch = new SomeClass(); + _something.Anything(Arg.Is(classToMatch)).Returns(456); - Assert.That(_something.Anything(classToMatch), Is.EqualTo(456)); - Assert.That(_something.Anything(new SomeClass()), Is.EqualTo(0)); - } + Assert.That(_something.Anything(classToMatch), Is.EqualTo(456)); + Assert.That(_something.Anything(new SomeClass()), Is.EqualTo(0)); + } - [Test] - public void Return_result_with_only_one_matcher_for_that_type() - { - _something.Funky(Arg.Any(), 12, "Lots", null).Returns(42); + [Test] + public void Return_result_with_only_one_matcher_for_that_type() + { + _something.Funky(Arg.Any(), 12, "Lots", null).Returns(42); - Assert.That(_something.Funky(123.456f, 12, "Lots", null), Is.EqualTo(42)); - Assert.That(_something.Funky(0.0f, 12, "Lots", null), Is.EqualTo(42)); - Assert.That(_something.Funky(0.0f, 11, "Lots", null), Is.EqualTo(0)); - } + Assert.That(_something.Funky(123.456f, 12, "Lots", null), Is.EqualTo(42)); + Assert.That(_something.Funky(0.0f, 12, "Lots", null), Is.EqualTo(42)); + Assert.That(_something.Funky(0.0f, 11, "Lots", null), Is.EqualTo(0)); + } - [Test] - public void Return_result_for_property_argument() - { - _something.SomeProperty = 2; - _something.Echo(_something.SomeProperty).Returns("two"); + [Test] + public void Return_result_for_property_argument() + { + _something.SomeProperty = 2; + _something.Echo(_something.SomeProperty).Returns("two"); - Assert.That(_something.Echo(1), Is.EqualTo(""), "First return"); - Assert.That(_something.Echo(2), Is.EqualTo("two"), "Second return"); - } + Assert.That(_something.Echo(1), Is.EqualTo(""), "First return"); + Assert.That(_something.Echo(2), Is.EqualTo("two"), "Second return"); + } - [Test] - public void Received_for_any_argument() - { - _something.Echo(7); + [Test] + public void Received_for_any_argument() + { + _something.Echo(7); - _something.Received().Echo(Arg.Any()); - } + _something.Received().Echo(Arg.Any()); + } - [Test] - public void Received_for_specific_argument() - { - _something.Echo(3); + [Test] + public void Received_for_specific_argument() + { + _something.Echo(3); - _something.Received().Echo(Arg.Is(3)); - } + _something.Received().Echo(Arg.Is(3)); + } - [Test] - public void Received_for_argument_matching_predicate() - { - _something.Echo(7); + [Test] + public void Received_for_argument_matching_predicate() + { + _something.Echo(7); - _something.Received().Echo(Arg.Is(x => x > 3)); - } + _something.Received().Echo(Arg.Is(x => x > 3)); + } - [Test] - public void Received_for_only_one_matcher_for_that_type() - { - _something.Funky(123.456f, 12, "Lots", null); + [Test] + public void Received_for_only_one_matcher_for_that_type() + { + _something.Funky(123.456f, 12, "Lots", null); - _something.Received().Funky(Arg.Any(), 12, "Lots", null); - } + _something.Received().Funky(Arg.Any(), 12, "Lots", null); + } - [Test] - public void Received_for_async_method_can_be_awaited() - { - TestReceivedAsync().Wait(); - } + [Test] + public void Received_for_async_method_can_be_awaited() + { + TestReceivedAsync().Wait(); + } - private async System.Threading.Tasks.Task TestReceivedAsync() - { - await _something.Async(); - await _something.Received().Async(); - } + private async System.Threading.Tasks.Task TestReceivedAsync() + { + await _something.Async(); + await _something.Received().Async(); + } - [Test] - public void DidNotReceive_for_async_method_can_be_awaited() - { - TestDidNotReceiveAsync().Wait(); - } + [Test] + public void DidNotReceive_for_async_method_can_be_awaited() + { + TestDidNotReceiveAsync().Wait(); + } - private async System.Threading.Tasks.Task TestDidNotReceiveAsync() - { - await _something.DidNotReceive().Async(); - } + private async System.Threading.Tasks.Task TestDidNotReceiveAsync() + { + await _something.DidNotReceive().Async(); + } - [Test] - public void Resolve_potentially_ambiguous_matches_by_checking_for_non_default_argument_values() - { - _something.Add(10, Arg.Any()).Returns(1); + [Test] + public void Resolve_potentially_ambiguous_matches_by_checking_for_non_default_argument_values() + { + _something.Add(10, Arg.Any()).Returns(1); - Assert.That(_something.Add(10, 5), Is.EqualTo(1)); - } + Assert.That(_something.Add(10, 5), Is.EqualTo(1)); + } - [Test] - public void Received_should_compare_elements_for_params_arguments() - { - const string first = "first"; - const string second = "second"; - _something.WithParams(1, first, second); - - _something.Received().WithParams(1, first, second); - _something.Received().WithParams(1, Arg.Any(), second); - _something.Received().WithParams(1, first, Arg.Any()); - _something.Received().WithParams(1, new[] { first, second }); - _something.Received().WithParams(1, Arg.Any()); - _something.Received().WithParams(1, Arg.Is(x => x.Length == 2)); - _something.DidNotReceive().WithParams(2, first, second); - _something.DidNotReceive().WithParams(2, first, Arg.Any()); - _something.DidNotReceive().WithParams(1, first, first); - _something.DidNotReceive().WithParams(1, null); - _something.DidNotReceive().WithParams(1, Arg.Is(x => x.Length > 3)); - } - - [Test] - public void Should_allow_to_specify_any_for_ref_argument() - { - _something.MethodWithRefParameter(Arg.Any(), ref Arg.Any()).Returns(42); + [Test] + public void Received_should_compare_elements_for_params_arguments() + { + const string first = "first"; + const string second = "second"; + _something.WithParams(1, first, second); + + _something.Received().WithParams(1, first, second); + _something.Received().WithParams(1, Arg.Any(), second); + _something.Received().WithParams(1, first, Arg.Any()); + _something.Received().WithParams(1, new[] { first, second }); + _something.Received().WithParams(1, Arg.Any()); + _something.Received().WithParams(1, Arg.Is(x => x.Length == 2)); + _something.DidNotReceive().WithParams(2, first, second); + _something.DidNotReceive().WithParams(2, first, Arg.Any()); + _something.DidNotReceive().WithParams(1, first, first); + _something.DidNotReceive().WithParams(1, null); + _something.DidNotReceive().WithParams(1, Arg.Is(x => x.Length > 3)); + } - var refArg = 10; - var result = _something.MethodWithRefParameter(0, ref refArg); - Assert.That(result, Is.EqualTo(42)); - } + [Test] + public void Should_allow_to_specify_any_for_ref_argument() + { + _something.MethodWithRefParameter(Arg.Any(), ref Arg.Any()).Returns(42); - [Test] - public void Should_allow_to_specify_exact_is_for_ref_argument() - { - _something.MethodWithRefParameter(Arg.Any(), ref Arg.Is(24)).Returns(42); - - var refArg = 24; - var matchingResult = _something.MethodWithRefParameter(0, ref refArg); - refArg = 10; - var nonMatchingResult = _something.MethodWithRefParameter(0, ref refArg); - Assert.That(matchingResult, Is.EqualTo(42)); - Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); - } - - [Test] - public void Should_allow_to_specify_is_expression_for_ref_argument() - { - _something.MethodWithRefParameter(Arg.Any(), ref Arg.Is(x => x == 24)).Returns(42); - - var refArg = 24; - var matchingResult = _something.MethodWithRefParameter(0, ref refArg); - refArg = 10; - var nonMatchingResult = _something.MethodWithRefParameter(0, ref refArg); - Assert.That(matchingResult, Is.EqualTo(42)); - Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); - } - - [Test] - public void Should_allow_to_specify_any_for_out_argument() - { - _something.MethodWithOutParameter(Arg.Any(), out Arg.Any()).Returns(42); + var refArg = 10; + var result = _something.MethodWithRefParameter(0, ref refArg); + Assert.That(result, Is.EqualTo(42)); + } - var outArg = 10; - var result1 = _something.MethodWithOutParameter(0, out outArg); - var result2 = _something.MethodWithOutParameter(0, out int _); - Assert.That(result1, Is.EqualTo(42)); - Assert.That(result2, Is.EqualTo(42)); - } + [Test] + public void Should_allow_to_specify_exact_is_for_ref_argument() + { + _something.MethodWithRefParameter(Arg.Any(), ref Arg.Is(24)).Returns(42); + + var refArg = 24; + var matchingResult = _something.MethodWithRefParameter(0, ref refArg); + refArg = 10; + var nonMatchingResult = _something.MethodWithRefParameter(0, ref refArg); + Assert.That(matchingResult, Is.EqualTo(42)); + Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); + } - [Test] - public void Should_allow_to_specify_exact_is_for_out_argument() - { - _something.MethodWithOutParameter(Arg.Any(), out Arg.Is(24)).Returns(42); + [Test] + public void Should_allow_to_specify_is_expression_for_ref_argument() + { + _something.MethodWithRefParameter(Arg.Any(), ref Arg.Is(x => x == 24)).Returns(42); + + var refArg = 24; + var matchingResult = _something.MethodWithRefParameter(0, ref refArg); + refArg = 10; + var nonMatchingResult = _something.MethodWithRefParameter(0, ref refArg); + Assert.That(matchingResult, Is.EqualTo(42)); + Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); + } - var outArg = 24; - var matchingResult = _something.MethodWithOutParameter(0, out outArg); - var nonMatchingResult = _something.MethodWithOutParameter(0, out int _); - Assert.That(matchingResult, Is.EqualTo(42)); - Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); - } + [Test] + public void Should_allow_to_specify_any_for_out_argument() + { + _something.MethodWithOutParameter(Arg.Any(), out Arg.Any()).Returns(42); - [Test] - public void Should_allow_to_specify_is_expression_for_out_argument() - { - _something.MethodWithOutParameter(Arg.Any(), out Arg.Is(x => x == 24)).Returns(42); + var outArg = 10; + var result1 = _something.MethodWithOutParameter(0, out outArg); + var result2 = _something.MethodWithOutParameter(0, out int _); + Assert.That(result1, Is.EqualTo(42)); + Assert.That(result2, Is.EqualTo(42)); + } + + [Test] + public void Should_allow_to_specify_exact_is_for_out_argument() + { + _something.MethodWithOutParameter(Arg.Any(), out Arg.Is(24)).Returns(42); - var outArg = 24; - var matchingResult = _something.MethodWithOutParameter(0, out outArg); - var nonMatchingResult = _something.MethodWithOutParameter(0, out int _); - Assert.That(matchingResult, Is.EqualTo(42)); - Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); - } + var outArg = 24; + var matchingResult = _something.MethodWithOutParameter(0, out outArg); + var nonMatchingResult = _something.MethodWithOutParameter(0, out int _); + Assert.That(matchingResult, Is.EqualTo(42)); + Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); + } - [Test] - public void Should_allow_to_check_received_using_properties_from_other_substitutes() - { - // Arrange - var otherSubs = Substitute.For(); - otherSubs.SomeProperty.Returns(42); + [Test] + public void Should_allow_to_specify_is_expression_for_out_argument() + { + _something.MethodWithOutParameter(Arg.Any(), out Arg.Is(x => x == 24)).Returns(42); + + var outArg = 24; + var matchingResult = _something.MethodWithOutParameter(0, out outArg); + var nonMatchingResult = _something.MethodWithOutParameter(0, out int _); + Assert.That(matchingResult, Is.EqualTo(42)); + Assert.That(nonMatchingResult, Is.Not.EqualTo(42)); + } - // Act - _something.Echo(42); + [Test] + public void Should_allow_to_check_received_using_properties_from_other_substitutes() + { + // Arrange + var otherSubs = Substitute.For(); + otherSubs.SomeProperty.Returns(42); - // Assert - _something.Received().Echo(otherSubs.SomeProperty); - } + // Act + _something.Echo(42); - [Test] - public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v1() - { - Assert.Throws(() => - { - _something.Add(0, Arg.Any()).Returns(1); - Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + - "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); - }); - } - - [Test] - public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v2() + // Assert + _something.Received().Echo(otherSubs.SomeProperty); + } + + [Test] + public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v1() + { + Assert.Throws(() => + { + _something.Add(0, Arg.Any()).Returns(1); + Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + + "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); + }); + } + + [Test] + public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v2() + { + Assert.Throws(() => { - Assert.Throws(() => - { - _something.MethodWithRefParameter(0, ref Arg.Any()).Returns(42); - Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + - "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); - }); - } - - [Test] - public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v3() + _something.MethodWithRefParameter(0, ref Arg.Any()).Returns(42); + Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + + "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); + }); + } + + [Test] + public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v3() + { + Assert.Throws(() => { - Assert.Throws(() => - { - int defValue = 0; - _something.MethodWithMultipleRefParameters(42, ref defValue, ref Arg.Any()).Returns(42); - Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + - "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); - }); - } - - [Test] - public void Should_add_list_of_all_pending_specifications_to_ambiguous_exception_message() + int defValue = 0; + _something.MethodWithMultipleRefParameters(42, ref defValue, ref Arg.Any()).Returns(42); + Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + + "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); + }); + } + + [Test] + public void Should_add_list_of_all_pending_specifications_to_ambiguous_exception_message() + { + var exception = Assert.Throws(() => { - var exception = Assert.Throws(() => - { - _something.Add(0, Arg.Is(42)).Returns(1); - }); + _something.Add(0, Arg.Is(42)).Returns(1); + }); - Assert.That(exception.Message, Contains.Substring("42")); - } + Assert.That(exception.Message, Contains.Substring("42")); + } - [Test] - public void Returns_should_work_with_params() - { - _something.WithParams(Arg.Any(), Arg.Is(x => x == "one")).Returns("fred"); + [Test] + public void Returns_should_work_with_params() + { + _something.WithParams(Arg.Any(), Arg.Is(x => x == "one")).Returns("fred"); - Assert.That(_something.WithParams(1, "one"), Is.EqualTo("fred")); - } + Assert.That(_something.WithParams(1, "one"), Is.EqualTo("fred")); + } - [Test] - public void Resolve_setter_arg_matcher_with_more_specific_type_than_member_signature() - { - const string value = "some string"; - const string key = "key"; + [Test] + public void Resolve_setter_arg_matcher_with_more_specific_type_than_member_signature() + { + const string value = "some string"; + const string key = "key"; - _something[key] = value; + _something[key] = value; - _something.Received()[key] = Arg.Is(value); - } + _something.Received()[key] = Arg.Is(value); + } - [Test] - public void Resolve_argument_matcher_for_more_specific_type() - { - _something.Anything("Hello"); - _something.Received().Anything(Arg.Any()); - _something.DidNotReceive().Anything(Arg.Any()); - } + [Test] + public void Resolve_argument_matcher_for_more_specific_type() + { + _something.Anything("Hello"); + _something.Received().Anything(Arg.Any()); + _something.DidNotReceive().Anything(Arg.Any()); + } - [Test] - public void Set_returns_using_more_specific_type_matcher() - { - _something.Anything(Arg.Is(x => x.Contains("world"))).Returns(123); + [Test] + public void Set_returns_using_more_specific_type_matcher() + { + _something.Anything(Arg.Is(x => x.Contains("world"))).Returns(123); - Assert.That(_something.Anything("Hello world!"), Is.EqualTo(123)); - Assert.That(_something.Anything("Howdy"), Is.EqualTo(0)); - Assert.That(_something.Anything(2), Is.EqualTo(0)); - } + Assert.That(_something.Anything("Hello world!"), Is.EqualTo(123)); + Assert.That(_something.Anything("Howdy"), Is.EqualTo(0)); + Assert.That(_something.Anything(2), Is.EqualTo(0)); + } - [Test] - public void Override_subclass_arg_matcher_when_returning_for_any_args() - { - _something.Anything(Arg.Any()).ReturnsForAnyArgs(123); + [Test] + public void Override_subclass_arg_matcher_when_returning_for_any_args() + { + _something.Anything(Arg.Any()).ReturnsForAnyArgs(123); - Assert.That(_something.Anything(new object()), Is.EqualTo(123)); - } + Assert.That(_something.Anything(new object()), Is.EqualTo(123)); + } - [Test] - public void Nullable_args_null_value() - { - _something.WithNullableArg(Arg.Any()).ReturnsForAnyArgs(123); + [Test] + public void Nullable_args_null_value() + { + _something.WithNullableArg(Arg.Any()).ReturnsForAnyArgs(123); - Assert.That(_something.WithNullableArg(null), Is.EqualTo(123)); - } + Assert.That(_something.WithNullableArg(null), Is.EqualTo(123)); + } - [Test] - public void Nullable_args_notnull_value() - { - _something.WithNullableArg(Arg.Any()).ReturnsForAnyArgs(123); + [Test] + public void Nullable_args_notnull_value() + { + _something.WithNullableArg(Arg.Any()).ReturnsForAnyArgs(123); - Assert.That(_something.WithNullableArg(234), Is.EqualTo(123)); - } + Assert.That(_something.WithNullableArg(234), Is.EqualTo(123)); + } - public interface IMethodsWithParamsArgs - { - int GetValue(int primary, params int[] others); - } + public interface IMethodsWithParamsArgs + { + int GetValue(int primary, params int[] others); + } - [Test] - public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_1() + [Test] + public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_1() + { + var target = Substitute.For(); + + Assert.Throws(() => { - var target = Substitute.For(); + target.GetValue(0, Arg.Any()).Returns(42); + }); + } - Assert.Throws(() => - { - target.GetValue(0, Arg.Any()).Returns(42); - }); - } + [Test] + public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_2() + { + var target = Substitute.For(); - [Test] - public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_2() + Assert.Throws(() => { - var target = Substitute.For(); + target.GetValue(Arg.Any(), 0).Returns(42); + }); + } - Assert.Throws(() => - { - target.GetValue(Arg.Any(), 0).Returns(42); - }); - } + [Test] + public void Should_correctly_use_matchers_crossing_the_params_boundary() + { + var target = Substitute.For(); + target.GetValue(Arg.Is(0), Arg.Any()).Returns(42); - [Test] - public void Should_correctly_use_matchers_crossing_the_params_boundary() - { - var target = Substitute.For(); - target.GetValue(Arg.Is(0), Arg.Any()).Returns(42); + var result = target.GetValue(0, 100); - var result = target.GetValue(0, 100); + Assert.That(result, Is.EqualTo(42)); + } - Assert.That(result, Is.EqualTo(42)); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_1() + { + // This spec will be ignored, however it's good to let user know that test might not work how he expects. + Arg.Is(42); - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_1() + Assert.Throws(() => { - // This spec will be ignored, however it's good to let user know that test might not work how he expects. - Arg.Is(42); + _something.Echo(10); + }); + } - Assert.Throws(() => - { - _something.Echo(10); - }); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_2() + { + // This one will be used instead of Arg.Any<>(), causing the confusion. + Arg.Is(42); - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_2() + Assert.Throws(() => { - // This one will be used instead of Arg.Any<>(), causing the confusion. - Arg.Is(42); + _something.Echo(Arg.Any()); + }); + } - Assert.Throws(() => - { - _something.Echo(Arg.Any()); - }); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_3() + { + // This spec will be ignored, however it's good to let user know that test might not work how he expects. + Arg.Is(42); - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_3() + var ex = Assert.Throws(() => { - // This spec will be ignored, however it's good to let user know that test might not work how he expects. - Arg.Is(42); - - var ex = Assert.Throws(() => - { - _something.SomeProperty = 24; - }); - Assert.That(ex.Message, Contains.Substring("42")); - } - - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_4() - { - _something.SomeProperty = 2; - // This spec will be ignored, however it's good to let user know that test might not work how he expects. - Arg.Is(42); - - var ex = Assert.Throws(() => - { - _something.Echo(_something.SomeProperty); - }); - Assert.That(ex.Message, Contains.Substring("42")); - } - - [Test] - public void Redundant_argument_matcher_exception_should_contain_list_of_all_matchers() - { - Arg.Is(42); + _something.SomeProperty = 24; + }); + Assert.That(ex.Message, Contains.Substring("42")); + } - var ex = Assert.Throws(() => { _something.Echo(Arg.Is(24)); }); - Assert.That(ex.Message, Contains.Substring("42")); - Assert.That(ex.Message, Contains.Substring("24")); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_4() + { + _something.SomeProperty = 2; + // This spec will be ignored, however it's good to let user know that test might not work how he expects. + Arg.Is(42); - [Test] - public void Should_fail_with_redundant_exceptions_if_arg_matchers_misused() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + _something.Echo(_something.SomeProperty); + }); + Assert.That(ex.Message, Contains.Substring("42")); + } - var misused = Arg.Is("test"); + [Test] + public void Redundant_argument_matcher_exception_should_contain_list_of_all_matchers() + { + Arg.Is(42); - Assert.Throws(() => - { - foo.Echo(2).Returns("42"); - }); - } + var ex = Assert.Throws(() => { _something.Echo(Arg.Is(24)); }); + Assert.That(ex.Message, Contains.Substring("42")); + Assert.That(ex.Message, Contains.Substring("24")); + } - public interface IInterfaceForAmbiguous - { - int MultipleMixedArgs(int arg1, double arg2, int arg3, double arg4); - int ParamsArgs(int arg1, int arg2, params int[] rest); - int GenericMethod(T arg1, T arg2); - int MethodWithRefAndOut(int arg1, int arg2, ref int refArg, out bool outArg); - int this[int key1, int key2] { get; } - } - - [Test] - public void Should_show_already_resolved_matchers_in_ambiguous_exception_v1() - { - var foo = Substitute.For(); + [Test] + public void Should_fail_with_redundant_exceptions_if_arg_matchers_misused() + { + var foo = Substitute.For(); - var ex = Assert.Throws(() => - { - foo.MultipleMixedArgs(Arg.Any(), Arg.Any(), 0, 0d).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(any Int32, any Double, ???, ???")); - } + var misused = Arg.Is("test"); - [Test] - public void Should_show_already_resolved_matchers_in_ambiguous_exception_v2() + Assert.Throws(() => { - var foo = Substitute.For(); + foo.Echo(2).Returns("42"); + }); + } - var ex = Assert.Throws(() => - { - foo.MultipleMixedArgs(42, Arg.Any(), 123, 0d).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(42, any Double, 123, ???)")); - } + public interface IInterfaceForAmbiguous + { + int MultipleMixedArgs(int arg1, double arg2, int arg3, double arg4); + int ParamsArgs(int arg1, int arg2, params int[] rest); + int GenericMethod(T arg1, T arg2); + int MethodWithRefAndOut(int arg1, int arg2, ref int refArg, out bool outArg); + int this[int key1, int key2] { get; } + } + + [Test] + public void Should_show_already_resolved_matchers_in_ambiguous_exception_v1() + { + var foo = Substitute.For(); - [Test] - public void Should_show_question_marks_for_non_resolved_matchers_in_ambiguous_exception() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.MultipleMixedArgs(Arg.Any(), Arg.Any(), 0, 0d).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(any Int32, any Double, ???, ???")); + } - var ex = Assert.Throws(() => - { - foo.MultipleMixedArgs(Arg.Any(), Arg.Any(), 0, 0).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(any Int32, any Double, ???, ???)")); - } + [Test] + public void Should_show_already_resolved_matchers_in_ambiguous_exception_v2() + { + var foo = Substitute.For(); - [Test] - public void Should_show_question_mark_for_each_params_arg_in_ambiguous_exception_v1() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.MultipleMixedArgs(42, Arg.Any(), 123, 0d).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(42, any Double, 123, ???)")); + } - var ex = Assert.Throws(() => - { - foo.ParamsArgs(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), 0, 0).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("ParamsArgs(any Int32, any Int32, any Int32, any Int32, ???, ???)")); - } + [Test] + public void Should_show_question_marks_for_non_resolved_matchers_in_ambiguous_exception() + { + var foo = Substitute.For(); - [Test] - public void Should_show_question_mark_for_each_params_arg_in_ambiguous_exception_v2() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.MultipleMixedArgs(Arg.Any(), Arg.Any(), 0, 0).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(any Int32, any Double, ???, ???)")); + } - var ex = Assert.Throws(() => - { - foo.ParamsArgs(Arg.Any(), Arg.Any(), 0).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("ParamsArgs(any Int32, any Int32, ???)")); - } + [Test] + public void Should_show_question_mark_for_each_params_arg_in_ambiguous_exception_v1() + { + var foo = Substitute.For(); - [Test] - public void Should_show_generic_types_for_question_mark_line_in_ambiguous_exception() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.ParamsArgs(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), 0, 0).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("ParamsArgs(any Int32, any Int32, any Int32, any Int32, ???, ???)")); + } - var ex = Assert.Throws(() => - { - foo.GenericMethod(null, Arg.Any>>()).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("GenericMethod>>(any IEnumerable>, ???)")); - } + [Test] + public void Should_show_question_mark_for_each_params_arg_in_ambiguous_exception_v2() + { + var foo = Substitute.For(); - [Test] - public void Should_show_method_signature_in_ambiguous_exception_v1() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.ParamsArgs(Arg.Any(), Arg.Any(), 0).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("ParamsArgs(any Int32, any Int32, ???)")); + } - var ex = Assert.Throws(() => - { - foo.MultipleMixedArgs(0, 0d, Arg.Any(), Arg.Any()).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(Int32, Double, Int32, Double)")); - } + [Test] + public void Should_show_generic_types_for_question_mark_line_in_ambiguous_exception() + { + var foo = Substitute.For(); - [Test] - public void Should_show_method_signature_in_ambiguous_exception_v2() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); - - var ex = Assert.Throws(() => - { - int refValue = 42; - foo.MethodWithRefAndOut(0, Arg.Any(), ref refValue, out _).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("MethodWithRefAndOut(Int32, Int32, ref Int32, out Boolean)")); - } - - [Test] - public void Should_show_method_signature_in_ambiguous_exception_v3() + foo.GenericMethod(null, Arg.Any>>()).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("GenericMethod>>(any IEnumerable>, ???)")); + } + + [Test] + public void Should_show_method_signature_in_ambiguous_exception_v1() + { + var foo = Substitute.For(); + + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.MultipleMixedArgs(0, 0d, Arg.Any(), Arg.Any()).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(Int32, Double, Int32, Double)")); + } - var ex = Assert.Throws(() => - { - foo.ParamsArgs(0, Arg.Any()).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("ParamsArgs(Int32, Int32, params Int32[])")); - } + [Test] + public void Should_show_method_signature_in_ambiguous_exception_v2() + { + var foo = Substitute.For(); - [Test] - public void Should_show_generic_method_signature_in_ambiguous_exception() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + int refValue = 42; + foo.MethodWithRefAndOut(0, Arg.Any(), ref refValue, out _).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("MethodWithRefAndOut(Int32, Int32, ref Int32, out Boolean)")); + } - var ex = Assert.Throws(() => - { - foo.GenericMethod(null, Arg.Any>()).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("GenericMethod>(List, List)")); - } + [Test] + public void Should_show_method_signature_in_ambiguous_exception_v3() + { + var foo = Substitute.For(); - [Test] - public void Should_show_actual_method_arguments_in_ambiguous_exception_v1() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.ParamsArgs(0, Arg.Any()).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("ParamsArgs(Int32, Int32, params Int32[])")); + } - var ex = Assert.Throws(() => - { - foo.MultipleMixedArgs(0, 0d, Arg.Any(), Arg.Any()).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(*0*, *0*, *0*, *0*)")); - } + [Test] + public void Should_show_generic_method_signature_in_ambiguous_exception() + { + var foo = Substitute.For(); - [Test] - public void Should_show_actual_method_arguments_in_ambiguous_exception_v2() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.GenericMethod(null, Arg.Any>()).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("GenericMethod>(List, List)")); + } - var ex = Assert.Throws(() => - { - foo.ParamsArgs(42, 0, Arg.Any(), 15).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("ParamsArgs(42, *0*, *0*, 15)")); - } + [Test] + public void Should_show_actual_method_arguments_in_ambiguous_exception_v1() + { + var foo = Substitute.For(); - [Test] - public void Should_show_actual_generic_method_arguments_in_ambiguous_exception() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.MultipleMixedArgs(0, 0d, Arg.Any(), Arg.Any()).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("MultipleMixedArgs(*0*, *0*, *0*, *0*)")); + } - var ex = Assert.Throws(() => - { - foo.GenericMethod(null, Arg.Any>()).Returns(42); - }); - Assert.That(ex.Message, Does.Contain("GenericMethod>(**, **)")); - } + [Test] + public void Should_show_actual_method_arguments_in_ambiguous_exception_v2() + { + var foo = Substitute.For(); - [Test] - public void Show_correctly_format_indexer_call_in_ambiguous_exception() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + foo.ParamsArgs(42, 0, Arg.Any(), 15).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("ParamsArgs(42, *0*, *0*, 15)")); + } + + [Test] + public void Should_show_actual_generic_method_arguments_in_ambiguous_exception() + { + var foo = Substitute.For(); - var ex = Assert.Throws(() => - { - foo[0, Arg.Any()].Returns(42); - }); - Assert.That(ex.Message, Does.Contain("[any Int32, ???]")); - } + var ex = Assert.Throws(() => + { + foo.GenericMethod(null, Arg.Any>()).Returns(42); + }); + Assert.That(ex.Message, Does.Contain("GenericMethod>(**, **)")); + } - public delegate string DelegateWithOutParameter(string input, out string result); + [Test] + public void Show_correctly_format_indexer_call_in_ambiguous_exception() + { + var foo = Substitute.For(); - [Test] - public void Should_recognize_out_parameters_for_delegate_and_match_specification() + var ex = Assert.Throws(() => { - var subs = Substitute.For(); + foo[0, Arg.Any()].Returns(42); + }); + Assert.That(ex.Message, Does.Contain("[any Int32, ???]")); + } - subs.Invoke(Arg.Any(), out string _).Returns("42"); + public delegate string DelegateWithOutParameter(string input, out string result); - var result = subs("foo", out string _); - Assert.That(result, Is.EqualTo("42")); - } + [Test] + public void Should_recognize_out_parameters_for_delegate_and_match_specification() + { + var subs = Substitute.For(); - public class IsFortyTwo : IArgumentMatcher, IDescribeNonMatches - { - public static int Arg() => ArgumentMatcher.Enqueue(new IsFortyTwo()); + subs.Invoke(Arg.Any(), out string _).Returns("42"); - public bool IsSatisfiedBy(int argument) => argument == 42; + var result = subs("foo", out string _); + Assert.That(result, Is.EqualTo("42")); + } - public string DescribeFor(object argument) => $"{argument} is not forty two"; - } + public class IsFortyTwo : IArgumentMatcher, IDescribeNonMatches + { + public static int Arg() => ArgumentMatcher.Enqueue(new IsFortyTwo()); - [Test] - public void Supports_custom_argument_matchers() - { - var subs = Substitute.For(); + public bool IsSatisfiedBy(int argument) => argument == 42; - subs.Echo(IsFortyTwo.Arg()).Returns("42"); + public string DescribeFor(object argument) => $"{argument} is not forty two"; + } - var result = subs.Echo(42); - Assert.That(result, Is.EqualTo("42")); - } + [Test] + public void Supports_custom_argument_matchers() + { + var subs = Substitute.For(); - [Test] - public void Supports_custom_argument_matcher_descriptions() - { - var subs = Substitute.For(); + subs.Echo(IsFortyTwo.Arg()).Returns("42"); - subs.Echo(24); + var result = subs.Echo(42); + Assert.That(result, Is.EqualTo("42")); + } + + [Test] + public void Supports_custom_argument_matcher_descriptions() + { + var subs = Substitute.For(); - var ex = Assert.Throws(() => - { - // - subs.Received().Echo(IsFortyTwo.Arg()); - }); - Assert.That(ex.Message, Contains.Substring("24 is not forty two")); - } + subs.Echo(24); - [SetUp] - public void SetUp() + var ex = Assert.Throws(() => { - _something = Substitute.For(); - } + // + subs.Received().Echo(IsFortyTwo.Arg()); + }); + Assert.That(ex.Message, Contains.Substring("24 is not forty two")); + } + + [SetUp] + public void SetUp() + { + _something = Substitute.For(); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ArgumentMatchingCompat.cs b/tests/NSubstitute.Acceptance.Specs/ArgumentMatchingCompat.cs index 29835d6ab..08f68aadd 100644 --- a/tests/NSubstitute.Acceptance.Specs/ArgumentMatchingCompat.cs +++ b/tests/NSubstitute.Acceptance.Specs/ArgumentMatchingCompat.cs @@ -2,367 +2,366 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +[TestFixture] +public class ArgumentMatchingCompat { - [TestFixture] - public class ArgumentMatchingCompat + private ISomething _something; + + [Test] + public void Return_result_for_any_argument() { - private ISomething _something; + _something.Echo(Arg.Compat.Any()).Returns("anything"); - [Test] - public void Return_result_for_any_argument() - { - _something.Echo(Arg.Compat.Any()).Returns("anything"); + Assert.That(_something.Echo(1), Is.EqualTo("anything"), "First return"); + Assert.That(_something.Echo(2), Is.EqualTo("anything"), "Second return"); + } - Assert.That(_something.Echo(1), Is.EqualTo("anything"), "First return"); - Assert.That(_something.Echo(2), Is.EqualTo("anything"), "Second return"); - } + [Test] + public void Return_result_for_specific_argument() + { + _something.Echo(Arg.Compat.Is(3)).Returns("three"); + _something.Echo(4).Returns("four"); - [Test] - public void Return_result_for_specific_argument() - { - _something.Echo(Arg.Compat.Is(3)).Returns("three"); - _something.Echo(4).Returns("four"); + Assert.That(_something.Echo(3), Is.EqualTo("three"), "First return"); + Assert.That(_something.Echo(4), Is.EqualTo("four"), "Second return"); + } - Assert.That(_something.Echo(3), Is.EqualTo("three"), "First return"); - Assert.That(_something.Echo(4), Is.EqualTo("four"), "Second return"); - } + [Test] + public void Return_result_for_argument_matching_predicate() + { + _something.Echo(Arg.Compat.Is(x => x <= 3)).Returns("small"); + _something.Echo(Arg.Compat.Is(x => x > 3)).Returns("big"); - [Test] - public void Return_result_for_argument_matching_predicate() - { - _something.Echo(Arg.Compat.Is(x => x <= 3)).Returns("small"); - _something.Echo(Arg.Compat.Is(x => x > 3)).Returns("big"); + Assert.That(_something.Echo(1), Is.EqualTo("small"), "First return"); + Assert.That(_something.Echo(4), Is.EqualTo("big"), "Second return"); + } - Assert.That(_something.Echo(1), Is.EqualTo("small"), "First return"); - Assert.That(_something.Echo(4), Is.EqualTo("big"), "Second return"); - } + [Test] + public void Should_not_match_when_arg_matcher_throws() + { + _something.Say(Arg.Compat.Is(x => x.Length < 2)).Returns("?"); - [Test] - public void Should_not_match_when_arg_matcher_throws() - { - _something.Say(Arg.Compat.Is(x => x.Length < 2)).Returns("?"); + Assert.That(_something.Say("e"), Is.EqualTo("?")); + Assert.That(_something.Say("eh"), Is.EqualTo(string.Empty)); + Assert.That(_something.Say(null), Is.EqualTo(string.Empty)); + } - Assert.That(_something.Say("e"), Is.EqualTo("?")); - Assert.That(_something.Say("eh"), Is.EqualTo(string.Empty)); - Assert.That(_something.Say(null), Is.EqualTo(string.Empty)); - } + [Test] + public void Return_result_with_only_one_matcher_for_that_type() + { + _something.Funky(Arg.Compat.Any(), 12, "Lots", null).Returns(42); - [Test] - public void Return_result_with_only_one_matcher_for_that_type() - { - _something.Funky(Arg.Compat.Any(), 12, "Lots", null).Returns(42); + Assert.That(_something.Funky(123.456f, 12, "Lots", null), Is.EqualTo(42)); + Assert.That(_something.Funky(0.0f, 12, "Lots", null), Is.EqualTo(42)); + Assert.That(_something.Funky(0.0f, 11, "Lots", null), Is.EqualTo(0)); + } - Assert.That(_something.Funky(123.456f, 12, "Lots", null), Is.EqualTo(42)); - Assert.That(_something.Funky(0.0f, 12, "Lots", null), Is.EqualTo(42)); - Assert.That(_something.Funky(0.0f, 11, "Lots", null), Is.EqualTo(0)); - } + [Test] + public void Return_result_for_property_argument() + { + _something.SomeProperty = 2; + _something.Echo(_something.SomeProperty).Returns("two"); - [Test] - public void Return_result_for_property_argument() - { - _something.SomeProperty = 2; - _something.Echo(_something.SomeProperty).Returns("two"); + Assert.That(_something.Echo(1), Is.EqualTo(""), "First return"); + Assert.That(_something.Echo(2), Is.EqualTo("two"), "Second return"); + } - Assert.That(_something.Echo(1), Is.EqualTo(""), "First return"); - Assert.That(_something.Echo(2), Is.EqualTo("two"), "Second return"); - } + [Test] + public void Received_for_any_argument() + { + _something.Echo(7); - [Test] - public void Received_for_any_argument() - { - _something.Echo(7); + _something.Received().Echo(Arg.Compat.Any()); + } - _something.Received().Echo(Arg.Compat.Any()); - } + [Test] + public void Received_for_specific_argument() + { + _something.Echo(3); - [Test] - public void Received_for_specific_argument() - { - _something.Echo(3); + _something.Received().Echo(Arg.Compat.Is(3)); + } - _something.Received().Echo(Arg.Compat.Is(3)); - } + [Test] + public void Received_for_argument_matching_predicate() + { + _something.Echo(7); - [Test] - public void Received_for_argument_matching_predicate() - { - _something.Echo(7); + _something.Received().Echo(Arg.Compat.Is(x => x > 3)); + } - _something.Received().Echo(Arg.Compat.Is(x => x > 3)); - } + [Test] + public void Received_for_only_one_matcher_for_that_type() + { + _something.Funky(123.456f, 12, "Lots", null); - [Test] - public void Received_for_only_one_matcher_for_that_type() - { - _something.Funky(123.456f, 12, "Lots", null); + _something.Received().Funky(Arg.Compat.Any(), 12, "Lots", null); + } - _something.Received().Funky(Arg.Compat.Any(), 12, "Lots", null); - } + [Test] + public void Received_for_async_method_can_be_awaited() + { + TestReceivedAsync().Wait(); + } - [Test] - public void Received_for_async_method_can_be_awaited() - { - TestReceivedAsync().Wait(); - } + private async System.Threading.Tasks.Task TestReceivedAsync() + { + await _something.Async(); + await _something.Received().Async(); + } - private async System.Threading.Tasks.Task TestReceivedAsync() - { - await _something.Async(); - await _something.Received().Async(); - } + [Test] + public void DidNotReceive_for_async_method_can_be_awaited() + { + TestDidNotReceiveAsync().Wait(); + } - [Test] - public void DidNotReceive_for_async_method_can_be_awaited() - { - TestDidNotReceiveAsync().Wait(); - } + private async System.Threading.Tasks.Task TestDidNotReceiveAsync() + { + await _something.DidNotReceive().Async(); + } - private async System.Threading.Tasks.Task TestDidNotReceiveAsync() - { - await _something.DidNotReceive().Async(); - } + [Test] + public void Resolve_potentially_ambiguous_matches_by_checking_for_non_default_argument_values() + { + _something.Add(10, Arg.Compat.Any()).Returns(1); - [Test] - public void Resolve_potentially_ambiguous_matches_by_checking_for_non_default_argument_values() - { - _something.Add(10, Arg.Compat.Any()).Returns(1); + Assert.That(_something.Add(10, 5), Is.EqualTo(1)); + } - Assert.That(_something.Add(10, 5), Is.EqualTo(1)); - } + [Test] + public void Received_should_compare_elements_for_params_arguments() + { + const string first = "first"; + const string second = "second"; + _something.WithParams(1, first, second); + + _something.Received().WithParams(1, first, second); + _something.Received().WithParams(1, Arg.Compat.Any(), second); + _something.Received().WithParams(1, first, Arg.Compat.Any()); + _something.Received().WithParams(1, new[] { first, second }); + _something.Received().WithParams(1, Arg.Compat.Any()); + _something.Received().WithParams(1, Arg.Compat.Is(x => x.Length == 2)); + _something.DidNotReceive().WithParams(2, first, second); + _something.DidNotReceive().WithParams(2, first, Arg.Compat.Any()); + _something.DidNotReceive().WithParams(1, first, first); + _something.DidNotReceive().WithParams(1, null); + _something.DidNotReceive().WithParams(1, Arg.Compat.Is(x => x.Length > 3)); + } - [Test] - public void Received_should_compare_elements_for_params_arguments() - { - const string first = "first"; - const string second = "second"; - _something.WithParams(1, first, second); - - _something.Received().WithParams(1, first, second); - _something.Received().WithParams(1, Arg.Compat.Any(), second); - _something.Received().WithParams(1, first, Arg.Compat.Any()); - _something.Received().WithParams(1, new[] { first, second }); - _something.Received().WithParams(1, Arg.Compat.Any()); - _something.Received().WithParams(1, Arg.Compat.Is(x => x.Length == 2)); - _something.DidNotReceive().WithParams(2, first, second); - _something.DidNotReceive().WithParams(2, first, Arg.Compat.Any()); - _something.DidNotReceive().WithParams(1, first, first); - _something.DidNotReceive().WithParams(1, null); - _something.DidNotReceive().WithParams(1, Arg.Compat.Is(x => x.Length > 3)); - } - - [Test] - public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v1() - { - Assert.Throws(() => - { - _something.Add(0, Arg.Compat.Any()).Returns(1); - Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + - "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); - }); - } - - [Test] - public void Should_add_list_of_all_pending_specifications_to_ambiguous_exception_message() + [Test] + public void Throw_with_ambiguous_arguments_when_given_an_arg_matcher_and_a_default_arg_value_v1() + { + Assert.Throws(() => + { + _something.Add(0, Arg.Compat.Any()).Returns(1); + Assert.Fail("Should not make it here, as it can't work out which arg the matcher refers to." + + "If it does this will throw an AssertionException rather than AmbiguousArgumentsException."); + }); + } + + [Test] + public void Should_add_list_of_all_pending_specifications_to_ambiguous_exception_message() + { + var exception = Assert.Throws(() => { - var exception = Assert.Throws(() => - { - _something.Add(0, Arg.Compat.Is(42)).Returns(1); - }); + _something.Add(0, Arg.Compat.Is(42)).Returns(1); + }); - Assert.That(exception.Message, Contains.Substring("42")); - } + Assert.That(exception.Message, Contains.Substring("42")); + } - [Test] - public void Returns_should_work_with_params() - { - _something.WithParams(Arg.Compat.Any(), Arg.Compat.Is(x => x == "one")).Returns("fred"); + [Test] + public void Returns_should_work_with_params() + { + _something.WithParams(Arg.Compat.Any(), Arg.Compat.Is(x => x == "one")).Returns("fred"); - Assert.That(_something.WithParams(1, "one"), Is.EqualTo("fred")); - } + Assert.That(_something.WithParams(1, "one"), Is.EqualTo("fred")); + } - [Test] - public void Resolve_setter_arg_matcher_with_more_specific_type_than_member_signature() - { - const string value = "some string"; - const string key = "key"; + [Test] + public void Resolve_setter_arg_matcher_with_more_specific_type_than_member_signature() + { + const string value = "some string"; + const string key = "key"; - _something[key] = value; + _something[key] = value; - _something.Received()[key] = Arg.Compat.Is(value); - } + _something.Received()[key] = Arg.Compat.Is(value); + } - [Test] - public void Resolve_argument_matcher_for_more_specific_type() - { - _something.Anything("Hello"); - _something.Received().Anything(Arg.Compat.Any()); - _something.DidNotReceive().Anything(Arg.Compat.Any()); - } + [Test] + public void Resolve_argument_matcher_for_more_specific_type() + { + _something.Anything("Hello"); + _something.Received().Anything(Arg.Compat.Any()); + _something.DidNotReceive().Anything(Arg.Compat.Any()); + } - [Test] - public void Set_returns_using_more_specific_type_matcher() - { - _something.Anything(Arg.Compat.Is(x => x.Contains("world"))).Returns(123); + [Test] + public void Set_returns_using_more_specific_type_matcher() + { + _something.Anything(Arg.Compat.Is(x => x.Contains("world"))).Returns(123); - Assert.That(_something.Anything("Hello world!"), Is.EqualTo(123)); - Assert.That(_something.Anything("Howdy"), Is.EqualTo(0)); - Assert.That(_something.Anything(2), Is.EqualTo(0)); - } + Assert.That(_something.Anything("Hello world!"), Is.EqualTo(123)); + Assert.That(_something.Anything("Howdy"), Is.EqualTo(0)); + Assert.That(_something.Anything(2), Is.EqualTo(0)); + } - [Test] - public void Override_subclass_arg_matcher_when_returning_for_any_args() - { - _something.Anything(Arg.Compat.Any()).ReturnsForAnyArgs(123); + [Test] + public void Override_subclass_arg_matcher_when_returning_for_any_args() + { + _something.Anything(Arg.Compat.Any()).ReturnsForAnyArgs(123); - Assert.That(_something.Anything(new object()), Is.EqualTo(123)); - } + Assert.That(_something.Anything(new object()), Is.EqualTo(123)); + } - [Test] - public void Nullable_args_null_value() - { - _something.WithNullableArg(Arg.Compat.Any()).ReturnsForAnyArgs(123); + [Test] + public void Nullable_args_null_value() + { + _something.WithNullableArg(Arg.Compat.Any()).ReturnsForAnyArgs(123); - Assert.That(_something.WithNullableArg(null), Is.EqualTo(123)); - } + Assert.That(_something.WithNullableArg(null), Is.EqualTo(123)); + } - [Test] - public void Nullable_args_notnull_value() - { - _something.WithNullableArg(Arg.Compat.Any()).ReturnsForAnyArgs(123); + [Test] + public void Nullable_args_notnull_value() + { + _something.WithNullableArg(Arg.Compat.Any()).ReturnsForAnyArgs(123); - Assert.That(_something.WithNullableArg(234), Is.EqualTo(123)); - } + Assert.That(_something.WithNullableArg(234), Is.EqualTo(123)); + } - public interface IMethodsWithParamsArgs - { - int GetValue(int primary, params int[] others); - } + public interface IMethodsWithParamsArgs + { + int GetValue(int primary, params int[] others); + } + + [Test] + public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_1() + { + var target = Substitute.For(); - [Test] - public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_1() + Assert.Throws(() => { - var target = Substitute.For(); + target.GetValue(0, Arg.Compat.Any()).Returns(42); + }); + } - Assert.Throws(() => - { - target.GetValue(0, Arg.Compat.Any()).Returns(42); - }); - } + [Test] + public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_2() + { + var target = Substitute.For(); - [Test] - public void Should_fail_with_ambiguous_exception_if_params_boundary_is_crossed_scenario_2() + Assert.Throws(() => { - var target = Substitute.For(); + target.GetValue(Arg.Compat.Any(), 0).Returns(42); + }); + } - Assert.Throws(() => - { - target.GetValue(Arg.Compat.Any(), 0).Returns(42); - }); - } + [Test] + public void Should_correctly_use_matchers_crossing_the_params_boundary() + { + var target = Substitute.For(); + target.GetValue(Arg.Compat.Is(0), Arg.Compat.Any()).Returns(42); - [Test] - public void Should_correctly_use_matchers_crossing_the_params_boundary() - { - var target = Substitute.For(); - target.GetValue(Arg.Compat.Is(0), Arg.Compat.Any()).Returns(42); + var result = target.GetValue(0, 100); - var result = target.GetValue(0, 100); + Assert.That(result, Is.EqualTo(42)); + } - Assert.That(result, Is.EqualTo(42)); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_1() + { + // This spec will be ignored, however it's good to let user know that test might not work how he expects. + Arg.Compat.Is(42); - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_1() + Assert.Throws(() => { - // This spec will be ignored, however it's good to let user know that test might not work how he expects. - Arg.Compat.Is(42); + _something.Echo(10); + }); + } - Assert.Throws(() => - { - _something.Echo(10); - }); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_2() + { + // This one will be used instead of Arg.Compat.Any<>(), causing the confusion. + Arg.Compat.Is(42); - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_2() + Assert.Throws(() => { - // This one will be used instead of Arg.Compat.Any<>(), causing the confusion. - Arg.Compat.Is(42); + _something.Echo(Arg.Compat.Any()); + }); + } - Assert.Throws(() => - { - _something.Echo(Arg.Compat.Any()); - }); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_3() + { + // This spec will be ignored, however it's good to let user know that test might not work how he expects. + Arg.Compat.Is(42); - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_3() + var ex = Assert.Throws(() => { - // This spec will be ignored, however it's good to let user know that test might not work how he expects. - Arg.Compat.Is(42); - - var ex = Assert.Throws(() => - { - _something.SomeProperty = 24; - }); - Assert.That(ex.Message, Contains.Substring("42")); - } - - [Test] - public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_4() - { - _something.SomeProperty = 2; - // This spec will be ignored, however it's good to let user know that test might not work how he expects. - Arg.Compat.Is(42); - - var ex = Assert.Throws(() => - { - _something.Echo(_something.SomeProperty); - }); - Assert.That(ex.Message, Contains.Substring("42")); - } - - [Test] - public void Redundant_argument_matcher_exception_should_contain_list_of_all_matchers() - { - Arg.Compat.Is(42); + _something.SomeProperty = 24; + }); + Assert.That(ex.Message, Contains.Substring("42")); + } - var ex = Assert.Throws(() => { _something.Echo(Arg.Compat.Is(24)); }); - Assert.That(ex.Message, Contains.Substring("42")); - Assert.That(ex.Message, Contains.Substring("24")); - } + [Test] + public void Should_fail_with_redundant_exception_if_more_specifications_than_arguments_scenario_4() + { + _something.SomeProperty = 2; + // This spec will be ignored, however it's good to let user know that test might not work how he expects. + Arg.Compat.Is(42); - [Test] - public void Should_fail_with_redundant_exceptions_if_arg_matchers_misused() + var ex = Assert.Throws(() => { - var foo = Substitute.For(); + _something.Echo(_something.SomeProperty); + }); + Assert.That(ex.Message, Contains.Substring("42")); + } - var misused = Arg.Compat.Is("test"); + [Test] + public void Redundant_argument_matcher_exception_should_contain_list_of_all_matchers() + { + Arg.Compat.Is(42); - Assert.Throws(() => - { - foo.Echo(2).Returns("42"); - }); - } + var ex = Assert.Throws(() => { _something.Echo(Arg.Compat.Is(24)); }); + Assert.That(ex.Message, Contains.Substring("42")); + Assert.That(ex.Message, Contains.Substring("24")); + } - public delegate string DelegateWithOutParameter(string input, out string result); + [Test] + public void Should_fail_with_redundant_exceptions_if_arg_matchers_misused() + { + var foo = Substitute.For(); + + var misused = Arg.Compat.Is("test"); - [Test] - public void Should_recognize_out_parameters_for_delegate_and_match_specification() + Assert.Throws(() => { - var subs = Substitute.For(); - string _; - subs.Invoke(Arg.Compat.Any(), out _).Returns("42"); + foo.Echo(2).Returns("42"); + }); + } - var result = subs("foo", out _); - Assert.That(result, Is.EqualTo("42")); - } + public delegate string DelegateWithOutParameter(string input, out string result); - [SetUp] - public void SetUp() - { - _something = Substitute.For(); - } + [Test] + public void Should_recognize_out_parameters_for_delegate_and_match_specification() + { + var subs = Substitute.For(); + string _; + subs.Invoke(Arg.Compat.Any(), out _).Returns("42"); + + var result = subs("foo", out _); + Assert.That(result, Is.EqualTo("42")); + } + + [SetUp] + public void SetUp() + { + _something = Substitute.For(); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/AssemblySigningTest.cs b/tests/NSubstitute.Acceptance.Specs/AssemblySigningTest.cs index 0eb4ebca0..0b8f29d13 100644 --- a/tests/NSubstitute.Acceptance.Specs/AssemblySigningTest.cs +++ b/tests/NSubstitute.Acceptance.Specs/AssemblySigningTest.cs @@ -1,17 +1,16 @@ using System.Reflection; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class AssemblySigningTest { - public class AssemblySigningTest + [Test] + public void NSubstitute_assembly_should_be_signed() { - [Test] - public void NSubstitute_assembly_should_be_signed() - { - var assemblyName = typeof(Substitute).GetTypeInfo().Assembly.GetName(); - var publicKeyToken = string.Join("", assemblyName.GetPublicKeyToken().Select(x => x.ToString("x"))); + var assemblyName = typeof(Substitute).GetTypeInfo().Assembly.GetName(); + var publicKeyToken = string.Join("", assemblyName.GetPublicKeyToken().Select(x => x.ToString("x"))); - Assert.That(publicKeyToken, Is.EqualTo("92dd2e9066daa5ca")); - } + Assert.That(publicKeyToken, Is.EqualTo("92dd2e9066daa5ca")); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/AutoValuesForSubs.cs b/tests/NSubstitute.Acceptance.Specs/AutoValuesForSubs.cs index b8aa12468..45f2c6b59 100644 --- a/tests/NSubstitute.Acceptance.Specs/AutoValuesForSubs.cs +++ b/tests/NSubstitute.Acceptance.Specs/AutoValuesForSubs.cs @@ -1,249 +1,248 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class AutoValuesForSubs { - public class AutoValuesForSubs + private ISample _sample; + + public class PureVirtualClass { public virtual void Foo() { } } + public class NonVirtualClass { public void Bar() { } } + public sealed class SealedClass { } + delegate ISample SampleFactory(); + + public interface ISample { - private ISample _sample; + int[] GetNumbers(); + IEnumerable GetObjects(); + string Name { get; set; } + List ListOfStrings { get; set; } + int? GetNullableNumber(); + PureVirtualClass VirtualClass { get; set; } + NonVirtualClass NonVirtualClass { get; set; } + SealedClass SealedClass { get; set; } + IQueryable Queryable(); + } - public class PureVirtualClass { public virtual void Foo() { } } - public class NonVirtualClass { public void Bar() { } } - public sealed class SealedClass { } - delegate ISample SampleFactory(); + [SetUp] + public void SetUp() + { + _sample = Substitute.For(); + } - public interface ISample - { - int[] GetNumbers(); - IEnumerable GetObjects(); - string Name { get; set; } - List ListOfStrings { get; set; } - int? GetNullableNumber(); - PureVirtualClass VirtualClass { get; set; } - NonVirtualClass NonVirtualClass { get; set; } - SealedClass SealedClass { get; set; } - IQueryable Queryable(); - } + [Test] + public void Should_auto_return_empty_array() + { + Assert.That(_sample.GetNumbers().Length, Is.EqualTo(0)); + } - [SetUp] - public void SetUp() - { - _sample = Substitute.For(); - } + [Test] + public void Should_auto_return_empty_enumerable() + { + Assert.That(_sample.GetObjects(), Is.Not.Null); + Assert.That(_sample.GetObjects().Count(), Is.EqualTo(0)); + } - [Test] - public void Should_auto_return_empty_array() - { - Assert.That(_sample.GetNumbers().Length, Is.EqualTo(0)); - } + [Test] + public void Should_auto_return_empty_string() + { + Assert.That(_sample.Name.Length, Is.EqualTo(0)); + } - [Test] - public void Should_auto_return_empty_enumerable() - { - Assert.That(_sample.GetObjects(), Is.Not.Null); - Assert.That(_sample.GetObjects().Count(), Is.EqualTo(0)); - } + [Test] + public void Should_return_null_for_nullables() + { + Assert.That(_sample.GetNullableNumber(), Is.Null); + } - [Test] - public void Should_auto_return_empty_string() - { - Assert.That(_sample.Name.Length, Is.EqualTo(0)); - } + [Test] + public void Should_return_same_empty_value_for_auto_values_for_reference_types() + { + var autoArrayValue = _sample.GetNumbers(); + Assert.That(_sample.GetNumbers(), Is.SameAs(autoArrayValue)); + } - [Test] - public void Should_return_null_for_nullables() - { - Assert.That(_sample.GetNullableNumber(), Is.Null); - } + [Test] + public void Should_return_substitute_for_pure_virtual_class() + { + Assert.That(_sample.VirtualClass, Is.Not.Null); + } - [Test] - public void Should_return_same_empty_value_for_auto_values_for_reference_types() - { - var autoArrayValue = _sample.GetNumbers(); - Assert.That(_sample.GetNumbers(), Is.SameAs(autoArrayValue)); - } + [Test] + public void Should_return_default_value_for_non_virtual_class() + { + Assert.That(_sample.NonVirtualClass, Is.Null); + } - [Test] - public void Should_return_substitute_for_pure_virtual_class() - { - Assert.That(_sample.VirtualClass, Is.Not.Null); - } + [Test] + public void Should_return_default_value_for_sealed_class() + { + Assert.That(_sample.SealedClass, Is.Null); + } - [Test] - public void Should_return_default_value_for_non_virtual_class() - { - Assert.That(_sample.NonVirtualClass, Is.Null); - } + [Test] + [Pending, Explicit] + public void Should_auto_return_empty_string_list() + { + Assert.That(_sample.ListOfStrings, Is.Not.Null); + Assert.That(_sample.ListOfStrings.Count(), Is.EqualTo(0)); + } - [Test] - public void Should_return_default_value_for_sealed_class() - { - Assert.That(_sample.SealedClass, Is.Null); - } + [Test] + public void Should_auto_return_a_substitute_from_a_function_that_returns_an_interface() + { + var x = Substitute.For>(); + var returnedFromFunc = x(); + Assert.That(returnedFromFunc, Is.Not.Null); + AssertObjectIsASubstitute(returnedFromFunc); + } - [Test] - [Pending, Explicit] - public void Should_auto_return_empty_string_list() - { - Assert.That(_sample.ListOfStrings, Is.Not.Null); - Assert.That(_sample.ListOfStrings.Count(), Is.EqualTo(0)); - } + [Test] + public void Should_auto_return_an_empty_string_from_a_func_that_returns_a_string() + { + var x = Substitute.For>(); - [Test] - public void Should_auto_return_a_substitute_from_a_function_that_returns_an_interface() - { - var x = Substitute.For>(); - var returnedFromFunc = x(); - Assert.That(returnedFromFunc, Is.Not.Null); - AssertObjectIsASubstitute(returnedFromFunc); - } + Assert.That(x(_sample).Length, Is.EqualTo(0)); + } - [Test] - public void Should_auto_return_an_empty_string_from_a_func_that_returns_a_string() - { - var x = Substitute.For>(); + [Test] + public void Should_auto_return_for_iqueryable() + { + var sample = Substitute.For(); + Assert.IsEmpty(sample.Queryable().Select(x => x + 1).ToList()); + Assert.NotNull(sample.Queryable().Expression); + } - Assert.That(x(_sample).Length, Is.EqualTo(0)); - } + [Test] + public void Should_auto_return_a_substitute_from_a_func_that_returns_a_pure_virtual_class() + { + var x = Substitute.For>(); + var returnedFromFunc = x(); - [Test] - public void Should_auto_return_for_iqueryable() - { - var sample = Substitute.For(); - Assert.IsEmpty(sample.Queryable().Select(x => x + 1).ToList()); - Assert.NotNull(sample.Queryable().Expression); - } + Assert.That(returnedFromFunc, Is.Not.Null); + AssertObjectIsASubstitute(returnedFromFunc); + } - [Test] - public void Should_auto_return_a_substitute_from_a_func_that_returns_a_pure_virtual_class() - { - var x = Substitute.For>(); - var returnedFromFunc = x(); + [Test] + public void Should_not_auto_return_a_substitute_from_a_func_that_returns_a_non_virtual_class() + { + var x = Substitute.For>(); + var returnedFromFunc = x(); - Assert.That(returnedFromFunc, Is.Not.Null); - AssertObjectIsASubstitute(returnedFromFunc); - } + Assert.That(returnedFromFunc, Is.Null); + } - [Test] - public void Should_not_auto_return_a_substitute_from_a_func_that_returns_a_non_virtual_class() - { - var x = Substitute.For>(); - var returnedFromFunc = x(); + [Test] + public void Should_auto_return_a_substitute_from_a_delegate_that_returns_an_interface() + { + var x = Substitute.For(); - Assert.That(returnedFromFunc, Is.Null); - } + var returnedFromFunc = x(); - [Test] - public void Should_auto_return_a_substitute_from_a_delegate_that_returns_an_interface() - { - var x = Substitute.For(); + Assert.That(returnedFromFunc, Is.Not.Null); + AssertObjectIsASubstitute(returnedFromFunc); + } - var returnedFromFunc = x(); + [Test] + public void Should_auto_return_a_value_from_a_task() + { + var sub = Substitute.For(); + var task = sub.GetIntAsync(); + Assert.That(task.IsCompleted, Is.True); + Assert.That(task.Result, Is.EqualTo(0)); + } - Assert.That(returnedFromFunc, Is.Not.Null); - AssertObjectIsASubstitute(returnedFromFunc); - } + [Test] + public void Should_auto_return_an_autosub_from_a_task() + { + var sub = Substitute.For(); - [Test] - public void Should_auto_return_a_value_from_a_task() - { - var sub = Substitute.For(); - var task = sub.GetIntAsync(); - Assert.That(task.IsCompleted, Is.True); - Assert.That(task.Result, Is.EqualTo(0)); - } + var task = sub.GetSample(); - [Test] - public void Should_auto_return_an_autosub_from_a_task() - { - var sub = Substitute.For(); + Assert.That(task.IsCompleted, Is.True); + var sample = task.Result; + AssertObjectIsASubstitute(sample); + sample.Name = "test"; + Assert.That(sample.Name, Is.EqualTo("test")); + } - var task = sub.GetSample(); + [Test] + public void Should_auto_return_a_completed_non_generic_task() + { + var sub = Substitute.For(); + var task = sub.GetNonGenericTask(); + Assert.That(task.IsCompleted, Is.True); + } - Assert.That(task.IsCompleted, Is.True); - var sample = task.Result; - AssertObjectIsASubstitute(sample); - sample.Name = "test"; - Assert.That(sample.Name, Is.EqualTo("test")); - } + public interface IFooWithTasks + { + System.Threading.Tasks.Task GetSample(); + System.Threading.Tasks.Task GetIntAsync(); + System.Threading.Tasks.Task GetNonGenericTask(); + } - [Test] - public void Should_auto_return_a_completed_non_generic_task() - { - var sub = Substitute.For(); - var task = sub.GetNonGenericTask(); - Assert.That(task.IsCompleted, Is.True); - } + [Test] + public void Should_auto_return_an_observable() + { + var sub = Substitute.For(); + int sample = -42; + sub.GetInts().Subscribe(new AnonymousObserver(x => sample = x)); + Assert.That(sample, Is.EqualTo(0)); + } - public interface IFooWithTasks - { - System.Threading.Tasks.Task GetSample(); - System.Threading.Tasks.Task GetIntAsync(); - System.Threading.Tasks.Task GetNonGenericTask(); - } + [Test] + public void Should_auto_return_an_autosub_from_an_observable() + { + var sub = Substitute.For(); + ISample sample = null; + sub.GetSamples().Subscribe(new AnonymousObserver(x => sample = x)); + AssertObjectIsASubstitute(sample); - [Test] - public void Should_auto_return_an_observable() - { - var sub = Substitute.For(); - int sample = -42; - sub.GetInts().Subscribe(new AnonymousObserver(x => sample = x)); - Assert.That(sample, Is.EqualTo(0)); - } + sample.Name = "test"; + Assert.That(sample.Name, Is.EqualTo("test")); + } - [Test] - public void Should_auto_return_an_autosub_from_an_observable() - { - var sub = Substitute.For(); - ISample sample = null; - sub.GetSamples().Subscribe(new AnonymousObserver(x => sample = x)); - AssertObjectIsASubstitute(sample); + [Test] + public void Multiple_calls_to_observable_method() + { + var sub = Substitute.For(); + ISample sample1 = null; + ISample sample2 = null; + sub.GetSamples().Subscribe(new AnonymousObserver(x => sample1 = x)); + sub.GetSamples().Subscribe(new AnonymousObserver(x => sample2 = x)); + AssertObjectIsASubstitute(sample1); + AssertObjectIsASubstitute(sample2); + + Assert.That(sample1, Is.SameAs(sample2)); + } - sample.Name = "test"; - Assert.That(sample.Name, Is.EqualTo("test")); - } + public interface IFooWithObservable + { + IObservable GetInts(); + IObservable GetSamples(); + } - [Test] - public void Multiple_calls_to_observable_method() - { - var sub = Substitute.For(); - ISample sample1 = null; - ISample sample2 = null; - sub.GetSamples().Subscribe(new AnonymousObserver(x => sample1 = x)); - sub.GetSamples().Subscribe(new AnonymousObserver(x => sample2 = x)); - AssertObjectIsASubstitute(sample1); - AssertObjectIsASubstitute(sample2); - - Assert.That(sample1, Is.SameAs(sample2)); - } + //Copied from NSubstitute.Specs.AnonymousObserver (PR #137) + private class AnonymousObserver : IObserver + { + Action _onNext; + Action _onError; + Action _onCompleted; - public interface IFooWithObservable + public AnonymousObserver(Action onNext, Action onError = null, Action onCompleted = null) { - IObservable GetInts(); - IObservable GetSamples(); + _onNext = onNext ?? (_ => { }); + _onError = onError ?? (_ => { }); + _onCompleted = onCompleted ?? (() => { }); } - //Copied from NSubstitute.Specs.AnonymousObserver (PR #137) - private class AnonymousObserver : IObserver - { - Action _onNext; - Action _onError; - Action _onCompleted; - - public AnonymousObserver(Action onNext, Action onError = null, Action onCompleted = null) - { - _onNext = onNext ?? (_ => { }); - _onError = onError ?? (_ => { }); - _onCompleted = onCompleted ?? (() => { }); - } - - public void OnNext(T value) { _onNext(value); } - public void OnError(Exception error) { _onError(error); } - public void OnCompleted() { _onCompleted(); } - } + public void OnNext(T value) { _onNext(value); } + public void OnError(Exception error) { _onError(error); } + public void OnCompleted() { _onCompleted(); } + } - private static void AssertObjectIsASubstitute(T obj) where T : class - { - Assert.That(obj.ReceivedCalls(), Is.Empty); - } + private static void AssertObjectIsASubstitute(T obj) where T : class + { + Assert.That(obj.ReceivedCalls(), Is.Empty); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/CallbackCalling.cs b/tests/NSubstitute.Acceptance.Specs/CallbackCalling.cs index 392e551b5..8868a470d 100644 --- a/tests/NSubstitute.Acceptance.Specs/CallbackCalling.cs +++ b/tests/NSubstitute.Acceptance.Specs/CallbackCalling.cs @@ -2,341 +2,340 @@ using NSubstitute.Core; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +[TestFixture] +public class CallbackCalling { - [TestFixture] - public class CallbackCalling + private ISomething _something; + + [Test] + public void Execute_when_called() { - private ISomething _something; + var called = false; + _something.When(substitute => substitute.Echo(1)).Do(Callback.Always(info => called = true)); - [Test] - public void Execute_when_called() - { - var called = false; - _something.When(substitute => substitute.Echo(1)).Do(Callback.Always(info => called = true)); + Assert.That(called, Is.False, "Called"); + _something.Echo(1); + Assert.That(called, Is.True, "Called"); + } - Assert.That(called, Is.False, "Called"); - _something.Echo(1); - Assert.That(called, Is.True, "Called"); - } + [Test] + public void Capture_arguments_when_called() + { + int firstArgument = 0; + _something.When(substitute => substitute.Echo(1)).Do(Callback.Always(info => firstArgument = (int)info[0])); - [Test] - public void Capture_arguments_when_called() - { - int firstArgument = 0; - _something.When(substitute => substitute.Echo(1)).Do(Callback.Always(info => firstArgument = (int)info[0])); + Assert.That(firstArgument, Is.EqualTo(0), "firstArgument"); + _something.Echo(1); + Assert.That(firstArgument, Is.EqualTo(1), "firstArgument"); + } - Assert.That(firstArgument, Is.EqualTo(0), "firstArgument"); - _something.Echo(1); - Assert.That(firstArgument, Is.EqualTo(1), "firstArgument"); - } + [Test] + public void Run_multiple_actions_when_called() + { + int called = 0; + _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); + _something.When(x => x.Echo(4)).Do(Callback.Always(x => called++)); + _something.WhenForAnyArgs(x => x.Echo(1234)).Do(Callback.Always(x => called++)); + + Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); + _something.Echo(4); + Assert.That(called, Is.EqualTo(3)); + } - [Test] - public void Run_multiple_actions_when_called() - { - int called = 0; - _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); - _something.When(x => x.Echo(4)).Do(Callback.Always(x => called++)); - _something.WhenForAnyArgs(x => x.Echo(1234)).Do(Callback.Always(x => called++)); - - Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); - _something.Echo(4); - Assert.That(called, Is.EqualTo(3)); - } + [Test] + public void Only_do_matching_actions() + { + int called = 0; + _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); + _something.When(x => x.Echo(4)).Do(Callback.Always(x => called++)); - [Test] - public void Only_do_matching_actions() - { - int called = 0; - _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); - _something.When(x => x.Echo(4)).Do(Callback.Always(x => called++)); + Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); + _something.Echo(1); + Assert.That(called, Is.EqualTo(1)); + } - Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); - _something.Echo(1); - Assert.That(called, Is.EqualTo(1)); - } + [Test] + public void Execute_when_called_for_any_args() + { + var called = false; + _something.WhenForAnyArgs(x => x.Echo(1)).Do(Callback.Always(x => called = true)); - [Test] - public void Execute_when_called_for_any_args() - { - var called = false; - _something.WhenForAnyArgs(x => x.Echo(1)).Do(Callback.Always(x => called = true)); + Assert.That(called, Is.False, "Called"); + _something.Echo(1234); + Assert.That(called, Is.True, "Called"); + } - Assert.That(called, Is.False, "Called"); - _something.Echo(1234); - Assert.That(called, Is.True, "Called"); - } + [Test] + public void Throw_exception_when_Throw_with_generic_exception() + { + int called = 0; + _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); + var expectedException = new ArgumentException(); + _something.When(x => x.Echo(Arg.Any())).Do(Callback.FirstThrow(expectedException)); + + Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); + var actualException = Assert.Throws(() => _something.Echo(1234)); + Assert.That(actualException, Is.EqualTo(expectedException)); + Assert.That(called, Is.EqualTo(1)); + } - [Test] - public void Throw_exception_when_Throw_with_generic_exception() - { - int called = 0; - _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); - var expectedException = new ArgumentException(); - _something.When(x => x.Echo(Arg.Any())).Do(Callback.FirstThrow(expectedException)); - - Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); - var actualException = Assert.Throws(() => _something.Echo(1234)); - Assert.That(actualException, Is.EqualTo(expectedException)); - Assert.That(called, Is.EqualTo(1)); - } + [Test] + public void Throw_exception_when_Throw_with_specific_exception() + { + var exception = new IndexOutOfRangeException("Test"); + int called = 0; + _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); + _something.When(x => x.Echo(Arg.Any())).Do(Callback.FirstThrow(exception)); + + Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); + var thrownException = Assert.Throws(() => _something.Echo(1234)); + Assert.That(thrownException, Is.EqualTo(exception)); + Assert.That(called, Is.EqualTo(1)); + } - [Test] - public void Throw_exception_when_Throw_with_specific_exception() - { - var exception = new IndexOutOfRangeException("Test"); - int called = 0; - _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); - _something.When(x => x.Echo(Arg.Any())).Do(Callback.FirstThrow(exception)); - - Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); - var thrownException = Assert.Throws(() => _something.Echo(1234)); - Assert.That(thrownException, Is.EqualTo(exception)); - Assert.That(called, Is.EqualTo(1)); - } + [Test] + public void Throw_exception_when_Throw_with_exception_generator() + { + Func createException = ci => new ArgumentException("Argument: " + ci.Args()[0]); + int called = 0; + _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); + _something.When(x => x.Echo(Arg.Any())).Do(Callback.AlwaysThrow(createException)); + + Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); + var thrownException = Assert.Throws(() => _something.Echo(1234)); + Assert.That(thrownException.Message, Is.EqualTo("Argument: 1234")); + Assert.That(called, Is.EqualTo(1)); + } - [Test] - public void Throw_exception_when_Throw_with_exception_generator() - { - Func createException = ci => new ArgumentException("Argument: " + ci.Args()[0]); - int called = 0; - _something.When(x => x.Echo(Arg.Any())).Do(Callback.Always(x => called++)); - _something.When(x => x.Echo(Arg.Any())).Do(Callback.AlwaysThrow(createException)); - - Assert.That(called, Is.EqualTo(0), "Should not have been called yet"); - var thrownException = Assert.Throws(() => _something.Echo(1234)); - Assert.That(thrownException.Message, Is.EqualTo("Argument: 1234")); - Assert.That(called, Is.EqualTo(1)); - } + [Test] + public void FirstIsRunOnce() + { + var calls = new List(); + int callCount = 0; + _something.When(x => x.Count()).Do(Callback.First(x => calls.Add(++callCount))); + + Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); + _something.Count(); + _something.Count(); + Assert.AreEqual(new List { 1 }, calls); + } - [Test] - public void FirstIsRunOnce() - { - var calls = new List(); - int callCount = 0; - _something.When(x => x.Count()).Do(Callback.First(x => calls.Add(++callCount))); + [Test] + public void AlwaysIsCalledAlways() + { + var calls = new List(); + int callCount = 0; + _something.When(x => x.Count()).Do(Callback.Always(x => calls.Add(++callCount))); + + Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); + _something.Count(); + _something.Count(); + Assert.AreEqual(new List { 1, 2 }, calls); + } - Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); - _something.Count(); - _something.Count(); - Assert.AreEqual(new List { 1 }, calls); - } + [Test] + public void ThenIsCalledAfterFirst() + { + var calls = new List(); + int callCount = 0; + _something.When(x => x.Count()).Do( + Callback + .First(x => calls.Add(++callCount)) + .Then(x => calls.Add(++callCount)) + ); + + Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); + _something.Count(); + _something.Count(); + Assert.AreEqual(new List { 1, 2 }, calls); + } - [Test] - public void AlwaysIsCalledAlways() - { - var calls = new List(); - int callCount = 0; - _something.When(x => x.Count()).Do(Callback.Always(x => calls.Add(++callCount))); + [Test] + public void TwoThensAreCalledInRightOrderAfterFirst() + { + bool first = false; + bool then = false; + bool secondThen = false; + _something.When(x => x.Count()).Do( + Callback + .First(x => first = true) + .Then(x => then = true) + .Then(x => secondThen = true) + ); + + _something.Count(); + Assert.IsTrue(first); + _something.Count(); + Assert.IsTrue(then); + _something.Count(); + Assert.IsTrue(secondThen); + } - Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); - _something.Count(); - _something.Count(); - Assert.AreEqual(new List { 1, 2 }, calls); - } + [Test] + public void AlwaysIsCalledEvenIfFirstAndThenIsDefined() + { + bool first = false; + bool then = false; + int callCount = 0; + _something.When(x => x.Count()).Do( + Callback + .First(x => first = true) + .Then(x => then = true) + .AndAlways(x => callCount++) + ); + + _something.Count(); + Assert.IsTrue(first); + _something.Count(); + Assert.IsTrue(then); + _something.Count(); + Assert.AreEqual(3, callCount); + } - [Test] - public void ThenIsCalledAfterFirst() - { - var calls = new List(); - int callCount = 0; - _something.When(x => x.Count()).Do( - Callback - .First(x => calls.Add(++callCount)) - .Then(x => calls.Add(++callCount)) - ); + [Test] + public void ThenIsCalledAfterFirstThrow() + { + var exception = new Exception(); + var calls = new List(); + int callCount = 0; + _something.When(x => x.Count()).Do( + Callback + .FirstThrow(exception) + .Then(x => calls.Add(++callCount)) + ); + + Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); + var ex = Assert.Throws(() => _something.Count()); + Assert.AreSame(exception, ex); + + _something.Count(); + Assert.AreEqual(new List { 1 }, calls); + } - Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); - _something.Count(); - _something.Count(); - Assert.AreEqual(new List { 1, 2 }, calls); - } + [Test] + public void ThenIsCalledAfterThenThrow() + { + var exception = new Exception(); + var calls = new List(); + int callCount = 0; + _something.When(x => x.Count()).Do( + Callback + .First(info => calls.Add(++callCount)) + .ThenThrow(exception) + .Then(x => calls.Add(++callCount)) + ); + + Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); + _something.Count(); + var ex = Assert.Throws(() => _something.Count()); + Assert.AreSame(exception, ex); + + _something.Count(); + Assert.AreEqual(new List { 1, 2 }, calls); + } - [Test] - public void TwoThensAreCalledInRightOrderAfterFirst() - { - bool first = false; - bool then = false; - bool secondThen = false; - _something.When(x => x.Count()).Do( - Callback - .First(x => first = true) - .Then(x => then = true) - .Then(x => secondThen = true) - ); + [Test] + public void AlwaysIsCalledEvenThrowIfIsDefined() + { + var exception = new Exception(); + int callCount = 0; + _something.When(x => x.Count()).Do( + Callback + .FirstThrow(exception) + .ThenThrow(exception) + .AndAlways(x => callCount++) + ); + + Assert.Throws(() => _something.Count()); + Assert.Throws(() => _something.Count()); + Assert.AreEqual(2, callCount); + } - _something.Count(); - Assert.IsTrue(first); - _something.Count(); - Assert.IsTrue(then); - _something.Count(); - Assert.IsTrue(secondThen); - } + [Test] + public void WhenRunOutOfCallbacks() + { + var calls = new List(); - [Test] - public void AlwaysIsCalledEvenIfFirstAndThenIsDefined() - { - bool first = false; - bool then = false; - int callCount = 0; - _something.When(x => x.Count()).Do( - Callback - .First(x => first = true) - .Then(x => then = true) - .AndAlways(x => callCount++) + _something.When(x => x.Count()) + .Do( + Callback.First(x => calls.Add("1")) + .Then(x => calls.Add("2")) + .Then(x => calls.Add("3")) ); - _something.Count(); - Assert.IsTrue(first); - _something.Count(); - Assert.IsTrue(then); - _something.Count(); - Assert.AreEqual(3, callCount); - } - - [Test] - public void ThenIsCalledAfterFirstThrow() + for (int i = 0; i < 10; i++) { - var exception = new Exception(); - var calls = new List(); - int callCount = 0; - _something.When(x => x.Count()).Do( - Callback - .FirstThrow(exception) - .Then(x => calls.Add(++callCount)) - ); - - Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); - var ex = Assert.Throws(() => _something.Count()); - Assert.AreSame(exception, ex); - _something.Count(); - Assert.AreEqual(new List { 1 }, calls); } + Assert.That(calls, Is.EqualTo(new[] { "1", "2", "3" })); + } - [Test] - public void ThenIsCalledAfterThenThrow() - { - var exception = new Exception(); - var calls = new List(); - int callCount = 0; - _something.When(x => x.Count()).Do( - Callback - .First(info => calls.Add(++callCount)) - .ThenThrow(exception) - .Then(x => calls.Add(++callCount)) + [Test] + public void WhenToldToKeepDoingSomething() + { + var calls = new List(); + + _something.When(x => x.Count()) + .Do( + Callback.First(x => calls.Add("1")) + .Then(x => calls.Add("2")) + .Then(x => calls.Add("3")) + .ThenKeepDoing(x => calls.Add("+")) ); - Assert.That(callCount, Is.EqualTo(0), "Should not have been called yet"); - _something.Count(); - var ex = Assert.Throws(() => _something.Count()); - Assert.AreSame(exception, ex); - + for (int i = 0; i < 5; i++) + { _something.Count(); - Assert.AreEqual(new List { 1, 2 }, calls); } + Assert.That(calls, Is.EqualTo(new[] { "1", "2", "3", "+", "+" })); + } - [Test] - public void AlwaysIsCalledEvenThrowIfIsDefined() - { - var exception = new Exception(); - int callCount = 0; - _something.When(x => x.Count()).Do( - Callback - .FirstThrow(exception) - .ThenThrow(exception) - .AndAlways(x => callCount++) + [Test] + public void WhenToldToKeepThrowingAfterCallbacks() + { + var calls = new List(); + var ex = new Exception(); + _something.When(x => x.Count()) + .Do( + Callback.First(x => calls.Add("1")) + .Then(x => calls.Add("2")) + .ThenKeepThrowing(x => ex) ); - Assert.Throws(() => _something.Count()); - Assert.Throws(() => _something.Count()); - Assert.AreEqual(2, callCount); - } - - [Test] - public void WhenRunOutOfCallbacks() - { - var calls = new List(); - - _something.When(x => x.Count()) - .Do( - Callback.First(x => calls.Add("1")) - .Then(x => calls.Add("2")) - .Then(x => calls.Add("3")) - ); - - for (int i = 0; i < 10; i++) - { - _something.Count(); - } - Assert.That(calls, Is.EqualTo(new[] { "1", "2", "3" })); - } + _something.Count(); + _something.Count(); + Assert.Throws(() => _something.Count()); + Assert.Throws(() => _something.Count()); + Assert.Throws(() => _something.Count()); + Assert.That(calls, Is.EqualTo(new[] { "1", "2" })); + } - [Test] - public void WhenToldToKeepDoingSomething() - { - var calls = new List(); - - _something.When(x => x.Count()) - .Do( - Callback.First(x => calls.Add("1")) - .Then(x => calls.Add("2")) - .Then(x => calls.Add("3")) - .ThenKeepDoing(x => calls.Add("+")) - ); - - for (int i = 0; i < 5; i++) - { - _something.Count(); - } - Assert.That(calls, Is.EqualTo(new[] { "1", "2", "3", "+", "+" })); - } + [Test] + public void KeepDoingAndAlwaysDo() + { + var calls = new List(); + var count = 0; + + _something.When(x => x.Count()) + .Do( + Callback.First(x => calls.Add("1")) + .ThenKeepDoing(x => calls.Add("+")) + .AndAlways(x => count++) + ); - [Test] - public void WhenToldToKeepThrowingAfterCallbacks() + for (int i = 0; i < 5; i++) { - var calls = new List(); - var ex = new Exception(); - _something.When(x => x.Count()) - .Do( - Callback.First(x => calls.Add("1")) - .Then(x => calls.Add("2")) - .ThenKeepThrowing(x => ex) - ); - - _something.Count(); _something.Count(); - Assert.Throws(() => _something.Count()); - Assert.Throws(() => _something.Count()); - Assert.Throws(() => _something.Count()); - Assert.That(calls, Is.EqualTo(new[] { "1", "2" })); - } - - [Test] - public void KeepDoingAndAlwaysDo() - { - var calls = new List(); - var count = 0; - - _something.When(x => x.Count()) - .Do( - Callback.First(x => calls.Add("1")) - .ThenKeepDoing(x => calls.Add("+")) - .AndAlways(x => count++) - ); - - for (int i = 0; i < 5; i++) - { - _something.Count(); - } - Assert.That(calls, Is.EqualTo(new[] { "1", "+", "+", "+", "+" })); - Assert.That(count, Is.EqualTo(5)); } + Assert.That(calls, Is.EqualTo(new[] { "1", "+", "+", "+", "+" })); + Assert.That(count, Is.EqualTo(5)); + } - [SetUp] - public void SetUp() - { - _something = Substitute.For(); - } + [SetUp] + public void SetUp() + { + _something = Substitute.For(); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ClearSubstitute.cs b/tests/NSubstitute.Acceptance.Specs/ClearSubstitute.cs index f6f64078b..d9eb20e65 100644 --- a/tests/NSubstitute.Acceptance.Specs/ClearSubstitute.cs +++ b/tests/NSubstitute.Acceptance.Specs/ClearSubstitute.cs @@ -2,58 +2,57 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +[TestFixture] +public class ClearSubstitute { - [TestFixture] - public class ClearSubstitute + public interface ICalculator { - public interface ICalculator - { - int Add(int a, int b); - } + int Add(int a, int b); + } - [Test] - public void Can_clear_received_calls_on_a_substitute() - { - var substitute = Substitute.For(); - substitute.Add(1, 1); - substitute.Add(2, 2); - substitute.Received().Add(1, 1); - substitute.ClearSubstitute(ClearOptions.ReceivedCalls); - Assert.Throws(() => substitute.Received().Add(1, 1)); - } + [Test] + public void Can_clear_received_calls_on_a_substitute() + { + var substitute = Substitute.For(); + substitute.Add(1, 1); + substitute.Add(2, 2); + substitute.Received().Add(1, 1); + substitute.ClearSubstitute(ClearOptions.ReceivedCalls); + Assert.Throws(() => substitute.Received().Add(1, 1)); + } - [Test] - public void Can_clear_received_calls_on_a_substitute_with_ClearReceivedCalls() - { - var substitute = Substitute.For(); - substitute.Add(1, 1); - substitute.Add(2, 2); - substitute.Received().Add(1, 1); - substitute.ClearReceivedCalls(); - Assert.Throws(() => substitute.Received().Add(1, 1)); - } + [Test] + public void Can_clear_received_calls_on_a_substitute_with_ClearReceivedCalls() + { + var substitute = Substitute.For(); + substitute.Add(1, 1); + substitute.Add(2, 2); + substitute.Received().Add(1, 1); + substitute.ClearReceivedCalls(); + Assert.Throws(() => substitute.Received().Add(1, 1)); + } - [Test] - public void Clear_results() - { - var substitute = Substitute.For(); - substitute.Add(1, 1).Returns(12); - substitute.ClearSubstitute(ClearOptions.ReturnValues); - Assert.AreEqual(0, substitute.Add(1, 1)); - } + [Test] + public void Clear_results() + { + var substitute = Substitute.For(); + substitute.Add(1, 1).Returns(12); + substitute.ClearSubstitute(ClearOptions.ReturnValues); + Assert.AreEqual(0, substitute.Add(1, 1)); + } - [Test] - public void Clear_callbacks() - { - var count = 0; - var substitute = Substitute.For(); - substitute.When(x => x.Add(1, 1)).Do(x => count++); - substitute.ClearSubstitute(ClearOptions.CallActions); - substitute.Add(1, 1); - substitute.Add(1, 1); - substitute.Add(1, 1); - Assert.AreEqual(0, count); - } + [Test] + public void Clear_callbacks() + { + var count = 0; + var substitute = Substitute.For(); + substitute.When(x => x.Add(1, 1)).Do(x => count++); + substitute.ClearSubstitute(ClearOptions.CallActions); + substitute.Add(1, 1); + substitute.Add(1, 1); + substitute.Add(1, 1); + Assert.AreEqual(0, count); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/CompatArgsTests.cs b/tests/NSubstitute.Acceptance.Specs/CompatArgsTests.cs index 603856086..8e8c7deaa 100644 --- a/tests/NSubstitute.Acceptance.Specs/CompatArgsTests.cs +++ b/tests/NSubstitute.Acceptance.Specs/CompatArgsTests.cs @@ -2,56 +2,55 @@ using NSubstitute.Compatibility; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + + +public class CompatArgsTests { - public class CompatArgsTests + [Test] + public void CompatAndCompatArgInstanceShouldBeInSync() { + var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; + var compatMembers = + typeof(Arg.Compat).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); + var compatInstanceMembers = + typeof(CompatArg).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); + + Assert.AreEqual( + compatMembers.ToList(), compatInstanceMembers.ToList(), + "Arg.Compat and CompatArg should have static/instance versions of the same methods" + ); + } - [Test] - public void CompatAndCompatArgInstanceShouldBeInSync() - { - var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; - var compatMembers = - typeof(Arg.Compat).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); - var compatInstanceMembers = - typeof(CompatArg).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); - - Assert.AreEqual( - compatMembers.ToList(), compatInstanceMembers.ToList(), - "Arg.Compat and CompatArg should have static/instance versions of the same methods" - ); - } - - [Test] - public void CompatAndArgShouldBeInSync() - { - var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; - var argMembers = - typeof(Arg).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); - var compatMembers = - typeof(Arg.Compat).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); - - Assert.AreEqual( - argMembers.ToList(), compatMembers.ToList(), - "Arg and Arg.Compat should have the same methods (just vary by out/ref)" - ); - } - - private static string DescribeMethod(MethodInfo m) - { - return $"{m.Name}<{DescribeTypeList(m.GetGenericArguments())}>({DescribeParameters(m.GetParameters())})"; - } - - private static string DescribeTypeList(Type[] args) - { - return string.Join(", ", args.Select(x => x.Name)); - } - - private static string DescribeParameters(ParameterInfo[] parameters) - { - return string.Join(", ", parameters.Select(x => $"{x.ParameterType.Name} {x.Name}")); - } + [Test] + public void CompatAndArgShouldBeInSync() + { + var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; + var argMembers = + typeof(Arg).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); + var compatMembers = + typeof(Arg.Compat).GetMethods(flags).Select(DescribeMethod).OrderBy(x => x); + + Assert.AreEqual( + argMembers.ToList(), compatMembers.ToList(), + "Arg and Arg.Compat should have the same methods (just vary by out/ref)" + ); + } + private static string DescribeMethod(MethodInfo m) + { + return $"{m.Name}<{DescribeTypeList(m.GetGenericArguments())}>({DescribeParameters(m.GetParameters())})"; } + + private static string DescribeTypeList(Type[] args) + { + return string.Join(", ", args.Select(x => x.Name)); + } + + private static string DescribeParameters(ParameterInfo[] parameters) + { + return string.Join(", ", parameters.Select(x => $"{x.ParameterType.Name} {x.Name}")); + } + } diff --git a/tests/NSubstitute.Acceptance.Specs/ConcurrencyTests.cs b/tests/NSubstitute.Acceptance.Specs/ConcurrencyTests.cs index 28d76ff0d..ba67dc3c0 100644 --- a/tests/NSubstitute.Acceptance.Specs/ConcurrencyTests.cs +++ b/tests/NSubstitute.Acceptance.Specs/ConcurrencyTests.cs @@ -3,273 +3,272 @@ using NSubstitute.Extensions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class ConcurrencyTests { - public class ConcurrencyTests + [Test] + public async Task Call_between_invocation_and_received_does_not_cause_issue() { - [Test] - public async Task Call_between_invocation_and_received_does_not_cause_issue() + // Arrange + var subs = Substitute.For(); + + var backgroundReady = new AutoResetEvent(false); + + // Act + // 1 + var dummy = subs.Say("ping"); + + var bg = RunInOtherThread(() => { - // Arrange - var subs = Substitute.For(); + // 2 + subs.Echo(42); + backgroundReady.Set(); + }); - var backgroundReady = new AutoResetEvent(false); + backgroundReady.WaitOne(); - // Act - // 1 - var dummy = subs.Say("ping"); + // 3 + dummy.Returns("pong"); - var bg = RunInOtherThread(() => - { - // 2 - subs.Echo(42); - backgroundReady.Set(); - }); + // Assert + var actualResult = subs.Say("ping"); - backgroundReady.WaitOne(); + Assert.That(actualResult, Is.EqualTo("pong")); + await bg; + } - // 3 - dummy.Returns("pong"); + [Test] + public async Task Background_invocation_does_not_delete_specification() + { + // Arrange + var subs = Substitute.For(); - // Assert - var actualResult = subs.Say("ping"); + var backgroundReady = new AutoResetEvent(false); - Assert.That(actualResult, Is.EqualTo("pong")); - await bg; - } + // Act + // 1 + var dummy = subs.Say(Arg.Any()); - [Test] - public async Task Background_invocation_does_not_delete_specification() + var bg = RunInOtherThread(() => { - // Arrange - var subs = Substitute.For(); + // 2 + subs.Say("hello"); + backgroundReady.Set(); + }); - var backgroundReady = new AutoResetEvent(false); + backgroundReady.WaitOne(); - // Act - // 1 - var dummy = subs.Say(Arg.Any()); + // 3 + dummy.Returns("42"); - var bg = RunInOtherThread(() => - { - // 2 - subs.Say("hello"); - backgroundReady.Set(); - }); + // Assert + Assert.That(subs.Say("Alex"), Is.EqualTo("42")); + await bg; + } - backgroundReady.WaitOne(); + [Test] + public async Task Both_threads_can_configure_returns_concurrently() + { + // Arrange + var subs = Substitute.For(); - // 3 - dummy.Returns("42"); + var foregroundReady = new AutoResetEvent(false); + var backgroundReady = new AutoResetEvent(false); - // Assert - Assert.That(subs.Say("Alex"), Is.EqualTo("42")); - await bg; - } + // Act + // 1 + var dummy = subs.Say("ping"); - [Test] - public async Task Both_threads_can_configure_returns_concurrently() + var bg = RunInOtherThread(() => { - // Arrange - var subs = Substitute.For(); + // 2 + var d = subs.Echo(42); + SignalAndWait(backgroundReady, foregroundReady); - var foregroundReady = new AutoResetEvent(false); - var backgroundReady = new AutoResetEvent(false); + // 4 + d.Returns("42"); + backgroundReady.Set(); + }); - // Act - // 1 - var dummy = subs.Say("ping"); + backgroundReady.WaitOne(); - var bg = RunInOtherThread(() => - { - // 2 - var d = subs.Echo(42); - SignalAndWait(backgroundReady, foregroundReady); + // 3 + dummy.Returns("pong"); + SignalAndWait(foregroundReady, backgroundReady); - // 4 - d.Returns("42"); - backgroundReady.Set(); - }); + // Assert + Assert.That(subs.Say("ping"), Is.EqualTo("pong")); + Assert.That(subs.Echo(42), Is.EqualTo("42")); + await bg; + } - backgroundReady.WaitOne(); + [Test] + public async Task Both_threads_can_verify_received_calls_concurrently() + { + // arrange + var subs = Substitute.For(); - // 3 - dummy.Returns("pong"); - SignalAndWait(foregroundReady, backgroundReady); + var foregroundReady = new AutoResetEvent(false); + var backgroundReady = new AutoResetEvent(false); - // Assert - Assert.That(subs.Say("ping"), Is.EqualTo("pong")); - Assert.That(subs.Echo(42), Is.EqualTo("42")); - await bg; - } + // act + // 1 + subs.Add(1, 2); + subs.Echo(42); - [Test] - public async Task Both_threads_can_verify_received_calls_concurrently() + subs.Received(); + + var bg = RunInOtherThread(() => { - // arrange - var subs = Substitute.For(); + // 2 + subs.Received(); + SignalAndWait(backgroundReady, foregroundReady); - var foregroundReady = new AutoResetEvent(false); - var backgroundReady = new AutoResetEvent(false); + // 4 + // Make exceptional situation, as otherwise it isn't clear whether call is actually verified. + Assert.Throws(() => subs.Echo(99)); // This call is checked for being received. + }); - // act - // 1 - subs.Add(1, 2); - subs.Echo(42); + backgroundReady.WaitOne(); - subs.Received(); + // 3 + subs.Add(1, 2); // This call is checked for being received. + foregroundReady.Set(); - var bg = RunInOtherThread(() => - { - // 2 - subs.Received(); - SignalAndWait(backgroundReady, foregroundReady); + await bg; + } - // 4 - // Make exceptional situation, as otherwise it isn't clear whether call is actually verified. - Assert.Throws(() => subs.Echo(99)); // This call is checked for being received. - }); + [Test] + public async Task Both_threads_can_verify_received_calls_with_any_args_concurrently() + { + // arrange + var subs = Substitute.For(); - backgroundReady.WaitOne(); + var foregroundReady = new AutoResetEvent(false); + var backgroundReady = new AutoResetEvent(false); - // 3 - subs.Add(1, 2); // This call is checked for being received. - foregroundReady.Set(); + // act + // 1 + subs.Add(1, 2); + subs.Echo(42); - await bg; - } + subs.ReceivedWithAnyArgs(); - [Test] - public async Task Both_threads_can_verify_received_calls_with_any_args_concurrently() + var bg = RunInOtherThread(() => { - // arrange - var subs = Substitute.For(); - - var foregroundReady = new AutoResetEvent(false); - var backgroundReady = new AutoResetEvent(false); + // 2 + subs.DidNotReceiveWithAnyArgs(); + SignalAndWait(backgroundReady, foregroundReady); - // act - // 1 - subs.Add(1, 2); - subs.Echo(42); + // 4 + // Make exceptional situation, as otherwise it isn't clear whether call is actually verified. + Assert.Throws(() => subs.Echo(default)); // This call is checked for being received. + }); - subs.ReceivedWithAnyArgs(); + backgroundReady.WaitOne(); - var bg = RunInOtherThread(() => - { - // 2 - subs.DidNotReceiveWithAnyArgs(); - SignalAndWait(backgroundReady, foregroundReady); + // 3 + subs.Add(default, default); // This call is checked for being received. + foregroundReady.Set(); - // 4 - // Make exceptional situation, as otherwise it isn't clear whether call is actually verified. - Assert.Throws(() => subs.Echo(default)); // This call is checked for being received. - }); + await bg; + } - backgroundReady.WaitOne(); + [Test] + public async Task Can_configure_using_Configure_method_concurrently() + { + // Arrange + var subs = Substitute.ForPartsOf(); - // 3 - subs.Add(default, default); // This call is checked for being received. - foregroundReady.Set(); + var foregroundReady = new AutoResetEvent(false); + var backgroundReady = new AutoResetEvent(false); - await bg; - } + // Act + // 1 + subs.Configure(); - [Test] - public async Task Can_configure_using_Configure_method_concurrently() + var bg = RunInOtherThread(() => { - // Arrange - var subs = Substitute.ForPartsOf(); + // 2 + subs.Configure(); + SignalAndWait(backgroundReady, foregroundReady); + + // 4 + subs.EchoMethodB(42).Returns(42); + backgroundReady.Set(); + }); + + backgroundReady.WaitOne(); + + // 3 + subs.EchoMethodA(42).Returns(42); + SignalAndWait(foregroundReady, backgroundReady); + + // Assert + // 5 + var resultA = subs.EchoMethodA(42); + var resultB = subs.EchoMethodB(42); + Assert.That(resultA, Is.EqualTo(42)); + Assert.That(resultB, Is.EqualTo(42)); + await bg; + } - var foregroundReady = new AutoResetEvent(false); - var backgroundReady = new AutoResetEvent(false); + [Test] + public async Task Configure_in_one_thread_should_not_affect_substitute_in_other_thread() + { + // Arrange + var subs = Substitute.For(); + var backgroundReady = new AutoResetEvent(false); - // Act - // 1 - subs.Configure(); + // Act + // 1 + subs.Echo(42).Returns("42"); - var bg = RunInOtherThread(() => - { - // 2 - subs.Configure(); - SignalAndWait(backgroundReady, foregroundReady); - - // 4 - subs.EchoMethodB(42).Returns(42); - backgroundReady.Set(); - }); - - backgroundReady.WaitOne(); - - // 3 - subs.EchoMethodA(42).Returns(42); - SignalAndWait(foregroundReady, backgroundReady); - - // Assert - // 5 - var resultA = subs.EchoMethodA(42); - var resultB = subs.EchoMethodB(42); - Assert.That(resultA, Is.EqualTo(42)); - Assert.That(resultB, Is.EqualTo(42)); - await bg; - } - - [Test] - public async Task Configure_in_one_thread_should_not_affect_substitute_in_other_thread() - { - // Arrange - var subs = Substitute.For(); - var backgroundReady = new AutoResetEvent(false); - - // Act - // 1 - subs.Echo(42).Returns("42"); - - var bg = RunInOtherThread(() => - { - // 2 - subs.Configure(); - backgroundReady.Set(); - }); - - backgroundReady.WaitOne(); - // 3 - var result = subs.Echo(42); - - // Assert - Assert.That(result, Is.EqualTo("42")); - await bg; - } - - [Test] - public async Task Configuration_works_fine_for_async_methods() + var bg = RunInOtherThread(() => { - // Arrange - var subs = Substitute.For(); + // 2 + subs.Configure(); + backgroundReady.Set(); + }); - // Act - subs.EchoAsync(42).Returns("42"); + backgroundReady.WaitOne(); + // 3 + var result = subs.Echo(42); - // Assert - var result = await subs.EchoAsync(42); - Assert.That(result, Is.EqualTo("42")); - } + // Assert + Assert.That(result, Is.EqualTo("42")); + await bg; + } - private static Task RunInOtherThread(Action action) - { - return Task.Factory.StartNew(action); - } + [Test] + public async Task Configuration_works_fine_for_async_methods() + { + // Arrange + var subs = Substitute.For(); - private static void SignalAndWait(EventWaitHandle toSignal, EventWaitHandle toWait) - { - toSignal.Set(); - toWait.WaitOne(); - } + // Act + subs.EchoAsync(42).Returns("42"); - public class TypeWhichThrows - { - public virtual int EchoMethodA(int value) => throw new NotImplementedException(); - public virtual int EchoMethodB(int value) => throw new NotImplementedException(); - } + // Assert + var result = await subs.EchoAsync(42); + Assert.That(result, Is.EqualTo("42")); + } + + private static Task RunInOtherThread(Action action) + { + return Task.Factory.StartNew(action); + } + + private static void SignalAndWait(EventWaitHandle toSignal, EventWaitHandle toWait) + { + toSignal.Set(); + toWait.WaitOne(); + } + + public class TypeWhichThrows + { + public virtual int EchoMethodA(int value) => throw new NotImplementedException(); + public virtual int EchoMethodB(int value) => throw new NotImplementedException(); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ConfigurationExtensionTests.cs b/tests/NSubstitute.Acceptance.Specs/ConfigurationExtensionTests.cs index 10e3527f0..a83c5771c 100644 --- a/tests/NSubstitute.Acceptance.Specs/ConfigurationExtensionTests.cs +++ b/tests/NSubstitute.Acceptance.Specs/ConfigurationExtensionTests.cs @@ -4,91 +4,90 @@ using NSubstitute.Extensions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class ConfigurationExtensionTests { - public class ConfigurationExtensionTests + public class TypeWithThrowingMembers + { + public virtual int GetValue() => throw new NotImplementedException(); + public virtual int Value => throw new NotImplementedException(); + } + + public class ThrowingCallHandler : ICallHandler + { + public RouteAction Handle(ICall call) => throw new NotSupportedException(); + } + + [Test] + public void Should_not_return_the_previously_configured_result() + { + // Arrange + var mock = Substitute.For(); + + // Act + mock.Echo(Arg.Any()).Returns("1", "2", "3"); + mock.Configure().Echo(42).Returns("42"); + + // Assert + Assert.That(mock.Echo(10), Is.EqualTo("1")); + Assert.That(mock.Echo(10), Is.EqualTo("2")); + Assert.That(mock.Echo(42), Is.EqualTo("42")); + } + + [Test] + public void Should_be_possible_to_reconfigure_configured_throwing_calls() + { + // Arrange + var mock = Substitute.For(); + + // Act + mock.Echo(Arg.Any()).Throws(); + mock.Configure().Echo(42).Returns("42"); + + // Assert + Assert.That(mock.Echo(42), Is.EqualTo("42")); + } + + [Test] + public void Should_be_possible_to_configure_base_throwing_method() + { + // Arrange + var mock = Substitute.ForPartsOf(); + + // Act + mock.Configure().GetValue().Returns(42); + + // Assert + Assert.That(mock.GetValue(), Is.EqualTo(42)); + } + + [Test] + public void Should_be_possible_to_configure_base_throwing_property() { - public class TypeWithThrowingMembers - { - public virtual int GetValue() => throw new NotImplementedException(); - public virtual int Value => throw new NotImplementedException(); - } - - public class ThrowingCallHandler : ICallHandler - { - public RouteAction Handle(ICall call) => throw new NotSupportedException(); - } - - [Test] - public void Should_not_return_the_previously_configured_result() - { - // Arrange - var mock = Substitute.For(); - - // Act - mock.Echo(Arg.Any()).Returns("1", "2", "3"); - mock.Configure().Echo(42).Returns("42"); - - // Assert - Assert.That(mock.Echo(10), Is.EqualTo("1")); - Assert.That(mock.Echo(10), Is.EqualTo("2")); - Assert.That(mock.Echo(42), Is.EqualTo("42")); - } - - [Test] - public void Should_be_possible_to_reconfigure_configured_throwing_calls() - { - // Arrange - var mock = Substitute.For(); - - // Act - mock.Echo(Arg.Any()).Throws(); - mock.Configure().Echo(42).Returns("42"); - - // Assert - Assert.That(mock.Echo(42), Is.EqualTo("42")); - } - - [Test] - public void Should_be_possible_to_configure_base_throwing_method() - { - // Arrange - var mock = Substitute.ForPartsOf(); - - // Act - mock.Configure().GetValue().Returns(42); - - // Assert - Assert.That(mock.GetValue(), Is.EqualTo(42)); - } - - [Test] - public void Should_be_possible_to_configure_base_throwing_property() - { - // Arrange - var mock = Substitute.ForPartsOf(); - - // Act - mock.Configure().Value.Returns(42); - - // Assert - Assert.That(mock.Value, Is.EqualTo(42)); - } - - [Test] - public void Should_be_possible_to_disable_custom_call_handler_for_specification_call() - { - // Arrange - var mock = Substitute.For(); - - var callRouter = SubstitutionContext.Current.GetCallRouterFor(mock); - callRouter.RegisterCustomCallHandlerFactory(_ => new ThrowingCallHandler()); - - // Act - mock.Configure().Count().Returns(42); - - // Assert - Assert.That(mock.Count(), Is.EqualTo(42)); - } + // Arrange + var mock = Substitute.ForPartsOf(); + + // Act + mock.Configure().Value.Returns(42); + + // Assert + Assert.That(mock.Value, Is.EqualTo(42)); + } + + [Test] + public void Should_be_possible_to_disable_custom_call_handler_for_specification_call() + { + // Arrange + var mock = Substitute.For(); + + var callRouter = SubstitutionContext.Current.GetCallRouterFor(mock); + callRouter.RegisterCustomCallHandlerFactory(_ => new ThrowingCallHandler()); + + // Act + mock.Configure().Count().Returns(42); + + // Assert + Assert.That(mock.Count(), Is.EqualTo(42)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/CustomHandlersSpecs.cs b/tests/NSubstitute.Acceptance.Specs/CustomHandlersSpecs.cs index ec02bf306..ab8eb35df 100644 --- a/tests/NSubstitute.Acceptance.Specs/CustomHandlersSpecs.cs +++ b/tests/NSubstitute.Acceptance.Specs/CustomHandlersSpecs.cs @@ -1,234 +1,233 @@ using NSubstitute.Core; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +[TestFixture] +public class CustomHandlersSpecs { - [TestFixture] - public class CustomHandlersSpecs + [Test] + public void Value_from_custom_handler_is_returned() { - [Test] - public void Value_from_custom_handler_is_returned() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); - - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - _ => RouteAction.Return("42"))); + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); - //act - var result = source.GetValue(); + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + _ => RouteAction.Return("42"))); - //assert - Assert.That(result, Is.EqualTo("42")); - } - - [Test] - public void Value_from_custom_handler_is_returned_for_setup_after_invocation() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + //act + var result = source.GetValue(); - //invoke it before registering handler - source.GetValue(); + //assert + Assert.That(result, Is.EqualTo("42")); + } - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - _ => RouteAction.Return("42"))); + [Test] + public void Value_from_custom_handler_is_returned_for_setup_after_invocation() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); - //act - var result = source.GetValue(); + //invoke it before registering handler + source.GetValue(); - //assert - Assert.That(result, Is.EqualTo("42")); - } + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + _ => RouteAction.Return("42"))); - [Test] - public void Custom_handler_is_called_for_each_time() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + //act + var result = source.GetValue(); - var values = new Queue(new[] { "42", "10" }); + //assert + Assert.That(result, Is.EqualTo("42")); + } - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - _ => RouteAction.Return(values.Dequeue()))); + [Test] + public void Custom_handler_is_called_for_each_time() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); - //act - var result = source.GetValue(); - result = source.GetValue(); + var values = new Queue(new[] { "42", "10" }); - //assert - Assert.That(result, Is.EqualTo("10")); - } + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + _ => RouteAction.Return(values.Dequeue()))); - [Test] - public void Configured_call_has_more_priority_than_custom_handler() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + //act + var result = source.GetValue(); + result = source.GetValue(); - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - _ => RouteAction.Return("xxx"))); + //assert + Assert.That(result, Is.EqualTo("10")); + } - source.GetValue().Returns("42"); + [Test] + public void Configured_call_has_more_priority_than_custom_handler() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); - //act - var result = source.GetValue(); + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + _ => RouteAction.Return("xxx"))); - //assert - Assert.That(result, Is.EqualTo("42")); - } + source.GetValue().Returns("42"); - [Test] - public void Updated_ref_parameter_doesnt_affect_call_specification() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + //act + var result = source.GetValue(); - //Configure our handler to update "ref" argument value - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - call => - { - if (call.GetMethodInfo().Name != nameof(IValueSource.GetValueWithRef)) - return RouteAction.Continue(); + //assert + Assert.That(result, Is.EqualTo("42")); + } - var args = call.GetArguments(); - args[0] = "refArg"; + [Test] + public void Updated_ref_parameter_doesnt_affect_call_specification() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); + + //Configure our handler to update "ref" argument value + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + call => + { + if (call.GetMethodInfo().Name != nameof(IValueSource.GetValueWithRef)) + return RouteAction.Continue(); - return RouteAction.Return("xxx"); - })); + var args = call.GetArguments(); + args[0] = "refArg"; - string refValue = "ref"; - source.GetValueWithRef(ref refValue).Returns("42"); + return RouteAction.Return("xxx"); + })); - //act - refValue = "ref"; - var result = source.GetValueWithRef(ref refValue); + string refValue = "ref"; + source.GetValueWithRef(ref refValue).Returns("42"); - //assert - Assert.That(result, Is.EqualTo("42")); - } + //act + refValue = "ref"; + var result = source.GetValueWithRef(ref refValue); - [Test] - public void Set_out_parameter_doesnt_affect_call_specification() - { - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + //assert + Assert.That(result, Is.EqualTo("42")); + } - //Configure our handler to update "out" argument value - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - call => - { - if (call.GetMethodInfo().Name != nameof(IValueSource.GetValueWithOut)) - return RouteAction.Continue(); + [Test] + public void Set_out_parameter_doesnt_affect_call_specification() + { + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); + + //Configure our handler to update "out" argument value + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + call => + { + if (call.GetMethodInfo().Name != nameof(IValueSource.GetValueWithOut)) + return RouteAction.Continue(); - var args = call.GetArguments(); - args[0] = "outArg"; + var args = call.GetArguments(); + args[0] = "outArg"; - return RouteAction.Return("xxx"); - })); + return RouteAction.Return("xxx"); + })); - string outArg; - source.GetValueWithOut(out outArg).Returns("42"); + string outArg; + source.GetValueWithOut(out outArg).Returns("42"); - //act - string otherOutArg; - var result = source.GetValueWithOut(out otherOutArg); + //act + string otherOutArg; + var result = source.GetValueWithOut(out otherOutArg); - //assert - Assert.That(result, Is.EqualTo("42")); - } + //assert + Assert.That(result, Is.EqualTo("42")); + } - [Test] - public void Is_not_called_for_specifying_call() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); - - bool wasInvoked = false; - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler(_ => - { - wasInvoked = true; - return RouteAction.Continue(); - })); + [Test] + public void Is_not_called_for_specifying_call() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); + + bool wasInvoked = false; + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler(_ => + { + wasInvoked = true; + return RouteAction.Continue(); + })); + + //act + source.MethodWithArgs(Arg.Any(), Arg.Is("42")).Returns(""); + + //assert + Assert.That(wasInvoked, Is.False); + } - //act - source.MethodWithArgs(Arg.Any(), Arg.Is("42")).Returns(""); + [Test] + public void Auto_value_is_returned_if_skipped() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); - //assert - Assert.That(wasInvoked, Is.False); - } + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler(_ => RouteAction.Continue())); - [Test] - public void Auto_value_is_returned_if_skipped() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + //act + var result = source.GetValue(); - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler(_ => RouteAction.Continue())); + //assert + Assert.That(result, Is.Not.Null); + } - //act - var result = source.GetValue(); + [Test] + public void First_added_handler_has_precedence() + { + //arrange + var source = Substitute.For(); + var router = SubstitutionContext.Current.GetCallRouterFor(source); - //assert - Assert.That(result, Is.Not.Null); - } + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + _ => RouteAction.Return("42"))); - [Test] - public void First_added_handler_has_precedence() - { - //arrange - var source = Substitute.For(); - var router = SubstitutionContext.Current.GetCallRouterFor(source); + router.RegisterCustomCallHandlerFactory(state => + new ActionHandler( + _ => RouteAction.Return("10"))); - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - _ => RouteAction.Return("42"))); + //act + var result = source.GetValue(); - router.RegisterCustomCallHandlerFactory(state => - new ActionHandler( - _ => RouteAction.Return("10"))); + //assert + Assert.That(result, Is.EqualTo("42")); + } - //act - var result = source.GetValue(); - //assert - Assert.That(result, Is.EqualTo("42")); - } + public interface IValueSource + { + string GetValue(); + string GetValueWithRef(ref string arg1); + string GetValueWithOut(out string arg1); + string MethodWithArgs(string arg1, string arg2); + } + private class ActionHandler : ICallHandler + { + private readonly Func _handler; - public interface IValueSource + public ActionHandler(Func handler) { - string GetValue(); - string GetValueWithRef(ref string arg1); - string GetValueWithOut(out string arg1); - string MethodWithArgs(string arg1, string arg2); + _handler = handler; } - private class ActionHandler : ICallHandler - { - private readonly Func _handler; - - public ActionHandler(Func handler) - { - _handler = handler; - } - - public RouteAction Handle(ICall call) => _handler.Invoke(call); - } + public RouteAction Handle(ICall call) => _handler.Invoke(call); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/DynamicCalls.cs b/tests/NSubstitute.Acceptance.Specs/DynamicCalls.cs index b6f640e5f..052f55596 100644 --- a/tests/NSubstitute.Acceptance.Specs/DynamicCalls.cs +++ b/tests/NSubstitute.Acceptance.Specs/DynamicCalls.cs @@ -1,80 +1,79 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class DynamicCalls { - public class DynamicCalls + public interface IInterface + { + dynamic ReturnsDynamic(string a); + dynamic ReturnsAndGetsDynamic(dynamic a); + int GetsDynamic(dynamic a); + dynamic DynamicProperty { get; set; } + } + + [Test] + [Pending, Explicit] + public void MethodGetsDynamicAndSpecifiedWithDynamic() + { + var sut = Substitute.For(); + // Fails + // Because dynamic typing doesn't support extension methods + // We can't do much here, I see only two options: + // 1. Good documentation. Tell people to use exact type instead of dynamic or use static Returns method. + // 2. Try to catch calls with dynamic typing and throw descriptive exception. Can be made via StackTrace. A bit hacky and risky. + // TBD + sut.GetsDynamic(Arg.Any()).Returns(1); + + dynamic expando = new System.Dynamic.ExpandoObject(); + var result = sut.GetsDynamic(expando); + + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void MethodGetsDynamicButSpecifiedWithExplicitType() + { + var sut = Substitute.For(); + sut.GetsDynamic(Arg.Any()).Returns(1); + + dynamic expando = new System.Dynamic.ExpandoObject(); + var result = sut.GetsDynamic(expando); + + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void DynamicProperty() { - public interface IInterface - { - dynamic ReturnsDynamic(string a); - dynamic ReturnsAndGetsDynamic(dynamic a); - int GetsDynamic(dynamic a); - dynamic DynamicProperty { get; set; } - } - - [Test] - [Pending, Explicit] - public void MethodGetsDynamicAndSpecifiedWithDynamic() - { - var sut = Substitute.For(); - // Fails - // Because dynamic typing doesn't support extension methods - // We can't do much here, I see only two options: - // 1. Good documentation. Tell people to use exact type instead of dynamic or use static Returns method. - // 2. Try to catch calls with dynamic typing and throw descriptive exception. Can be made via StackTrace. A bit hacky and risky. - // TBD - sut.GetsDynamic(Arg.Any()).Returns(1); - - dynamic expando = new System.Dynamic.ExpandoObject(); - var result = sut.GetsDynamic(expando); - - Assert.That(result, Is.EqualTo(1)); - } - - [Test] - public void MethodGetsDynamicButSpecifiedWithExplicitType() - { - var sut = Substitute.For(); - sut.GetsDynamic(Arg.Any()).Returns(1); - - dynamic expando = new System.Dynamic.ExpandoObject(); - var result = sut.GetsDynamic(expando); - - Assert.That(result, Is.EqualTo(1)); - } - - [Test] - public void DynamicProperty() - { - var sut = Substitute.For(); - sut.DynamicProperty.Returns(1); - - var result = sut.DynamicProperty; - - Assert.That(result, Is.EqualTo(1)); - } - - [Test] - public void MethodGetsDynamicAsAnArgumentAndReturnsDynamic() - { - var sut = Substitute.For(); - sut.ReturnsAndGetsDynamic(Arg.Any()).Returns(1); - - dynamic expando = new System.Dynamic.ExpandoObject(); - var result = sut.ReturnsAndGetsDynamic(expando); - - Assert.That(result, Is.EqualTo(1)); - } - - [Test] - public void MethodReturnsDynamic() - { - var sut = Substitute.For(); - sut.ReturnsDynamic(Arg.Any()).Returns(1); - - var result = sut.ReturnsDynamic(""); - - Assert.That(result, Is.EqualTo(1)); - } + var sut = Substitute.For(); + sut.DynamicProperty.Returns(1); + + var result = sut.DynamicProperty; + + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void MethodGetsDynamicAsAnArgumentAndReturnsDynamic() + { + var sut = Substitute.For(); + sut.ReturnsAndGetsDynamic(Arg.Any()).Returns(1); + + dynamic expando = new System.Dynamic.ExpandoObject(); + var result = sut.ReturnsAndGetsDynamic(expando); + + Assert.That(result, Is.EqualTo(1)); + } + + [Test] + public void MethodReturnsDynamic() + { + var sut = Substitute.For(); + sut.ReturnsDynamic(Arg.Any()).Returns(1); + + var result = sut.ReturnsDynamic(""); + + Assert.That(result, Is.EqualTo(1)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/EventChecking.cs b/tests/NSubstitute.Acceptance.Specs/EventChecking.cs index 83f060ade..651a8f160 100644 --- a/tests/NSubstitute.Acceptance.Specs/EventChecking.cs +++ b/tests/NSubstitute.Acceptance.Specs/EventChecking.cs @@ -1,53 +1,52 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class EventChecking { - public class EventChecking + [Test] + public void Check_if_event_was_subscribed_to() { - [Test] - public void Check_if_event_was_subscribed_to() - { - var engine = Substitute.For(); - Action handler = () => { }; - Action someOtherHandler = () => { }; - engine.Started += handler; - engine.Received().Started += handler; - Assert.Throws(() => engine.Received().Started += someOtherHandler); - } + var engine = Substitute.For(); + Action handler = () => { }; + Action someOtherHandler = () => { }; + engine.Started += handler; + engine.Received().Started += handler; + Assert.Throws(() => engine.Received().Started += someOtherHandler); + } - [Test] - public void Check_if_nullHandlers_are_ignored() - { - var raised = false; - var source = Substitute.For(); - source.Started += null; - source.Started += () => raised = true; - source.Started += Raise.Event(); + [Test] + public void Check_if_nullHandlers_are_ignored() + { + var raised = false; + var source = Substitute.For(); + source.Started += null; + source.Started += () => raised = true; + source.Started += Raise.Event(); - Assert.IsTrue(raised); - } + Assert.IsTrue(raised); + } - [Test] - public void Check_if_multiple_handlers_get_called() - { - var raised1 = false; - var raised2 = false; - var raised3 = false; - var source = Substitute.For(); - source.Started += () => raised1 = true; - source.Started += () => raised2 = true; - source.Started += () => raised3 = true; - source.Started += Raise.Event(); + [Test] + public void Check_if_multiple_handlers_get_called() + { + var raised1 = false; + var raised2 = false; + var raised3 = false; + var source = Substitute.For(); + source.Started += () => raised1 = true; + source.Started += () => raised2 = true; + source.Started += () => raised3 = true; + source.Started += Raise.Event(); - Assert.IsTrue(raised1, "The first handler was not called"); - Assert.IsTrue(raised2, "The second handler was not called"); - Assert.IsTrue(raised3, "The third handler was not called"); - } + Assert.IsTrue(raised1, "The first handler was not called"); + Assert.IsTrue(raised2, "The second handler was not called"); + Assert.IsTrue(raised3, "The third handler was not called"); + } - public interface IEngine - { - event Action Started; - } + public interface IEngine + { + event Action Started; } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/EventRaising.cs b/tests/NSubstitute.Acceptance.Specs/EventRaising.cs index 1ca4cbb98..91b49d1b7 100644 --- a/tests/NSubstitute.Acceptance.Specs/EventRaising.cs +++ b/tests/NSubstitute.Acceptance.Specs/EventRaising.cs @@ -1,344 +1,343 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class EventRaising { - public class EventRaising + [Test] + public void Raise_event_with_standard_event_args() { - [Test] - public void Raise_event_with_standard_event_args() - { - var sender = new object(); - var arguments = new EventArgs(); + var sender = new object(); + var arguments = new EventArgs(); - var eventSource = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSource.StandardEventHandler += eventRecorder.Record; - eventSource.StandardEventHandler += Raise.EventWith(sender, arguments); + var eventSource = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSource.StandardEventHandler += eventRecorder.Record; + eventSource.StandardEventHandler += Raise.EventWith(sender, arguments); - Assert.That(eventRecorder.Sender, Is.SameAs(sender)); - Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); - } + Assert.That(eventRecorder.Sender, Is.SameAs(sender)); + Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); + } - [Test] - public void Raise_event_with_custom_event_args() - { - var sender = new object(); - var arguments = new CustomEventArgs(); + [Test] + public void Raise_event_with_custom_event_args() + { + var sender = new object(); + var arguments = new CustomEventArgs(); - var eventSamples = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSamples.EventHandlerWithCustomArgs += eventRecorder.Record; - eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(sender, arguments); + var eventSamples = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSamples.EventHandlerWithCustomArgs += eventRecorder.Record; + eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(sender, arguments); - Assert.That(eventRecorder.Sender, Is.SameAs(sender)); - Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); - } + Assert.That(eventRecorder.Sender, Is.SameAs(sender)); + Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); + } - [Test] - public void Raise_event_with_standard_event_args_and_sender_automatically_set_to_substitute() - { - var arguments = new EventArgs(); + [Test] + public void Raise_event_with_standard_event_args_and_sender_automatically_set_to_substitute() + { + var arguments = new EventArgs(); - var eventSource = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSource.StandardEventHandler += eventRecorder.Record; - eventSource.StandardEventHandler += Raise.EventWith(arguments); + var eventSource = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSource.StandardEventHandler += eventRecorder.Record; + eventSource.StandardEventHandler += Raise.EventWith(arguments); - Assert.That(eventRecorder.Sender, Is.SameAs(eventSource)); - Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); - } + Assert.That(eventRecorder.Sender, Is.SameAs(eventSource)); + Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); + } - [Test] - public void Raise_event_with_standard_event_args_as_generic_and_sender_automatically_set_to_substitute() - { - var arguments = new EventArgs(); + [Test] + public void Raise_event_with_standard_event_args_as_generic_and_sender_automatically_set_to_substitute() + { + var arguments = new EventArgs(); - var eventSource = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSource.StandardGenericEventHandler += eventRecorder.Record; - eventSource.StandardGenericEventHandler += Raise.EventWith(arguments); + var eventSource = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSource.StandardGenericEventHandler += eventRecorder.Record; + eventSource.StandardGenericEventHandler += Raise.EventWith(arguments); - Assert.That(eventRecorder.Sender, Is.SameAs(eventSource)); - Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); - } + Assert.That(eventRecorder.Sender, Is.SameAs(eventSource)); + Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); + } - [Test] - public void Raise_event_with_custom_event_args_and_sender_automatically_set_to_substitute() - { - var arguments = new CustomEventArgs(); + [Test] + public void Raise_event_with_custom_event_args_and_sender_automatically_set_to_substitute() + { + var arguments = new CustomEventArgs(); - var eventSamples = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSamples.EventHandlerWithCustomArgs += eventRecorder.Record; - eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(arguments); + var eventSamples = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSamples.EventHandlerWithCustomArgs += eventRecorder.Record; + eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(arguments); - Assert.That(eventRecorder.Sender, Is.SameAs(eventSamples)); - Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); - } + Assert.That(eventRecorder.Sender, Is.SameAs(eventSamples)); + Assert.That(eventRecorder.EventArgs, Is.SameAs(arguments)); + } - [Test] - public void Raise_standard_event_with_empty_event_args() - { - var eventSamples = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSamples.StandardEventHandler += eventRecorder.Record; - eventSamples.StandardEventHandler += Raise.Event(); + [Test] + public void Raise_standard_event_with_empty_event_args() + { + var eventSamples = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSamples.StandardEventHandler += eventRecorder.Record; + eventSamples.StandardEventHandler += Raise.Event(); - Assert.That(eventRecorder.Sender, Is.EqualTo(eventSamples)); - Assert.That(eventRecorder.EventArgs, Is.EqualTo(EventArgs.Empty)); - } + Assert.That(eventRecorder.Sender, Is.EqualTo(eventSamples)); + Assert.That(eventRecorder.EventArgs, Is.EqualTo(EventArgs.Empty)); + } - [Test] - public void Raise_standard_generic_event_with_empty_event_args() - { - var eventSamples = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSamples.StandardGenericEventHandler += eventRecorder.Record; - eventSamples.StandardGenericEventHandler += Raise.Event(); + [Test] + public void Raise_standard_generic_event_with_empty_event_args() + { + var eventSamples = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSamples.StandardGenericEventHandler += eventRecorder.Record; + eventSamples.StandardGenericEventHandler += Raise.Event(); - Assert.That(eventRecorder.Sender, Is.EqualTo(eventSamples)); - Assert.That(eventRecorder.EventArgs, Is.EqualTo(EventArgs.Empty)); - } + Assert.That(eventRecorder.Sender, Is.EqualTo(eventSamples)); + Assert.That(eventRecorder.EventArgs, Is.EqualTo(EventArgs.Empty)); + } - [Test] - public void Raise_event_with_custom_event_args_that_have_a_default_ctor_and_automatically_set_sender_and_args() - { - var eventSamples = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSamples.EventHandlerWithCustomArgs += eventRecorder.Record; - eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(); + [Test] + public void Raise_event_with_custom_event_args_that_have_a_default_ctor_and_automatically_set_sender_and_args() + { + var eventSamples = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSamples.EventHandlerWithCustomArgs += eventRecorder.Record; + eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(); - Assert.That(eventRecorder.Sender, Is.SameAs(eventSamples)); - Assert.That(eventRecorder.EventArgs, Is.Not.Null); - } + Assert.That(eventRecorder.Sender, Is.SameAs(eventSamples)); + Assert.That(eventRecorder.EventArgs, Is.Not.Null); + } - [Test] - public void Raise_event_with_custom_event_args_with_no_default_ctor_should_throw() - { - var eventSamples = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - eventSamples.EventHandlerWithCustomArgsAndNoDefaultCtor += eventRecorder.Record; + [Test] + public void Raise_event_with_custom_event_args_with_no_default_ctor_should_throw() + { + var eventSamples = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + eventSamples.EventHandlerWithCustomArgsAndNoDefaultCtor += eventRecorder.Record; - Assert.Throws(() => - eventSamples.EventHandlerWithCustomArgsAndNoDefaultCtor += Raise.EventWith() - ); - } + Assert.Throws(() => + eventSamples.EventHandlerWithCustomArgsAndNoDefaultCtor += Raise.EventWith() + ); + } - [Test] - public void Raise_event_declared_as_action() - { - var wasStarted = false; - var eventSamples = Substitute.For(); - eventSamples.ActionEvent += () => wasStarted = true; + [Test] + public void Raise_event_declared_as_action() + { + var wasStarted = false; + var eventSamples = Substitute.For(); + eventSamples.ActionEvent += () => wasStarted = true; - Assert.That(wasStarted, Is.False, "Why is this started before event was raised? Something has gone wrong!"); - eventSamples.ActionEvent += Raise.Event(); - Assert.That(wasStarted); - } + Assert.That(wasStarted, Is.False, "Why is this started before event was raised? Something has gone wrong!"); + eventSamples.ActionEvent += Raise.Event(); + Assert.That(wasStarted); + } - [Test] - public void Raise_event_declared_as_action_with_one_parameter() - { - var arg = 0; - var eventSamples = Substitute.For(); - eventSamples.ActionEventWithOneArg += x => arg = x; + [Test] + public void Raise_event_declared_as_action_with_one_parameter() + { + var arg = 0; + var eventSamples = Substitute.For(); + eventSamples.ActionEventWithOneArg += x => arg = x; - Assert.That(arg, Is.EqualTo(0)); - eventSamples.ActionEventWithOneArg += Raise.Event>(42); - Assert.That(arg, Is.EqualTo(42)); - } + Assert.That(arg, Is.EqualTo(0)); + eventSamples.ActionEventWithOneArg += Raise.Event>(42); + Assert.That(arg, Is.EqualTo(42)); + } - [Test] - public void Raise_event_declared_as_custom_delegate_type() - { - var intArg = 0; - var stringArg = ""; - var eventSamples = Substitute.For(); - eventSamples.FuncDelegateWithArgs += (x, y) => { intArg = x; stringArg = y; return 0; }; - - eventSamples.FuncDelegateWithArgs += Raise.Event(87, "hello"); - Assert.That(intArg, Is.EqualTo(87)); - Assert.That(stringArg, Is.EqualTo("hello")); - } + [Test] + public void Raise_event_declared_as_custom_delegate_type() + { + var intArg = 0; + var stringArg = ""; + var eventSamples = Substitute.For(); + eventSamples.FuncDelegateWithArgs += (x, y) => { intArg = x; stringArg = y; return 0; }; + + eventSamples.FuncDelegateWithArgs += Raise.Event(87, "hello"); + Assert.That(intArg, Is.EqualTo(87)); + Assert.That(stringArg, Is.EqualTo("hello")); + } - [Test] - public void Raise_event_will_throw_same_exception_as_thrown_in_event_handler() - { - var eventSamples = Substitute.For(); - eventSamples.EventHandlerWithCustomArgs += (sender, e) => { throw new Exception(); }; - Assert.Throws(() => eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(new CustomEventArgs())); - } + [Test] + public void Raise_event_will_throw_same_exception_as_thrown_in_event_handler() + { + var eventSamples = Substitute.For(); + eventSamples.EventHandlerWithCustomArgs += (sender, e) => { throw new Exception(); }; + Assert.Throws(() => eventSamples.EventHandlerWithCustomArgs += Raise.EventWith(new CustomEventArgs())); + } - [Test] - public void Raise_event_declared_as_delegate_with_no_args() - { - var sub = Substitute.For(); - var wasRaised = false; - sub.DelegateEventWithoutArgs += () => wasRaised = true; - sub.DelegateEventWithoutArgs += Raise.Event(); - Assert.That(wasRaised); - } + [Test] + public void Raise_event_declared_as_delegate_with_no_args() + { + var sub = Substitute.For(); + var wasRaised = false; + sub.DelegateEventWithoutArgs += () => wasRaised = true; + sub.DelegateEventWithoutArgs += Raise.Event(); + Assert.That(wasRaised); + } - [Test] - public void Raise_event_declared_as_delegate_with_event_args() - { - var sub = Substitute.For(); - var recorder = new RaisedEventRecorder(); - sub.DelegateEventWithEventArgs += (sender, args) => recorder.Record(sender, args); - sub.DelegateEventWithEventArgs += Raise.Event(); - Assert.That(recorder.WasCalled); - Assert.That(recorder.EventArgs, Is.EqualTo(EventArgs.Empty)); - } + [Test] + public void Raise_event_declared_as_delegate_with_event_args() + { + var sub = Substitute.For(); + var recorder = new RaisedEventRecorder(); + sub.DelegateEventWithEventArgs += (sender, args) => recorder.Record(sender, args); + sub.DelegateEventWithEventArgs += Raise.Event(); + Assert.That(recorder.WasCalled); + Assert.That(recorder.EventArgs, Is.EqualTo(EventArgs.Empty)); + } - [Test] - public void Raise_event_declared_as_delegate_with_an_integer_arg() - { - var sub = Substitute.For(); - var wasCalledWithArg = -1; - sub.DelegateEventWithAnArg += x => wasCalledWithArg = x; - sub.DelegateEventWithAnArg += Raise.Event(123); - Assert.That(wasCalledWithArg, Is.EqualTo(123)); - } + [Test] + public void Raise_event_declared_as_delegate_with_an_integer_arg() + { + var sub = Substitute.For(); + var wasCalledWithArg = -1; + sub.DelegateEventWithAnArg += x => wasCalledWithArg = x; + sub.DelegateEventWithAnArg += Raise.Event(123); + Assert.That(wasCalledWithArg, Is.EqualTo(123)); + } - [Test] - public void Raise_event_with_incorrect_number_of_args() - { - var expectedExceptionMessage = string.Format( - "Cannot raise event with the provided arguments. Use Raise.Event<{0}>({1}) to raise this event.", - typeof(VoidDelegateWithAnArg).Name, - typeof(int).Name - ); - var sub = Substitute.For(); - Assert.That( - () => { sub.DelegateEventWithAnArg += Raise.Event(); }, - Throws.TypeOf().With.Message.EqualTo(expectedExceptionMessage) - ); - } + [Test] + public void Raise_event_with_incorrect_number_of_args() + { + var expectedExceptionMessage = string.Format( + "Cannot raise event with the provided arguments. Use Raise.Event<{0}>({1}) to raise this event.", + typeof(VoidDelegateWithAnArg).Name, + typeof(int).Name + ); + var sub = Substitute.For(); + Assert.That( + () => { sub.DelegateEventWithAnArg += Raise.Event(); }, + Throws.TypeOf().With.Message.EqualTo(expectedExceptionMessage) + ); + } - [Test] - public void Raise_event_with_incorrect_arg_types() - { - var expectedExceptionMessage = string.Format( - "Cannot raise event with the provided arguments. Use Raise.Event<{0}>({1}, {2}) to raise this event.", - typeof(VoidDelegateWithMultipleArgs).Name, - typeof(int).Name, - typeof(string).Name - ); - var sub = Substitute.For(); - Assert.That( - () => { sub.DelegateEventWithMultipleArgs += Raise.Event("test", "test"); }, - Throws.TypeOf().With.Message.EqualTo(expectedExceptionMessage) - ); - } + [Test] + public void Raise_event_with_incorrect_arg_types() + { + var expectedExceptionMessage = string.Format( + "Cannot raise event with the provided arguments. Use Raise.Event<{0}>({1}, {2}) to raise this event.", + typeof(VoidDelegateWithMultipleArgs).Name, + typeof(int).Name, + typeof(string).Name + ); + var sub = Substitute.For(); + Assert.That( + () => { sub.DelegateEventWithMultipleArgs += Raise.Event("test", "test"); }, + Throws.TypeOf().With.Message.EqualTo(expectedExceptionMessage) + ); + } - [Test] - public void Raise_event_for_delegate_with_return_value() - { - var sub = Substitute.For(); - var wasCalled = false; - sub.FuncDelegate += () => { wasCalled = true; return 0; }; - sub.FuncDelegate += Raise.Event(); - Assert.That(wasCalled); - } + [Test] + public void Raise_event_for_delegate_with_return_value() + { + var sub = Substitute.For(); + var wasCalled = false; + sub.FuncDelegate += () => { wasCalled = true; return 0; }; + sub.FuncDelegate += Raise.Event(); + Assert.That(wasCalled); + } - [Test] - public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler() - { - var sender = new object(); - var eventArgs = new CustomEventArgs(); - var sub = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; - - sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(sender, eventArgs); - Assert.That(eventRecorder.WasCalled); - Assert.That(eventRecorder.EventArgs, Is.SameAs(eventArgs)); - Assert.That(eventRecorder.Sender, Is.SameAs(sender)); - } + [Test] + public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler() + { + var sender = new object(); + var eventArgs = new CustomEventArgs(); + var sub = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; + + sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(sender, eventArgs); + Assert.That(eventRecorder.WasCalled); + Assert.That(eventRecorder.EventArgs, Is.SameAs(eventArgs)); + Assert.That(eventRecorder.Sender, Is.SameAs(sender)); + } - [Test] - public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler_without_providing_arguments() - { - var sub = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; - - sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(); - Assert.That(eventRecorder.WasCalled); - Assert.That(eventRecorder.EventArgs, Is.Not.Null); - Assert.That(eventRecorder.Sender, Is.SameAs(sub)); - } + [Test] + public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler_without_providing_arguments() + { + var sub = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; + + sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(); + Assert.That(eventRecorder.WasCalled); + Assert.That(eventRecorder.EventArgs, Is.Not.Null); + Assert.That(eventRecorder.Sender, Is.SameAs(sub)); + } - [Test] - public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler_when_only_providing_event_args() - { - var eventArgs = new CustomEventArgs(); - var sub = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; - - sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(eventArgs); - Assert.That(eventRecorder.WasCalled); - Assert.That(eventRecorder.EventArgs, Is.SameAs(eventArgs)); - Assert.That(eventRecorder.Sender, Is.SameAs(sub)); - } + [Test] + public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler_when_only_providing_event_args() + { + var eventArgs = new CustomEventArgs(); + var sub = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; + + sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(eventArgs); + Assert.That(eventRecorder.WasCalled); + Assert.That(eventRecorder.EventArgs, Is.SameAs(eventArgs)); + Assert.That(eventRecorder.Sender, Is.SameAs(sub)); + } - [Test] - public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler_when_only_providing_sender() - { - var sender = new object(); - var sub = Substitute.For(); - var eventRecorder = new RaisedEventRecorder(); - sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; - - sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(sender); - Assert.That(eventRecorder.WasCalled); - Assert.That(eventRecorder.EventArgs, Is.Not.Null); - Assert.That(eventRecorder.Sender, Is.SameAs(sender)); - } + [Test] + public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_from_EventHandler_when_only_providing_sender() + { + var sender = new object(); + var sub = Substitute.For(); + var eventRecorder = new RaisedEventRecorder(); + sub.CustomEventThatDoesNotInheritFromEventHandler += eventRecorder.Record; + + sub.CustomEventThatDoesNotInheritFromEventHandler += Raise.Event(sender); + Assert.That(eventRecorder.WasCalled); + Assert.That(eventRecorder.EventArgs, Is.Not.Null); + Assert.That(eventRecorder.Sender, Is.SameAs(sender)); + } - class RaisedEventRecorder - { - public object Sender; - public T EventArgs; - public bool WasCalled; - - public void Record(object sender, T eventArgs) - { - WasCalled = true; - Sender = sender; - EventArgs = eventArgs; - } - } + class RaisedEventRecorder + { + public object Sender; + public T EventArgs; + public bool WasCalled; - public interface IEventSamples - { - event Action ActionEvent; - event Action ActionEventWithOneArg; - event VoidDelegateWithEventArgs DelegateEventWithEventArgs; - event VoidDelegateWithoutArgs DelegateEventWithoutArgs; - event VoidDelegateWithAnArg DelegateEventWithAnArg; - event VoidDelegateWithMultipleArgs DelegateEventWithMultipleArgs; - event FuncDelegateWithoutArgs FuncDelegate; - event FuncDelegateWithArgs FuncDelegateWithArgs; - event EventHandler StandardEventHandler; - event EventHandler StandardGenericEventHandler; - event EventHandler EventHandlerWithCustomArgs; - event EventHandler EventHandlerWithCustomArgsAndNoDefaultCtor; - event CustomEventThatDoesNotInheritFromEventHandler CustomEventThatDoesNotInheritFromEventHandler; - } - public delegate void VoidDelegateWithoutArgs(); - public delegate void VoidDelegateWithEventArgs(object sender, EventArgs args); - public delegate void VoidDelegateWithAnArg(int arg); - public delegate void VoidDelegateWithMultipleArgs(int intArg, string stringArg); - public delegate int FuncDelegateWithoutArgs(); - public delegate int FuncDelegateWithArgs(int intArg, string stringArg); - public delegate void CustomEventThatDoesNotInheritFromEventHandler(object sender, CustomEventArgs args); - public class CustomEventArgs : EventArgs { } - public class CustomEventArgsWithNoDefaultCtor : EventArgs + public void Record(object sender, T eventArgs) { - public CustomEventArgsWithNoDefaultCtor(string arg) { } + WasCalled = true; + Sender = sender; + EventArgs = eventArgs; } } + + public interface IEventSamples + { + event Action ActionEvent; + event Action ActionEventWithOneArg; + event VoidDelegateWithEventArgs DelegateEventWithEventArgs; + event VoidDelegateWithoutArgs DelegateEventWithoutArgs; + event VoidDelegateWithAnArg DelegateEventWithAnArg; + event VoidDelegateWithMultipleArgs DelegateEventWithMultipleArgs; + event FuncDelegateWithoutArgs FuncDelegate; + event FuncDelegateWithArgs FuncDelegateWithArgs; + event EventHandler StandardEventHandler; + event EventHandler StandardGenericEventHandler; + event EventHandler EventHandlerWithCustomArgs; + event EventHandler EventHandlerWithCustomArgsAndNoDefaultCtor; + event CustomEventThatDoesNotInheritFromEventHandler CustomEventThatDoesNotInheritFromEventHandler; + } + public delegate void VoidDelegateWithoutArgs(); + public delegate void VoidDelegateWithEventArgs(object sender, EventArgs args); + public delegate void VoidDelegateWithAnArg(int arg); + public delegate void VoidDelegateWithMultipleArgs(int intArg, string stringArg); + public delegate int FuncDelegateWithoutArgs(); + public delegate int FuncDelegateWithArgs(int intArg, string stringArg); + public delegate void CustomEventThatDoesNotInheritFromEventHandler(object sender, CustomEventArgs args); + public class CustomEventArgs : EventArgs { } + public class CustomEventArgsWithNoDefaultCtor : EventArgs + { + public CustomEventArgsWithNoDefaultCtor(string arg) { } + } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingReceivedCalls.cs b/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingReceivedCalls.cs index 2a550c3f4..7c1800cfa 100644 --- a/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingReceivedCalls.cs +++ b/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingReceivedCalls.cs @@ -1,120 +1,119 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +public class ExceptionsWhenCheckingReceivedCalls { - public class ExceptionsWhenCheckingReceivedCalls + public interface IFoo { - public interface IFoo - { - void Bar(); - void Zap(int a); - } + void Bar(); + void Zap(int a); + } - IFoo _foo; + IFoo _foo; - [SetUp] - public void SetUp() - { - _foo = Substitute.For(); - } + [SetUp] + public void SetUp() + { + _foo = Substitute.For(); + } - [Test] - public void Expected_call_was_not_received() - { - ShouldThrow(() => _foo.Received().Bar()); - } + [Test] + public void Expected_call_was_not_received() + { + ShouldThrow(() => _foo.Received().Bar()); + } - [Test] - public void Unexpected_call_was_received() - { - _foo.Bar(); + [Test] + public void Unexpected_call_was_received() + { + _foo.Bar(); - ShouldThrow(() => _foo.DidNotReceive().Bar()); - ShouldThrow(() => _foo.Received(0).Bar()); - } + ShouldThrow(() => _foo.DidNotReceive().Bar()); + ShouldThrow(() => _foo.Received(0).Bar()); + } - [Test] - public void Expected_call_was_received_too_many_times() - { - _foo.Bar(); - _foo.Bar(); - _foo.Bar(); + [Test] + public void Expected_call_was_received_too_many_times() + { + _foo.Bar(); + _foo.Bar(); + _foo.Bar(); - ShouldThrow(() => _foo.Received(2).Bar()); - } + ShouldThrow(() => _foo.Received(2).Bar()); + } - [Test] - public void Expected_call_was_not_received_enough_times() - { - _foo.Bar(); + [Test] + public void Expected_call_was_not_received_enough_times() + { + _foo.Bar(); - ShouldThrow(() => _foo.Received(2).Bar()); - } + ShouldThrow(() => _foo.Received(2).Bar()); + } - [Test] - public void Expected_single_call() - { - _foo.Bar(); - _foo.Bar(); - ShouldThrow(() => _foo.Received(1).Bar()); - } + [Test] + public void Expected_single_call() + { + _foo.Bar(); + _foo.Bar(); + ShouldThrow(() => _foo.Received(1).Bar()); + } - [Test] - public void Expected_call_not_received_enough_times_and_other_related_calls_received() - { - _foo.Zap(1); - _foo.Zap(1); - _foo.Zap(1); - _foo.Zap(2); + [Test] + public void Expected_call_not_received_enough_times_and_other_related_calls_received() + { + _foo.Zap(1); + _foo.Zap(1); + _foo.Zap(1); + _foo.Zap(2); - ShouldThrow(() => _foo.Received(4).Zap(1)); - } + ShouldThrow(() => _foo.Received(4).Zap(1)); + } - [Test] - public void Expected_call_received_enough_times_and_other_related_calls_received() - { - _foo.Zap(1); - _foo.Zap(1); - _foo.Zap(1); - _foo.Zap(2); + [Test] + public void Expected_call_received_enough_times_and_other_related_calls_received() + { + _foo.Zap(1); + _foo.Zap(1); + _foo.Zap(1); + _foo.Zap(2); - ShouldThrow(() => _foo.Received(2).Zap(1)); - } + ShouldThrow(() => _foo.Received(2).Zap(1)); + } - [Test] - public void Expected_call_specified_with_argument_matchers_not_received_enough_times() - { - _foo.Zap(1); - _foo.Zap(2); - _foo.Zap(3); - _foo.Zap(4); + [Test] + public void Expected_call_specified_with_argument_matchers_not_received_enough_times() + { + _foo.Zap(1); + _foo.Zap(2); + _foo.Zap(3); + _foo.Zap(4); - ShouldThrow(() => _foo.Received(4).Zap(Arg.Is(x => x < 4))); - } + ShouldThrow(() => _foo.Received(4).Zap(Arg.Is(x => x < 4))); + } - [Test] - public void Expected_call_specified_with_argument_matchers_received_enough_times() - { - _foo.Zap(1); - _foo.Zap(2); - _foo.Zap(3); - _foo.Zap(4); + [Test] + public void Expected_call_specified_with_argument_matchers_received_enough_times() + { + _foo.Zap(1); + _foo.Zap(2); + _foo.Zap(3); + _foo.Zap(4); - _foo.Received(3).Zap(Arg.Is(x => x < 4)); - } + _foo.Received(3).Zap(Arg.Is(x => x < 4)); + } - void ShouldThrow(Action action) + void ShouldThrow(Action action) + { + try + { + action(); + } + catch (ReceivedCallsException) { - try - { - action(); - } - catch (ReceivedCallsException) - { - return; - } - Assert.Fail("Exception not thrown."); + return; } + Assert.Fail("Exception not thrown."); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingSequencesOfCalls.cs b/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingSequencesOfCalls.cs index 214149c11..5e46f77d8 100644 --- a/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingSequencesOfCalls.cs +++ b/tests/NSubstitute.Acceptance.Specs/ExceptionsWhenCheckingSequencesOfCalls.cs @@ -1,41 +1,41 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs +namespace NSubstitute.Acceptance.Specs; + +/***** Types should be declared outside of the class, otherwise they are rendered as nested in error message *****/ +public interface IFoo { - /***** Types should be declared outside of the class, otherwise they are rendered as nested in error message *****/ - public interface IFoo - { - void Bar(); - void Zap(); - } + void Bar(); + void Zap(); +} - public interface IBaz - { - void Gloop(int i); - void Slop(object o, string s); - } +public interface IBaz +{ + void Gloop(int i); + void Slop(object o, string s); +} - public interface IBar - { - int Huh(); - } +public interface IBar +{ + int Huh(); +} - [TestFixture] - public class ExceptionsWhenCheckingSequencesOfCalls +[TestFixture] +public class ExceptionsWhenCheckingSequencesOfCalls +{ + [Test] + public void When_missing_a_call() { - [Test] - public void When_missing_a_call() - { - var sub = Substitute.For(); - sub.Bar(); - - Action action = () => - { - sub.Bar(); - sub.Zap(); - }; - ExpectMessageFromQuery(action, @" + var sub = Substitute.For(); + sub.Bar(); + + Action action = () => + { + sub.Bar(); + sub.Zap(); + }; + ExpectMessageFromQuery(action, @" Expected to receive these calls in order: Bar() @@ -44,24 +44,24 @@ public void When_missing_a_call() Actually received matching calls in this order: Bar()"); - } - - [Test] - public void When_non_matching_args() - { - var anObject = new object(); - var sub = Substitute.For(); - sub.Gloop(2); - sub.Slop(anObject, "hello"); - sub.Gloop(3); - - Action action = () => - { - sub.Gloop(2); - sub.Slop(anObject, "hi"); - sub.Gloop(123); - }; - ExpectMessageFromQuery(action, @"Expected to receive these calls in order: + } + + [Test] + public void When_non_matching_args() + { + var anObject = new object(); + var sub = Substitute.For(); + sub.Gloop(2); + sub.Slop(anObject, "hello"); + sub.Gloop(3); + + Action action = () => + { + sub.Gloop(2); + sub.Slop(anObject, "hi"); + sub.Gloop(123); + }; + ExpectMessageFromQuery(action, @"Expected to receive these calls in order: Gloop(2) Slop(Object, ""hi"") @@ -70,23 +70,23 @@ public void When_non_matching_args() Actually received matching calls in this order: Gloop(2)"); - } + } - [Test] - public void When_extra_call() - { - var sub = Substitute.For(); - sub.Bar(); - sub.Bar(); - sub.Zap(); + [Test] + public void When_extra_call() + { + var sub = Substitute.For(); + sub.Bar(); + sub.Bar(); + sub.Zap(); - Action action = () => - { - sub.Bar(); - sub.Zap(); - }; + Action action = () => + { + sub.Bar(); + sub.Zap(); + }; - ExpectMessageFromQuery(action, @"Expected to receive these calls in order: + ExpectMessageFromQuery(action, @"Expected to receive these calls in order: Bar() Zap() @@ -97,29 +97,29 @@ public void When_extra_call() Bar() Zap() "); - } - - [Test] - public void When_checking_across_multiple_subs_with_same_type() - { - var sub0 = Substitute.For(); - var sub1 = Substitute.For(); - - sub0.Bar(); - sub1.Bar(); - sub0.Zap(); - sub1.Zap(); - - Action action = () => - { - sub0.Bar(); - sub1.Bar(); - sub1.Bar(); - sub1.Zap(); - sub0.Zap(); - }; - - ExpectMessageFromQuery(action, @"Expected to receive these calls in order: + } + + [Test] + public void When_checking_across_multiple_subs_with_same_type() + { + var sub0 = Substitute.For(); + var sub1 = Substitute.For(); + + sub0.Bar(); + sub1.Bar(); + sub0.Zap(); + sub1.Zap(); + + Action action = () => + { + sub0.Bar(); + sub1.Bar(); + sub1.Bar(); + sub1.Zap(); + sub0.Zap(); + }; + + ExpectMessageFromQuery(action, @"Expected to receive these calls in order: 1@IFoo.Bar() 2@IFoo.Bar() @@ -133,29 +133,29 @@ public void When_checking_across_multiple_subs_with_same_type() 2@IFoo.Bar() 1@IFoo.Zap() 2@IFoo.Zap()"); - } - - [Test] - public void When_checking_across_multiple_subs_including_delegates() - { - var sub0 = Substitute.For(); - var sub1 = Substitute.For>(); - var sub2 = Substitute.For(); - - sub0.Bar(); - sub1(2); - sub0.Zap(); - sub2.Zap(); - - Action action = () => - { - sub0.Bar(); - sub1(2); - sub2.Zap(); - sub0.Zap(); - }; - - ExpectMessageFromQuery(action, @"Expected to receive these calls in order: + } + + [Test] + public void When_checking_across_multiple_subs_including_delegates() + { + var sub0 = Substitute.For(); + var sub1 = Substitute.For>(); + var sub2 = Substitute.For(); + + sub0.Bar(); + sub1(2); + sub0.Zap(); + sub2.Zap(); + + Action action = () => + { + sub0.Bar(); + sub1(2); + sub2.Zap(); + sub0.Zap(); + }; + + ExpectMessageFromQuery(action, @"Expected to receive these calls in order: 1@IFoo.Bar() 2@Func.Invoke(2) @@ -168,29 +168,29 @@ public void When_checking_across_multiple_subs_including_delegates() 2@Func.Invoke(2) 1@IFoo.Zap() 3@IFoo.Zap()"); - } - - [Test] - public void Do_not_number_instances_when_types_are_sufficient_to_identify_calls() - { - var a = Substitute.For(); - var b = Substitute.For(); - var c = Substitute.For(); - - a.Zap(); - c.Huh(); - b.Gloop(1); - a.Bar(); - - Action query = () => - { - a.Zap(); - b.Gloop(1); - c.Huh(); - a.Bar(); - }; - - ExpectMessageFromQuery(query, @"Expected to receive these calls in order: + } + + [Test] + public void Do_not_number_instances_when_types_are_sufficient_to_identify_calls() + { + var a = Substitute.For(); + var b = Substitute.For(); + var c = Substitute.For(); + + a.Zap(); + c.Huh(); + b.Gloop(1); + a.Bar(); + + Action query = () => + { + a.Zap(); + b.Gloop(1); + c.Huh(); + a.Bar(); + }; + + ExpectMessageFromQuery(query, @"Expected to receive these calls in order: IFoo.Zap() IBaz.Gloop(1) @@ -203,18 +203,17 @@ public void Do_not_number_instances_when_types_are_sufficient_to_identify_calls( IBar.Huh() IBaz.Gloop(1) IFoo.Bar()"); - } + } - private void ExpectMessageFromQuery(Action query, string message) - { - var actualMessage = Assert.Throws(() => Received.InOrder(query)).Message; + private void ExpectMessageFromQuery(Action query, string message) + { + var actualMessage = Assert.Throws(() => Received.InOrder(query)).Message; - Assert.That(TrimAndFixLineEndings(actualMessage), Does.StartWith(TrimAndFixLineEndings(message))); - } + Assert.That(TrimAndFixLineEndings(actualMessage), Does.StartWith(TrimAndFixLineEndings(message))); + } - private string TrimAndFixLineEndings(string s) - { - return s.Trim().Replace("\r\n", "\n"); - } + private string TrimAndFixLineEndings(string s) + { + return s.Trim().Replace("\r\n", "\n"); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithNestedSubCalls.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithNestedSubCalls.cs index 75ffe97bf..078c61f3a 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithNestedSubCalls.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithNestedSubCalls.cs @@ -1,40 +1,39 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class ArgMatchingWithNestedSubCalls { - public class ArgMatchingWithNestedSubCalls + public interface IHaveAMethod { void Method(int a, string b); } + public interface IStealArgMatchers + { + string StealMatcherBeforeUsedElsewhere { get; } + string this[int i] { get; } + } + + [Test] + public void Use_arg_matcher_then_access_another_sub_without_args_before_call_spec_is_created() { - public interface IHaveAMethod { void Method(int a, string b); } - public interface IStealArgMatchers - { - string StealMatcherBeforeUsedElsewhere { get; } - string this[int i] { get; } - } - - [Test] - public void Use_arg_matcher_then_access_another_sub_without_args_before_call_spec_is_created() - { - var sub = Substitute.For(); - var stealer = Substitute.For(); - - sub.Method(2, stealer.StealMatcherBeforeUsedElsewhere); - - sub.Received().Method(Arg.Any(), stealer.StealMatcherBeforeUsedElsewhere); - } - - [Test] - [Pending, Explicit] - public void Use_arg_matcher_then_access_another_sub_with_args_before_call_spec_is_created() - { - var sub = Substitute.For(); - var stealer = Substitute.For(); - stealer[0].Returns("a"); - - sub.Method(2, stealer[0]); - - //This example still blows up because the call to stealer[0] takes the Arg.Any() matcher - //away. The call router thinks the Arg.Any belongs to that call, not the sub.Method() call. - sub.Received().Method(Arg.Any(), stealer[0]); - } + var sub = Substitute.For(); + var stealer = Substitute.For(); + + sub.Method(2, stealer.StealMatcherBeforeUsedElsewhere); + + sub.Received().Method(Arg.Any(), stealer.StealMatcherBeforeUsedElsewhere); + } + + [Test] + [Pending, Explicit] + public void Use_arg_matcher_then_access_another_sub_with_args_before_call_spec_is_created() + { + var sub = Substitute.For(); + var stealer = Substitute.For(); + stealer[0].Returns("a"); + + sub.Method(2, stealer[0]); + + //This example still blows up because the call to stealer[0] takes the Arg.Any() matcher + //away. The call router thinks the Arg.Any belongs to that call, not the sub.Method() call. + sub.Received().Method(Arg.Any(), stealer[0]); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithValueTypeArgSpecsForObjectArguments.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithValueTypeArgSpecsForObjectArguments.cs index 9fbf878c9..144ef1da6 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithValueTypeArgSpecsForObjectArguments.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/ArgMatchingWithValueTypeArgSpecsForObjectArguments.cs @@ -1,53 +1,52 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class ArgMatchingWithValueTypeArgSpecsForObjectArguments { - public class ArgMatchingWithValueTypeArgSpecsForObjectArguments + public interface IInterface { - public interface IInterface - { - void DoSomething(object input); - void DoSomething(object first, object second, object third); - } + void DoSomething(object input); + void DoSomething(object first, object second, object third); + } - [Test] - public void Match_value_type_arg_spec_provided_for_object_argument() - { - var sub = Substitute.For(); + [Test] + public void Match_value_type_arg_spec_provided_for_object_argument() + { + var sub = Substitute.For(); - sub.DoSomething(Guid.NewGuid()); + sub.DoSomething(Guid.NewGuid()); - sub.Received().DoSomething(Arg.Any()); - } + sub.Received().DoSomething(Arg.Any()); + } - [Test] - public void Value_type_arg_spec_should_filter_out_call_made_passing_in_an_object() - { - var sub = Substitute.For(); + [Test] + public void Value_type_arg_spec_should_filter_out_call_made_passing_in_an_object() + { + var sub = Substitute.For(); - sub.DoSomething(new object()); + sub.DoSomething(new object()); - sub.DidNotReceive().DoSomething(Arg.Any()); - } + sub.DidNotReceive().DoSomething(Arg.Any()); + } - [Test] - public void Checking_some_multiple_argument_cases() - { - var anObject = new object(); + [Test] + public void Checking_some_multiple_argument_cases() + { + var anObject = new object(); - var sub = Substitute.For(); + var sub = Substitute.For(); - sub.DoSomething(Guid.NewGuid(), 123, anObject); + sub.DoSomething(Guid.NewGuid(), 123, anObject); - sub.Received().DoSomething(Arg.Any(), Arg.Any(), anObject); - sub.Received().DoSomething(Arg.Any(), Arg.Any(), anObject); - sub.Received().DoSomething(Arg.Any(), Arg.Any(), anObject); - sub.Received().DoSomething(Arg.Any(), Arg.Any(), Arg.Any()); - sub.Received().DoSomething(Arg.Any(), Arg.Any(), Arg.Any()); - sub.Received().DoSomething(Arg.Any(), 123, Arg.Any()); + sub.Received().DoSomething(Arg.Any(), Arg.Any(), anObject); + sub.Received().DoSomething(Arg.Any(), Arg.Any(), anObject); + sub.Received().DoSomething(Arg.Any(), Arg.Any(), anObject); + sub.Received().DoSomething(Arg.Any(), Arg.Any(), Arg.Any()); + sub.Received().DoSomething(Arg.Any(), Arg.Any(), Arg.Any()); + sub.Received().DoSomething(Arg.Any(), 123, Arg.Any()); - sub.DidNotReceive().DoSomething(Arg.Any(), Arg.Any(), anObject); - sub.DidNotReceive().DoSomething(Arg.Any(), Arg.Any(), anObject); - } + sub.DidNotReceive().DoSomething(Arg.Any(), Arg.Any(), anObject); + sub.DidNotReceive().DoSomething(Arg.Any(), Arg.Any(), anObject); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/CallingIntoNewSubWithinReturns.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/CallingIntoNewSubWithinReturns.cs index dacb39cfb..d7daa153a 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/CallingIntoNewSubWithinReturns.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/CallingIntoNewSubWithinReturns.cs @@ -1,72 +1,71 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class CallingIntoNewSubWithinReturns { - public class CallingIntoNewSubWithinReturns - { - public interface IFoo { string SomeString { get; set; } } - public interface IBar { IFoo GetFoo(); } - public interface IZap { int Num { get; set; } } + public interface IFoo { string SomeString { get; set; } } + public interface IBar { IFoo GetFoo(); } + public interface IZap { int Num { get; set; } } - [Test] - public void ShouldDetectTypeMismatchInReturns() - { - var sub = Substitute.For(); + [Test] + public void ShouldDetectTypeMismatchInReturns() + { + var sub = Substitute.For(); - var ex = - Assert.Throws(() => - // GetFoo() called, then IPityTheFoo(), then Returns(..) is called. - // This means Returns(..) tries to update the last called sub, - // which is IFoo.SomeString, not IBar.GetFoo(). - sub.GetFoo().Returns(IPityTheFoo()) - ); + var ex = + Assert.Throws(() => + // GetFoo() called, then IPityTheFoo(), then Returns(..) is called. + // This means Returns(..) tries to update the last called sub, + // which is IFoo.SomeString, not IBar.GetFoo(). + sub.GetFoo().Returns(IPityTheFoo()) + ); - Assert.That(ex.Message, Does.StartWith("Can not return value of type ")); - } + Assert.That(ex.Message, Does.StartWith("Can not return value of type ")); + } - private IFoo IPityTheFoo() - { - var foo = Substitute.For(); - foo.SomeString = "call a property so static LastCalled is updated"; - return foo; - } + private IFoo IPityTheFoo() + { + var foo = Substitute.For(); + foo.SomeString = "call a property so static LastCalled is updated"; + return foo; + } - [Test] - public void ShouldDetectedWhenNestedReturnsClearsLastCallRouter() - { - var sub = Substitute.For(); + [Test] + public void ShouldDetectedWhenNestedReturnsClearsLastCallRouter() + { + var sub = Substitute.For(); - Assert.Throws(() => - sub.GetFoo().Returns(CreateFooAndCallReturns()) - ); - } + Assert.Throws(() => + sub.GetFoo().Returns(CreateFooAndCallReturns()) + ); + } - private IFoo CreateFooAndCallReturns() - { - var foo = Substitute.For(); - foo.SomeString.Returns("nested set"); - return foo; - } + private IFoo CreateFooAndCallReturns() + { + var foo = Substitute.For(); + foo.SomeString.Returns("nested set"); + return foo; + } - [Test] - public void ShouldDetectTypeMismatchWhenNullIsInvolved() - { - var sub = Substitute.For(); + [Test] + public void ShouldDetectTypeMismatchWhenNullIsInvolved() + { + var sub = Substitute.For(); - var ex = - Assert.Throws(() => - sub.GetFoo().Returns(DoEvilAndReturnNullRef()) - ); + var ex = + Assert.Throws(() => + sub.GetFoo().Returns(DoEvilAndReturnNullRef()) + ); - Assert.That(ex.Message, Does.StartWith("Can not return null for")); - } + Assert.That(ex.Message, Does.StartWith("Can not return null for")); + } - private IFoo DoEvilAndReturnNullRef() - { - var zap = Substitute.For(); - zap.Num = 2; - return null; - } + private IFoo DoEvilAndReturnNullRef() + { + var zap = Substitute.For(); + zap.Num = 2; + return null; } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/DisposeWithThreadLocal.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/DisposeWithThreadLocal.cs index df31fcd53..8ea82344f 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/DisposeWithThreadLocal.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/DisposeWithThreadLocal.cs @@ -1,28 +1,27 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class DisposeWithThreadLocal { - public class DisposeWithThreadLocal + [Test] + public void DisposeSubstituteAndPerformGC() { - [Test] - public void DisposeSubstituteAndPerformGC() - { - using (var s = Substitute.For()) { } - GC.Collect(); - GC.WaitForPendingFinalizers(); + using (var s = Substitute.For()) { } + GC.Collect(); + GC.WaitForPendingFinalizers(); - //Exception thrown on background thread. Can view this from output of test runner. - } + //Exception thrown on background thread. Can view this from output of test runner. + } - public class DisposableClass : IDisposable + public class DisposableClass : IDisposable + { + bool disposed = false; + ~DisposableClass() { Dispose(false); } + public virtual void Dispose() { Dispose(true); } + protected virtual void Dispose(bool disposing) { - bool disposed = false; - ~DisposableClass() { Dispose(false); } - public virtual void Dispose() { Dispose(true); } - protected virtual void Dispose(bool disposing) - { - if (!disposed) { if (disposing) { disposed = true; } } - } + if (!disposed) { if (disposing) { disposed = true; } } } } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/EqualsBehaviourOnClassSubs.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/EqualsBehaviourOnClassSubs.cs index c83411a08..83e51993e 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/EqualsBehaviourOnClassSubs.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/EqualsBehaviourOnClassSubs.cs @@ -1,19 +1,18 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class EqualsBehaviourOnClassSubs { - public class EqualsBehaviourOnClassSubs + [Test] + public void Equals_should_work_as_expected_for_class_substitutes() { - [Test] - public void Equals_should_work_as_expected_for_class_substitutes() - { - var firstSub = Substitute.For(); - var secondSub = Substitute.For(); - - Assert.AreEqual(firstSub, firstSub); - Assert.AreNotEqual(firstSub, secondSub); - } + var firstSub = Substitute.For(); + var secondSub = Substitute.For(); - public class AClass { } + Assert.AreEqual(firstSub, firstSub); + Assert.AreNotEqual(firstSub, secondSub); } + + public class AClass { } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/ExceptionsThrownFromCustomArgumentMatchers.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/ExceptionsThrownFromCustomArgumentMatchers.cs index a9a4b2325..8ef1126d8 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/ExceptionsThrownFromCustomArgumentMatchers.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/ExceptionsThrownFromCustomArgumentMatchers.cs @@ -1,91 +1,90 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class ExceptionsThrownFromCustomArgumentMatchers { - public class ExceptionsThrownFromCustomArgumentMatchers + public interface IRequest + { + string Get(string url); + string[] GetMultiple(string[] url); + } + + [Test] + public void Single_condition_that_does_not_handle_nulls() + { + var request = Substitute.For(); + request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); + + Assert.That(request.Get("greeting"), Is.EqualTo("hello world")); + Assert.That(request.Get(null), Is.EqualTo("")); + } + + [Test] + public void Single_negated_condition_that_does_not_handle_nulls() { - public interface IRequest - { - string Get(string url); - string[] GetMultiple(string[] url); - } - - [Test] - public void Single_condition_that_does_not_handle_nulls() - { - var request = Substitute.For(); - request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); - - Assert.That(request.Get("greeting"), Is.EqualTo("hello world")); - Assert.That(request.Get(null), Is.EqualTo("")); - } - - [Test] - public void Single_negated_condition_that_does_not_handle_nulls() - { - var request = Substitute.For(); - request.Get(Arg.Is(x => !x.Contains("please"))).Returns("ask nicely"); - - Assert.That(request.Get("greeting"), Is.EqualTo("ask nicely")); - Assert.That(request.Get(null), Is.EqualTo("")); - } - - [Test] - public void Multiple_conditions_that_require_an_object_reference() - { - var request = Substitute.For(); - request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); - request.Get(Arg.Is(x => x.Length < 5)).Returns("?"); - - Assert.That(request.Get("greeting"), Is.EqualTo("hello world")); - Assert.That(request.Get(""), Is.EqualTo("?")); - Assert.That(request.Get(null), Is.EqualTo("")); - } - - [Test] - public void Multiple_negated_conditions_that_requires_an_object_reference() - { - var request = Substitute.For(); - request.Get(Arg.Is(x => !x.StartsWith("please"))).Returns("ask nicely"); - request.Get(Arg.Is(x => x.Length > 10)).Returns("request too long"); - - Assert.That(request.Get("greeting"), Is.EqualTo("ask nicely")); - Assert.That(request.Get("please provide me with a greeting"), Is.EqualTo("request too long")); - Assert.That(request.Get(null), Is.EqualTo("")); - } - - [Test] - public void Condition_that_requires_object_ref_and_condition_that_covers_null() - { - var request = Substitute.For(); - request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); - request.Get(null).Returns("?"); - - Assert.That(request.Get(null), Is.EqualTo("?")); - } - - [Test] - [Pending, Explicit] - public void Multiple_conditions_with_multiple_returns() - { - var request = Substitute.For(); - request.Get(null).Returns("huh?", "what?", "pardon?"); - request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); - - Assert.That(request.Get(null), Is.EqualTo("huh?")); - Assert.That(request.Get(null), Is.EqualTo("what?")); - } - - [Test] - public void Multiple_conditions_where_one_requires_an_array_index_available() - { - var emptyArray = new string[0]; - var request = Substitute.For(); - request.GetMultiple(Arg.Is(x => x[0] == "greeting")).Returns(new[] { "hello", "bye" }); - request.GetMultiple(emptyArray).Returns(new[] { "?" }); - - Assert.That(request.GetMultiple(new[] { "greeting" }), Is.EqualTo(new[] { "hello", "bye" })); - Assert.That(request.GetMultiple(emptyArray), Is.EqualTo(new[] { "?" })); - } + var request = Substitute.For(); + request.Get(Arg.Is(x => !x.Contains("please"))).Returns("ask nicely"); + + Assert.That(request.Get("greeting"), Is.EqualTo("ask nicely")); + Assert.That(request.Get(null), Is.EqualTo("")); + } + + [Test] + public void Multiple_conditions_that_require_an_object_reference() + { + var request = Substitute.For(); + request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); + request.Get(Arg.Is(x => x.Length < 5)).Returns("?"); + + Assert.That(request.Get("greeting"), Is.EqualTo("hello world")); + Assert.That(request.Get(""), Is.EqualTo("?")); + Assert.That(request.Get(null), Is.EqualTo("")); + } + + [Test] + public void Multiple_negated_conditions_that_requires_an_object_reference() + { + var request = Substitute.For(); + request.Get(Arg.Is(x => !x.StartsWith("please"))).Returns("ask nicely"); + request.Get(Arg.Is(x => x.Length > 10)).Returns("request too long"); + + Assert.That(request.Get("greeting"), Is.EqualTo("ask nicely")); + Assert.That(request.Get("please provide me with a greeting"), Is.EqualTo("request too long")); + Assert.That(request.Get(null), Is.EqualTo("")); + } + + [Test] + public void Condition_that_requires_object_ref_and_condition_that_covers_null() + { + var request = Substitute.For(); + request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); + request.Get(null).Returns("?"); + + Assert.That(request.Get(null), Is.EqualTo("?")); + } + + [Test] + [Pending, Explicit] + public void Multiple_conditions_with_multiple_returns() + { + var request = Substitute.For(); + request.Get(null).Returns("huh?", "what?", "pardon?"); + request.Get(Arg.Is(x => x.Contains("greeting"))).Returns("hello world"); + + Assert.That(request.Get(null), Is.EqualTo("huh?")); + Assert.That(request.Get(null), Is.EqualTo("what?")); + } + + [Test] + public void Multiple_conditions_where_one_requires_an_array_index_available() + { + var emptyArray = new string[0]; + var request = Substitute.For(); + request.GetMultiple(Arg.Is(x => x[0] == "greeting")).Returns(new[] { "hello", "bye" }); + request.GetMultiple(emptyArray).Returns(new[] { "?" }); + + Assert.That(request.GetMultiple(new[] { "greeting" }), Is.EqualTo(new[] { "hello", "bye" })); + Assert.That(request.GetMultiple(emptyArray), Is.EqualTo(new[] { "?" })); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue110_CustomExceptions.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue110_CustomExceptions.cs index 30c08f5c7..4adbdbe69 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue110_CustomExceptions.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue110_CustomExceptions.cs @@ -1,24 +1,23 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue110_CustomExceptions { - public class Issue110_CustomExceptions - { - public class MyException : Exception { } + public class MyException : Exception { } - public interface IThrow { void Throw(); } - public interface IDoStuff { event Action StuffDone; } + public interface IThrow { void Throw(); } + public interface IDoStuff { event Action StuffDone; } - [Test] - public void ThrowExceptionWithoutSerialisationConstructor() - { - var ithrow = Substitute.For(); - var doStuff = Substitute.For(); + [Test] + public void ThrowExceptionWithoutSerialisationConstructor() + { + var ithrow = Substitute.For(); + var doStuff = Substitute.For(); - ithrow.When(x => x.Throw()).Do(x => { throw new MyException(); }); - doStuff.StuffDone += ithrow.Throw; + ithrow.When(x => x.Throw()).Do(x => { throw new MyException(); }); + doStuff.StuffDone += ithrow.Throw; - Assert.Throws(() => doStuff.StuffDone += Raise.Event()); - } + Assert.Throws(() => doStuff.StuffDone += Raise.Event()); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue111_ArgMatchesWithRefAndOutParams.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue111_ArgMatchesWithRefAndOutParams.cs index 2d64aa5f7..c3b57d942 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue111_ArgMatchesWithRefAndOutParams.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue111_ArgMatchesWithRefAndOutParams.cs @@ -1,117 +1,116 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +[TestFixture] +public class Issue111_ArgMatchesWithRefAndOutParams { - [TestFixture] - public class Issue111_ArgMatchesWithRefAndOutParams + public interface IRefAndOutParams { - public interface IRefAndOutParams - { - bool SomeMethodWithRefArg(ref string str); - bool SomeMethodWithOutArg(out int str); - } + bool SomeMethodWithRefArg(ref string str); + bool SomeMethodWithOutArg(out int str); + } - private bool CallMethodWithRefParam(IRefAndOutParams refAndOutParams) - { - var test = "hello"; - return refAndOutParams.SomeMethodWithRefArg(ref test); - } + private bool CallMethodWithRefParam(IRefAndOutParams refAndOutParams) + { + var test = "hello"; + return refAndOutParams.SomeMethodWithRefArg(ref test); + } - private bool CallMethodWithOutParam(IRefAndOutParams refAndOutParams) - { - var test = 45; - return refAndOutParams.SomeMethodWithOutArg(out test); - } + private bool CallMethodWithOutParam(IRefAndOutParams refAndOutParams) + { + var test = 45; + return refAndOutParams.SomeMethodWithOutArg(out test); + } - [Test] - public void Match_Any_ref_argument_in_When_and_execute_Do() - { - var substitute = Substitute.For(); - var counter = 0; - var strArg = Arg.Any(); - substitute.When(x => x.SomeMethodWithRefArg(ref strArg)).Do(x => counter++); - CallMethodWithRefParam(substitute); - Assert.That(counter, Is.EqualTo(1)); - } + [Test] + public void Match_Any_ref_argument_in_When_and_execute_Do() + { + var substitute = Substitute.For(); + var counter = 0; + var strArg = Arg.Any(); + substitute.When(x => x.SomeMethodWithRefArg(ref strArg)).Do(x => counter++); + CallMethodWithRefParam(substitute); + Assert.That(counter, Is.EqualTo(1)); + } - [Test] - public void Should_not_execute_Do_if_given_ref_argument_with_different_value() - { - var substitute = Substitute.For(); - var counter = 0; - var strArg = "what"; - substitute.When(x => x.SomeMethodWithRefArg(ref strArg)).Do(x => counter++); - CallMethodWithRefParam(substitute); - Assert.That(counter, Is.EqualTo(0)); - } + [Test] + public void Should_not_execute_Do_if_given_ref_argument_with_different_value() + { + var substitute = Substitute.For(); + var counter = 0; + var strArg = "what"; + substitute.When(x => x.SomeMethodWithRefArg(ref strArg)).Do(x => counter++); + CallMethodWithRefParam(substitute); + Assert.That(counter, Is.EqualTo(0)); + } - [Test] - public void Match_Any_out_argument_in_When_and_execute_Do() - { - var substitute = Substitute.For(); - var counter = 0; - var intArg = Arg.Any(); - substitute.When(x => x.SomeMethodWithOutArg(out intArg)).Do(x => counter++); - CallMethodWithOutParam(substitute); - Assert.That(counter, Is.EqualTo(1)); - } + [Test] + public void Match_Any_out_argument_in_When_and_execute_Do() + { + var substitute = Substitute.For(); + var counter = 0; + var intArg = Arg.Any(); + substitute.When(x => x.SomeMethodWithOutArg(out intArg)).Do(x => counter++); + CallMethodWithOutParam(substitute); + Assert.That(counter, Is.EqualTo(1)); + } - [Test] - public void Match_out_argument_with_actual_value_in_When_and_execute_Do() - { - var substitute = Substitute.For(); - var counter = 0; - var intArg = 45; - substitute.When(x => x.SomeMethodWithOutArg(out intArg)).Do(x => counter++); - CallMethodWithOutParam(substitute); - Assert.That(counter, Is.EqualTo(1)); - } + [Test] + public void Match_out_argument_with_actual_value_in_When_and_execute_Do() + { + var substitute = Substitute.For(); + var counter = 0; + var intArg = 45; + substitute.When(x => x.SomeMethodWithOutArg(out intArg)).Do(x => counter++); + CallMethodWithOutParam(substitute); + Assert.That(counter, Is.EqualTo(1)); + } - [Test] - public void Should_not_execute_Do_if_given_out_argument_with_different_value() - { - var substitute = Substitute.For(); - var counter = 0; - var intArg = 3; - substitute.When(x => x.SomeMethodWithOutArg(out intArg)).Do(x => counter++); - CallMethodWithOutParam(substitute); - Assert.That(counter, Is.EqualTo(0)); - } + [Test] + public void Should_not_execute_Do_if_given_out_argument_with_different_value() + { + var substitute = Substitute.For(); + var counter = 0; + var intArg = 3; + substitute.When(x => x.SomeMethodWithOutArg(out intArg)).Do(x => counter++); + CallMethodWithOutParam(substitute); + Assert.That(counter, Is.EqualTo(0)); + } - [Test] - public void Return_given_value_when_matching_any_ref_argument() - { - var substitute = Substitute.For(); - var strArg = Arg.Any(); - substitute.SomeMethodWithRefArg(ref strArg).Returns(true); - Assert.That(CallMethodWithRefParam(substitute), Is.True); - } + [Test] + public void Return_given_value_when_matching_any_ref_argument() + { + var substitute = Substitute.For(); + var strArg = Arg.Any(); + substitute.SomeMethodWithRefArg(ref strArg).Returns(true); + Assert.That(CallMethodWithRefParam(substitute), Is.True); + } - [Test] - public void Return_given_value_when_matching_any_out_argument() - { - var substitute = Substitute.For(); - var intArg = Arg.Any(); - substitute.SomeMethodWithOutArg(out intArg).Returns(true); - Assert.That(CallMethodWithOutParam(substitute), Is.True); - } + [Test] + public void Return_given_value_when_matching_any_out_argument() + { + var substitute = Substitute.For(); + var intArg = Arg.Any(); + substitute.SomeMethodWithOutArg(out intArg).Returns(true); + Assert.That(CallMethodWithOutParam(substitute), Is.True); + } - [Test] - public void Check_call_was_received_with_any_ref_argument() - { - var substitute = Substitute.For(); - CallMethodWithRefParam(substitute); - var strArg = Arg.Any(); - substitute.Received().SomeMethodWithRefArg(ref strArg); - } + [Test] + public void Check_call_was_received_with_any_ref_argument() + { + var substitute = Substitute.For(); + CallMethodWithRefParam(substitute); + var strArg = Arg.Any(); + substitute.Received().SomeMethodWithRefArg(ref strArg); + } - [Test] - public void Check_call_was_received_with_any_out_argument() - { - var substitute = Substitute.For(); - CallMethodWithOutParam(substitute); - var intArg = Arg.Any(); - substitute.Received().SomeMethodWithOutArg(out intArg); - } + [Test] + public void Check_call_was_received_with_any_out_argument() + { + var substitute = Substitute.For(); + CallMethodWithOutParam(substitute); + var intArg = Arg.Any(); + substitute.Received().SomeMethodWithOutArg(out intArg); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue114_ArgumentCheckOfOptionalParameter.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue114_ArgumentCheckOfOptionalParameter.cs index ae4f861cc..a679b802d 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue114_ArgumentCheckOfOptionalParameter.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue114_ArgumentCheckOfOptionalParameter.cs @@ -1,43 +1,42 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue114_ArgumentCheckOfOptionalParameter { - public class Issue114_ArgumentCheckOfOptionalParameter + public interface IInterface { - public interface IInterface - { - void MethodWithOptionalParameter(object obligatory, object optional = null); - } + void MethodWithOptionalParameter(object obligatory, object optional = null); + } - [Test] - public void PassArgumentCheckForOptionalParameter() - { - var substitute = Substitute.For(); - substitute.MethodWithOptionalParameter(new object()); - substitute.Received().MethodWithOptionalParameter(Arg.Any()); - substitute.Received().MethodWithOptionalParameter(Arg.Any(), null); - substitute.Received().MethodWithOptionalParameter(Arg.Any()); - substitute.ReceivedWithAnyArgs().MethodWithOptionalParameter(null); - substitute.ReceivedWithAnyArgs().MethodWithOptionalParameter(null, null); - } + [Test] + public void PassArgumentCheckForOptionalParameter() + { + var substitute = Substitute.For(); + substitute.MethodWithOptionalParameter(new object()); + substitute.Received().MethodWithOptionalParameter(Arg.Any()); + substitute.Received().MethodWithOptionalParameter(Arg.Any(), null); + substitute.Received().MethodWithOptionalParameter(Arg.Any()); + substitute.ReceivedWithAnyArgs().MethodWithOptionalParameter(null); + substitute.ReceivedWithAnyArgs().MethodWithOptionalParameter(null, null); + } - [Test] - public void MatchWhenAllArgumentsSpecified() - { - var substitute = Substitute.For(); - substitute.MethodWithOptionalParameter(new object(), 2); - substitute.Received().MethodWithOptionalParameter(Arg.Any(), Arg.Any()); - substitute.Received().MethodWithOptionalParameter(Arg.Any(), 2); - } + [Test] + public void MatchWhenAllArgumentsSpecified() + { + var substitute = Substitute.For(); + substitute.MethodWithOptionalParameter(new object(), 2); + substitute.Received().MethodWithOptionalParameter(Arg.Any(), Arg.Any()); + substitute.Received().MethodWithOptionalParameter(Arg.Any(), 2); + } - [Test] - public void DetectsMismatchedArgs() - { - var substitute = Substitute.For(); - substitute.MethodWithOptionalParameter(new object(), 2); - substitute.DidNotReceive().MethodWithOptionalParameter(Arg.Any()); - substitute.DidNotReceive().MethodWithOptionalParameter(Arg.Any(), 3); - substitute.DidNotReceive().MethodWithOptionalParameter(Arg.Any(), "asdf"); - } + [Test] + public void DetectsMismatchedArgs() + { + var substitute = Substitute.For(); + substitute.MethodWithOptionalParameter(new object(), 2); + substitute.DidNotReceive().MethodWithOptionalParameter(Arg.Any()); + substitute.DidNotReceive().MethodWithOptionalParameter(Arg.Any(), 3); + substitute.DidNotReceive().MethodWithOptionalParameter(Arg.Any(), "asdf"); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue118_ConcreteClassWithPublicStaticMethod.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue118_ConcreteClassWithPublicStaticMethod.cs index 011444e5c..81273586a 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue118_ConcreteClassWithPublicStaticMethod.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue118_ConcreteClassWithPublicStaticMethod.cs @@ -1,84 +1,83 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +class Issue118_ConcreteClassWithPublicStaticMethod { - class Issue118_ConcreteClassWithPublicStaticMethod + [Test] + public void Interface_returning_concrete_without_static_member_should_return_substitute_by_default() { - [Test] - public void Interface_returning_concrete_without_static_member_should_return_substitute_by_default() - { - var sub = Substitute.For(); + var sub = Substitute.For(); - var returnedClass = sub.AMethod(); + var returnedClass = sub.AMethod(); - Assert.That(returnedClass, Is.InstanceOf()); - } + Assert.That(returnedClass, Is.InstanceOf()); + } - [Test] - public void Interface_returning_concrete_without_static_member_should_return_object_if_instructed_to() - { - var sub = Substitute.For(); - var obj = new ConcreteWithoutPublicStaticMethod(); - sub.AMethod().Returns(obj); + [Test] + public void Interface_returning_concrete_without_static_member_should_return_object_if_instructed_to() + { + var sub = Substitute.For(); + var obj = new ConcreteWithoutPublicStaticMethod(); + sub.AMethod().Returns(obj); - var returnedClass = sub.AMethod(); + var returnedClass = sub.AMethod(); - Assert.That(returnedClass, Is.SameAs(obj)); - } + Assert.That(returnedClass, Is.SameAs(obj)); + } - [Test] - public void Interface_returning_concrete_with_static_member_should_return_substitute_by_default() - { - var sub = Substitute.For(); + [Test] + public void Interface_returning_concrete_with_static_member_should_return_substitute_by_default() + { + var sub = Substitute.For(); - var returnedClass = sub.AMethod(); + var returnedClass = sub.AMethod(); - Assert.That(returnedClass, Is.InstanceOf()); - } + Assert.That(returnedClass, Is.InstanceOf()); + } - [Test] - public void Interface_returning_concrete_with_static_member_should_return_object_if_instructed_to() - { - var sub = Substitute.For(); - var obj = new ConcreteWithPublicStaticMethod(); - sub.AMethod().Returns(obj); + [Test] + public void Interface_returning_concrete_with_static_member_should_return_object_if_instructed_to() + { + var sub = Substitute.For(); + var obj = new ConcreteWithPublicStaticMethod(); + sub.AMethod().Returns(obj); - var returnedClass = sub.AMethod(); + var returnedClass = sub.AMethod(); - Assert.That(returnedClass, Is.SameAs(obj)); - } + Assert.That(returnedClass, Is.SameAs(obj)); + } - [Test] - public void Substitute_of_concrete_with_static_member_should_allow_setup_of_return_value() - { - const string value = "test"; - var sub = Substitute.For(); - sub.AProperty.Returns(value); + [Test] + public void Substitute_of_concrete_with_static_member_should_allow_setup_of_return_value() + { + const string value = "test"; + var sub = Substitute.For(); + sub.AProperty.Returns(value); - var returnedValue = sub.AProperty; + var returnedValue = sub.AProperty; - Assert.That(returnedValue, Is.EqualTo(value)); - } + Assert.That(returnedValue, Is.EqualTo(value)); } +} - public class ConcreteWithPublicStaticMethod - { - public virtual string AProperty { get; set; } - public static void AStaticMethod() { } - } +public class ConcreteWithPublicStaticMethod +{ + public virtual string AProperty { get; set; } + public static void AStaticMethod() { } +} - public class ConcreteWithoutPublicStaticMethod - { - public virtual string AProperty { get; set; } - } +public class ConcreteWithoutPublicStaticMethod +{ + public virtual string AProperty { get; set; } +} - public interface IInterfaceReturningConcreteWithPublicStaticMethod - { - ConcreteWithPublicStaticMethod AMethod(); - } +public interface IInterfaceReturningConcreteWithPublicStaticMethod +{ + ConcreteWithPublicStaticMethod AMethod(); +} - public interface IInterfaceReturningConcreteWithoutPublicStaticMethod - { - ConcreteWithoutPublicStaticMethod AMethod(); - } +public interface IInterfaceReturningConcreteWithoutPublicStaticMethod +{ + ConcreteWithoutPublicStaticMethod AMethod(); } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue125_MethodWithSealedClassReturnType.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue125_MethodWithSealedClassReturnType.cs index d528b2781..e3532758b 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue125_MethodWithSealedClassReturnType.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue125_MethodWithSealedClassReturnType.cs @@ -1,26 +1,25 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue125_MethodWithSealedClassReturnType { - public class Issue125_MethodWithSealedClassReturnType - { - public sealed class SealedClass { } + public sealed class SealedClass { } - public interface IInterface - { - SealedClass MethodWithSealedClassReturnType(); - } + public interface IInterface + { + SealedClass MethodWithSealedClassReturnType(); + } - [Test] - public void MethodWithSealedClassReturnTypeReturnsCorrectResult() - { - var substitute = Substitute.For(); - var expected = new SealedClass(); - substitute.MethodWithSealedClassReturnType().Returns(expected); + [Test] + public void MethodWithSealedClassReturnTypeReturnsCorrectResult() + { + var substitute = Substitute.For(); + var expected = new SealedClass(); + substitute.MethodWithSealedClassReturnType().Returns(expected); - var result = substitute.MethodWithSealedClassReturnType(); + var result = substitute.MethodWithSealedClassReturnType(); - Assert.That(result, Is.EqualTo(expected)); - } + Assert.That(result, Is.EqualTo(expected)); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue129_AmbiguousArgsWithOutRef.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue129_AmbiguousArgsWithOutRef.cs index 3f3d8ceef..e6df0b29b 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue129_AmbiguousArgsWithOutRef.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue129_AmbiguousArgsWithOutRef.cs @@ -1,74 +1,73 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue129_AmbiguousArgsWithOutRef { - public class Issue129_AmbiguousArgsWithOutRef + public interface ITestInterface { - public interface ITestInterface - { - bool DoStuff(string input, out string output); - bool DoStuffWithRef(string input, ref string output); - } + bool DoStuff(string input, out string output); + bool DoStuffWithRef(string input, ref string output); + } - [Test] - public void Test() + [Test] + public void Test() + { + string someType; + var substitute = Substitute.For(); + substitute.DoStuff(Arg.Any(), out someType).ReturnsForAnyArgs(info => { - string someType; - var substitute = Substitute.For(); - substitute.DoStuff(Arg.Any(), out someType).ReturnsForAnyArgs(info => - { - info[1] = "test"; - return true; - }); + info[1] = "test"; + return true; + }); - string outString; - var result = substitute.DoStuff("a", out outString); + string outString; + var result = substitute.DoStuff("a", out outString); - Assert.That(result); - Assert.That(outString, Is.EqualTo("test")); - } + Assert.That(result); + Assert.That(outString, Is.EqualTo("test")); + } - [Test] - public void TestRef() + [Test] + public void TestRef() + { + string someType = "x"; + var substitute = Substitute.For(); + substitute.DoStuffWithRef(Arg.Any(), ref someType).Returns(info => { - string someType = "x"; - var substitute = Substitute.For(); - substitute.DoStuffWithRef(Arg.Any(), ref someType).Returns(info => - { - info[1] = "test"; - return true; - }); + info[1] = "test"; + return true; + }); - var result = substitute.DoStuffWithRef("a", ref someType); + var result = substitute.DoStuffWithRef("a", ref someType); - Assert.That(result); - Assert.That(someType, Is.EqualTo("test")); + Assert.That(result); + Assert.That(someType, Is.EqualTo("test")); - someType = "y"; - result = substitute.DoStuffWithRef("a", ref someType); + someType = "y"; + result = substitute.DoStuffWithRef("a", ref someType); - Assert.That(result, Is.False); - Assert.That(someType, Is.Not.EqualTo("test")); - } + Assert.That(result, Is.False); + Assert.That(someType, Is.Not.EqualTo("test")); + } - [Test] - public void WorkAround() + [Test] + public void WorkAround() + { + string someType; + var substitute = Substitute.For(); + var arg0 = Arg.Any(); + var arg1 = Arg.Any(); + substitute.DoStuff(arg0, out someType).ReturnsForAnyArgs(info => { - string someType; - var substitute = Substitute.For(); - var arg0 = Arg.Any(); - var arg1 = Arg.Any(); - substitute.DoStuff(arg0, out someType).ReturnsForAnyArgs(info => - { - info[1] = "test"; - return true; - }); + info[1] = "test"; + return true; + }); - string outString; - var result = substitute.DoStuff("a", out outString); + string outString; + var result = substitute.DoStuff("a", out outString); - Assert.That(result); - Assert.That(outString, Is.EqualTo("test")); - } + Assert.That(result); + Assert.That(outString, Is.EqualTo("test")); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue149_ArgMatcherInReturns.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue149_ArgMatcherInReturns.cs index 4e8fac9d1..1bc3c0f0e 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue149_ArgMatcherInReturns.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue149_ArgMatcherInReturns.cs @@ -1,37 +1,36 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue149_ArgMatcherInReturns { - public class Issue149_ArgMatcherInReturns - { - public interface ISub1 { Item GetItem(string s); } - public interface ISub2 { string GetSignature(int i); } - public class Item { } + public interface ISub1 { Item GetItem(string s); } + public interface ISub2 { string GetSignature(int i); } + public class Item { } - [Test] - public void MatcherInReturnsShouldThrow() - { - var sub2 = Substitute.For(); - Assert.Throws( - () => sub2.GetSignature(1).Returns(Arg.Any())); - } + [Test] + public void MatcherInReturnsShouldThrow() + { + var sub2 = Substitute.For(); + Assert.Throws( + () => sub2.GetSignature(1).Returns(Arg.Any())); + } - // Original example from https://github.com/nsubstitute/NSubstitute/issues/149 - [Test] - public void OriginalMatcherInReturnsExample() - { - var sub1 = Substitute.For(); - var sub2 = Substitute.For(); - sub1.GetItem(Arg.Any()).Returns(new Item()); + // Original example from https://github.com/nsubstitute/NSubstitute/issues/149 + [Test] + public void OriginalMatcherInReturnsExample() + { + var sub1 = Substitute.For(); + var sub2 = Substitute.For(); + sub1.GetItem(Arg.Any()).Returns(new Item()); - Assert.Throws(() => - sub2.GetSignature(1).Returns(Arg.Any()) // <-- THIS IS THE PROBLEM - ); + Assert.Throws(() => + sub2.GetSignature(1).Returns(Arg.Any()) // <-- THIS IS THE PROBLEM + ); - sub1.GetItem("mystring"); + sub1.GetItem("mystring"); - sub1.ReceivedWithAnyArgs(1).GetItem("mystring"); - } + sub1.ReceivedWithAnyArgs(1).GetItem("mystring"); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue170_MultidimensionalArray.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue170_MultidimensionalArray.cs index 307427d2d..8090fd0bd 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue170_MultidimensionalArray.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue170_MultidimensionalArray.cs @@ -1,19 +1,18 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue170_MultidimensionalArray { - public class Issue170_MultidimensionalArray + public interface ITest { - public interface ITest - { - bool[,] Method(); - } + bool[,] Method(); + } - [Test] - public void Method_Works() - { - var test = Substitute.For(); - test.Method(); - } + [Test] + public void Method_Works() + { + var test = Substitute.For(); + test.Method(); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue211_ReceivedInOrderParamsFormatting.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue211_ReceivedInOrderParamsFormatting.cs index c2090f841..eecad1b68 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue211_ReceivedInOrderParamsFormatting.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue211_ReceivedInOrderParamsFormatting.cs @@ -2,50 +2,50 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue211_ReceivedInOrderParamsFormatting { - public class Issue211_ReceivedInOrderParamsFormatting + public interface IAmAnInterface + { + void ParamsCall(params int[] i); + void ParamsCall(params string[] i); + } + + [Test] + public void TestFormattingForStandardReceived() { - public interface IAmAnInterface - { - void ParamsCall(params int[] i); - void ParamsCall(params string[] i); - } - - [Test] - public void TestFormattingForStandardReceived() - { - var sub = Substitute.For(); - - sub.ParamsCall(1, 42); - - var ex = Assert.Throws(() => - sub.Received().ParamsCall(1, 1) - ); - - //Show expected call: - Assert.That(ex.Message, Does.Contain("ParamsCall(1, 1)")); - //Show actual call: - Assert.That(ex.Message, Does.Contain("ParamsCall(1, *42*)")); - } - - [Test] - public void TestFormattingReceivedInOrder() - { - var sub = Substitute.For(); - - sub.ParamsCall(1, 1); - sub.ParamsCall(1, 2); - - Action assertion = () => - Received.InOrder(() => - { - sub.ParamsCall(1, 2); - sub.ParamsCall(1, 1); - }); - - var ex = Assert.Throws(() => assertion()); - var expectedMessage = @" + var sub = Substitute.For(); + + sub.ParamsCall(1, 42); + + var ex = Assert.Throws(() => + sub.Received().ParamsCall(1, 1) + ); + + //Show expected call: + Assert.That(ex.Message, Does.Contain("ParamsCall(1, 1)")); + //Show actual call: + Assert.That(ex.Message, Does.Contain("ParamsCall(1, *42*)")); + } + + [Test] + public void TestFormattingReceivedInOrder() + { + var sub = Substitute.For(); + + sub.ParamsCall(1, 1); + sub.ParamsCall(1, 2); + + Action assertion = () => + Received.InOrder(() => + { + sub.ParamsCall(1, 2); + sub.ParamsCall(1, 1); + }); + + var ex = Assert.Throws(() => assertion()); + var expectedMessage = @" Expected to receive these calls in order: ParamsCall(1, 2) @@ -57,16 +57,15 @@ public void TestFormattingReceivedInOrder() ParamsCall(1, 2) "; - ContainsExcludingWhitespace(ex.Message, expectedMessage); - } + ContainsExcludingWhitespace(ex.Message, expectedMessage); + } - static void ContainsExcludingWhitespace(string haystack, string needle) - { - var ws = new Regex(@"\s+"); - var spacifiedHaystack = ws.Replace(haystack, " "); - var spacifiedNeedle = ws.Replace(needle, " "); + static void ContainsExcludingWhitespace(string haystack, string needle) + { + var ws = new Regex(@"\s+"); + var spacifiedHaystack = ws.Replace(haystack, " "); + var spacifiedNeedle = ws.Replace(needle, " "); - Assert.That(spacifiedHaystack, Does.Contain(spacifiedNeedle)); - } + Assert.That(spacifiedHaystack, Does.Contain(spacifiedNeedle)); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue225_ConfiguredValueIsUsedInSubsequentSetups.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue225_ConfiguredValueIsUsedInSubsequentSetups.cs index 8b240500f..271cf29a1 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue225_ConfiguredValueIsUsedInSubsequentSetups.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue225_ConfiguredValueIsUsedInSubsequentSetups.cs @@ -1,27 +1,26 @@ using NSubstitute.Acceptance.Specs.Infrastructure; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue225_ConfiguredValueIsUsedInSubsequentSetups { - public class Issue225_ConfiguredValueIsUsedInSubsequentSetups + [Test] + public void ShouldNotUseTheConfiguredValueDuringSubsequentSetup() { - [Test] - public void ShouldNotUseTheConfiguredValueDuringSubsequentSetup() - { - // Arrange - var target = Substitute.For(); + // Arrange + var target = Substitute.For(); - // Act - target.Echo(Arg.Is(0)).Returns("00", "01", "02"); - target.Echo(Arg.Is(1)).Returns("10", "11", "12"); + // Act + target.Echo(Arg.Is(0)).Returns("00", "01", "02"); + target.Echo(Arg.Is(1)).Returns("10", "11", "12"); - // Assert - Assert.AreEqual("00", target.Echo(0)); - Assert.AreEqual("10", target.Echo(1)); - Assert.AreEqual("01", target.Echo(0)); - Assert.AreEqual("11", target.Echo(1)); - Assert.AreEqual("02", target.Echo(0)); - Assert.AreEqual("12", target.Echo(1)); - } + // Assert + Assert.AreEqual("00", target.Echo(0)); + Assert.AreEqual("10", target.Echo(1)); + Assert.AreEqual("01", target.Echo(0)); + Assert.AreEqual("11", target.Echo(1)); + Assert.AreEqual("02", target.Echo(0)); + Assert.AreEqual("12", target.Echo(1)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue237_ReceivedInOrderErrorHandling.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue237_ReceivedInOrderErrorHandling.cs index 0350ab5c5..ebbb169f3 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue237_ReceivedInOrderErrorHandling.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue237_ReceivedInOrderErrorHandling.cs @@ -1,67 +1,66 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue237_ReceivedInOrderErrorHandling { - public class Issue237_ReceivedInOrderErrorHandling + public interface IAmAnInterface { - public interface IAmAnInterface - { - void MethodA(int a, int b); - void MethodB(int a, int b); + void MethodA(int a, int b); + void MethodB(int a, int b); - int MethodC(); - } + int MethodC(); + } - [Test] - public void AnExceptionIsReceivedWhenExpected() - { - Assert.Throws(() => - Received.InOrder(() => - { - throw new Exception("An Exception!"); - })); - } + [Test] + public void AnExceptionIsReceivedWhenExpected() + { + Assert.Throws(() => + Received.InOrder(() => + { + throw new Exception("An Exception!"); + })); + } - [Test] - public void MethodCallsAreReceivedInOrder() + [Test] + public void MethodCallsAreReceivedInOrder() + { + IAmAnInterface _interface = Substitute.For(); + _interface.MethodA(1, 2); + _interface.MethodB(1, 2); + Received.InOrder(() => { - IAmAnInterface _interface = Substitute.For(); _interface.MethodA(1, 2); _interface.MethodB(1, 2); - Received.InOrder(() => - { - _interface.MethodA(1, 2); - _interface.MethodB(1, 2); - }); - } + }); + } - [Test] - public void AfterTheFailingTestIsRunWhenTheSuccessfulTestIsRunTheSuccessfulTestShouldSucceed() + [Test] + public void AfterTheFailingTestIsRunWhenTheSuccessfulTestIsRunTheSuccessfulTestShouldSucceed() + { + try { - try - { - AnExceptionIsReceivedWhenExpected(); - } - catch (Exception) - { - // suppress exception from first test - } - MethodCallsAreReceivedInOrder(); + AnExceptionIsReceivedWhenExpected(); + } + catch (Exception) + { + // suppress exception from first test } + MethodCallsAreReceivedInOrder(); + } - [Test] - public void AfterTheFailingTestIsRunIShouldBeAbleToConfigureASubstitute() + [Test] + public void AfterTheFailingTestIsRunIShouldBeAbleToConfigureASubstitute() + { + try { - try - { - AnExceptionIsReceivedWhenExpected(); - } - catch (Exception) - { - // suppress failure of test A - } - var foo = Substitute.For(); - foo.MethodC().Returns(1); + AnExceptionIsReceivedWhenExpected(); + } + catch (Exception) + { + // suppress failure of test A } + var foo = Substitute.For(); + foo.MethodC().Returns(1); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue262_NonPublicSetterCall.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue262_NonPublicSetterCall.cs index 3db4abca3..06bb17f10 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue262_NonPublicSetterCall.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue262_NonPublicSetterCall.cs @@ -1,57 +1,56 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +/// +/// Scenarios for the issue: https://github.com/nsubstitute/NSubstitute/issues/626 +/// +/// Do not test internal members, as we don't want to set InternalsVisibleTo attribute. +/// +public class Issue262_NonPublicSetterCall { - /// - /// Scenarios for the issue: https://github.com/nsubstitute/NSubstitute/issues/626 - /// - /// Do not test internal members, as we don't want to set InternalsVisibleTo attribute. - /// - public class Issue262_NonPublicSetterCall + [Test] + public void ShouldHandleProtectedProperties() { - [Test] - public void ShouldHandleProtectedProperties() - { - var subs = Substitute.For(); - - subs.SetProtectedProp(42); - - var result = subs.GetProtectedProp(); - Assert.That(result, Is.EqualTo(expected: 42)); - } - - [Test] - public void ShouldHandlePropertyWithProtectedSetter() - { - var subs = Substitute.For(); - - subs.SetProtectedSetterProp(42); - - var result = subs.ProtectedSetterProp; - Assert.That(result, Is.EqualTo(expected: 42)); - } - [Test] - public void ShouldHandlePropertyWithProtectedGetter() - { - var subs = Substitute.For(); - - subs.ProtectedGetterProp = 42; - - var result = subs.GetProtectedGetterProp(); - Assert.That(result, Is.EqualTo(expected: 42)); - } - - public abstract class TestClass - { - protected abstract int ProtectedProp { get; set; } - public void SetProtectedProp(int value) => ProtectedProp = value; - public int GetProtectedProp() => ProtectedProp; - - public abstract int ProtectedSetterProp { get; protected set; } - public void SetProtectedSetterProp(int value) => ProtectedSetterProp = value; - - public abstract int ProtectedGetterProp { protected get; set; } - public int GetProtectedGetterProp() => ProtectedGetterProp; - } + var subs = Substitute.For(); + + subs.SetProtectedProp(42); + + var result = subs.GetProtectedProp(); + Assert.That(result, Is.EqualTo(expected: 42)); + } + + [Test] + public void ShouldHandlePropertyWithProtectedSetter() + { + var subs = Substitute.For(); + + subs.SetProtectedSetterProp(42); + + var result = subs.ProtectedSetterProp; + Assert.That(result, Is.EqualTo(expected: 42)); + } + [Test] + public void ShouldHandlePropertyWithProtectedGetter() + { + var subs = Substitute.For(); + + subs.ProtectedGetterProp = 42; + + var result = subs.GetProtectedGetterProp(); + Assert.That(result, Is.EqualTo(expected: 42)); + } + + public abstract class TestClass + { + protected abstract int ProtectedProp { get; set; } + public void SetProtectedProp(int value) => ProtectedProp = value; + public int GetProtectedProp() => ProtectedProp; + + public abstract int ProtectedSetterProp { get; protected set; } + public void SetProtectedSetterProp(int value) => ProtectedSetterProp = value; + + public abstract int ProtectedGetterProp { protected get; set; } + public int GetProtectedGetterProp() => ProtectedGetterProp; } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue271_DelegateOutArgument.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue271_DelegateOutArgument.cs index 4a0374839..67333e7c4 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue271_DelegateOutArgument.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue271_DelegateOutArgument.cs @@ -1,21 +1,20 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue271_DelegateOutArgument { - public class Issue271_DelegateOutArgument - { - public delegate void Foo(out int bar); + public delegate void Foo(out int bar); - [Test] - public void DelegateReturnsOutParameter() - { - var foo = Substitute.For(); - int bar; - foo.When(x => x(out bar)).Do(x => { x[0] = 42; }); + [Test] + public void DelegateReturnsOutParameter() + { + var foo = Substitute.For(); + int bar; + foo.When(x => x(out bar)).Do(x => { x[0] = 42; }); - foo(out bar); + foo(out bar); - Assert.AreEqual(42, bar); - } + Assert.AreEqual(42, bar); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue279_ShouldFailOnRedundantArguments.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue279_ShouldFailOnRedundantArguments.cs index e0f60d4d2..f3de52c6b 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue279_ShouldFailOnRedundantArguments.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue279_ShouldFailOnRedundantArguments.cs @@ -1,36 +1,35 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue279_ShouldFailOnRedundantArguments { - public class Issue279_ShouldFailOnRedundantArguments + public interface IFoo { - public interface IFoo - { - int Blah(double s); - } + int Blah(double s); + } + + [Test] + public void Should_fail_with_redundant_exception_if_matcher_is_not_used_due_to_implicit_cast_scenario_1() + { + var foo = Substitute.For(); - [Test] - public void Should_fail_with_redundant_exception_if_matcher_is_not_used_due_to_implicit_cast_scenario_1() + Assert.Throws(() => { - var foo = Substitute.For(); + foo.Blah(Arg.Any()).Returns(42); + }); + } - Assert.Throws(() => - { - foo.Blah(Arg.Any()).Returns(42); - }); - } + [Test] + public void Should_fail_with_redundant_exception_if_matcher_is_not_used_due_to_implicit_cast_scenario_2() + { + var foo = Substitute.For(); - [Test] - public void Should_fail_with_redundant_exception_if_matcher_is_not_used_due_to_implicit_cast_scenario_2() + Assert.Throws(() => { - var foo = Substitute.For(); - - Assert.Throws(() => - { - // Fails because Is() type is deduced to int, so specifier is not matched later. - foo.Blah(Arg.Is(10)).Returns(42); - }); - } + // Fails because Is() type is deduced to int, so specifier is not matched later. + foo.Blah(Arg.Is(10)).Returns(42); + }); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue282_MultipleReturnValuesParallelism.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue282_MultipleReturnValuesParallelism.cs index 06688cb1e..6ea29905b 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue282_MultipleReturnValuesParallelism.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue282_MultipleReturnValuesParallelism.cs @@ -1,31 +1,30 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +[TestFixture] +public class Issue282_MultipleReturnValuesParallelism { - [TestFixture] - public class Issue282_MultipleReturnValuesParallelism + public interface IFoo { - public interface IFoo - { - string Foo(); - } + string Foo(); + } - [Test] - public void ReturnsMultipleValuesInParallel() - { - var ret1 = "One"; - var ret2 = "Two"; + [Test] + public void ReturnsMultipleValuesInParallel() + { + var ret1 = "One"; + var ret2 = "Two"; - var substitute = Substitute.For(); - substitute.Foo().Returns(ret1, ret2); + var substitute = Substitute.For(); + substitute.Foo().Returns(ret1, ret2); - var runningTask1 = Task.Run(() => substitute.Foo()); - var runningTask2 = Task.Run(() => substitute.Foo()); + var runningTask1 = Task.Run(() => substitute.Foo()); + var runningTask2 = Task.Run(() => substitute.Foo()); - var results = Task.WhenAll(runningTask1, runningTask2).Result; + var results = Task.WhenAll(runningTask1, runningTask2).Result; - Assert.Contains(ret1, results); - Assert.Contains(ret2, results); - } + Assert.Contains(ret1, results); + Assert.Contains(ret2, results); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue291_CannotReconfigureThrowingConfiguration.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue291_CannotReconfigureThrowingConfiguration.cs index 0aaf70456..9f7d5979c 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue291_CannotReconfigureThrowingConfiguration.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue291_CannotReconfigureThrowingConfiguration.cs @@ -2,49 +2,48 @@ using NSubstitute.ExceptionExtensions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue291_CannotReconfigureThrowingConfiguration { - public class Issue291_CannotReconfigureThrowingConfiguration + // Based on: https://stackoverflow.com/q/42686269/906 + + public interface IRequest { } + public interface IResponse { } + public interface IDeliver { IResponse Send(IRequest msg); } + + public class Message1 : IRequest { } + public class Message2 : IRequest { } + public class Response : IResponse { } + + [Test] + public void ShouldBePossibleToReConfigureThrowingConfiguration() { - // Based on: https://stackoverflow.com/q/42686269/906 - - public interface IRequest { } - public interface IResponse { } - public interface IDeliver { IResponse Send(IRequest msg); } - - public class Message1 : IRequest { } - public class Message2 : IRequest { } - public class Response : IResponse { } - - [Test] - public void ShouldBePossibleToReConfigureThrowingConfiguration() - { - // Arrange - var response = new Response(); - var deliver = Substitute.For(); - - // Act - deliver.Send(Arg.Any()).Throws(); - deliver.Send(Arg.Any()).Returns(response); - - // Assert - Assert.Throws(() => deliver.Send(new Message1())); - Assert.AreSame(response, deliver.Send(new Message2())); - } - - [Test] - public void ShouldBePossibleToConfigureConstantAfterThrowForAny() - { - // Arrange - var something = Substitute.For(); - - // Act - something.Echo(Arg.Any()).Throws(); - something.Echo(Arg.Is(42)).Returns("42"); - - // Assert - Assert.Throws(() => something.Echo(100)); - Assert.AreEqual("42", something.Echo(42)); - } + // Arrange + var response = new Response(); + var deliver = Substitute.For(); + + // Act + deliver.Send(Arg.Any()).Throws(); + deliver.Send(Arg.Any()).Returns(response); + + // Assert + Assert.Throws(() => deliver.Send(new Message1())); + Assert.AreSame(response, deliver.Send(new Message2())); + } + + [Test] + public void ShouldBePossibleToConfigureConstantAfterThrowForAny() + { + // Arrange + var something = Substitute.For(); + + // Act + something.Echo(Arg.Any()).Throws(); + something.Echo(Arg.Is(42)).Returns("42"); + + // Assert + Assert.Throws(() => something.Echo(100)); + Assert.AreEqual("42", something.Echo(42)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue33_RaisingINotifyPropertyChangedEvents.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue33_RaisingINotifyPropertyChangedEvents.cs index 17bdfa5bf..2d1daf8b3 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue33_RaisingINotifyPropertyChangedEvents.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue33_RaisingINotifyPropertyChangedEvents.cs @@ -1,20 +1,19 @@ using System.ComponentModel; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue33_RaisingINotifyPropertyChangedEvents { - public class Issue33_RaisingINotifyPropertyChangedEvents + [Test] + public void Should_be_able_to_raise_event() { - [Test] - public void Should_be_able_to_raise_event() - { - var sub = Substitute.For(); - bool wasCalled = false; - sub.PropertyChanged += (sender, args) => wasCalled = true; + var sub = Substitute.For(); + bool wasCalled = false; + sub.PropertyChanged += (sender, args) => wasCalled = true; - sub.PropertyChanged += Raise.Event(this, new PropertyChangedEventArgs("test")); + sub.PropertyChanged += Raise.Event(this, new PropertyChangedEventArgs("test")); - Assert.That(wasCalled); - } + Assert.That(wasCalled); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue372_InterfaceSameNameOfMethods.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue372_InterfaceSameNameOfMethods.cs index 3f14a7d51..1425d0644 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue372_InterfaceSameNameOfMethods.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue372_InterfaceSameNameOfMethods.cs @@ -1,28 +1,27 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue372_InterfaceSameNameOfMethods { - public class Issue372_InterfaceSameNameOfMethods + public interface A { - public interface A - { - } + } - public interface B - { - } + public interface B + { + } - public interface X - { - Task Foo(B bar); - Task Foo(A bar); - } + public interface X + { + Task Foo(B bar); + Task Foo(A bar); + } - [Test] - public void Should_create_substitute() - { - var sut = Substitute.For(); - Assert.NotNull(sut); - } + [Test] + public void Should_create_substitute() + { + var sut = Substitute.For(); + Assert.NotNull(sut); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue378_InValueTypes.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue378_InValueTypes.cs index 33e78aa1a..1f2527d90 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue378_InValueTypes.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue378_InValueTypes.cs @@ -1,97 +1,96 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +/// +/// Issue from https://github.com/nsubstitute/NSubstitute/issues/378. +/// +public class Issue378_InValueTypes { - /// - /// Issue from https://github.com/nsubstitute/NSubstitute/issues/378. - /// - public class Issue378_InValueTypes + public readonly struct Struct { - public readonly struct Struct + public Struct(int value) { - public Struct(int value) - { - Value = value; - } - - public int Value { get; } + Value = value; } - public interface IStructByReadOnlyRefConsumer { void Consume(in Struct value); } + public int Value { get; } + } - public interface IStructByValueConsumer { void Consume(Struct value); } + public interface IStructByReadOnlyRefConsumer { void Consume(in Struct value); } - public delegate void DelegateStructByReadOnlyRefConsumer(in Struct value); + public interface IStructByValueConsumer { void Consume(Struct value); } - public delegate void DelegateStructByReadOnlyRefConsumerMultipleArgs(in Struct value1, in Struct value2); + public delegate void DelegateStructByReadOnlyRefConsumer(in Struct value); - [Test] - public void IStructByReadOnlyRefConsumer_Test() - { - var value = new Struct(42); + public delegate void DelegateStructByReadOnlyRefConsumerMultipleArgs(in Struct value1, in Struct value2); - var subs = Substitute.For(); - subs.Consume(in value); - } + [Test] + public void IStructByReadOnlyRefConsumer_Test() + { + var value = new Struct(42); - [Test] - public void IStructByValueConsumer_Test() - { - var value = new Struct(42); + var subs = Substitute.For(); + subs.Consume(in value); + } - var subs = Substitute.For(); - subs.Consume(value); - } + [Test] + public void IStructByValueConsumer_Test() + { + var value = new Struct(42); - [Test] - public void DelegateByReadOnlyRefConsumer_Test() - { - var value = new Struct(42); + var subs = Substitute.For(); + subs.Consume(value); + } - var subs = Substitute.For(); - subs.Invoke(in value); - } + [Test] + public void DelegateByReadOnlyRefConsumer_Test() + { + var value = new Struct(42); - [Test] - public void InterfaceReadOnlyRefCannotBeModified() - { - var readOnlyValue = new Struct(42); + var subs = Substitute.For(); + subs.Invoke(in value); + } - var subs = Substitute.For(); - subs.When(x => x.Consume(Arg.Any())).Do(c => { c[0] = new Struct(24); }); + [Test] + public void InterfaceReadOnlyRefCannotBeModified() + { + var readOnlyValue = new Struct(42); - subs.Consume(in readOnlyValue); + var subs = Substitute.For(); + subs.When(x => x.Consume(Arg.Any())).Do(c => { c[0] = new Struct(24); }); - Assert.That(readOnlyValue.Value, Is.EqualTo(42)); - } + subs.Consume(in readOnlyValue); - [Test] - public void DelegateReadOnlyRefCannotBeModified() - { - var readOnlyValue = new Struct(42); + Assert.That(readOnlyValue.Value, Is.EqualTo(42)); + } - var subs = Substitute.For(); - subs.When(x => x.Invoke(Arg.Any())).Do(c => { c[0] = new Struct(24); }); + [Test] + public void DelegateReadOnlyRefCannotBeModified() + { + var readOnlyValue = new Struct(42); - subs.Invoke(in readOnlyValue); + var subs = Substitute.For(); + subs.When(x => x.Invoke(Arg.Any())).Do(c => { c[0] = new Struct(24); }); - Assert.That(readOnlyValue.Value, Is.EqualTo(42)); - } + subs.Invoke(in readOnlyValue); - [Test] - public void DelegateMultipleReadOnlyRefCannotBeModified() - { - var readOnlyValue1 = new Struct(42); - var readOnlyValue2 = new Struct(42); + Assert.That(readOnlyValue.Value, Is.EqualTo(42)); + } - var subs = Substitute.For(); - subs.When(x => x.Invoke(Arg.Any(), Arg.Any())) - .Do(c => { c[0] = new Struct(24); c[1] = new Struct(24); }); + [Test] + public void DelegateMultipleReadOnlyRefCannotBeModified() + { + var readOnlyValue1 = new Struct(42); + var readOnlyValue2 = new Struct(42); - subs.Invoke(in readOnlyValue1, in readOnlyValue2); + var subs = Substitute.For(); + subs.When(x => x.Invoke(Arg.Any(), Arg.Any())) + .Do(c => { c[0] = new Struct(24); c[1] = new Struct(24); }); - Assert.That(readOnlyValue1.Value, Is.EqualTo(42)); - Assert.That(readOnlyValue2.Value, Is.EqualTo(42)); - } + subs.Invoke(in readOnlyValue1, in readOnlyValue2); + + Assert.That(readOnlyValue1.Value, Is.EqualTo(42)); + Assert.That(readOnlyValue2.Value, Is.EqualTo(42)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue38_SettingNullReturnValue.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue38_SettingNullReturnValue.cs index 2d65d7aa6..f8f4626d8 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue38_SettingNullReturnValue.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue38_SettingNullReturnValue.cs @@ -1,30 +1,29 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue38_SettingNullReturnValue { - public class Issue38_SettingNullReturnValue + public interface IDoSomething { - public interface IDoSomething - { - object Something(); - int SomethingWithValueType(); - } + object Something(); + int SomethingWithValueType(); + } - [Test] - public void CanSetCallToReturnNull() - { - var doSomething = Substitute.For(); - doSomething.Something().Returns(null); - var result = doSomething.Something(); - Assert.That(result, Is.Null); - } + [Test] + public void CanSetCallToReturnNull() + { + var doSomething = Substitute.For(); + doSomething.Something().Returns(null); + var result = doSomething.Something(); + Assert.That(result, Is.Null); + } - [Test] - public void SettingCallWhichReturnsAValueTypeToNullShouldThrow() - { - var doSomething = Substitute.For(); - Assert.That(() => doSomething.SomethingWithValueType().Returns(null), Throws.TypeOf()); - } + [Test] + public void SettingCallWhichReturnsAValueTypeToNullShouldThrow() + { + var doSomething = Substitute.For(); + Assert.That(() => doSomething.SomethingWithValueType().Returns(null), Throws.TypeOf()); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue423_SetVirtualMembersInConstructor.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue423_SetVirtualMembersInConstructor.cs index aa122911d..1b22924b3 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue423_SetVirtualMembersInConstructor.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue423_SetVirtualMembersInConstructor.cs @@ -1,78 +1,77 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue423_SetVirtualMembersInConstructor { - public class Issue423_SetVirtualMembersInConstructor + public class TypeWithVirtualMembers { - public class TypeWithVirtualMembers + public virtual string Property { get; set; } + public virtual string ReadOnlyProp { get; } + public virtual string IndirectlyInitProperty { get; set; } + protected virtual string ProtectedProp { get; set; } + + public TypeWithVirtualMembers(string propertyValue) { - public virtual string Property { get; set; } - public virtual string ReadOnlyProp { get; } - public virtual string IndirectlyInitProperty { get; set; } - protected virtual string ProtectedProp { get; set; } - - public TypeWithVirtualMembers(string propertyValue) - { - Property = propertyValue; - ReadOnlyProp = propertyValue; - ProtectedProp = propertyValue; - InitPropertyIndirectly(propertyValue); - - SomeVirtualMethod(); - } - - public virtual void SomeVirtualMethod() - { - } - - public string GetProtectedPropertyValue() => ProtectedProp; - - public void InitPropertyIndirectly(string value) - { - IndirectlyInitProperty = value; - } + Property = propertyValue; + ReadOnlyProp = propertyValue; + ProtectedProp = propertyValue; + InitPropertyIndirectly(propertyValue); + + SomeVirtualMethod(); } - [Test] - public void ShouldSetVirtualPropertiesForPartialSubstitution() + public virtual void SomeVirtualMethod() { - var propValue = "42"; + } - var subs = Substitute.ForPartsOf(propValue); + public string GetProtectedPropertyValue() => ProtectedProp; - Assert.That(subs.Property, Is.EqualTo(propValue)); - Assert.That(subs.ReadOnlyProp, Is.EqualTo(propValue)); - Assert.That(subs.GetProtectedPropertyValue(), Is.EqualTo(propValue)); + public void InitPropertyIndirectly(string value) + { + IndirectlyInitProperty = value; } + } - [Test] - public void ShouldInvokeVirtualMembersCalledInConstructor() - { - var propValue = "42"; + [Test] + public void ShouldSetVirtualPropertiesForPartialSubstitution() + { + var propValue = "42"; - var subs = Substitute.ForPartsOf(propValue); + var subs = Substitute.ForPartsOf(propValue); - Assert.That(subs.IndirectlyInitProperty, Is.EqualTo(propValue)); - } + Assert.That(subs.Property, Is.EqualTo(propValue)); + Assert.That(subs.ReadOnlyProp, Is.EqualTo(propValue)); + Assert.That(subs.GetProtectedPropertyValue(), Is.EqualTo(propValue)); + } - [Test] - public void ShouldNotCountInvokedMethodInConstructor() - { - var subs = Substitute.ForPartsOf("42"); + [Test] + public void ShouldInvokeVirtualMembersCalledInConstructor() + { + var propValue = "42"; - subs.DidNotReceive().SomeVirtualMethod(); - } + var subs = Substitute.ForPartsOf(propValue); - [Test] - public void VirtualPropertyValuesShouldNotBePreservedForRegularSubstitution() - { - var propValue = "42"; + Assert.That(subs.IndirectlyInitProperty, Is.EqualTo(propValue)); + } - var subs = Substitute.For(propValue); + [Test] + public void ShouldNotCountInvokedMethodInConstructor() + { + var subs = Substitute.ForPartsOf("42"); - Assert.That(subs.Property, Is.Not.EqualTo(propValue)); - Assert.That(subs.ReadOnlyProp, Is.Not.EqualTo(propValue)); - Assert.That(subs.GetProtectedPropertyValue(), Is.Not.EqualTo(propValue)); - } + subs.DidNotReceive().SomeVirtualMethod(); + } + + [Test] + public void VirtualPropertyValuesShouldNotBePreservedForRegularSubstitution() + { + var propValue = "42"; + + var subs = Substitute.For(propValue); + + Assert.That(subs.Property, Is.Not.EqualTo(propValue)); + Assert.That(subs.ReadOnlyProp, Is.Not.EqualTo(propValue)); + Assert.That(subs.GetProtectedPropertyValue(), Is.Not.EqualTo(propValue)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue45_CallInfoArgAccessFailsForNull.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue45_CallInfoArgAccessFailsForNull.cs index f65f7b881..ca5efaf97 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue45_CallInfoArgAccessFailsForNull.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue45_CallInfoArgAccessFailsForNull.cs @@ -1,26 +1,25 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue45_CallInfoArgAccessFailsForNull { - public class Issue45_CallInfoArgAccessFailsForNull + public interface IAmAnInterface { - public interface IAmAnInterface - { - bool ThatHasAMethodWithArgs(string s, object o); - } + bool ThatHasAMethodWithArgs(string s, object o); + } - [Test] - public void Should_be_able_to_find_a_null_arg_by_type() - { - string stringArgumentUsed = ""; + [Test] + public void Should_be_able_to_find_a_null_arg_by_type() + { + string stringArgumentUsed = ""; - var sub = Substitute.For(); - sub.ThatHasAMethodWithArgs(null, null) - .ReturnsForAnyArgs(x => { stringArgumentUsed = x.Arg(); return true; }); + var sub = Substitute.For(); + sub.ThatHasAMethodWithArgs(null, null) + .ReturnsForAnyArgs(x => { stringArgumentUsed = x.Arg(); return true; }); - sub.ThatHasAMethodWithArgs(null, 42); + sub.ThatHasAMethodWithArgs(null, 42); - Assert.That(stringArgumentUsed, Is.Null); - } + Assert.That(stringArgumentUsed, Is.Null); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue47_RaisingEventsWithNullArg.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue47_RaisingEventsWithNullArg.cs index 83bad5a65..78b9fa236 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue47_RaisingEventsWithNullArg.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue47_RaisingEventsWithNullArg.cs @@ -1,29 +1,28 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue47_RaisingEventsWithNullArg { - public class Issue47_RaisingEventsWithNullArg + public delegate void ProgressEventHandler(int progress, string message); + public delegate void EventLikeHandler(object sender, EventArgs args); + public interface IFoo { - public delegate void ProgressEventHandler(int progress, string message); - public delegate void EventLikeHandler(object sender, EventArgs args); - public interface IFoo - { - event ProgressEventHandler OnProgress; - event EventLikeHandler OnEventishThing; - } + event ProgressEventHandler OnProgress; + event EventLikeHandler OnEventishThing; + } - [Test] - public void Pass_null_when_raising_delegate_event() - { - var sub = Substitute.For(); - sub.OnProgress += Raise.Event(1, null); - } + [Test] + public void Pass_null_when_raising_delegate_event() + { + var sub = Substitute.For(); + sub.OnProgress += Raise.Event(1, null); + } - [Test] - public void Pass_null_when_raising_eventhandlerish_event() - { - var sub = Substitute.For(); - sub.OnEventishThing += Raise.Event(new object[] { null }); - } + [Test] + public void Pass_null_when_raising_eventhandlerish_event() + { + var sub = Substitute.For(); + sub.OnEventishThing += Raise.Event(new object[] { null }); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue500_SpecialMethodsWithoutAttribute.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue500_SpecialMethodsWithoutAttribute.cs index 73daeefa3..7a52bc719 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue500_SpecialMethodsWithoutAttribute.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue500_SpecialMethodsWithoutAttribute.cs @@ -2,112 +2,111 @@ using System.Reflection.Emit; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue500_SpecialMethodsWithoutAttribute { - public class Issue500_SpecialMethodsWithoutAttribute + private const string EventName = "MyEvent"; + private const string PropertyName = "MyProperty"; + private static readonly Type TypeWithMissingSpecialNameMethodAttributes; + + static Issue500_SpecialMethodsWithoutAttribute() { - private const string EventName = "MyEvent"; - private const string PropertyName = "MyProperty"; - private static readonly Type TypeWithMissingSpecialNameMethodAttributes; + TypeWithMissingSpecialNameMethodAttributes = GenerateTypeWithMissingSpecialNameAttributes(); + } - static Issue500_SpecialMethodsWithoutAttribute() - { - TypeWithMissingSpecialNameMethodAttributes = GenerateTypeWithMissingSpecialNameAttributes(); - } + [Test] + public void ShouldCorrectlyConfigureProperty() + { + var substitute = Substitute.For(new[] { TypeWithMissingSpecialNameMethodAttributes }, new object[0]); + var fixture = new GeneratedTypeFixture(substitute); - [Test] - public void ShouldCorrectlyConfigureProperty() - { - var substitute = Substitute.For(new[] { TypeWithMissingSpecialNameMethodAttributes }, new object[0]); - var fixture = new GeneratedTypeFixture(substitute); + fixture.MyProperty = "42"; - fixture.MyProperty = "42"; + var result = fixture.MyProperty; + Assert.That(result, Is.EqualTo("42")); + } - var result = fixture.MyProperty; - Assert.That(result, Is.EqualTo("42")); - } + [Test] + public void ShouldCorrectlyConfigureEvent() + { + object substitute = Substitute.For(new[] { TypeWithMissingSpecialNameMethodAttributes }, new object[0]); + var fixture = new GeneratedTypeFixture(substitute); - [Test] - public void ShouldCorrectlyConfigureEvent() - { - object substitute = Substitute.For(new[] { TypeWithMissingSpecialNameMethodAttributes }, new object[0]); - var fixture = new GeneratedTypeFixture(substitute); + bool wasCalled = false; + fixture.MyEvent += (sender, args) => wasCalled = true; + fixture.MyEvent += Raise.Event(); - bool wasCalled = false; - fixture.MyEvent += (sender, args) => wasCalled = true; - fixture.MyEvent += Raise.Event(); + Assert.That(wasCalled, Is.EqualTo(true)); + } - Assert.That(wasCalled, Is.EqualTo(true)); + private static Type GenerateTypeWithMissingSpecialNameAttributes() + { + const string assemblyName = "Issue500_SpecialMethodsWithoutAttribute"; + + var assembly = AssemblyBuilder + .DefineDynamicAssembly( + new AssemblyName(assemblyName), + AssemblyBuilderAccess.Run); + var module = assembly.DefineDynamicModule(assemblyName); + var typeBuilder = module.DefineType("TypeWithMissingSpecialAttributes", + TypeAttributes.Public | TypeAttributes.Abstract); + + var evBuilder = typeBuilder.DefineEvent(EventName, EventAttributes.None, typeof(EventHandler)); + var evAdder = typeBuilder.DefineMethod( + $"add_{EventName}", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | + MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, + typeof(void), + new[] { typeof(EventHandler) }); + var evRemover = typeBuilder.DefineMethod( + $"remove_{EventName}", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | + MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, + typeof(void), + new[] { typeof(EventHandler) }); + evBuilder.SetAddOnMethod(evAdder); + evBuilder.SetRemoveOnMethod(evRemover); + + var propBuilder = + typeBuilder.DefineProperty(PropertyName, PropertyAttributes.None, typeof(string), Type.EmptyTypes); + var propGetter = typeBuilder.DefineMethod( + $"get_{PropertyName}", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | + MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, + typeof(object), + Type.EmptyTypes); + var propSetter = typeBuilder.DefineMethod( + $"set_{PropertyName}", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | + MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, + typeof(void), + new[] { typeof(object) }); + propBuilder.SetGetMethod(propGetter); + propBuilder.SetSetMethod(propSetter); + + return typeBuilder.CreateTypeInfo().AsType(); + } + + private class GeneratedTypeFixture + { + private readonly object _substitute; + + public GeneratedTypeFixture(object substitute) + { + _substitute = substitute; } - private static Type GenerateTypeWithMissingSpecialNameAttributes() + public object MyProperty { - const string assemblyName = "Issue500_SpecialMethodsWithoutAttribute"; - - var assembly = AssemblyBuilder - .DefineDynamicAssembly( - new AssemblyName(assemblyName), - AssemblyBuilderAccess.Run); - var module = assembly.DefineDynamicModule(assemblyName); - var typeBuilder = module.DefineType("TypeWithMissingSpecialAttributes", - TypeAttributes.Public | TypeAttributes.Abstract); - - var evBuilder = typeBuilder.DefineEvent(EventName, EventAttributes.None, typeof(EventHandler)); - var evAdder = typeBuilder.DefineMethod( - $"add_{EventName}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | - MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, - typeof(void), - new[] { typeof(EventHandler) }); - var evRemover = typeBuilder.DefineMethod( - $"remove_{EventName}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | - MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, - typeof(void), - new[] { typeof(EventHandler) }); - evBuilder.SetAddOnMethod(evAdder); - evBuilder.SetRemoveOnMethod(evRemover); - - var propBuilder = - typeBuilder.DefineProperty(PropertyName, PropertyAttributes.None, typeof(string), Type.EmptyTypes); - var propGetter = typeBuilder.DefineMethod( - $"get_{PropertyName}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | - MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, - typeof(object), - Type.EmptyTypes); - var propSetter = typeBuilder.DefineMethod( - $"set_{PropertyName}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | - MethodAttributes.HideBySig | MethodAttributes.NewSlot /* | MethodAttributes.SpecialName */, - typeof(void), - new[] { typeof(object) }); - propBuilder.SetGetMethod(propGetter); - propBuilder.SetSetMethod(propSetter); - - return typeBuilder.CreateTypeInfo().AsType(); + get => _substitute.GetType().GetProperty(PropertyName).GetValue(_substitute); + set => _substitute.GetType().GetProperty(PropertyName).SetValue(_substitute, value); } - private class GeneratedTypeFixture + public event EventHandler MyEvent { - private readonly object _substitute; - - public GeneratedTypeFixture(object substitute) - { - _substitute = substitute; - } - - public object MyProperty - { - get => _substitute.GetType().GetProperty(PropertyName).GetValue(_substitute); - set => _substitute.GetType().GetProperty(PropertyName).SetValue(_substitute, value); - } - - public event EventHandler MyEvent - { - add => _substitute.GetType().GetEvent(EventName).AddEventHandler(_substitute, value); - remove => _substitute.GetType().GetEvent(EventName).RemoveEventHandler(_substitute, value); - } + add => _substitute.GetType().GetEvent(EventName).AddEventHandler(_substitute, value); + remove => _substitute.GetType().GetEvent(EventName).RemoveEventHandler(_substitute, value); } } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue515_OutOfRangeExceptionForNestedGenericTypes.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue515_OutOfRangeExceptionForNestedGenericTypes.cs index 02e3e9887..be4907a89 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue515_OutOfRangeExceptionForNestedGenericTypes.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue515_OutOfRangeExceptionForNestedGenericTypes.cs @@ -1,62 +1,61 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports -{ - using NestedGeneric = Issue515_OutOfRangeExceptionForNestedGenericTypes.Foo.Intermediate.Nested>; - using NestedNonGeneric = Issue515_OutOfRangeExceptionForNestedGenericTypes.Bar.Intermediate.Nested; +namespace NSubstitute.Acceptance.Specs.FieldReports; + +using NestedGeneric = Issue515_OutOfRangeExceptionForNestedGenericTypes.Foo.Intermediate.Nested>; +using NestedNonGeneric = Issue515_OutOfRangeExceptionForNestedGenericTypes.Bar.Intermediate.Nested; - public class Issue515_OutOfRangeExceptionForNestedGenericTypes +public class Issue515_OutOfRangeExceptionForNestedGenericTypes +{ + [Test] + public void ShouldCorrectlyFormatNestedGenericTypeName() { - [Test] - public void ShouldCorrectlyFormatNestedGenericTypeName() - { - var sub = Substitute.For(); - sub.ConsumeGeneric(new NestedGeneric()); + var sub = Substitute.For(); + sub.ConsumeGeneric(new NestedGeneric()); - var ex = Assert.Throws( - () => sub.Received().ConsumeGeneric(null)); - Assert.That(ex.Message, Contains.Substring( - "ConsumeGeneric(*Issue515_OutOfRangeExceptionForNestedGenericTypes+Foo+Intermediate+Nested>*)")); - } + var ex = Assert.Throws( + () => sub.Received().ConsumeGeneric(null)); + Assert.That(ex.Message, Contains.Substring( + "ConsumeGeneric(*Issue515_OutOfRangeExceptionForNestedGenericTypes+Foo+Intermediate+Nested>*)")); + } - [Test] - public void ShouldCorrectlyFormatNestedNonGenericTypeName() - { - var sub = Substitute.For(); - sub.ConsumeNonGeneric(new NestedNonGeneric()); + [Test] + public void ShouldCorrectlyFormatNestedNonGenericTypeName() + { + var sub = Substitute.For(); + sub.ConsumeNonGeneric(new NestedNonGeneric()); - var ex = Assert.Throws( - () => sub.Received().ConsumeNonGeneric(null)); - Assert.That(ex.Message, Contains.Substring( - "ConsumeNonGeneric(*Issue515_OutOfRangeExceptionForNestedGenericTypes+Bar+Intermediate+Nested*)")); - } + var ex = Assert.Throws( + () => sub.Received().ConsumeNonGeneric(null)); + Assert.That(ex.Message, Contains.Substring( + "ConsumeNonGeneric(*Issue515_OutOfRangeExceptionForNestedGenericTypes+Bar+Intermediate+Nested*)")); + } - public interface IConsumer - { - void ConsumeGeneric(NestedGeneric arg); - void ConsumeNonGeneric(NestedNonGeneric arg); - } + public interface IConsumer + { + void ConsumeGeneric(NestedGeneric arg); + void ConsumeNonGeneric(NestedNonGeneric arg); + } - public class Foo + public class Foo + { + public class Intermediate { - public class Intermediate + public class Nested where T3 : IEnumerable { - public class Nested where T3 : IEnumerable - { - public int Baz { get; } = 42; - } + public int Baz { get; } = 42; } } + } - public class Bar + public class Bar + { + public class Intermediate { - public class Intermediate + public class Nested { - public class Nested - { - public int Baz { get; } = 42; - } + public int Baz { get; } = 42; } } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue533_TaskExceptionMightBeSwallowed.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue533_TaskExceptionMightBeSwallowed.cs index 52e5eeff6..f968c6aef 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue533_TaskExceptionMightBeSwallowed.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue533_TaskExceptionMightBeSwallowed.cs @@ -2,235 +2,234 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue533_TaskExceptionMightBeSwallowed { - public class Issue533_TaskExceptionMightBeSwallowed + [Test] + public void ClientScenario_ShouldFailWithRedundantArgMatcherException() { - [Test] - public void ClientScenario_ShouldFailWithRedundantArgMatcherException() - { - var substitute = Substitute.For(); + var substitute = Substitute.For(); - Assert.Throws(() => - MainModuleExtensions - .Work(substitute, Arg.Any(), Arg.Any()) - .Returns(Guid.Empty) - ); - } + Assert.Throws(() => + MainModuleExtensions + .Work(substitute, Arg.Any(), Arg.Any()) + .Returns(Guid.Empty) + ); + } - [Test] - public void ShouldRethrowOriginalSubstituteException_TaskValue() - { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoAsync(substitute, Arg.Any()).Returns("42"); - }); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_TaskValue() + { + var substitute = Substitute.For(); - [Test] - public void ShouldRethrowOriginalSubstituteException_TaskValueForAny() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoAsync(substitute, Arg.Any()).ReturnsForAnyArgs("42"); - }); - } + Arg.Any(); + InvokeEchoAsync(substitute, Arg.Any()).Returns("42"); + }); + } - [Test] - public void ShouldRethrowOriginalSubstituteException_TaskCallback() - { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoAsync(substitute, Arg.Any()).Returns(c => "42"); - }); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_TaskValueForAny() + { + var substitute = Substitute.For(); - [Test] - public void ShouldRethrowOriginalSubstituteException_TaskCallbackForAny() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoAsync(substitute, Arg.Any()).ReturnsForAnyArgs(c => "42"); - }); - } + Arg.Any(); + InvokeEchoAsync(substitute, Arg.Any()).ReturnsForAnyArgs("42"); + }); + } - [Test] - public void ShouldRethrowOriginalSubstituteException_ValueTaskValue() - { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoValueTaskAsync(substitute, Arg.Any()).Returns("42"); - }); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_TaskCallback() + { + var substitute = Substitute.For(); - [Test] - public void ShouldRethrowOriginalSubstituteException_ValueTaskValueForAny() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoValueTaskAsync(substitute, Arg.Any()).ReturnsForAnyArgs("42"); - }); - } + Arg.Any(); + InvokeEchoAsync(substitute, Arg.Any()).Returns(c => "42"); + }); + } - [Test] - public void ShouldRethrowOriginalSubstituteException_ValueTaskCallback() - { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoValueTaskAsync(substitute, Arg.Any()).Returns(c => "42"); - }); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_TaskCallbackForAny() + { + var substitute = Substitute.For(); - [Test] - public void ShouldRethrowOriginalSubstituteException_ValueTaskCallbackForAny() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.For(); - - substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. - Assert.Throws(() => - { - Arg.Any(); - InvokeEchoValueTaskAsync(substitute, Arg.Any()).ReturnsForAnyArgs(c => "42"); - }); - } + Arg.Any(); + InvokeEchoAsync(substitute, Arg.Any()).ReturnsForAnyArgs(c => "42"); + }); + } + + [Test] + public void ShouldRethrowOriginalSubstituteException_ValueTaskValue() + { + var substitute = Substitute.For(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_TaskValue() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.ForPartsOf(); + Arg.Any(); + InvokeEchoValueTaskAsync(substitute, Arg.Any()).Returns("42"); + }); + } - Assert.DoesNotThrow(() => - substitute.GetValue().Returns(42)); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_ValueTaskValueForAny() + { + var substitute = Substitute.For(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_TaskValueAnyArg() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.ForPartsOf(); + Arg.Any(); + InvokeEchoValueTaskAsync(substitute, Arg.Any()).ReturnsForAnyArgs("42"); + }); + } - Assert.DoesNotThrow(() => - substitute.GetValue().ReturnsForAnyArgs(42)); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_ValueTaskCallback() + { + var substitute = Substitute.For(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_TaskCallback() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.ForPartsOf(); + Arg.Any(); + InvokeEchoValueTaskAsync(substitute, Arg.Any()).Returns(c => "42"); + }); + } - Assert.DoesNotThrow(() => - substitute.GetValue().Returns(c => 42)); - } + [Test] + public void ShouldRethrowOriginalSubstituteException_ValueTaskCallbackForAny() + { + var substitute = Substitute.For(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_TaskCallbackAnyArg() + substitute.Say("42"); // If task exception is not unwrapped, then type mismatch exception will be throw. + Assert.Throws(() => { - var substitute = Substitute.ForPartsOf(); + Arg.Any(); + InvokeEchoValueTaskAsync(substitute, Arg.Any()).ReturnsForAnyArgs(c => "42"); + }); + } - Assert.DoesNotThrow(() => - substitute.GetValue().ReturnsForAnyArgs(c => 42)); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_TaskValue() + { + var substitute = Substitute.ForPartsOf(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskValue() - { - var substitute = Substitute.ForPartsOf(); + Assert.DoesNotThrow(() => + substitute.GetValue().Returns(42)); + } - Assert.DoesNotThrow(() => - substitute.GetValueValueTask().Returns(42)); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_TaskValueAnyArg() + { + var substitute = Substitute.ForPartsOf(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskValueAnyArg() - { - var substitute = Substitute.ForPartsOf(); + Assert.DoesNotThrow(() => + substitute.GetValue().ReturnsForAnyArgs(42)); + } - Assert.DoesNotThrow(() => - substitute.GetValueValueTask().ReturnsForAnyArgs(42)); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_TaskCallback() + { + var substitute = Substitute.ForPartsOf(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskCallback() - { - var substitute = Substitute.ForPartsOf(); + Assert.DoesNotThrow(() => + substitute.GetValue().Returns(c => 42)); + } - Assert.DoesNotThrow(() => - substitute.GetValueValueTask().Returns(c => 42)); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_TaskCallbackAnyArg() + { + var substitute = Substitute.ForPartsOf(); - [Test] - public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskCallbackAnyArg() - { - var substitute = Substitute.ForPartsOf(); + Assert.DoesNotThrow(() => + substitute.GetValue().ReturnsForAnyArgs(c => 42)); + } - Assert.DoesNotThrow(() => - substitute.GetValueValueTask().ReturnsForAnyArgs(c => 42)); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskValue() + { + var substitute = Substitute.ForPartsOf(); - private static async Task InvokeEchoAsync(ISomething something, int value) - { - return await something.EchoAsync(value); - } + Assert.DoesNotThrow(() => + substitute.GetValueValueTask().Returns(42)); + } - private static async ValueTask InvokeEchoValueTaskAsync(ISomething something, int value) - { - return await something.EchoValueTaskAsync(value); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskValueAnyArg() + { + var substitute = Substitute.ForPartsOf(); - public interface IMainModule - { - IWorker Worker { get; } - } + Assert.DoesNotThrow(() => + substitute.GetValueValueTask().ReturnsForAnyArgs(42)); + } - public interface IWorker - { - Task DoSomethingAsync(Guid userId); - } + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskCallback() + { + var substitute = Substitute.ForPartsOf(); + + Assert.DoesNotThrow(() => + substitute.GetValueValueTask().Returns(c => 42)); + } + + [Test] + public void ShouldSwallowCustomExceptionThrownFromTask_ValueTaskCallbackAnyArg() + { + var substitute = Substitute.ForPartsOf(); + + Assert.DoesNotThrow(() => + substitute.GetValueValueTask().ReturnsForAnyArgs(c => 42)); + } + + private static async Task InvokeEchoAsync(ISomething something, int value) + { + return await something.EchoAsync(value); + } + + private static async ValueTask InvokeEchoValueTaskAsync(ISomething something, int value) + { + return await something.EchoValueTaskAsync(value); + } - private static class MainModuleExtensions + public interface IMainModule + { + IWorker Worker { get; } + } + + public interface IWorker + { + Task DoSomethingAsync(Guid userId); + } + + private static class MainModuleExtensions + { + public static async Task Work( + /* this - extensions are not supported for nested types */ IMainModule mainModule, + Guid userId, string s) { - public static async Task Work( - /* this - extensions are not supported for nested types */ IMainModule mainModule, - Guid userId, string s) - { - await mainModule.Worker.DoSomethingAsync(userId); - return Guid.NewGuid(); - } + await mainModule.Worker.DoSomethingAsync(userId); + return Guid.NewGuid(); } + } - public class ClassWithThrowingMethods - { + public class ClassWithThrowingMethods + { #pragma warning disable 1998 // Async is required here to wrap exception in task. - public virtual async Task GetValue() => throw new NotImplementedException(); - public virtual async ValueTask GetValueValueTask() => throw new NotImplementedException(); + public virtual async Task GetValue() => throw new NotImplementedException(); + public virtual async ValueTask GetValueValueTask() => throw new NotImplementedException(); #pragma warning restore 1998 - } } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue560_RaiseEventWithArrayArg.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue560_RaiseEventWithArrayArg.cs index c35bd32f7..21076ff5e 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue560_RaiseEventWithArrayArg.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue560_RaiseEventWithArrayArg.cs @@ -1,109 +1,108 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue560_RaiseEventWithArrayArg { - public class Issue560_RaiseEventWithArrayArg + [Test] + public void Raise_event_declared_as_action_with_ref_array_type() { - [Test] - public void Raise_event_declared_as_action_with_ref_array_type() - { - Widget[] arg = null; - Widget w1 = new Widget("hello"); - Widget w2 = new Widget("world"); - - var eventSamples = Substitute.For(); - eventSamples.ActionWithRefArrayType += x => arg = x; - - eventSamples.ActionWithRefArrayType += Raise.Event>(new[] { w1, w2 }); - Assert.That(arg, Is.Not.Null); - Assert.That(arg.Length, Is.EqualTo(2)); - Assert.That(arg[0], Is.EqualTo(w1)); - Assert.That(arg[1], Is.EqualTo(w2)); - } + Widget[] arg = null; + Widget w1 = new Widget("hello"); + Widget w2 = new Widget("world"); + + var eventSamples = Substitute.For(); + eventSamples.ActionWithRefArrayType += x => arg = x; + + eventSamples.ActionWithRefArrayType += Raise.Event>(new[] { w1, w2 }); + Assert.That(arg, Is.Not.Null); + Assert.That(arg.Length, Is.EqualTo(2)); + Assert.That(arg[0], Is.EqualTo(w1)); + Assert.That(arg[1], Is.EqualTo(w2)); + } - [Test] - public void Should_raise_event_for_object_array_arg() - { - object[] capturedArg = null; - var arg1 = new[] { new object(), new object() }; + [Test] + public void Should_raise_event_for_object_array_arg() + { + object[] capturedArg = null; + var arg1 = new[] { new object(), new object() }; - var eventSamples = Substitute.For(); - eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; + var eventSamples = Substitute.For(); + eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; - eventSamples.ActionWithParamOfObjectArray += Raise.Event>(arg1); - Assert.That(capturedArg, Is.EqualTo(arg1)); - } + eventSamples.ActionWithParamOfObjectArray += Raise.Event>(arg1); + Assert.That(capturedArg, Is.EqualTo(arg1)); + } - [Test] - public void Should_raise_event_for_object_array_arg_with_covariance() - { - object[] capturedArg = null; - var arg1 = new[] { "hello", "world" }; + [Test] + public void Should_raise_event_for_object_array_arg_with_covariance() + { + object[] capturedArg = null; + var arg1 = new[] { "hello", "world" }; - var eventSamples = Substitute.For(); - eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; + var eventSamples = Substitute.For(); + eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; - eventSamples.ActionWithParamOfObjectArray += Raise.Event>(arg1); - Assert.That(capturedArg, Is.EqualTo(arg1)); - } + eventSamples.ActionWithParamOfObjectArray += Raise.Event>(arg1); + Assert.That(capturedArg, Is.EqualTo(arg1)); + } - [Test] - public void Should_raise_event_for_object_array_arg_provided_without_using_params_syntax() - { - object[] capturedArg = null; - var arg1 = new[] { new object(), new object() }; + [Test] + public void Should_raise_event_for_object_array_arg_provided_without_using_params_syntax() + { + object[] capturedArg = null; + var arg1 = new[] { new object(), new object() }; - var eventSamples = Substitute.For(); - eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; + var eventSamples = Substitute.For(); + eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; - eventSamples.ActionWithParamOfObjectArray += Raise.Event>(new object[] { arg1 }); - Assert.That(capturedArg, Is.EqualTo(arg1)); - } + eventSamples.ActionWithParamOfObjectArray += Raise.Event>(new object[] { arg1 }); + Assert.That(capturedArg, Is.EqualTo(arg1)); + } - [Test] - public void Should_raise_event_for_object_array_arg_provided_without_using_params_syntax_with_covariance() - { - object[] capturedArg = null; - var arg1 = new[] { "hello", "world" }; + [Test] + public void Should_raise_event_for_object_array_arg_provided_without_using_params_syntax_with_covariance() + { + object[] capturedArg = null; + var arg1 = new[] { "hello", "world" }; - var eventSamples = Substitute.For(); - eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; + var eventSamples = Substitute.For(); + eventSamples.ActionWithParamOfObjectArray += x => capturedArg = x; - eventSamples.ActionWithParamOfObjectArray += Raise.Event>(new object[] { arg1 }); - Assert.That(capturedArg, Is.EqualTo(arg1)); - } + eventSamples.ActionWithParamOfObjectArray += Raise.Event>(new object[] { arg1 }); + Assert.That(capturedArg, Is.EqualTo(arg1)); + } - [Test] - public void Should_raise_event_for_multiple_object_array_args() - { - Tuple capturedArgs = null; - var arg1 = new[] { new object(), new object() }; - var arg2 = new[] { new object(), new object() }; + [Test] + public void Should_raise_event_for_multiple_object_array_args() + { + Tuple capturedArgs = null; + var arg1 = new[] { new object(), new object() }; + var arg2 = new[] { new object(), new object() }; - var eventSamples = Substitute.For(); - eventSamples.ActionWithParamsOfObjectArray += (a1, a2) => capturedArgs = Tuple.Create(a1, a2); + var eventSamples = Substitute.For(); + eventSamples.ActionWithParamsOfObjectArray += (a1, a2) => capturedArgs = Tuple.Create(a1, a2); - eventSamples.ActionWithParamsOfObjectArray += Raise.Event>(arg1, arg2); - Assert.That(capturedArgs, Is.Not.Null); - Assert.That(capturedArgs.Item1, Is.EqualTo(arg1)); - Assert.That(capturedArgs.Item2, Is.EqualTo(arg2)); - } + eventSamples.ActionWithParamsOfObjectArray += Raise.Event>(arg1, arg2); + Assert.That(capturedArgs, Is.Not.Null); + Assert.That(capturedArgs.Item1, Is.EqualTo(arg1)); + Assert.That(capturedArgs.Item2, Is.EqualTo(arg2)); + } - public interface IEventSamples - { - event Action ActionWithRefArrayType; - event Action ActionWithParamOfObjectArray; - event Action ActionWithParamsOfObjectArray; - } + public interface IEventSamples + { + event Action ActionWithRefArrayType; + event Action ActionWithParamOfObjectArray; + event Action ActionWithParamsOfObjectArray; + } - public class Widget - { - public string Name { get; } + public class Widget + { + public string Name { get; } - public Widget(string name) - { - Name = name; - } + public Widget(string name) + { + Name = name; } } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue569_QueryShouldNotInvokeConfiguredResult.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue569_QueryShouldNotInvokeConfiguredResult.cs index 98d4f0ca1..0272a571f 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue569_QueryShouldNotInvokeConfiguredResult.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue569_QueryShouldNotInvokeConfiguredResult.cs @@ -2,81 +2,80 @@ using NSubstitute.ExceptionExtensions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue569_QueryShouldNotInvokeConfiguredResult { - public class Issue569_QueryShouldNotInvokeConfiguredResult + [Test] + public void Should_not_invoke_configured_handler_in_query_original() { - [Test] - public void Should_not_invoke_configured_handler_in_query_original() - { - // Arrange - var substitute = Substitute.For>(); - substitute.Invoke().Returns(x => throw new Exception("SOME EXCEPTION")); - - // Act - try - { - substitute.Invoke(); - Assert.Fail(); - } - catch (Exception) - { - // ignored - } + // Arrange + var substitute = Substitute.For>(); + substitute.Invoke().Returns(x => throw new Exception("SOME EXCEPTION")); - // Assert - Assert.DoesNotThrow(() => - { - Received.InOrder(() => - { - substitute.Invoke(); - }); - }); + // Act + try + { + substitute.Invoke(); + Assert.Fail(); } - - [Test] - public void Should_not_throw_configured_exception_in_query() + catch (Exception) { - // Arrange - var substitute = Substitute.For(); - substitute.Echo(Arg.Any()).Throws(); - try - { - substitute.Echo(42); - } - catch (InvalidOperationException) - { - // Ignore - } + // ignored + } - // Act & Assert - Assert.DoesNotThrow(() => + // Assert + Assert.DoesNotThrow(() => + { + Received.InOrder(() => { - Received.InOrder(() => - { - substitute.Echo(Arg.Any()); - }); + substitute.Invoke(); }); - } + }); + } - [Test] - public void Should_not_invoke_configured_argument_actions_in_query() + [Test] + public void Should_not_throw_configured_exception_in_query() + { + // Arrange + var substitute = Substitute.For(); + substitute.Echo(Arg.Any()).Throws(); + try { - // Arrange - var substitute = Substitute.For(); - bool wasCalled = false; - substitute.Echo(Arg.Do(_ => wasCalled = true)); substitute.Echo(42); + } + catch (InvalidOperationException) + { + // Ignore + } - // Act - wasCalled = false; + // Act & Assert + Assert.DoesNotThrow(() => + { Received.InOrder(() => { - substitute.Echo(42); + substitute.Echo(Arg.Any()); }); + }); + } - // Assert - Assert.That(wasCalled, Is.False); - } + [Test] + public void Should_not_invoke_configured_argument_actions_in_query() + { + // Arrange + var substitute = Substitute.For(); + bool wasCalled = false; + substitute.Echo(Arg.Do(_ => wasCalled = true)); + substitute.Echo(42); + + // Act + wasCalled = false; + Received.InOrder(() => + { + substitute.Echo(42); + }); + + // Assert + Assert.That(wasCalled, Is.False); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue577_CannotSetOutValue.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue577_CannotSetOutValue.cs index b7fd59244..a06dff415 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue577_CannotSetOutValue.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue577_CannotSetOutValue.cs @@ -1,105 +1,104 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue577_CannotSetOutValueWhenPassedValueIsOfIncompatibleType { - public class Issue577_CannotSetOutValueWhenPassedValueIsOfIncompatibleType + [Test] + public void Should_reassign_out_value_when_type_is_incompatible_with_passed_value_original() { - [Test] - public void Should_reassign_out_value_when_type_is_incompatible_with_passed_value_original() + // Arrange + var keyValueDatabase = Substitute.For(); + + var a = Substitute.For(); + var b = Substitute.For(); + + keyValueDatabase.GetKeyValue( + Arg.Any(), + out Arg.Any() + ).Returns(info => { - // Arrange - var keyValueDatabase = Substitute.For(); + var id = (string)info[0]; + if (id != null && id == "a") + { + info[1] = a; + } + else + { + info[1] = b; + } + + return true; + }); + + // Act + IKeyValue outVal; + keyValueDatabase.GetKeyValue("a", out outVal); + keyValueDatabase.GetKeyValue("b", out outVal); + } - var a = Substitute.For(); - var b = Substitute.For(); + [Test] + public void Should_reassign_out_value_when_type_is_incompatible_with_passed_value() + { + // Arrange + var db = Substitute.For(); + + var a = Substitute.For(); + var b = Substitute.For(); - keyValueDatabase.GetKeyValue( - Arg.Any(), - out Arg.Any() - ).Returns(info => + db.GetKeyValue(Arg.Any(), out Arg.Any()) + .Returns(c => { - var id = (string)info[0]; - if (id != null && id == "a") - { - info[1] = a; - } - else - { - info[1] = b; - } + c[1] = b; + return true; + }); + + // Act + IKeyValue result = a; + db.GetKeyValue("42", out result); + Assert.That(result, Is.EqualTo(b)); + } + + [Test] + public void Should_reassign_ref_value_when_type_is_incompatible_with_passed_value() + { + // Arrange + var db = Substitute.For(); + var a = Substitute.For(); + var b = Substitute.For(); + + db.GetKeyValueRef(Arg.Any(), ref Arg.Any()) + .Returns(c => + { + c[1] = b; return true; }); - // Act - IKeyValue outVal; - keyValueDatabase.GetKeyValue("a", out outVal); - keyValueDatabase.GetKeyValue("b", out outVal); - } + // Act + IKeyValue result = a; + db.GetKeyValueRef("42", ref result); + Assert.That(result, Is.EqualTo(b)); + } - [Test] - public void Should_reassign_out_value_when_type_is_incompatible_with_passed_value() - { - // Arrange - var db = Substitute.For(); - - var a = Substitute.For(); - var b = Substitute.For(); - - db.GetKeyValue(Arg.Any(), out Arg.Any()) - .Returns(c => - { - c[1] = b; - return true; - }); - - // Act - IKeyValue result = a; - db.GetKeyValue("42", out result); - Assert.That(result, Is.EqualTo(b)); - } - - [Test] - public void Should_reassign_ref_value_when_type_is_incompatible_with_passed_value() - { - // Arrange - var db = Substitute.For(); - - var a = Substitute.For(); - var b = Substitute.For(); - - db.GetKeyValueRef(Arg.Any(), ref Arg.Any()) - .Returns(c => - { - c[1] = b; - return true; - }); - - // Act - IKeyValue result = a; - db.GetKeyValueRef("42", ref result); - Assert.That(result, Is.EqualTo(b)); - } - - public interface IKeyValue - { - string ID { get; set; } - } + public interface IKeyValue + { + string ID { get; set; } + } - public interface IKeyValueDouble : IKeyValue - { - double Value { get; set; } - } + public interface IKeyValueDouble : IKeyValue + { + double Value { get; set; } + } - public interface IKeyValueString : IKeyValue - { - string Value { get; set; } - } + public interface IKeyValueString : IKeyValue + { + string Value { get; set; } + } - public interface IDatabase - { - bool GetKeyValue(string id, out IKeyValue value); - bool GetKeyValueRef(string id, ref IKeyValue value); - } + public interface IDatabase + { + bool GetKeyValue(string id, out IKeyValue value); + bool GetKeyValueRef(string id, ref IKeyValue value); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue57_SettingVirtualPropertyInCtor.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue57_SettingVirtualPropertyInCtor.cs index de66639dd..18401a722 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue57_SettingVirtualPropertyInCtor.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue57_SettingVirtualPropertyInCtor.cs @@ -1,42 +1,41 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue57_SettingVirtualPropertyInCtorCausesReturnsToUseAutoSub { - public class Issue57_SettingVirtualPropertyInCtorCausesReturnsToUseAutoSub + public class MyEntity + { + public MyEntity() { Name = "Name1"; } + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } + + public interface IEntityRepository { MyEntity Get(Guid id); } + + [Test] + public void TestGetFromRepository() + { + var repository = Substitute.For(); + var fakeEntity = new MyEntity { Id = Guid.NewGuid() }; + + repository.Get(Arg.Any()).Returns(fakeEntity); + + var result = repository.Get(fakeEntity.Id); + Assert.That(result, Is.SameAs(fakeEntity)); + Assert.That(result.Id, Is.EqualTo(fakeEntity.Id)); + } + + [Test] + public void TestGetUsingAutoSubs() { - public class MyEntity - { - public MyEntity() { Name = "Name1"; } - public virtual Guid Id { get; set; } - public virtual string Name { get; set; } - } - - public interface IEntityRepository { MyEntity Get(Guid id); } - - [Test] - public void TestGetFromRepository() - { - var repository = Substitute.For(); - var fakeEntity = new MyEntity { Id = Guid.NewGuid() }; - - repository.Get(Arg.Any()).Returns(fakeEntity); - - var result = repository.Get(fakeEntity.Id); - Assert.That(result, Is.SameAs(fakeEntity)); - Assert.That(result.Id, Is.EqualTo(fakeEntity.Id)); - } - - [Test] - public void TestGetUsingAutoSubs() - { - var repository = Substitute.For(); - var fakeEntity = repository.Get(Arg.Any()); - fakeEntity.Id = Guid.NewGuid(); - - var result = repository.Get(fakeEntity.Id); - - Assert.That(result, Is.SameAs(fakeEntity)); - Assert.That(result.Id, Is.EqualTo(fakeEntity.Id)); - } + var repository = Substitute.For(); + var fakeEntity = repository.Get(Arg.Any()); + fakeEntity.Id = Guid.NewGuid(); + + var result = repository.Get(fakeEntity.Id); + + Assert.That(result, Is.SameAs(fakeEntity)); + Assert.That(result.Id, Is.EqualTo(fakeEntity.Id)); } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue59_ArgDoWithReturns.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue59_ArgDoWithReturns.cs index 960050d2b..c5c84ddd5 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue59_ArgDoWithReturns.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue59_ArgDoWithReturns.cs @@ -1,58 +1,57 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue59_ArgDoWithReturns { - public class Issue59_ArgDoWithReturns + public interface IStudent + { + int Id { set; } + string Name { get; set; } + string Say(string something); + } + + [Test] + public void Returns_and_arg_do_for_method() + { + var sub = Substitute.For(); + var lastArgUsedInCallToSayMethod = ""; + + sub.Say(Arg.Do(x => lastArgUsedInCallToSayMethod = x)); + sub.Say("hello").Returns("world"); + var resultOfHowdy = sub.Say("howdy"); + + Assert.AreEqual("", resultOfHowdy); + Assert.AreEqual("howdy", lastArgUsedInCallToSayMethod); + Assert.AreEqual("world", sub.Say("hello")); + } + + [Test] + public void Returns_and_arg_do_for_property() { - public interface IStudent - { - int Id { set; } - string Name { get; set; } - string Say(string something); - } - - [Test] - public void Returns_and_arg_do_for_method() - { - var sub = Substitute.For(); - var lastArgUsedInCallToSayMethod = ""; - - sub.Say(Arg.Do(x => lastArgUsedInCallToSayMethod = x)); - sub.Say("hello").Returns("world"); - var resultOfHowdy = sub.Say("howdy"); - - Assert.AreEqual("", resultOfHowdy); - Assert.AreEqual("howdy", lastArgUsedInCallToSayMethod); - Assert.AreEqual("world", sub.Say("hello")); - } - - [Test] - public void Returns_and_arg_do_for_property() - { - var sub = Substitute.For(); - var name = ""; - - sub.Name = Arg.Do(x => name = x); - sub.Name = "Jane"; - sub.Name.Returns("Bob"); - - Assert.AreEqual("Jane", name); - Assert.AreEqual("Bob", sub.Name); - } - - [Test] - public void Returns_and_when_do() - { - var sub = Substitute.For(); - var name = ""; - - sub.When(x => x.Name = Arg.Any()).Do(x => name = x.Arg()); - sub.Name = "Jane"; - - sub.Name.Returns("Bob"); - - Assert.AreEqual("Jane", name); - Assert.AreEqual("Bob", sub.Name); - } + var sub = Substitute.For(); + var name = ""; + + sub.Name = Arg.Do(x => name = x); + sub.Name = "Jane"; + sub.Name.Returns("Bob"); + + Assert.AreEqual("Jane", name); + Assert.AreEqual("Bob", sub.Name); + } + + [Test] + public void Returns_and_when_do() + { + var sub = Substitute.For(); + var name = ""; + + sub.When(x => x.Name = Arg.Any()).Do(x => name = x.Arg()); + sub.Name = "Jane"; + + sub.Name.Returns("Bob"); + + Assert.AreEqual("Jane", name); + Assert.AreEqual("Bob", sub.Name); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue61_ArgAnyStringRegression.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue61_ArgAnyStringRegression.cs index 307d29edc..412bfc3e2 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue61_ArgAnyStringRegression.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue61_ArgAnyStringRegression.cs @@ -1,18 +1,17 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class ArgAnyStringRegression { - public class ArgAnyStringRegression - { - public interface IFoo { string Bar(string a, double b); } + public interface IFoo { string Bar(string a, double b); } - [Test] - public void Stub_any_string_and_call_with_null() - { - var foo = Substitute.For(); - foo.Bar(Arg.Any(), Arg.Any()).ReturnsForAnyArgs("hello"); + [Test] + public void Stub_any_string_and_call_with_null() + { + var foo = Substitute.For(); + foo.Bar(Arg.Any(), Arg.Any()).ReturnsForAnyArgs("hello"); - Assert.AreEqual("hello", foo.Bar(null, 0)); - } + Assert.AreEqual("hello", foo.Bar(null, 0)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue75_DoesNotWorkWithMembersThatUseDynamic.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue75_DoesNotWorkWithMembersThatUseDynamic.cs index ce5a9576b..0383eacae 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue75_DoesNotWorkWithMembersThatUseDynamic.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue75_DoesNotWorkWithMembersThatUseDynamic.cs @@ -1,69 +1,68 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue75_DoesNotWorkWithMembersThatUseDynamic { - public class Issue75_DoesNotWorkWithMembersThatUseDynamic + public interface ILog { void Error(Exception e); } + public interface IClient { dynamic Post(string a, string b); } + + public class ClassUnderTest { - public interface ILog { void Error(Exception e); } - public interface IClient { dynamic Post(string a, string b); } + private readonly IClient _client; + private readonly ILog _log; - public class ClassUnderTest + public ClassUnderTest(IClient client, ILog log) { - private readonly IClient _client; - private readonly ILog _log; - - public ClassUnderTest(IClient client, ILog log) - { - _client = client; - _log = log; - } - - public void Handle(string a) - { - dynamic response = _client.Post("asdf", "fdsa"); - var error = response.error; - _log.Error(new Exception(error)); - } + _client = client; + _log = log; } - [Test] - public void SampleTest() + public void Handle(string a) { - var client = Substitute.For(); - var log = Substitute.For(); - var target = new ClassUnderTest(client, log); - const string errorResponse = "some issue"; - dynamic postResponse = new { error = errorResponse }; - client.Post("", "").ReturnsForAnyArgs(postResponse); + dynamic response = _client.Post("asdf", "fdsa"); + var error = response.error; + _log.Error(new Exception(error)); + } + } - // Act - target.Handle("test"); + [Test] + public void SampleTest() + { + var client = Substitute.For(); + var log = Substitute.For(); + var target = new ClassUnderTest(client, log); + const string errorResponse = "some issue"; + dynamic postResponse = new { error = errorResponse }; + client.Post("", "").ReturnsForAnyArgs(postResponse); - // Assert - log.Received().Error(Arg.Is(x => x.Message == errorResponse)); - } + // Act + target.Handle("test"); - // src: https://stackoverflow.com/questions/13182007/nsubstitute-mock-generic-method/ - public interface ISettingsUtil - { - T GetConfig(string setting, dynamic settings); - } + // Assert + log.Received().Error(Arg.Is(x => x.Message == errorResponse)); + } - [Test] - [Pending, Explicit] - public void AnotherTest() - { - // Adapted from: https://stackoverflow.com/questions/13182007/nsubstitute-mock-generic-method/ - var settingsUtil = Substitute.For(); - // This works: - //SubstituteExtensions.Returns(settingsUtil.GetConfig("maxImageSize", Arg.Any()), 100L); + // src: https://stackoverflow.com/questions/13182007/nsubstitute-mock-generic-method/ + public interface ISettingsUtil + { + T GetConfig(string setting, dynamic settings); + } + + [Test] + [Pending, Explicit] + public void AnotherTest() + { + // Adapted from: https://stackoverflow.com/questions/13182007/nsubstitute-mock-generic-method/ + var settingsUtil = Substitute.For(); + // This works: + //SubstituteExtensions.Returns(settingsUtil.GetConfig("maxImageSize", Arg.Any()), 100L); - // This fails, with RuntimeBinderException: 'long' does not contain a definition for 'Returns': - settingsUtil.GetConfig("maxImageSize", Arg.Any()).Returns(100L); + // This fails, with RuntimeBinderException: 'long' does not contain a definition for 'Returns': + settingsUtil.GetConfig("maxImageSize", Arg.Any()).Returns(100L); - dynamic settings = new System.Dynamic.ExpandoObject(); - var result = settingsUtil.GetConfig("maxImageSize", settings); - Assert.That(result, Is.EqualTo(100L)); - } + dynamic settings = new System.Dynamic.ExpandoObject(); + var result = settingsUtil.GetConfig("maxImageSize", settings); + Assert.That(result, Is.EqualTo(100L)); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue77_EqualsBehaviourOnClassStubs.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue77_EqualsBehaviourOnClassStubs.cs index 6adc9ba0f..8a576304f 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue77_EqualsBehaviourOnClassStubs.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue77_EqualsBehaviourOnClassStubs.cs @@ -1,250 +1,249 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue77_BaseObjectBehaviourOnConcreteSubstitutesThatOverrideThoseMethods { - public class Issue77_BaseObjectBehaviourOnConcreteSubstitutesThatOverrideThoseMethods + [Test] + public void Equals_should_return_true_for_same_reference_for_class_substitutes_that_overwrite_equals() { - [Test] - public void Equals_should_return_true_for_same_reference_for_class_substitutes_that_overwrite_equals() - { - var substitute = Substitute.For(); + var substitute = Substitute.For(); - Assert.That(substitute.Equals(substitute), Is.True); - } + Assert.That(substitute.Equals(substitute), Is.True); + } - [Test] - public void Equals_should_return_true_for_same_object_for_class_substitutes_that_overwrite_equals() - { - var substitute = Substitute.For(); - substitute.Id = 1; - var substitute2 = Substitute.For(); - substitute2.Id = 1; + [Test] + public void Equals_should_return_true_for_same_object_for_class_substitutes_that_overwrite_equals() + { + var substitute = Substitute.For(); + substitute.Id = 1; + var substitute2 = Substitute.For(); + substitute2.Id = 1; - Assert.That(substitute.Equals(substitute2), Is.True); - } + Assert.That(substitute.Equals(substitute2), Is.True); + } - [Test] - public void Equals_should_return_false_for_different_objects_for_class_substitutes_that_overwrite_equals() - { - var substitute = Substitute.For(); - substitute.Id = 1; - var substitute2 = Substitute.For(); - substitute2.Id = 2; + [Test] + public void Equals_should_return_false_for_different_objects_for_class_substitutes_that_overwrite_equals() + { + var substitute = Substitute.For(); + substitute.Id = 1; + var substitute2 = Substitute.For(); + substitute2.Id = 2; - Assert.That(substitute.Equals(substitute2), Is.False); - } + Assert.That(substitute.Equals(substitute2), Is.False); + } - [Test] - public void Should_be_able_to_check_received_call_when_taking_class_substitutes_that_overwrite_equals() - { - var service = Substitute.For(); - var substitute = Substitute.For(); + [Test] + public void Should_be_able_to_check_received_call_when_taking_class_substitutes_that_overwrite_equals() + { + var service = Substitute.For(); + var substitute = Substitute.For(); - service.AMethod(substitute); + service.AMethod(substitute); - service.Received().AMethod(substitute); - } + service.Received().AMethod(substitute); + } - [Test] - public void Should_be_able_to_find_a_substitute_that_overrides_equals_in_a_collection() - { - var substitute = Substitute.For(); - substitute.Id = 2; - var classes = new[] { new AClassThatOverwritesBaseObjectMethods { Id = 1 }, substitute, new AClassThatOverwritesBaseObjectMethods { Id = 3 } }; + [Test] + public void Should_be_able_to_find_a_substitute_that_overrides_equals_in_a_collection() + { + var substitute = Substitute.For(); + substitute.Id = 2; + var classes = new[] { new AClassThatOverwritesBaseObjectMethods { Id = 1 }, substitute, new AClassThatOverwritesBaseObjectMethods { Id = 3 } }; - Assert.That(classes.Contains(substitute), Is.True); - } + Assert.That(classes.Contains(substitute), Is.True); + } - [Test] - public void Should_be_able_to_call_tostring_on_substitute_that_overrides_tostring() - { - var substitute = Substitute.For(); - substitute.Id = 2; + [Test] + public void Should_be_able_to_call_tostring_on_substitute_that_overrides_tostring() + { + var substitute = Substitute.For(); + substitute.Id = 2; - Assert.That(substitute.ToString(), Is.EqualTo("{Id=2}")); - } + Assert.That(substitute.ToString(), Is.EqualTo("{Id=2}")); + } - [Test] - public void Should_be_able_to_call_gethashcode_on_substitute_that_overrides_gethashcode() - { - var substitute = Substitute.For(); - substitute.Id = 2; + [Test] + public void Should_be_able_to_call_gethashcode_on_substitute_that_overrides_gethashcode() + { + var substitute = Substitute.For(); + substitute.Id = 2; - Assert.That(substitute.GetHashCode(), Is.EqualTo(2.GetHashCode())); - } + Assert.That(substitute.GetHashCode(), Is.EqualTo(2.GetHashCode())); + } - [Test] - [Pending, Explicit] - public void Should_be_able_to_mock_equals_against_same_object_on_substitute_that_overrides_equals() - { - var substitute = Substitute.For(); + [Test] + [Pending, Explicit] + public void Should_be_able_to_mock_equals_against_same_object_on_substitute_that_overrides_equals() + { + var substitute = Substitute.For(); - substitute.Equals(substitute).Returns(false); + substitute.Equals(substitute).Returns(false); - Assert.That(substitute.Equals(substitute), Is.False); - } + Assert.That(substitute.Equals(substitute), Is.False); + } - [Test] - [Pending, Explicit] - public void Should_be_able_to_mock_equals_on_a_sub_that_overrides_equals_against_another_substitute() - { - var first = Substitute.For(); - var second = Substitute.For(); + [Test] + [Pending, Explicit] + public void Should_be_able_to_mock_equals_on_a_sub_that_overrides_equals_against_another_substitute() + { + var first = Substitute.For(); + var second = Substitute.For(); - first.Equals(second).Returns(false); + first.Equals(second).Returns(false); - Assert.That(first.Equals(second), Is.False); - } + Assert.That(first.Equals(second), Is.False); + } - [Test] - [Pending, Explicit] - public void Should_be_able_to_mock_equals_on_substitute_that_overrides_equals() - { - var substitute = Substitute.For(); - var x = new object(); + [Test] + [Pending, Explicit] + public void Should_be_able_to_mock_equals_on_substitute_that_overrides_equals() + { + var substitute = Substitute.For(); + var x = new object(); - substitute.Equals(x).Returns(true); + substitute.Equals(x).Returns(true); - Assert.That(substitute.Equals(x), Is.True); - } + Assert.That(substitute.Equals(x), Is.True); + } - [Test] - [Pending, Explicit] - public void Should_be_able_to_mock_gethashcode_on_substitute_that_overrides_equals() - { - var substitute = Substitute.For(); + [Test] + [Pending, Explicit] + public void Should_be_able_to_mock_gethashcode_on_substitute_that_overrides_equals() + { + var substitute = Substitute.For(); - substitute.GetHashCode().Returns(5); + substitute.GetHashCode().Returns(5); - Assert.That(substitute.GetHashCode(), Is.EqualTo(5)); - } + Assert.That(substitute.GetHashCode(), Is.EqualTo(5)); + } - [Test] - [Pending, Explicit] - public void Should_be_able_to_mock_tostring_on_substitute_that_overrides_equals() - { - var substitute = Substitute.For(); + [Test] + [Pending, Explicit] + public void Should_be_able_to_mock_tostring_on_substitute_that_overrides_equals() + { + var substitute = Substitute.For(); - substitute.ToString().Returns("aString"); + substitute.ToString().Returns("aString"); - Assert.That(substitute.ToString(), Is.EqualTo("aString")); - } + Assert.That(substitute.ToString(), Is.EqualTo("aString")); + } - [Test] - public void Should_be_able_to_check_equality_of_substitute_that_overrides_base_object_methods_from_return() - { - var service = Substitute.For(); - var substitute = Substitute.For(); - substitute.Id = 1; + [Test] + public void Should_be_able_to_check_equality_of_substitute_that_overrides_base_object_methods_from_return() + { + var service = Substitute.For(); + var substitute = Substitute.For(); + substitute.Id = 1; - service.ReturnClassOverridingBaseObjectMethods(1).Returns(substitute); + service.ReturnClassOverridingBaseObjectMethods(1).Returns(substitute); - Assert.That(service.ReturnClassOverridingBaseObjectMethods(1), Is.EqualTo(substitute)); - Assert.That(service.ReturnClassOverridingBaseObjectMethods(2), Is.Not.EqualTo(substitute)); - } + Assert.That(service.ReturnClassOverridingBaseObjectMethods(1), Is.EqualTo(substitute)); + Assert.That(service.ReturnClassOverridingBaseObjectMethods(2), Is.Not.EqualTo(substitute)); + } - [Test] - public void Should_be_able_to_setup_return_for_call_taking_equal_class_substitutes_that_overwrite_equals() - { - var service = Substitute.For(); - var substitute = Substitute.For(); - substitute.Id = 1; - var substitute1 = Substitute.For(); - substitute1.Id = 1; - var substitute2 = Substitute.For(); - substitute2.Id = 1; - - service.AMethod(substitute).Returns(1); - service.AMethod(substitute2).Returns(2); - - // Reference for substitute doesn't take preference over substitute2.Equals(substitute) - Assert.That(service.AMethod(substitute), Is.EqualTo(2)); - Assert.That(service.AMethod(substitute1), Is.EqualTo(2)); - Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); - } + [Test] + public void Should_be_able_to_setup_return_for_call_taking_equal_class_substitutes_that_overwrite_equals() + { + var service = Substitute.For(); + var substitute = Substitute.For(); + substitute.Id = 1; + var substitute1 = Substitute.For(); + substitute1.Id = 1; + var substitute2 = Substitute.For(); + substitute2.Id = 1; + + service.AMethod(substitute).Returns(1); + service.AMethod(substitute2).Returns(2); + + // Reference for substitute doesn't take preference over substitute2.Equals(substitute) + Assert.That(service.AMethod(substitute), Is.EqualTo(2)); + Assert.That(service.AMethod(substitute1), Is.EqualTo(2)); + Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); + } - [Test] - public void Should_be_able_to_setup_return_for_call_taking_class_substitutes_that_overwrite_equals() - { - var service = Substitute.For(); - var substitute = Substitute.For(); - substitute.Id = 1; - var substitute2 = Substitute.For(); - substitute2.Id = 2; + [Test] + public void Should_be_able_to_setup_return_for_call_taking_class_substitutes_that_overwrite_equals() + { + var service = Substitute.For(); + var substitute = Substitute.For(); + substitute.Id = 1; + var substitute2 = Substitute.For(); + substitute2.Id = 2; - service.AMethod(substitute).Returns(1); - service.AMethod(substitute2).Returns(2); + service.AMethod(substitute).Returns(1); + service.AMethod(substitute2).Returns(2); - Assert.That(service.AMethod(substitute), Is.EqualTo(1)); - Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); - } + Assert.That(service.AMethod(substitute), Is.EqualTo(1)); + Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); + } - [Test] - public void Should_be_able_to_setup_return_for_call_taking_class_substitutes_that_overwrite_equals_as_base_equals() - { - var substitute = Substitute.For(); - var substitute2 = Substitute.For(); + [Test] + public void Should_be_able_to_setup_return_for_call_taking_class_substitutes_that_overwrite_equals_as_base_equals() + { + var substitute = Substitute.For(); + var substitute2 = Substitute.For(); - var service = Substitute.For(); - service.AMethod(substitute).Returns(1); - service.AMethod(substitute2).Returns(2); + var service = Substitute.For(); + service.AMethod(substitute).Returns(1); + service.AMethod(substitute2).Returns(2); - Assert.That(service.AMethod(substitute), Is.EqualTo(1)); - Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); - } + Assert.That(service.AMethod(substitute), Is.EqualTo(1)); + Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); + } - [Test] - public void Should_be_able_to_setup_return_for_call_taking_class_substitutes_that_dont_override_equals() - { - var substitute = Substitute.For(); - var substitute2 = Substitute.For(); + [Test] + public void Should_be_able_to_setup_return_for_call_taking_class_substitutes_that_dont_override_equals() + { + var substitute = Substitute.For(); + var substitute2 = Substitute.For(); - var service = Substitute.For(); - service.AMethod(substitute).Returns(1); - service.AMethod(substitute2).Returns(2); + var service = Substitute.For(); + service.AMethod(substitute).Returns(1); + service.AMethod(substitute2).Returns(2); - Assert.That(service.AMethod(substitute), Is.EqualTo(1)); - Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); - } + Assert.That(service.AMethod(substitute), Is.EqualTo(1)); + Assert.That(service.AMethod(substitute2), Is.EqualTo(2)); + } - public class AClassThatOverridesEquals + public class AClassThatOverridesEquals + { + public override bool Equals(object obj) { return base.Equals(obj); } + public override int GetHashCode() { return 0; } + } + + public class AClassThatDoesntOverrideEquals { } + + public class AClassThatOverwritesBaseObjectMethods + { + public int Id { get; set; } + + public override bool Equals(object obj) { - public override bool Equals(object obj) { return base.Equals(obj); } - public override int GetHashCode() { return 0; } - } + var aClassThatOverwritesEquals = obj as AClassThatOverwritesBaseObjectMethods; + if (aClassThatOverwritesEquals == null) + return false; - public class AClassThatDoesntOverrideEquals { } + return aClassThatOverwritesEquals.Id.Equals(Id); + } - public class AClassThatOverwritesBaseObjectMethods + public override int GetHashCode() { - public int Id { get; set; } - - public override bool Equals(object obj) - { - var aClassThatOverwritesEquals = obj as AClassThatOverwritesBaseObjectMethods; - if (aClassThatOverwritesEquals == null) - return false; - - return aClassThatOverwritesEquals.Id.Equals(Id); - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } - - public override string ToString() - { - return string.Format("{{Id={0}}}", Id); - } + return Id.GetHashCode(); } - public interface IService + public override string ToString() { - int AMethod(AClassThatOverwritesBaseObjectMethods aClassThatOverwritesBaseObjectMethods); - int AMethod(AClassThatOverridesEquals aClassThatOverridesEquals); - int AMethod(AClassThatDoesntOverrideEquals aClassThatDoesntOverrideEquals); - AClassThatOverwritesBaseObjectMethods ReturnClassOverridingBaseObjectMethods(int i); + return string.Format("{{Id={0}}}", Id); } } + + public interface IService + { + int AMethod(AClassThatOverwritesBaseObjectMethods aClassThatOverwritesBaseObjectMethods); + int AMethod(AClassThatOverridesEquals aClassThatOverridesEquals); + int AMethod(AClassThatDoesntOverrideEquals aClassThatDoesntOverrideEquals); + AClassThatOverwritesBaseObjectMethods ReturnClassOverridingBaseObjectMethods(int i); + } } diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue83_MethodsWithGenericStructConstraint.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue83_MethodsWithGenericStructConstraint.cs index 8790ba509..362825731 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue83_MethodsWithGenericStructConstraint.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue83_MethodsWithGenericStructConstraint.cs @@ -1,18 +1,17 @@ using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue83_MethodsWithGenericStructConstraint { - public class Issue83_MethodsWithGenericStructConstraint - { - public interface IService { T Get(T arg) where T : struct; } + public interface IService { T Get(T arg) where T : struct; } - [Test] - public void TestGenericCalls() - { - var id = Guid.NewGuid(); - var service = Substitute.For(); - service.Get(id); - service.Received().Get(id); - } + [Test] + public void TestGenericCalls() + { + var id = Guid.NewGuid(); + var service = Substitute.For(); + service.Get(id); + service.Received().Get(id); } } \ No newline at end of file diff --git a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue_RaiseEventOnNonSubstitute.cs b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue_RaiseEventOnNonSubstitute.cs index 15051f3d1..926bee588 100644 --- a/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue_RaiseEventOnNonSubstitute.cs +++ b/tests/NSubstitute.Acceptance.Specs/FieldReports/Issue_RaiseEventOnNonSubstitute.cs @@ -1,37 +1,36 @@ using NSubstitute.Exceptions; using NUnit.Framework; -namespace NSubstitute.Acceptance.Specs.FieldReports +namespace NSubstitute.Acceptance.Specs.FieldReports; + +public class Issue_RaiseEventOnNonSubstitute { - public class Issue_RaiseEventOnNonSubstitute + public class Button { - public class Button - { - public virtual event EventHandler Clicked = (s, e) => { }; - } + public virtual event EventHandler Clicked = (s, e) => { }; + } - public interface IController { void Load(); } + public interface IController { void Load(); } - [Test] - public void RaiseEventOnNonSub() - { - var notASub = new Button(); - notASub.Clicked += Raise.Event(); - var sub = Substitute.For(); - // Next call to a substitute will fail as it will attempt to raise an event - Assert.Throws(() => - sub.Load() - ); - } + [Test] + public void RaiseEventOnNonSub() + { + var notASub = new Button(); + notASub.Clicked += Raise.Event(); + var sub = Substitute.For(); + // Next call to a substitute will fail as it will attempt to raise an event + Assert.Throws(() => + sub.Load() + ); + } - [Test] - public void RaiseEventOnSub() - { - var clicked = false; - var sub = Substitute.For