Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 13 additions & 5 deletions Source/Mockolate.SourceGenerators/Sources/Sources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ public T Create<T>(BaseClass.ConstructorParameters constructorParameters, params
/// Wraps a concrete instance with a mock proxy that intercepts and delegates method calls,
/// supporting setup and verification on the wrapped instance.
/// </summary>
/// <typeparam name="T">Type to wrap, which can be an interface or a class.</typeparam>
/// <typeparam name="T">Type to wrap, which must be an interface.</typeparam>
/// <param name="instance">The concrete instance to wrap.</param>
/// <param name="setups">Optional setup actions to configure the mock.</param>
/// <remarks>
Expand All @@ -416,7 +416,7 @@ public static T Wrap<T>(T instance, params Action<IMockSetup<T>>[] setups)
throw new ArgumentNullException(nameof(instance));
}

ThrowIfNotMockable(typeof(T));
ThrowIfNotWrappable(typeof(T));

return new MockGenerator().GetWrapped<T>(instance, MockBehavior.Default, setups)
?? throw new MockException("Could not generate wrapped Mock<T>. Did the source generator run correctly?");
Expand All @@ -429,7 +429,7 @@ public static T Wrap<T>(T instance, params Action<IMockSetup<T>>[] setups)
/// Wraps a concrete instance with a mock proxy that intercepts and delegates method calls,
/// supporting setup and verification on the wrapped instance.
/// </summary>
/// <typeparam name="T">Type to wrap, which can be an interface or a class.</typeparam>
/// <typeparam name="T">Type to wrap, which must be an interface.</typeparam>
/// <param name="instance">The concrete instance to wrap.</param>
/// <param name="mockBehavior">The behavior settings for the mock.</param>
/// <param name="setups">Optional setup actions to configure the mock.</param>
Expand All @@ -446,7 +446,7 @@ public static T Wrap<T>(T instance, MockBehavior mockBehavior, params Action<IMo
throw new ArgumentNullException(nameof(instance));
}

ThrowIfNotMockable(typeof(T));
ThrowIfNotWrappable(typeof(T));

return new MockGenerator().GetWrapped<T>(instance, mockBehavior, setups)
?? throw new MockException("Could not generate wrapped Mock<T>. Did the source generator run correctly?");
Expand All @@ -459,7 +459,15 @@ private static void ThrowIfNotMockable(Type type)
{
if (type.IsSealed && type.BaseType != typeof(MulticastDelegate))
{
throw new MockException($"The type '{type}' is sealed and therefore not mockable.");
throw new MockException($"Unable to mock type '{type.FullName ?? type.Name}'. The type is sealed and therefore not mockable.");
}
}

private static void ThrowIfNotWrappable(Type type)
{
if (!type.IsInterface)
{
throw new MockException($"Unable to wrap type '{type.FullName ?? type.Name}'. When wrapping a concrete instance, only interfaces can be mocked.");
}
}
""");
Expand Down
20 changes: 10 additions & 10 deletions Tests/Mockolate.Tests/MockTests.FactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -38,7 +38,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -55,7 +55,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -72,7 +72,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -89,7 +89,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -106,7 +106,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -125,7 +125,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -143,7 +143,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -161,7 +161,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -178,7 +178,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand Down
33 changes: 33 additions & 0 deletions Tests/Mockolate.Tests/MockTests.WrapTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Mockolate.Exceptions;
using Mockolate.Tests.TestHelpers;

namespace Mockolate.Tests;
Expand Down Expand Up @@ -118,6 +119,36 @@ public async Task Wrap_Property_ShouldDelegateToWrappedInstance()
await That(myDispenser.TotalDispensed).IsEqualTo(12);
}

[Fact]
public async Task Wrap_WithClass_ShouldThrowMockException()
{
MyChocolateDispenser instance = new();

void Act()
{
_ = Mock.Wrap(instance);
}

await That(Act).Throws<MockException>()
.WithMessage(
"Unable to wrap type 'Mockolate.Tests.MockTests+WrapTests+MyChocolateDispenser'. When wrapping a concrete instance, only interfaces can be mocked.");
}

[Fact]
public async Task Wrap_WithDelegate_ShouldThrowMockException()
{
MyDelegate instance = () => { };

void Act()
{
_ = Mock.Wrap(instance);
}

await That(Act).Throws<MockException>()
.WithMessage(
"Unable to wrap type 'Mockolate.Tests.MockTests+WrapTests+MyDelegate'. When wrapping a concrete instance, only interfaces can be mocked.");
}

[Fact]
public async Task Wrap_WithSetup_ShouldOverrideMethod()
{
Expand Down Expand Up @@ -170,5 +201,7 @@ public bool Dispense(string type, int amount)

public event ChocolateDispensedDelegate? ChocolateDispensed;
}

public delegate void MyDelegate();
}
}
22 changes: 11 additions & 11 deletions Tests/Mockolate.Tests/MockTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -95,7 +95,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -110,7 +110,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -125,7 +125,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -140,7 +140,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -155,7 +155,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -170,7 +170,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -186,7 +186,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -202,7 +202,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand All @@ -217,7 +217,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand Down Expand Up @@ -267,7 +267,7 @@ void Act()

await That(Act).Throws<MockException>()
.WithMessage(
"The type 'Mockolate.Tests.MockTests+MySealedClass' is sealed and therefore not mockable.");
"Unable to mock type 'Mockolate.Tests.MockTests+MySealedClass'. The type is sealed and therefore not mockable.");
}

[Fact]
Expand Down
Loading