Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
674fbbb
Migrate to new Stunts nuget package, simplify build
kzu Oct 21, 2020
6e5dafa
Add github actions for CI
kzu Oct 21, 2020
135276b
Fix build from missing versioning logic in sample, bump stunts
kzu Oct 21, 2020
8c6d08e
Replace codecov token and move to secret
kzu Oct 21, 2020
ac3a340
Fix windows tests by strong-naming the sample
kzu Oct 21, 2020
034afe6
Remove stunt classes and use the ManualStunts package
kzu Oct 21, 2020
6bd315d
Bundle DynamicProxy in Moq itself for convenience
kzu Oct 22, 2020
d45d4e7
Switch from attribute-based registration to partial static ctor
kzu Oct 22, 2020
83a9dcd
Fix project reference in packaging project
kzu Oct 22, 2020
f3d229a
Basic implementation of the static mock factory
kzu Oct 22, 2020
c7e3e45
Bump Stunts
kzu Oct 22, 2020
3c39eef
Add static proxy generator based on Stunts.StaticProxy
kzu Oct 23, 2020
9d9b4ba
Eliminate all nullable warnings and accept most analysis suggestions
kzu Oct 23, 2020
07e1b2c
Remove unused code
kzu Oct 23, 2020
645ec40
Collect and upload binlogs and coverage reports
kzu Oct 23, 2020
452d3d7
Disable coverage online reporting since it's not working
kzu Oct 23, 2020
a498340
Move all projects one level up
kzu Oct 23, 2020
29c8667
Drop azure pipelines, GH actions are enough
kzu Oct 24, 2020
43c467c
Improve readme docs and dogfooding instructions
kzu Oct 24, 2020
6466cd8
Add minimum required recursive mocking support
kzu Oct 24, 2020
7b9d008
No need to multitarget the static proxy generator
kzu Oct 24, 2020
fd2173d
Make sure to also pack as buildTransitive for generators
kzu Oct 26, 2020
6465fde
Remove usage of older TypeInfo
kzu Oct 26, 2020
ce6e82b
Use TypeInfo in AnyMatcher to fix breakage of ref/out tests
kzu Oct 26, 2020
4f2ef0a
Remove unnecessary scope attribute
kzu Oct 26, 2020
cbf179e
Add test for setup scope recursive codegen
kzu Oct 26, 2020
d1727c8
Minor API docs improvements
kzu Oct 26, 2020
f670990
Add Setup extension method on mocks for discoverability
kzu Oct 26, 2020
630b728
Cleanup old samples, add new acceptance tests
kzu Oct 26, 2020
01e461e
Cleanup just the local build version of Moq
kzu Oct 26, 2020
c1250ea
Bump stunts
kzu Oct 26, 2020
8b2b914
Fix dynamic factory registration
kzu Oct 26, 2020
04af272
File header and pragmas have to be the last fixups to run
kzu Oct 26, 2020
614ca47
Add unit tests boilerplate project for Moq.CodeAnalysis
kzu Oct 26, 2020
e3f7bb3
Bump stunts to avoid warnings on generated code
kzu Oct 26, 2020
b36e0fb
Only push packages after build and acceptance
kzu Oct 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Eliminate all nullable warnings and accept most analysis suggestions
  • Loading branch information
kzu committed Oct 23, 2020
commit 9d9b4bacbd900ac7f975bbc344cca904127c93c1
4 changes: 2 additions & 2 deletions src/Moq/Moq.DynamicProxy/DynamicMockFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ protected override object CreateProxy(Type baseType, Type[] implementedInterface
return mocked;
}

