Skip to content

Comments

feat: add runtime validation for unsupported types in Mock.Wrap#305

Merged
vbreuss merged 5 commits intomainfrom
copilot/throw-runtime-exception-for-unsupported-types
Dec 12, 2025
Merged

feat: add runtime validation for unsupported types in Mock.Wrap#305
vbreuss merged 5 commits intomainfrom
copilot/throw-runtime-exception-for-unsupported-types

Conversation

Copy link
Contributor

Copilot AI commented Dec 12, 2025

Mockolate now throws MockException with clear error messages when attempting to mock or wrap unsupported types (enums, structs, sealed classes, or non-interface types for wrapping).

Changes

  • Enhanced ThrowIfNotMockable: Added runtime checks for enums and value types with specific error messages
  • New ThrowIfNotWrappable: Enforces that Mock.Wrap only accepts interfaces, throwing exception for classes, delegates, or other types
  • Error message format: Standardized to "Unable to [mock|wrap] type 'TypeName'. [Reason]."
  • Tests: Added validation tests for Mock.Wrap with non-interface types (classes, delegates)

Example

// Wrapping a class now throws with clear message
var dispenser = new ChocolateDispenser();
var wrapped = Mock.Wrap(dispenser); 
// MockException: Unable to wrap type 'ChocolateDispenser'. 
// When wrapping a concrete instance, only interfaces can be mocked.

// Mocking sealed class throws
var mock = Mock.Create<MySealedClass>();
// MockException: Unable to mock type 'MySealedClass'. 
// The type is sealed and therefore not mockable.

Validation Layers

  • Compile-time: where T : class constraint prevents value types
  • Analyzer: Mockolate0002 catches sealed classes, records at compile-time
  • Runtime: Clear exceptions for edge cases and reflection-based usage
Original prompt

This section details on the original issue you should resolve

<issue_title>Throw runtime exception when the type is not wrappable</issue_title>
<issue_description>When attempting to wrap an unsupported type—such as a class, delegate, or enum—the mocking functionality should fail gracefully. The API should either:

  • Prevent compilation via generic type constraints (where possible), or
  • Throw a MockException at runtime with an informative, actionable error message if a user attempts to wrap an unsupported type.

Please ensure:

  • Clear error messaging is provided, specifying which type could not be wrapped and why.
  • Edge cases, such as accidentally passing unsupported types, are covered.
  • New or existing tests verify that both compile-time and runtime errors are handled as expected, and that no silent or confusing failures occur.

Example error message:

MockException: Unable to wrap type 'MyEnum'. When wrapping a concrete instance, only interfaces can be mocked.

Tasks:

  • Implement detection of unsupported types at compile-time where possible, and runtime otherwise.
  • Ensure MockException is thrown for invalid types with a clear, explicit message.
  • Add or update tests to cover usage with classes, delegates, enums, and any other unsupported types.</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits December 12, 2025 03:40
…Wrap

Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com>
Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com>
Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement runtime exception for non-wrappable types Add runtime validation for unsupported types in Mock.Create and Mock.Wrap Dec 12, 2025
Copilot AI requested a review from vbreuss December 12, 2025 03:54
@vbreuss vbreuss changed the title Add runtime validation for unsupported types in Mock.Create and Mock.Wrap feat: add runtime validation for unsupported types in Mock.Wrap Dec 12, 2025
@vbreuss vbreuss marked this pull request as ready for review December 12, 2025 13:33
Copilot AI review requested due to automatic review settings December 12, 2025 13:33
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds runtime validation to ensure only supported types can be mocked or wrapped, providing clear error messages when unsupported types are used. The changes standardize error messages and add specific validation for Mock.Wrap to enforce interface-only wrapping.

  • Standardized error message format to "Unable to [mock|wrap] type 'TypeName'. [Reason]."
  • Added new ThrowIfNotWrappable method to validate that Mock.Wrap only accepts interfaces
  • Added runtime tests validating rejection of classes and delegates in Mock.Wrap

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
Tests/Mockolate.Tests/MockTests.cs Updated expected error messages for sealed class validation to use new standardized format
Tests/Mockolate.Tests/MockTests.WrapTests.cs Added tests for Mock.Wrap with unsupported types (classes, delegates) and a new test delegate type
Tests/Mockolate.Tests/MockTests.FactoryTests.cs Updated expected error messages for factory sealed class validation to use new standardized format
Source/Mockolate.SourceGenerators/Sources/Sources.cs Implemented ThrowIfNotWrappable method, updated XML documentation to specify interface requirement, and standardized error message format

@vbreuss vbreuss enabled auto-merge (squash) December 12, 2025 13:35
@sonarqubecloud
Copy link

@github-actions
Copy link

Test Results

    14 files  ± 0      14 suites  ±0   4m 11s ⏱️ -26s
 1 656 tests + 2   1 655 ✅ + 2  1 💤 ±0  0 ❌ ±0 
11 081 runs  +14  11 080 ✅ +14  1 💤 ±0  0 ❌ ±0 

Results for commit 038b0bf. ± Comparison against base commit ee96afd.

@vbreuss vbreuss merged commit eda9bc1 into main Dec 12, 2025
12 checks passed
@vbreuss vbreuss deleted the copilot/throw-runtime-exception-for-unsupported-types branch December 12, 2025 13:38
@github-actions
Copy link

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.3 LTS (Noble Numbat)
AMD EPYC 7763 2.77GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.101
[Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Method Mean Error StdDev Gen0 Gen1 Allocated
Simple_Mockolate 1.473 μs 0.0275 μs 0.0257 μs 0.2232 - 3.66 KB
Simple_Moq 173.575 μs 0.6393 μs 0.5667 μs 0.4883 - 14.55 KB
Simple_NSubstitute 6.153 μs 0.0526 μs 0.0492 μs 0.5569 0.0076 9.14 KB
Simple_FakeItEasy 6.348 μs 0.0325 μs 0.0271 μs 0.4959 - 8.11 KB

@github-actions
Copy link

This is addressed in release v0.44.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Throw runtime exception when the type is not wrappable

2 participants