class MockInterceptor : IInterceptor
private class MockInterceptor : IInterceptor
{
IMock? mock;
private IMock? mock;

public void Intercept(IInvocation invocation)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.DynamicProxy/Mock.DynamicFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Moq
{
partial class Mock
internal partial class Mock
{
static Mock()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Package/Mock.Overloads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Moq
/// <summary>
/// Instantiates stunts for the specified types.
/// </summary>
partial class Mock
internal partial class Mock
{
/// <summary>
/// Creates a mock that inherits or implements the type <typeparamref name="T"/>.
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Package/Mock.StaticFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Moq
{
partial class Mock
internal partial class Mock
{
static Mock()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Package/Mock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Moq
/// </summary>
[ExcludeFromCodeCoverage]
[CompilerGenerated]
partial class Mock
internal partial class Mock
{
/// <summary>
/// Gets the configuration and introspection for the given mocked instance.
Expand Down
5 changes: 2 additions & 3 deletions src/Moq/Moq.Sdk.Tests/AnyMatcherTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,8 @@ public void MatchesDerivedType()
Assert.True(x.Matches(new Derived()));
}

private class Base { }


class Base { }
class Derived : Base { }
private class Derived : Base { }
}
}
5 changes: 3 additions & 2 deletions src/Moq/Moq.Sdk.Tests/ConditionalMatcherTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public void EqualsByConditionFunctionAndName()
Assert.False(matcher.Equals(new ConditionalMatcher<int>(_ => true, "foo")));
}

class Base { }
class Derived : Base { }
private class Base { }

private class Derived : Base { }
}
}
6 changes: 3 additions & 3 deletions src/Moq/Moq.Sdk.Tests/DefaultMockTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ public void TracksTargetObject()
public void InitializesState()
=> Assert.NotNull(new FakeStunt().Mock.State);

class FakeStunt : IStunt, IMocked
private class FakeStunt : IStunt, IMocked
{
BehaviorPipeline pipeline = new BehaviorPipeline();
DefaultMock mock;
private readonly BehaviorPipeline pipeline = new BehaviorPipeline();
private DefaultMock mock;

public IList<IStuntBehavior> Behaviors => pipeline.Behaviors;

Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Sdk.Tests/EqualityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,6 @@ public void Matchers()
Assert.False(hash.Add(value2));
}

void AMethod(bool b, string s, PlatformID p) { }
private void AMethod(bool b, string s, PlatformID p) { }
}
}
2 changes: 1 addition & 1 deletion src/Moq/Moq.Sdk.Tests/Fakes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Moq.Sdk.Tests
{
public class FakeMock : IStunt, IMocked
{
DefaultMock mock;
private readonly DefaultMock mock;

protected BehaviorPipeline Pipeline = new BehaviorPipeline();

Expand Down
4 changes: 2 additions & 2 deletions src/Moq/Moq.Sdk.Tests/MockExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public void CanAssertInvocations()
Assert.Equal(0, target.Add(2, 3));
Assert.Single(target.AsMock().InvocationsFor(c => c.Add(2, 3)));
}
class FakeCalls : FakeMock

private class FakeCalls : FakeMock
{
public void TurnOn() => Pipeline.Execute(new MethodInvocation(this, MethodBase.GetCurrentMethod()));

Expand Down
3 changes: 1 addition & 2 deletions src/Moq/Moq.Sdk.Tests/MockTrackingBehaviorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ public void SkipInvocationRecordingIfSetupScopeActive()
Assert.Empty(target.Mock.Invocations);
}


class TrackingMock : FakeMock
private class TrackingMock : FakeMock
{
public void Do() => Pipeline.Execute(new MethodInvocation(this, MethodBase.GetCurrentMethod()));
}
Expand Down
4 changes: 2 additions & 2 deletions src/Moq/Moq.Sdk.Tests/Mocked.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace Moq.Sdk.Tests
{
public class Mocked : IMocked, IStunt
{
IMock mock;
IList<IStuntBehavior> behaviors = new ObservableCollection<IStuntBehavior>();
private IMock mock;
private readonly IList<IStuntBehavior> behaviors = new ObservableCollection<IStuntBehavior>();

public IMock Mock => LazyInitializer.EnsureInitialized(ref mock, () => new DefaultMock(this));

Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Sdk.Tests/NotMatcherTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void MatcherEquals()
Assert.Equal(expected.GetHashCode(), actual.GetHashCode());
}

class Value
private class Value
{
public Value(Guid id) => Id = id;

Expand Down
12 changes: 6 additions & 6 deletions src/Moq/Moq.Sdk/AnyMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace Moq.Sdk
/// </summary>
public class AnyMatcher : IArgumentMatcher, IEquatable<AnyMatcher>
{
TypeInfo info;
bool isValueType;
bool isNullable;
private readonly TypeInfo info;
private readonly bool isValueType;
private readonly bool isNullable;

/// <summary>
/// Initializes the matcher with the given <paramref name="argumentType"/>.
Expand All @@ -38,7 +38,7 @@ public AnyMatcher(Type argumentType)
/// <summary>
/// Evaluates whether the given value matches this instance.
/// </summary>
public bool Matches(object value)
public bool Matches(object? value)
{
// Non-nullable value types never match against a null value.
if (isValueType && !isNullable && value == null)
Expand All @@ -61,10 +61,10 @@ public bool Matches(object value)
#region Equality

/// <inheritdoc />
public bool Equals(AnyMatcher other) => other != null && info.Equals(other.info);
public bool Equals(AnyMatcher other) => info.Equals(other.info);

/// <inheritdoc />
public override bool Equals(object other) => Equals(other as AnyMatcher);
public override bool Equals(object other) => other is AnyMatcher matcher && Equals(matcher);

/// <inheritdoc />
public override int GetHashCode() => info.GetHashCode();
Expand Down
10 changes: 5 additions & 5 deletions src/Moq/Moq.Sdk/AnyMatcher`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ namespace Moq.Sdk
public class AnyMatcher<T> : IArgumentMatcher, IEquatable<AnyMatcher<T>>
{
// Disable warning since we only use this member from this class
static bool IsValueType = typeof(T).GetTypeInfo().IsValueType;
static bool IsNullable = typeof(T).GetTypeInfo().IsGenericType &&
private static readonly bool IsValueType = typeof(T).GetTypeInfo().IsValueType;
private static readonly bool IsNullable = typeof(T).GetTypeInfo().IsGenericType &&
typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);

/// <summary>
/// Gets the singleton instance of this matcher.
/// </summary>
public static IArgumentMatcher Default { get; } = new AnyMatcher<T>();

AnyMatcher() { }
private AnyMatcher() { }

/// <summary>
/// Gets the type of the argument this matcher supports.
Expand All @@ -33,7 +33,7 @@ public class AnyMatcher<T> : IArgumentMatcher, IEquatable<AnyMatcher<T>>
/// <summary>
/// Evaluates whether the given value matches this instance.
/// </summary>
public bool Matches(object value)
public bool Matches(object? value)
{
// Non-nullable value types never match against a null value.
if (IsValueType && !IsNullable && value == null)
Expand Down Expand Up @@ -71,7 +71,7 @@ public bool Matches(object value)
/// </summary>
/// <returns><see langword="true"/> if <paramref name="other"/> is not null and
/// it's an <see cref="AnyMatcher{T}"/> with the same <typeparamref name="T"/> .</returns>
public override bool Equals(object other) => Equals(other as AnyMatcher<T>);
public override bool Equals(object other) => other is AnyMatcher<T> matcher && Equals(matcher);

/// <inheritdoc />
public override int GetHashCode() => typeof(T).GetHashCode();
Expand Down
42 changes: 25 additions & 17 deletions src/Moq/Moq.Sdk/CallContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,44 @@ namespace Moq.Sdk
/// </summary>
public static class CallContext<T>
{
static readonly string defaultName = typeof(T).FullName;
static ConcurrentDictionary<string, AsyncLocal<T>> state = new ConcurrentDictionary<string, AsyncLocal<T>>();
private static readonly string defaultName = typeof(T).FullName;
private static readonly ConcurrentDictionary<string, AsyncLocal<T?>> state = new();

/// <summary>
/// Stores a given object.
/// </summary>
/// <param name="data">The object to store in the call context.</param>
public static void SetData(T data) => SetData(defaultName, data);
public static void SetData(T? data) => SetData(defaultName, data);

/// <summary>
/// Stores a given object and associates it with the specified name.
/// </summary>
/// <param name="name">The name with which to associate the new item in the call context.</param>
/// <param name="data">The object to store in the call context.</param>
public static void SetData(string name, T data) =>
state.GetOrAdd(name, _ => new AsyncLocal<T>()).Value = data;
public static void SetData(string name, T? data)
=> state.GetOrAdd(name, _ => new AsyncLocal<T?>()).Value = data;

/// <summary>
/// Retrieves an object from the <see cref="CallContext"/>.
/// </summary>
/// <returns>The object in the call context associated with the specified name, or a default value for <typeparamref name="T"/> if none is found.</returns>
public static T GetData() => GetData(defaultName);
public static T? GetData() => GetData(defaultName);

/// <summary>
/// Retrieves an object with the specified name from the <see cref="CallContext"/>.
/// </summary>
/// <param name="name">The name of the item in the call context.</param>
/// <returns>The object in the call context associated with the specified name, or a default value for <typeparamref name="T"/> if none is found.</returns>
public static T GetData(string name) =>
state.TryGetValue(name, out var data) ? data.Value : default;
public static T? GetData(string name)
=> state.TryGetValue(name, out var data) ? data.Value : default;

/// <summary>
/// Retrieves an object from the <see cref="CallContext"/>, and
/// sets an initial value if it was not found.
/// </summary>
/// <param name="setInitialValue">A function that will set the initial value of the given parameter, if it doesn't have a value already in the context.</param>
/// <returns>The object in the call context associated with the specified name, or the initial value returned from <paramref name="setInitialValue"/>.</returns>
public static T GetData(Func<T> setInitialValue) => GetData(defaultName, setInitialValue);
public static T? GetData(Func<T?> setInitialValue) => GetData(defaultName, setInitialValue);

/// <summary>
/// Retrieves an object with the specified name from the <see cref="CallContext"/>, and
Expand All @@ -56,10 +56,10 @@ public static T GetData(string name) =>
/// <param name="name">The name of the item in the call context.</param>
/// <param name="setInitialValue">A function that will set the initial value of the given parameter, if it doesn't have a value already in the context.</param>
/// <returns>The object in the call context associated with the specified name, or the initial value returned from <paramref name="setInitialValue"/>.</returns>
public static T GetData(string name, Func<T> setInitialValue)
public static T? GetData(string name, Func<T?> setInitialValue)
{
var local = state.GetOrAdd(name, _ => new AsyncLocal<T> { Value = setInitialValue() });
if (object.Equals(local.Value, default(T)))
var local = state.GetOrAdd(name, _ => new AsyncLocal<T?> { Value = setInitialValue() });
if (Equals(local.Value, default(T)))
local.Value = setInitialValue();

return local.Value;
Expand All @@ -72,22 +72,30 @@ public static T GetData(string name, Func<T> setInitialValue)
/// </summary>
public static class CallContext
{
static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();
private static readonly ConcurrentDictionary<string, AsyncLocal<object?>> state = new();

/// <summary>
/// Stores a given object and associates it with the specified name.
/// </summary>
/// <param name="name">The name with which to associate the new item in the call context.</param>
/// <param name="data">The object to store in the call context.</param>
public static void SetData(string name, object data) =>
state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = data;
public static void SetData(string name, object? data)
=> state.GetOrAdd(name, _ => new AsyncLocal<object?>()).Value = data;

/// <summary>
/// Retrieves an object with the specified name from the <see cref="CallContext"/>.
/// </summary>
/// <param name="name">The name of the item in the call context.</param>
/// <returns>The object in the call context associated with the specified name, or <see langword="null"/> if not found.</returns>
public static object GetData(string name) =>
state.TryGetValue(name, out var data) ? data.Value : null;
public static object? GetData(string name)
=> state.TryGetValue(name, out var data) ? data.Value : null;

/// <summary>
/// Throws <see cref="InvalidOperationException"/> with a message stating that an
/// unexpected null value was found in the context.
/// </summary>
/// <typeparam name="T">Type of value that was unexpectedly null in the context. This is used as the key.</typeparam>
public static T ThrowUnexpectedNull<T>()
=> throw new InvalidOperationException(ThisAssembly.Strings.UnexpectedNullContextState(typeof(T).FullName));
}
}
16 changes: 8 additions & 8 deletions src/Moq/Moq.Sdk/ConditionalMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ namespace Moq.Sdk
/// <typeparam name="T">Type of argument being conditioned.</typeparam>
public class ConditionalMatcher<T> : IArgumentMatcher, IEquatable<ConditionalMatcher<T>>
{
static readonly bool IsValueType = typeof(T).GetTypeInfo().IsValueType;
static readonly bool IsNullable = typeof(T).GetTypeInfo().IsGenericType &&
private static readonly bool IsValueType = typeof(T).GetTypeInfo().IsValueType;
private static readonly bool IsNullable = typeof(T).GetTypeInfo().IsGenericType &&
typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
readonly string name;
private readonly string name;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
readonly Func<T, bool> condition;
private readonly Func<T?, bool> condition;

/// <summary>
/// Initializes the matcher with the condition and optional friendly name.
/// </summary>
public ConditionalMatcher(Func<T, bool> condition, string name = "condition")
public ConditionalMatcher(Func<T?, bool> condition, string name = "condition")
{
this.condition = condition ?? throw new ArgumentNullException(nameof(condition));
this.name = name ?? throw new ArgumentNullException(nameof(name));
Expand All @@ -38,7 +38,7 @@ public ConditionalMatcher(Func<T, bool> condition, string name = "condition")
/// <summary>
/// Evaluates whether the given value matches this instance.
/// </summary>
public bool Matches(object value)
public bool Matches(object? value)
{
// Non-nullable value types never match against a null value.
if (IsValueType && !IsNullable && value == null)
Expand Down Expand Up @@ -67,12 +67,12 @@ public bool Matches(object value)
/// Checks whether <paramref name="other"/> has the same condition and friendly name.
/// </summary>
public bool Equals(ConditionalMatcher<T> other)
=> other != null && ReferenceEquals(condition, other.condition) && name.Equals(other.name);
=> ReferenceEquals(condition, other.condition) && name.Equals(other.name);

/// <summary>
/// Checks whether <paramref name="other"/> has the same condition and friendly name.
/// </summary>
public override bool Equals(object other) => Equals(other as ConditionalMatcher<T>);
public override bool Equals(object other) => other is ConditionalMatcher<T> matcher && Equals(matcher);

/// <inheritdoc />
public override int GetHashCode() => HashCode.Combine(condition, name);
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Sdk/DefaultMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public IMockBehaviorPipeline GetPipeline(IMockSetup setup)
return behavior;
});

void OnBehaviorsChanged(object sender, NotifyCollectionChangedEventArgs e)
private void OnBehaviorsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Moq/Moq.Sdk/DelegateMockBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace Moq.Sdk
[DebuggerDisplay("{DisplayName}")]
public class DelegateMockBehavior : IMockBehavior
{
readonly Lazy<string> displayName;
readonly ExecuteMockDelegate behavior;
private readonly Lazy<string> displayName;
private readonly ExecuteMockDelegate behavior;

/// <summary>
/// Creates an instance of the invokable behavior with the given
Expand Down
Loading