diff --git a/README.md b/README.md index 029bc5bcc..308307444 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# RSCG - 245 Examples of Roslyn Source Code Generators / 16 created by Microsoft / +# RSCG - 246 Examples of Roslyn Source Code Generators / 16 created by Microsoft / -The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 245 Roslyn Source Code Generator (RSCG) examples. The system transforms individual RSCG projects into structured documentation with code examples and cross-referenced content with a searchable website and code example exports. +The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 246 Roslyn Source Code Generator (RSCG) examples. The system transforms individual RSCG projects into structured documentation with code examples and cross-referenced content with a searchable website and code example exports. This system serves as both a learning resource for .NET developers interested in source generators and an automated pipeline for maintaining up-to-date documentation about the RSCG ecosystem -## Latest Update : 2025-12-12 => 12 December 2025 +## Latest Update : 2025-12-13 => 13 December 2025 If you want to see examples with code, please click ***[List V2](https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG)*** @@ -24,8 +24,30 @@ If you want to be notified each time I add a new RSCG example , please click htt ## Content -Those are the 245 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 246 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 16 from Microsoft ) +### 246. [Imposter](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter) , in the [Tests](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#tests) category + +Generated on : 2025-12-13 => 13 December 2025 + +
+ Expand + + + +Author: Bitchiko Tchelidze + +Imposter — Source-generated test doubles, zero runtime overhead. A high-performance Roslyn incremental source generator that produces imposters (mocks/stubs) for interfaces and overridable class members via GenerateImposterAttribute. Ships analyzer + runtime in a single package. + +Nuget: [https://www.nuget.org/packages/Imposter/](https://www.nuget.org/packages/Imposter/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter) + +Source: [https://github.com/themidnightgospel/Imposter](https://github.com/themidnightgospel/Imposter) + +
+ ### 245. [Monify](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Monify) , in the [PrimitiveObsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) category Generated on : 2025-12-12 => 12 December 2025 diff --git a/later.md b/later.md index 557055f51..d79c96437 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2025-12-12 => 12 December 2025 +## Latest Update : 2025-12-13 => 13 December 2025 diff --git a/v2/.tours/Imposter.tour b/v2/.tours/Imposter.tour new file mode 100644 index 000000000..22ff1589d --- /dev/null +++ b/v2/.tours/Imposter.tour @@ -0,0 +1,36 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "Imposter", + "steps": + [ + { + "file": "rscg_examples/Imposter/src/TestClock/TestClock.csproj", + "description": "First, we add Nuget [Imposter](https://www.nuget.org/packages/Imposter/) in csproj ", + "pattern": "Imposter" + } + + ,{ + "file": "rscg_examples/Imposter/src/TestClock/Usings.cs", + "description": "File Usings.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/Imposter/src/TestClock/TestClock.cs", + "description": "File TestClock.cs ", + "pattern": "this is the code" + } + + + ,{ + "file": "rscg_examples/Imposter/src/TestClock/obj/GX/Imposter.CodeGenerator/Imposter.CodeGenerator.CodeGenerator.ImposterGenerator/IMyClockImposter.g.cs", + "description": "Generated File 1 from 1 : IMyClockImposter.g.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv index 297951b95..0b6a54964 100644 --- a/v2/Generator/all.csv +++ b/v2/Generator/all.csv @@ -244,3 +244,4 @@ Nr,Key,Source,Category 243,RSCG_MCP2File, https://github.com/ignatandrei/RSCG_OpenApi2MCP,MCP 244,BoolParameterGenerator, https://github.com/9swampy/BoolEnumGenerator,Bool 245,Monify, https://github.com/MooVC/monify,PrimitiveObsession +246,Imposter, https://github.com/themidnightgospel/Imposter,Tests diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index 279942ef3..463324801 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1485,5 +1485,11 @@ "dtStart": "2025-12-12T00:00:00", "show": true -} +}, +{ + "ID": "Imposter", + "Category": 13, + "dtStart": "2025-12-13T00:00:00", + "show": true + }, ] \ No newline at end of file diff --git a/v2/book/examples/Imposter.html b/v2/book/examples/Imposter.html new file mode 100644 index 000000000..f6200a4e0 --- /dev/null +++ b/v2/book/examples/Imposter.html @@ -0,0 +1,59 @@ + +

RSCG nr 246 : Imposter

+ +

Info

+Nuget : https://www.nuget.org/packages/Imposter/ + +

You can find more details at : https://github.com/themidnightgospel/Imposter

+ +

Author :Bitchiko Tchelidze

+ +

Source: https://github.com/themidnightgospel/Imposter

+ +

About

+ +Generate classes from interfaces and allows return of mock data.Useful for testing and prototyping. + +

+ How to use +

+

+ Add reference to the Imposter in the csproj +

+ + +

This was for me the starting code

+ +
+ I have coded the file TestClock.cs +
+ +
+ +
+ I have coded the file Usings.cs +
+ +
+

And here are the generated files

+ +
+ The file generated is IMyClockImposter.g.cs +
+ + +

+ You can download the code and this page as pdf from + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter + +

+ + +

+ You can see the whole list at + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG + +

+ diff --git a/v2/book/list.html b/v2/book/list.html index eaf4e0e70..e8ea72657 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 245 RSCG with examples => +This is the list of 246 RSCG with examples =>

@@ -1006,6 +1006,10 @@

+ + + +
245 Monify
246Imposter
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index a8707b432..9b22bc4b3 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -259,6 +259,7 @@ input-files: - examples/RSCG_MCP2File.html - examples/BoolParameterGenerator.html - examples/Monify.html +- examples/Imposter.html # or you may use input-file: with a single value # defaults: diff --git a/v2/rscg_examples/Imposter/description.json b/v2/rscg_examples/Imposter/description.json new file mode 100644 index 000000000..853fed480 --- /dev/null +++ b/v2/rscg_examples/Imposter/description.json @@ -0,0 +1,22 @@ +{ + "generator":{ + "name":"Imposter", + "nuget":[ + "https://www.nuget.org/packages/Imposter/" + ], + "link":"https://github.com/themidnightgospel/Imposter", + "author":"Bitchiko Tchelidze", + "source":"https://github.com/themidnightgospel/Imposter" + }, + "data":{ + "goodFor":["Generate classes from interfaces and allows return of mock data.","Useful for testing and prototyping."], + "csprojDemo":"TestClock.csproj", + "csFiles":["TestClock.cs","Usings.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/Imposter/nuget.txt b/v2/rscg_examples/Imposter/nuget.txt new file mode 100644 index 000000000..f1984309b --- /dev/null +++ b/v2/rscg_examples/Imposter/nuget.txt @@ -0,0 +1 @@ +Imposter — Source-generated test doubles, zero runtime overhead. A high-performance Roslyn incremental source generator that produces imposters (mocks/stubs) for interfaces and overridable class members via GenerateImposterAttribute. Ships analyzer + runtime in a single package. \ No newline at end of file diff --git a/v2/rscg_examples/Imposter/readme.txt b/v2/rscg_examples/Imposter/readme.txt new file mode 100644 index 000000000..fbe15833f --- /dev/null +++ b/v2/rscg_examples/Imposter/readme.txt @@ -0,0 +1,154 @@ +

+ Imposter logo +

+ +

+ Fast and Memory-Efficient Mocking Library +

+ +[![Build, Test, and Format verification](https://github.com/themidnightgospel/Imposter/actions/workflows/build-and-test.yml/badge.svg?branch=master)](https://github.com/themidnightgospel/Imposter/actions/workflows/build-and-test.yml) +[![Nuget](https://img.shields.io/nuget/v/Imposter.svg)](https://www.nuget.org/packages/Imposter) + +Imposter is a mocking library that's using roslyn source generators to achieve high performance and low memory footprint. + +Visit the [Docs](https://themidnightgospel.github.io/Imposter/) for more information + +## 🚀 Quick Start + +Add nuget package reference: + +```bash +dotnet add package Imposter +``` + +Pick an interface or non-sealed class that you would like to generate an imposter for. + +Say we have a below interface + +```csharp + +namespace Application.Domain; + +public interface ICalculator +{ + int Add(int a, int b); +} +``` + +Use `[GenerateImposter]` attribute in your **tests** project, this will generate an imoster + +```csharp +[assembly: GenerateImposter(typeof(Application.Domain.ICalculator))] +``` + +Then use can use the generated imposter in your tests + +```csharp +using System.Threading.Tasks; +using Imposter.Abstractions; + +// c# 14 +var imposter = ICalculator.Imposter(); + +// c# 9 - 13 +// var imposter = new ICalculatorImposter(); + +imposter.Add(Arg.Any(), Arg.Any()) + .Returns(1) + .Then() + .Returns(2); + +var calculator = imposter.Instance(); + +calculator.Add(1, 2); // 1 +calculator.Add(1, 2); // 2 +``` + +Learn more: https://themidnightgospel.github.io/Imposter/ + +## ✨ Feature-Rich + + - [Method Impersonation](https://themidnightgospel.github.io/Imposter/latest/methods/) + - [Property Impersonation](https://themidnightgospel.github.io/Imposter/latest/properties/) + - [Indexer Impersonation](https://themidnightgospel.github.io/Imposter/latest/indexers/) + - [Event Impersonation](https://themidnightgospel.github.io/Imposter/latest/events/) + - [Class Impersonation](https://themidnightgospel.github.io/Imposter/latest/base-implementation/) + - [Generics](https://themidnightgospel.github.io/Imposter/latest/generics/) + - [Implicit & Explicit Modes](https://themidnightgospel.github.io/Imposter/latest/implicit-vs-explicit/) + - [Use Base implementation](https://themidnightgospel.github.io/Imposter/latest/base-implementation/) + - [Async Support](https://themidnightgospel.github.io/Imposter/latest/methods/#async-methods) + - [Protected members Impersonation](https://themidnightgospel.github.io/Imposter/latest/methods/protected-members/) + +## ⏱️ Benchmark + +We benchmarked the simple method-impersonation scenario: we set up a `Square` method to return `input * input` and ran it for 1, 10, 100, and 1000 iterations. + +```csharp +public interface ICalculator +{ + int Square(int input); +} +``` + +Mean execution time + +| Method | Iteration | Mean | +|-------------|-----------|----------------:| +| Moq | 1 | 69,346.1 ns | +| NSubstitute | 1 | 1,976.2 ns | +| FakItEasy | 1 | 2,006.7 ns | +| Imposter | 1 | **194.3 ns** | +| Moq | 10 | 686,282.9 ns | +| NSubstitute | 10 | 11,201.6 ns | +| FakItEasy | 10 | 12,399.0 ns | +| Imposter | 10 | **1,896.7 ns** | +| Moq | 100 | 6,804,897.3 ns | +| NSubstitute | 100 | 335,390.6 ns | +| FakItEasy | 100 | 258,220.2 ns | +| Imposter | 100 | **34,011.7 ns** | +| Moq | 1000 | 99,710,929.5 ns | +| NSubstitute | 1000 | 26,986,939.0 ns | +| FakItEasy | 1000 | 18,997,374.5 ns | +| Imposter | 1000 | **2,452,970.7 ns** | + + +Allocated Memory + +| Method | Iteration | Allocated | +|-------------|-----------|------------:| +| Moq | 1 | 13.05 KB | +| NSubstitute | 1 | 7.84 KB | +| FakeItEasy | 1 | 5.84 KB | +| Imposter | 1 | **2.4 KB** | +| Moq | 10 | 115.73 KB | +| NSubstitute | 10 | 29.29 KB | +| FakeItEasy | 10 | 38.81 KB | +| Imposter | 10 | **22.37 KB** | +| Moq | 100 | 1416.91 KB | +| NSubstitute | 100 | 247.26 KB | +| FakeItEasy | 100 | 1033.38 KB | +| Imposter | 100 | **222.05 KB** | +| Moq | 1000 | 42275.19 KB | +| NSubstitute | 1000 | 2420.82 KB | +| FakeItEasy | 1000 | 77101.74 KB | +| Imposter | 1000 | **2218.93 KB** | + + +Benchmark Environment + +``` +BenchmarkDotNet v0.15.6, Windows 11 (10.0.26200.6899) +13th Gen Intel Core i9-13900HX 2.20GHz, 1 CPU, 32 logical and 24 physical cores +.NET SDK 10.0.100 +[Host] : .NET 8.0.21 (8.0.21, 8.0.2125.47513), X64 RyuJIT x86-64-v3 +DefaultJob : .NET 8.0.21 (8.0.21, 8.0.2125.47513), X64 RyuJIT x86-64-v3 +``` + +See other benchmarks [benchmark](https://github.com/themidnightgospel/Imposter/blob/3172c333603fd2d76031b20be39753a9b62f31c3/benchmarks/Imposter.Benchmarks/ImposterVsMoqVsNSubstitute/SimpleMethodMockingBenchmarks.cs#L12) + +## Docs +Docs: https://themidnightgospel.github.io/Imposter/ + +## License + +Licensed under the MIT License. See LICENSE.txt for details. diff --git a/v2/rscg_examples/Imposter/src/MockData/IMyClock.cs b/v2/rscg_examples/Imposter/src/MockData/IMyClock.cs new file mode 100644 index 000000000..36d416543 --- /dev/null +++ b/v2/rscg_examples/Imposter/src/MockData/IMyClock.cs @@ -0,0 +1,7 @@ +namespace MockData; +public interface IMyClock +{ + public DateTime GetNow(); + public DateTime GetUtcNow(); + +} \ No newline at end of file diff --git a/v2/rscg_examples/Imposter/src/MockData/MockData.csproj b/v2/rscg_examples/Imposter/src/MockData/MockData.csproj new file mode 100644 index 000000000..f095b6dfa --- /dev/null +++ b/v2/rscg_examples/Imposter/src/MockData/MockData.csproj @@ -0,0 +1,10 @@ + + + + net10.0 + enable + enable + + + + diff --git a/v2/rscg_examples/Imposter/src/MockTest.slnx b/v2/rscg_examples/Imposter/src/MockTest.slnx new file mode 100644 index 000000000..7e4c29ad0 --- /dev/null +++ b/v2/rscg_examples/Imposter/src/MockTest.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/v2/rscg_examples/Imposter/src/TestClock/TestClock.cs b/v2/rscg_examples/Imposter/src/TestClock/TestClock.cs new file mode 100644 index 000000000..70af1a05c --- /dev/null +++ b/v2/rscg_examples/Imposter/src/TestClock/TestClock.cs @@ -0,0 +1,17 @@ + +using MockData; +namespace TestClock; + +[TestClass] +public class TestClock +{ + [TestMethod] + public void TestMyClock() + { + var mock = new IMyClockImposter(); + mock.GetUtcNow().Returns(DateTime.Now.AddYears(-1)); + mock.GetNow().Returns(DateTime.Now.AddYears(-1)); + IMyClock clock = mock.Instance(); + Assert.AreEqual(DateTime.Now.AddYears(-1).Year, clock.GetNow().Year); + } +} \ No newline at end of file diff --git a/v2/rscg_examples/Imposter/src/TestClock/TestClock.csproj b/v2/rscg_examples/Imposter/src/TestClock/TestClock.csproj new file mode 100644 index 000000000..2c4eb63a2 --- /dev/null +++ b/v2/rscg_examples/Imposter/src/TestClock/TestClock.csproj @@ -0,0 +1,31 @@ + + + + net10.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + true + $(BaseIntermediateOutputPath)\GX + + + diff --git a/v2/rscg_examples/Imposter/src/TestClock/Usings.cs b/v2/rscg_examples/Imposter/src/TestClock/Usings.cs new file mode 100644 index 000000000..906943495 --- /dev/null +++ b/v2/rscg_examples/Imposter/src/TestClock/Usings.cs @@ -0,0 +1,5 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Imposter.Abstractions; + +[assembly: GenerateImposter(typeof(MockData.IMyClock))] + diff --git a/v2/rscg_examples/Imposter/video.json b/v2/rscg_examples/Imposter/video.json new file mode 100644 index 000000000..94966c034 --- /dev/null +++ b/v2/rscg_examples/Imposter/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "Imposter", + "steps": +[ + {"typeStep":"exec","arg":"clipchamp.exe launch"}, + {"typeStep":"text","arg": "Welcome to Roslyn Examples"}, + {"typeStep":"text","arg":"If you want to see more examples , see List Of RSCG"}, + {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG"}, + {"typeStep":"text","arg": "My name is Andrei Ignat and I am deeply fond of Roslyn Source Code Generator. "}, + +{"typeStep":"text","arg": "Today I will present Imposter . Generate classes from interfaces and allows return of mock data.Useful for testing and prototyping. ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/Imposter/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter#download-example-net--c-"}, +{"typeStep":"text","arg":"Here is the code downloaded "}, +{"typeStep":"exec","arg":"explorer.exe /select,D:\\gth\\RSCG_Examples\\v2\\Generator.sln"}, +{"typeStep":"text","arg": "So , let's start the project with Visual Studio Code "}, +{"typeStep":"stepvscode","arg": "-n D:\\gth\\RSCG_Examples\\v2"}, + +{"typeStep":"text","arg": "To use it ,you will put the Nuget Imposter into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\Imposter\\src\\TestClock\\TestClock.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using Imposter"}, + +{"typeStep":"hide","arg": "now execute the tour in VSCode"}, +{"typeStep":"tour", "arg": "src/.tours/"}, +{"typeStep":"text","arg":" And I will execute the project"}, +{"typeStep":"showproj", "arg":"TestClock.csproj"}, +{"typeStep":"text","arg":" This concludes the project"}, +{"typeStep":"waitseconds","arg":"30"}, +{"typeStep":"text","arg": "Remember, you can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Authors/Bitchiko_Tchelidze.md b/v2/rscg_examples_site/docs/Authors/Bitchiko_Tchelidze.md new file mode 100644 index 000000000..50109a292 --- /dev/null +++ b/v2/rscg_examples_site/docs/Authors/Bitchiko_Tchelidze.md @@ -0,0 +1,7 @@ +# Author : Bitchiko Tchelidze + +Number RSCG: 1 + + + 1 [Imposter](/docs/Imposter) [![Nuget](https://img.shields.io/nuget/dt/Imposter?label=Imposter)](https://www.nuget.org/packages/Imposter/) ![GitHub Repo stars](https://img.shields.io/github/stars/themidnightgospel/Imposter?style=social) 2025-12-13 + diff --git a/v2/rscg_examples_site/docs/Categories/Tests.md b/v2/rscg_examples_site/docs/Categories/Tests.md index e3a14794b..11c4931b8 100644 --- a/v2/rscg_examples_site/docs/Categories/Tests.md +++ b/v2/rscg_examples_site/docs/Categories/Tests.md @@ -1,16 +1,18 @@

Tests

-Number RSCG: 6 +Number RSCG: 7 - 1 [mocklis](/docs/mocklis) [![Nuget](https://img.shields.io/nuget/dt/mocklis?label=mocklis)](https://www.nuget.org/packages/mocklis/) ![GitHub Repo stars](https://img.shields.io/github/stars/mocklis/mocklis?style=social) 2024-01-03 + 1 [Imposter](/docs/Imposter) [![Nuget](https://img.shields.io/nuget/dt/Imposter?label=Imposter)](https://www.nuget.org/packages/Imposter/) ![GitHub Repo stars](https://img.shields.io/github/stars/themidnightgospel/Imposter?style=social) 2025-12-13 - 2 [MockMe](/docs/MockMe) [![Nuget](https://img.shields.io/nuget/dt/MockMe?label=MockMe)](https://www.nuget.org/packages/MockMe/) ![GitHub Repo stars](https://img.shields.io/github/stars/connorivy/MockMe?style=social) 2025-02-10 + 2 [mocklis](/docs/mocklis) [![Nuget](https://img.shields.io/nuget/dt/mocklis?label=mocklis)](https://www.nuget.org/packages/mocklis/) ![GitHub Repo stars](https://img.shields.io/github/stars/mocklis/mocklis?style=social) 2024-01-03 - 3 [MSTest](/docs/MSTest) [![Nuget](https://img.shields.io/nuget/dt/MSTest.SourceGeneration?label=MSTest.SourceGeneration)](https://www.nuget.org/packages/MSTest.SourceGeneration/) ![GitHub Repo stars](https://img.shields.io/github/stars/microsoft/testfx?style=social) 2024-04-04 + 3 [MockMe](/docs/MockMe) [![Nuget](https://img.shields.io/nuget/dt/MockMe?label=MockMe)](https://www.nuget.org/packages/MockMe/) ![GitHub Repo stars](https://img.shields.io/github/stars/connorivy/MockMe?style=social) 2025-02-10 - 4 [Ridge](/docs/Ridge) [![Nuget](https://img.shields.io/nuget/dt/Ridge?label=Ridge)](https://www.nuget.org/packages/Ridge/) ![GitHub Repo stars](https://img.shields.io/github/stars/Melchy/Ridge?style=social) 2023-08-20 + 4 [MSTest](/docs/MSTest) [![Nuget](https://img.shields.io/nuget/dt/MSTest.SourceGeneration?label=MSTest.SourceGeneration)](https://www.nuget.org/packages/MSTest.SourceGeneration/) ![GitHub Repo stars](https://img.shields.io/github/stars/microsoft/testfx?style=social) 2024-04-04 - 5 [Rocks](/docs/Rocks) [![Nuget](https://img.shields.io/nuget/dt/Rocks?label=Rocks)](https://www.nuget.org/packages/Rocks/) ![GitHub Repo stars](https://img.shields.io/github/stars/JasonBock/Rocks?style=social) 2023-04-16 + 5 [Ridge](/docs/Ridge) [![Nuget](https://img.shields.io/nuget/dt/Ridge?label=Ridge)](https://www.nuget.org/packages/Ridge/) ![GitHub Repo stars](https://img.shields.io/github/stars/Melchy/Ridge?style=social) 2023-08-20 - 6 [TUnit](/docs/TUnit) [![Nuget](https://img.shields.io/nuget/dt/TUnit?label=TUnit)](https://www.nuget.org/packages/TUnit/) ![GitHub Repo stars](https://img.shields.io/github/stars/thomhurst/TUnit?style=social) 2025-11-08 + 6 [Rocks](/docs/Rocks) [![Nuget](https://img.shields.io/nuget/dt/Rocks?label=Rocks)](https://www.nuget.org/packages/Rocks/) ![GitHub Repo stars](https://img.shields.io/github/stars/JasonBock/Rocks?style=social) 2023-04-16 + + 7 [TUnit](/docs/TUnit) [![Nuget](https://img.shields.io/nuget/dt/TUnit?label=TUnit)](https://www.nuget.org/packages/TUnit/) ![GitHub Repo stars](https://img.shields.io/github/stars/thomhurst/TUnit?style=social) 2025-11-08 \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveTests.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveTests.mdx index e818cd88e..816acc669 100644 --- a/v2/rscg_examples_site/docs/Categories/_PrimitiveTests.mdx +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveTests.mdx @@ -1,16 +1,18 @@ ### Category "Tests" has the following generators: - 1 [mocklis](/docs/mocklis) [![Nuget](https://img.shields.io/nuget/dt/mocklis?label=mocklis)](https://www.nuget.org/packages/mocklis/) ![GitHub Repo stars](https://img.shields.io/github/stars/mocklis/mocklis?style=social) 2024-01-03 + 1 [Imposter](/docs/Imposter) [![Nuget](https://img.shields.io/nuget/dt/Imposter?label=Imposter)](https://www.nuget.org/packages/Imposter/) ![GitHub Repo stars](https://img.shields.io/github/stars/themidnightgospel/Imposter?style=social) 2025-12-13 - 2 [MockMe](/docs/MockMe) [![Nuget](https://img.shields.io/nuget/dt/MockMe?label=MockMe)](https://www.nuget.org/packages/MockMe/) ![GitHub Repo stars](https://img.shields.io/github/stars/connorivy/MockMe?style=social) 2025-02-10 + 2 [mocklis](/docs/mocklis) [![Nuget](https://img.shields.io/nuget/dt/mocklis?label=mocklis)](https://www.nuget.org/packages/mocklis/) ![GitHub Repo stars](https://img.shields.io/github/stars/mocklis/mocklis?style=social) 2024-01-03 - 3 [MSTest](/docs/MSTest) [![Nuget](https://img.shields.io/nuget/dt/MSTest.SourceGeneration?label=MSTest.SourceGeneration)](https://www.nuget.org/packages/MSTest.SourceGeneration/) ![GitHub Repo stars](https://img.shields.io/github/stars/microsoft/testfx?style=social) 2024-04-04 + 3 [MockMe](/docs/MockMe) [![Nuget](https://img.shields.io/nuget/dt/MockMe?label=MockMe)](https://www.nuget.org/packages/MockMe/) ![GitHub Repo stars](https://img.shields.io/github/stars/connorivy/MockMe?style=social) 2025-02-10 - 4 [Ridge](/docs/Ridge) [![Nuget](https://img.shields.io/nuget/dt/Ridge?label=Ridge)](https://www.nuget.org/packages/Ridge/) ![GitHub Repo stars](https://img.shields.io/github/stars/Melchy/Ridge?style=social) 2023-08-20 + 4 [MSTest](/docs/MSTest) [![Nuget](https://img.shields.io/nuget/dt/MSTest.SourceGeneration?label=MSTest.SourceGeneration)](https://www.nuget.org/packages/MSTest.SourceGeneration/) ![GitHub Repo stars](https://img.shields.io/github/stars/microsoft/testfx?style=social) 2024-04-04 - 5 [Rocks](/docs/Rocks) [![Nuget](https://img.shields.io/nuget/dt/Rocks?label=Rocks)](https://www.nuget.org/packages/Rocks/) ![GitHub Repo stars](https://img.shields.io/github/stars/JasonBock/Rocks?style=social) 2023-04-16 + 5 [Ridge](/docs/Ridge) [![Nuget](https://img.shields.io/nuget/dt/Ridge?label=Ridge)](https://www.nuget.org/packages/Ridge/) ![GitHub Repo stars](https://img.shields.io/github/stars/Melchy/Ridge?style=social) 2023-08-20 - 6 [TUnit](/docs/TUnit) [![Nuget](https://img.shields.io/nuget/dt/TUnit?label=TUnit)](https://www.nuget.org/packages/TUnit/) ![GitHub Repo stars](https://img.shields.io/github/stars/thomhurst/TUnit?style=social) 2025-11-08 + 6 [Rocks](/docs/Rocks) [![Nuget](https://img.shields.io/nuget/dt/Rocks?label=Rocks)](https://www.nuget.org/packages/Rocks/) ![GitHub Repo stars](https://img.shields.io/github/stars/JasonBock/Rocks?style=social) 2023-04-16 + + 7 [TUnit](/docs/TUnit) [![Nuget](https://img.shields.io/nuget/dt/TUnit?label=TUnit)](https://www.nuget.org/packages/TUnit/) ![GitHub Repo stars](https://img.shields.io/github/stars/thomhurst/TUnit?style=social) 2025-11-08 ### See category diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/Imposter.md b/v2/rscg_examples_site/docs/RSCG-Examples/Imposter.md new file mode 100644 index 000000000..97ea7d746 --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/Imposter.md @@ -0,0 +1,1093 @@ +--- +sidebar_position: 2460 +title: 246 - Imposter +description: Generate classes from interfaces and allows return of mock data. +slug: /Imposter +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveTests.mdx'; + +# Imposter by Bitchiko Tchelidze + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/Imposter?label=Imposter)](https://www.nuget.org/packages/Imposter/) +[![GitHub last commit](https://img.shields.io/github/last-commit/themidnightgospel/Imposter?label=updated)](https://github.com/themidnightgospel/Imposter) +![GitHub Repo stars](https://img.shields.io/github/stars/themidnightgospel/Imposter?style=social) + +## Details + +### Info +:::info + +Name: **Imposter** + +Imposter — Source-generated test doubles, zero runtime overhead. A high-performance Roslyn incremental source generator that produces imposters (mocks/stubs) for interfaces and overridable class members via GenerateImposterAttribute. Ships analyzer + runtime in a single package. + +Author: Bitchiko Tchelidze + +NuGet: +*https://www.nuget.org/packages/Imposter/* + + +You can find more details at https://github.com/themidnightgospel/Imposter + +Source: https://github.com/themidnightgospel/Imposter + +::: + +### Author +:::note +Bitchiko Tchelidze +![Alt text](https://github.com/themidnightgospel.png) +::: + +### Original Readme +:::note + +

+ Imposter logo +

+ +

+ Fast and Memory-Efficient Mocking Library +

+ +[![Build, Test, and Format verification](https://github.com/themidnightgospel/Imposter/actions/workflows/build-and-test.yml/badge.svg?branch=master)](https://github.com/themidnightgospel/Imposter/actions/workflows/build-and-test.yml) +[![Nuget](https://img.shields.io/nuget/v/Imposter.svg)](https://www.nuget.org/packages/Imposter) + +Imposter is a mocking library that's using roslyn source generators to achieve high performance and low memory footprint. + +Visit the [Docs](https://themidnightgospel.github.io/Imposter/) for more information + +## 🚀 Quick Start + +Add nuget package reference: + +```bash +dotnet add package Imposter +``` + +Pick an interface or non-sealed class that you would like to generate an imposter for. + +Say we have a below interface + +```csharp + +namespace Application.Domain; + +public interface ICalculator +{ + int Add(int a, int b); +} +``` + +Use `[GenerateImposter]` attribute in your **tests** project, this will generate an imoster + +```csharp +[assembly: GenerateImposter(typeof(Application.Domain.ICalculator))] +``` + +Then use can use the generated imposter in your tests + +```csharp +using System.Threading.Tasks; +using Imposter.Abstractions; + +// c# 14 +var imposter = ICalculator.Imposter(); + +// c# 9 - 13 +// var imposter = new ICalculatorImposter(); + +imposter.Add(Arg.Any(), Arg.Any()) + .Returns(1) + .Then() + .Returns(2); + +var calculator = imposter.Instance(); + +calculator.Add(1, 2); // 1 +calculator.Add(1, 2); // 2 +``` + +Learn more: https://themidnightgospel.github.io/Imposter/ + +## ✨ Feature-Rich + + - [Method Impersonation](https://themidnightgospel.github.io/Imposter/latest/methods/) + - [Property Impersonation](https://themidnightgospel.github.io/Imposter/latest/properties/) + - [Indexer Impersonation](https://themidnightgospel.github.io/Imposter/latest/indexers/) + - [Event Impersonation](https://themidnightgospel.github.io/Imposter/latest/events/) + - [Class Impersonation](https://themidnightgospel.github.io/Imposter/latest/base-implementation/) + - [Generics](https://themidnightgospel.github.io/Imposter/latest/generics/) + - [Implicit & Explicit Modes](https://themidnightgospel.github.io/Imposter/latest/implicit-vs-explicit/) + - [Use Base implementation](https://themidnightgospel.github.io/Imposter/latest/base-implementation/) + - [Async Support](https://themidnightgospel.github.io/Imposter/latest/methods/#async-methods) + - [Protected members Impersonation](https://themidnightgospel.github.io/Imposter/latest/methods/protected-members/) + +## ⏱️ Benchmark + +We benchmarked the simple method-impersonation scenario: we set up a `Square` method to return `input * input` and ran it for 1, 10, 100, and 1000 iterations. + +```csharp +public interface ICalculator +{ + int Square(int input); +} +``` + +Mean execution time + +| Method | Iteration | Mean | +|-------------|-----------|----------------:| +| Moq | 1 | 69,346.1 ns | +| NSubstitute | 1 | 1,976.2 ns | +| FakItEasy | 1 | 2,006.7 ns | +| Imposter | 1 | **194.3 ns** | +| Moq | 10 | 686,282.9 ns | +| NSubstitute | 10 | 11,201.6 ns | +| FakItEasy | 10 | 12,399.0 ns | +| Imposter | 10 | **1,896.7 ns** | +| Moq | 100 | 6,804,897.3 ns | +| NSubstitute | 100 | 335,390.6 ns | +| FakItEasy | 100 | 258,220.2 ns | +| Imposter | 100 | **34,011.7 ns** | +| Moq | 1000 | 99,710,929.5 ns | +| NSubstitute | 1000 | 26,986,939.0 ns | +| FakItEasy | 1000 | 18,997,374.5 ns | +| Imposter | 1000 | **2,452,970.7 ns** | + + +Allocated Memory + +| Method | Iteration | Allocated | +|-------------|-----------|------------:| +| Moq | 1 | 13.05 KB | +| NSubstitute | 1 | 7.84 KB | +| FakeItEasy | 1 | 5.84 KB | +| Imposter | 1 | **2.4 KB** | +| Moq | 10 | 115.73 KB | +| NSubstitute | 10 | 29.29 KB | +| FakeItEasy | 10 | 38.81 KB | +| Imposter | 10 | **22.37 KB** | +| Moq | 100 | 1416.91 KB | +| NSubstitute | 100 | 247.26 KB | +| FakeItEasy | 100 | 1033.38 KB | +| Imposter | 100 | **222.05 KB** | +| Moq | 1000 | 42275.19 KB | +| NSubstitute | 1000 | 2420.82 KB | +| FakeItEasy | 1000 | 77101.74 KB | +| Imposter | 1000 | **2218.93 KB** | + + +Benchmark Environment + +``` +BenchmarkDotNet v0.15.6, Windows 11 (10.0.26200.6899) +13th Gen Intel Core i9-13900HX 2.20GHz, 1 CPU, 32 logical and 24 physical cores +.NET SDK 10.0.100 +[Host] : .NET 8.0.21 (8.0.21, 8.0.2125.47513), X64 RyuJIT x86-64-v3 +DefaultJob : .NET 8.0.21 (8.0.21, 8.0.2125.47513), X64 RyuJIT x86-64-v3 +``` + +See other benchmarks [benchmark](https://github.com/themidnightgospel/Imposter/blob/3172c333603fd2d76031b20be39753a9b62f31c3/benchmarks/Imposter.Benchmarks/ImposterVsMoqVsNSubstitute/SimpleMethodMockingBenchmarks.cs#L12) + +## Docs +Docs: https://themidnightgospel.github.io/Imposter/ + +## License + +Licensed under the MIT License. See LICENSE.txt for details. + + +::: + +### About +:::note + +Generate classes from interfaces and allows return of mock data. + + +Useful for testing and prototyping. + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **Imposter** +```xml showLineNumbers {23} + + + + net10.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + true + $(BaseIntermediateOutputPath)\GX + + + + +``` + + + + + + This is the use of **Imposter** in *TestClock.cs* + +```csharp showLineNumbers + +using MockData; +namespace TestClock; + +[TestClass] +public class TestClock +{ + [TestMethod] + public void TestMyClock() + { + var mock = new IMyClockImposter(); + mock.GetUtcNow().Returns(DateTime.Now.AddYears(-1)); + mock.GetNow().Returns(DateTime.Now.AddYears(-1)); + IMyClock clock = mock.Instance(); + Assert.AreEqual(DateTime.Now.AddYears(-1).Year, clock.GetNow().Year); + } +} +``` + + + + + This is the use of **Imposter** in *Usings.cs* + +```csharp showLineNumbers +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Imposter.Abstractions; + +[assembly: GenerateImposter(typeof(MockData.IMyClock))] + + +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +// +#nullable enable +#pragma warning disable +using global::System; +using global::System.Linq; +using global::System.Collections.Generic; +using global::System.Threading.Tasks; +using global::System.Diagnostics; +using global::System.Runtime.CompilerServices; +using global::Imposter.Abstractions; +using global::System.Collections.Concurrent; + +namespace MockData +{ + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public sealed class IMyClockImposter : global::Imposter.Abstractions.IHaveImposterInstance + { + private readonly GetNowMethodImposter _getNowMethodImposter; + private readonly GetUtcNowMethodImposter _getUtcNowMethodImposter; + private readonly GetNowMethodInvocationHistoryCollection _getNowMethodInvocationHistoryCollection = new GetNowMethodInvocationHistoryCollection(); + private readonly GetUtcNowMethodInvocationHistoryCollection _getUtcNowMethodInvocationHistoryCollection = new GetUtcNowMethodInvocationHistoryCollection(); + public IGetNowMethodImposterBuilder GetNow() + { + return new GetNowMethodImposter.Builder(_getNowMethodImposter, _getNowMethodInvocationHistoryCollection); + } + + public IGetUtcNowMethodImposterBuilder GetUtcNow() + { + return new GetUtcNowMethodImposter.Builder(_getUtcNowMethodImposter, _getUtcNowMethodInvocationHistoryCollection); + } + + private readonly global::Imposter.Abstractions.ImposterMode _invocationBehavior; + private ImposterTargetInstance _imposterInstance; + global::MockData.IMyClock global::Imposter.Abstractions.IHaveImposterInstance.Instance() + { + return _imposterInstance; + } + + public delegate global::System.DateTime GetNowDelegate(); + public delegate void GetNowCallbackDelegate(); + public delegate global::System.Exception GetNowExceptionGeneratorDelegate(); + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetNowMethodInvocationHistory + { + bool Matches(); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class GetNowMethodInvocationHistory : IGetNowMethodInvocationHistory + { + internal global::System.DateTime? Result; + internal global::System.Exception? Exception; + public GetNowMethodInvocationHistory(global::System.DateTime? Result, global::System.Exception? Exception) + { + this.Result = Result; + this.Exception = Exception; + } + + public bool Matches() + { + return true; + } + + public override string ToString() + { + return "GetNow(" + "" + ")" + " => " + FormatValue(Result) + (Exception == null ? "" : " threw " + FormatValue(Exception)); + } + + private static string FormatValue(object? value) + { + return "<" + (value?.ToString() ?? "null") + ">"; + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class GetNowMethodInvocationHistoryCollection + { + private readonly global::System.Collections.Concurrent.ConcurrentStack _invocationHistory = new global::System.Collections.Concurrent.ConcurrentStack(); + internal void Add(IGetNowMethodInvocationHistory invocationHistory) + { + _invocationHistory.Push(invocationHistory); + } + + internal int Count() + { + return _invocationHistory.Count(it => it.Matches()); + } + + public override string ToString() + { + return string.Join(Environment.NewLine, _invocationHistory.Select(invocation => invocation.ToString())); + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + class GetNowMethodInvocationImposterGroup + { + internal static GetNowMethodInvocationImposterGroup Default = new GetNowMethodInvocationImposterGroup(); + private readonly global::System.Collections.Concurrent.ConcurrentQueue _invocationImposters = new global::System.Collections.Concurrent.ConcurrentQueue(); + private MethodInvocationImposter? _lastestInvocationImposter; + public GetNowMethodInvocationImposterGroup() + { + } + + internal MethodInvocationImposter AddInvocationImposter() + { + MethodInvocationImposter invocationImposter = new MethodInvocationImposter(); + _invocationImposters.Enqueue(invocationImposter); + return invocationImposter; + } + + private MethodInvocationImposter? GetInvocationImposter() + { + if (_invocationImposters.TryDequeue(out var invocationImposter)) + { + if (!invocationImposter.IsEmpty) + { + _lastestInvocationImposter = invocationImposter; + } + + return invocationImposter; + } + + return _lastestInvocationImposter; + } + + public global::System.DateTime Invoke(global::Imposter.Abstractions.ImposterMode invocationBehavior, string methodDisplayName) + { + var invocationImposter = GetInvocationImposter(); + if (invocationImposter == null) + { + if (invocationBehavior == global::Imposter.Abstractions.ImposterMode.Explicit) + { + throw new global::Imposter.Abstractions.MissingImposterException(methodDisplayName); + } + + invocationImposter = MethodInvocationImposter.Default; + } + + return invocationImposter.Invoke(invocationBehavior, methodDisplayName); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class MethodInvocationImposter + { + internal static MethodInvocationImposter Default; + static MethodInvocationImposter() + { + Default = new MethodInvocationImposter(); + Default.Returns(DefaultResultGenerator); + } + + private GetNowDelegate? _resultGenerator; + private readonly global::System.Collections.Concurrent.ConcurrentQueue _callbacks = new global::System.Collections.Concurrent.ConcurrentQueue(); + internal bool IsEmpty => (_resultGenerator == null) && (_callbacks.Count == 0); + + public global::System.DateTime Invoke(global::Imposter.Abstractions.ImposterMode invocationBehavior, string methodDisplayName) + { + if (_resultGenerator == null) + { + if (invocationBehavior == global::Imposter.Abstractions.ImposterMode.Explicit) + { + throw new global::Imposter.Abstractions.MissingImposterException(methodDisplayName); + } + + _resultGenerator = DefaultResultGenerator; + } + + global::System.DateTime result = _resultGenerator.Invoke(); + foreach (var callback in _callbacks) + { + callback(); + } + + return result; + } + + internal void Callback(GetNowCallbackDelegate callback) + { + _callbacks.Enqueue(callback); + } + + internal void Returns(GetNowDelegate resultGenerator) + { + _resultGenerator = resultGenerator; + } + + internal void Returns(global::System.DateTime value) + { + _resultGenerator = () => + { + return value; + }; + } + + internal void Throws(GetNowExceptionGeneratorDelegate exceptionGenerator) + { + _resultGenerator = () => + { + throw exceptionGenerator(); + }; + } + + internal static global::System.DateTime DefaultResultGenerator() + { + return default !; + } + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetNowMethodInvocationImposterGroupCallback + { + IGetNowMethodInvocationImposterGroupContinuation Callback(GetNowCallbackDelegate callback); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetNowMethodInvocationImposterGroupContinuation : IGetNowMethodInvocationImposterGroupCallback + { + IGetNowMethodInvocationImposterGroup Then(); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetNowMethodInvocationImposterGroup : IGetNowMethodInvocationImposterGroupCallback + { + IGetNowMethodInvocationImposterGroupContinuation Throws() + where TException : global::System.Exception, new(); + IGetNowMethodInvocationImposterGroupContinuation Throws(global::System.Exception exception); + IGetNowMethodInvocationImposterGroupContinuation Throws(GetNowExceptionGeneratorDelegate exceptionGenerator); + IGetNowMethodInvocationImposterGroupContinuation Returns(GetNowDelegate resultGenerator); + IGetNowMethodInvocationImposterGroupContinuation Returns(global::System.DateTime value); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface GetNowInvocationVerifier + { + void Called(Count count); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetNowMethodImposterBuilder : IGetNowMethodInvocationImposterGroup, IGetNowMethodInvocationImposterGroupCallback, GetNowInvocationVerifier + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class GetNowMethodImposter + { + private readonly global::System.Collections.Concurrent.ConcurrentStack _invocationImposters = new global::System.Collections.Concurrent.ConcurrentStack(); + private readonly GetNowMethodInvocationHistoryCollection _getNowMethodInvocationHistoryCollection; + private readonly global::Imposter.Abstractions.ImposterMode _invocationBehavior; + public GetNowMethodImposter(GetNowMethodInvocationHistoryCollection _getNowMethodInvocationHistoryCollection, global::Imposter.Abstractions.ImposterMode _invocationBehavior) + { + this._getNowMethodInvocationHistoryCollection = _getNowMethodInvocationHistoryCollection; + this._invocationBehavior = _invocationBehavior; + } + + public bool HasMatchingInvocationImposterGroup() + { + return FindMatchingInvocationImposterGroup() != null; + } + + private GetNowMethodInvocationImposterGroup? FindMatchingInvocationImposterGroup() + { + if (_invocationImposters.TryPeek(out var invocationImposterGroup)) + return invocationImposterGroup; + else + return null; + } + + public global::System.DateTime Invoke() + { + var matchingInvocationImposterGroup = FindMatchingInvocationImposterGroup(); + if (matchingInvocationImposterGroup == default) + { + if (_invocationBehavior == global::Imposter.Abstractions.ImposterMode.Explicit) + { + throw new global::Imposter.Abstractions.MissingImposterException("DateTime IMyClock.GetNow()"); + } + + matchingInvocationImposterGroup = GetNowMethodInvocationImposterGroup.Default; + } + + try + { + var result = matchingInvocationImposterGroup.Invoke(_invocationBehavior, "DateTime IMyClock.GetNow()"); + _getNowMethodInvocationHistoryCollection.Add(new GetNowMethodInvocationHistory(result, default)); + return result; + } + catch (global::System.Exception ex) + { + _getNowMethodInvocationHistoryCollection.Add(new GetNowMethodInvocationHistory(default !, ex)); + throw; + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class Builder : IGetNowMethodImposterBuilder, IGetNowMethodInvocationImposterGroupContinuation + { + private readonly GetNowMethodImposter _imposter; + private readonly GetNowMethodInvocationHistoryCollection _getNowMethodInvocationHistoryCollection; + private readonly GetNowMethodInvocationImposterGroup _invocationImposterGroup; + private GetNowMethodInvocationImposterGroup.MethodInvocationImposter _currentInvocationImposter; + public Builder(GetNowMethodImposter _imposter, GetNowMethodInvocationHistoryCollection _getNowMethodInvocationHistoryCollection) + { + this._imposter = _imposter; + this._getNowMethodInvocationHistoryCollection = _getNowMethodInvocationHistoryCollection; + this._invocationImposterGroup = new GetNowMethodInvocationImposterGroup(); + _imposter._invocationImposters.Push(_invocationImposterGroup); + this._currentInvocationImposter = this._invocationImposterGroup.AddInvocationImposter(); + } + + IGetNowMethodInvocationImposterGroupContinuation IGetNowMethodInvocationImposterGroup.Throws() + { + _currentInvocationImposter.Throws(() => + { + throw new TException(); + }); + return this; + } + + IGetNowMethodInvocationImposterGroupContinuation IGetNowMethodInvocationImposterGroup.Throws(global::System.Exception exception) + { + _currentInvocationImposter.Throws(() => + { + throw exception; + }); + return this; + } + + IGetNowMethodInvocationImposterGroupContinuation IGetNowMethodInvocationImposterGroup.Throws(GetNowExceptionGeneratorDelegate exceptionGenerator) + { + _currentInvocationImposter.Throws(() => + { + throw exceptionGenerator.Invoke(); + }); + return this; + } + + IGetNowMethodInvocationImposterGroupContinuation IGetNowMethodInvocationImposterGroupCallback.Callback(GetNowCallbackDelegate callback) + { + _currentInvocationImposter.Callback(callback); + return this; + } + + IGetNowMethodInvocationImposterGroupContinuation IGetNowMethodInvocationImposterGroup.Returns(GetNowDelegate resultGenerator) + { + _currentInvocationImposter.Returns(resultGenerator); + return this; + } + + IGetNowMethodInvocationImposterGroupContinuation IGetNowMethodInvocationImposterGroup.Returns(global::System.DateTime value) + { + _currentInvocationImposter.Returns(value); + return this; + } + + IGetNowMethodInvocationImposterGroup IGetNowMethodInvocationImposterGroupContinuation.Then() + { + this._currentInvocationImposter = _invocationImposterGroup.AddInvocationImposter(); + return this; + } + + void GetNowInvocationVerifier.Called(global::Imposter.Abstractions.Count count) + { + var invocationCount = _getNowMethodInvocationHistoryCollection.Count(); + if (!count.Matches(invocationCount)) + { + throw new global::Imposter.Abstractions.VerificationFailedException(count, invocationCount, _getNowMethodInvocationHistoryCollection.ToString()); + } + } + } + } + + public delegate global::System.DateTime GetUtcNowDelegate(); + public delegate void GetUtcNowCallbackDelegate(); + public delegate global::System.Exception GetUtcNowExceptionGeneratorDelegate(); + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetUtcNowMethodInvocationHistory + { + bool Matches(); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class GetUtcNowMethodInvocationHistory : IGetUtcNowMethodInvocationHistory + { + internal global::System.DateTime? Result; + internal global::System.Exception? Exception; + public GetUtcNowMethodInvocationHistory(global::System.DateTime? Result, global::System.Exception? Exception) + { + this.Result = Result; + this.Exception = Exception; + } + + public bool Matches() + { + return true; + } + + public override string ToString() + { + return "GetUtcNow(" + "" + ")" + " => " + FormatValue(Result) + (Exception == null ? "" : " threw " + FormatValue(Exception)); + } + + private static string FormatValue(object? value) + { + return "<" + (value?.ToString() ?? "null") + ">"; + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class GetUtcNowMethodInvocationHistoryCollection + { + private readonly global::System.Collections.Concurrent.ConcurrentStack _invocationHistory = new global::System.Collections.Concurrent.ConcurrentStack(); + internal void Add(IGetUtcNowMethodInvocationHistory invocationHistory) + { + _invocationHistory.Push(invocationHistory); + } + + internal int Count() + { + return _invocationHistory.Count(it => it.Matches()); + } + + public override string ToString() + { + return string.Join(Environment.NewLine, _invocationHistory.Select(invocation => invocation.ToString())); + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + class GetUtcNowMethodInvocationImposterGroup + { + internal static GetUtcNowMethodInvocationImposterGroup Default = new GetUtcNowMethodInvocationImposterGroup(); + private readonly global::System.Collections.Concurrent.ConcurrentQueue _invocationImposters = new global::System.Collections.Concurrent.ConcurrentQueue(); + private MethodInvocationImposter? _lastestInvocationImposter; + public GetUtcNowMethodInvocationImposterGroup() + { + } + + internal MethodInvocationImposter AddInvocationImposter() + { + MethodInvocationImposter invocationImposter = new MethodInvocationImposter(); + _invocationImposters.Enqueue(invocationImposter); + return invocationImposter; + } + + private MethodInvocationImposter? GetInvocationImposter() + { + if (_invocationImposters.TryDequeue(out var invocationImposter)) + { + if (!invocationImposter.IsEmpty) + { + _lastestInvocationImposter = invocationImposter; + } + + return invocationImposter; + } + + return _lastestInvocationImposter; + } + + public global::System.DateTime Invoke(global::Imposter.Abstractions.ImposterMode invocationBehavior, string methodDisplayName) + { + var invocationImposter = GetInvocationImposter(); + if (invocationImposter == null) + { + if (invocationBehavior == global::Imposter.Abstractions.ImposterMode.Explicit) + { + throw new global::Imposter.Abstractions.MissingImposterException(methodDisplayName); + } + + invocationImposter = MethodInvocationImposter.Default; + } + + return invocationImposter.Invoke(invocationBehavior, methodDisplayName); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class MethodInvocationImposter + { + internal static MethodInvocationImposter Default; + static MethodInvocationImposter() + { + Default = new MethodInvocationImposter(); + Default.Returns(DefaultResultGenerator); + } + + private GetUtcNowDelegate? _resultGenerator; + private readonly global::System.Collections.Concurrent.ConcurrentQueue _callbacks = new global::System.Collections.Concurrent.ConcurrentQueue(); + internal bool IsEmpty => (_resultGenerator == null) && (_callbacks.Count == 0); + + public global::System.DateTime Invoke(global::Imposter.Abstractions.ImposterMode invocationBehavior, string methodDisplayName) + { + if (_resultGenerator == null) + { + if (invocationBehavior == global::Imposter.Abstractions.ImposterMode.Explicit) + { + throw new global::Imposter.Abstractions.MissingImposterException(methodDisplayName); + } + + _resultGenerator = DefaultResultGenerator; + } + + global::System.DateTime result = _resultGenerator.Invoke(); + foreach (var callback in _callbacks) + { + callback(); + } + + return result; + } + + internal void Callback(GetUtcNowCallbackDelegate callback) + { + _callbacks.Enqueue(callback); + } + + internal void Returns(GetUtcNowDelegate resultGenerator) + { + _resultGenerator = resultGenerator; + } + + internal void Returns(global::System.DateTime value) + { + _resultGenerator = () => + { + return value; + }; + } + + internal void Throws(GetUtcNowExceptionGeneratorDelegate exceptionGenerator) + { + _resultGenerator = () => + { + throw exceptionGenerator(); + }; + } + + internal static global::System.DateTime DefaultResultGenerator() + { + return default !; + } + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetUtcNowMethodInvocationImposterGroupCallback + { + IGetUtcNowMethodInvocationImposterGroupContinuation Callback(GetUtcNowCallbackDelegate callback); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetUtcNowMethodInvocationImposterGroupContinuation : IGetUtcNowMethodInvocationImposterGroupCallback + { + IGetUtcNowMethodInvocationImposterGroup Then(); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetUtcNowMethodInvocationImposterGroup : IGetUtcNowMethodInvocationImposterGroupCallback + { + IGetUtcNowMethodInvocationImposterGroupContinuation Throws() + where TException : global::System.Exception, new(); + IGetUtcNowMethodInvocationImposterGroupContinuation Throws(global::System.Exception exception); + IGetUtcNowMethodInvocationImposterGroupContinuation Throws(GetUtcNowExceptionGeneratorDelegate exceptionGenerator); + IGetUtcNowMethodInvocationImposterGroupContinuation Returns(GetUtcNowDelegate resultGenerator); + IGetUtcNowMethodInvocationImposterGroupContinuation Returns(global::System.DateTime value); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface GetUtcNowInvocationVerifier + { + void Called(Count count); + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public interface IGetUtcNowMethodImposterBuilder : IGetUtcNowMethodInvocationImposterGroup, IGetUtcNowMethodInvocationImposterGroupCallback, GetUtcNowInvocationVerifier + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class GetUtcNowMethodImposter + { + private readonly global::System.Collections.Concurrent.ConcurrentStack _invocationImposters = new global::System.Collections.Concurrent.ConcurrentStack(); + private readonly GetUtcNowMethodInvocationHistoryCollection _getUtcNowMethodInvocationHistoryCollection; + private readonly global::Imposter.Abstractions.ImposterMode _invocationBehavior; + public GetUtcNowMethodImposter(GetUtcNowMethodInvocationHistoryCollection _getUtcNowMethodInvocationHistoryCollection, global::Imposter.Abstractions.ImposterMode _invocationBehavior) + { + this._getUtcNowMethodInvocationHistoryCollection = _getUtcNowMethodInvocationHistoryCollection; + this._invocationBehavior = _invocationBehavior; + } + + public bool HasMatchingInvocationImposterGroup() + { + return FindMatchingInvocationImposterGroup() != null; + } + + private GetUtcNowMethodInvocationImposterGroup? FindMatchingInvocationImposterGroup() + { + if (_invocationImposters.TryPeek(out var invocationImposterGroup)) + return invocationImposterGroup; + else + return null; + } + + public global::System.DateTime Invoke() + { + var matchingInvocationImposterGroup = FindMatchingInvocationImposterGroup(); + if (matchingInvocationImposterGroup == default) + { + if (_invocationBehavior == global::Imposter.Abstractions.ImposterMode.Explicit) + { + throw new global::Imposter.Abstractions.MissingImposterException("DateTime IMyClock.GetUtcNow()"); + } + + matchingInvocationImposterGroup = GetUtcNowMethodInvocationImposterGroup.Default; + } + + try + { + var result = matchingInvocationImposterGroup.Invoke(_invocationBehavior, "DateTime IMyClock.GetUtcNow()"); + _getUtcNowMethodInvocationHistoryCollection.Add(new GetUtcNowMethodInvocationHistory(result, default)); + return result; + } + catch (global::System.Exception ex) + { + _getUtcNowMethodInvocationHistoryCollection.Add(new GetUtcNowMethodInvocationHistory(default !, ex)); + throw; + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + internal class Builder : IGetUtcNowMethodImposterBuilder, IGetUtcNowMethodInvocationImposterGroupContinuation + { + private readonly GetUtcNowMethodImposter _imposter; + private readonly GetUtcNowMethodInvocationHistoryCollection _getUtcNowMethodInvocationHistoryCollection; + private readonly GetUtcNowMethodInvocationImposterGroup _invocationImposterGroup; + private GetUtcNowMethodInvocationImposterGroup.MethodInvocationImposter _currentInvocationImposter; + public Builder(GetUtcNowMethodImposter _imposter, GetUtcNowMethodInvocationHistoryCollection _getUtcNowMethodInvocationHistoryCollection) + { + this._imposter = _imposter; + this._getUtcNowMethodInvocationHistoryCollection = _getUtcNowMethodInvocationHistoryCollection; + this._invocationImposterGroup = new GetUtcNowMethodInvocationImposterGroup(); + _imposter._invocationImposters.Push(_invocationImposterGroup); + this._currentInvocationImposter = this._invocationImposterGroup.AddInvocationImposter(); + } + + IGetUtcNowMethodInvocationImposterGroupContinuation IGetUtcNowMethodInvocationImposterGroup.Throws() + { + _currentInvocationImposter.Throws(() => + { + throw new TException(); + }); + return this; + } + + IGetUtcNowMethodInvocationImposterGroupContinuation IGetUtcNowMethodInvocationImposterGroup.Throws(global::System.Exception exception) + { + _currentInvocationImposter.Throws(() => + { + throw exception; + }); + return this; + } + + IGetUtcNowMethodInvocationImposterGroupContinuation IGetUtcNowMethodInvocationImposterGroup.Throws(GetUtcNowExceptionGeneratorDelegate exceptionGenerator) + { + _currentInvocationImposter.Throws(() => + { + throw exceptionGenerator.Invoke(); + }); + return this; + } + + IGetUtcNowMethodInvocationImposterGroupContinuation IGetUtcNowMethodInvocationImposterGroupCallback.Callback(GetUtcNowCallbackDelegate callback) + { + _currentInvocationImposter.Callback(callback); + return this; + } + + IGetUtcNowMethodInvocationImposterGroupContinuation IGetUtcNowMethodInvocationImposterGroup.Returns(GetUtcNowDelegate resultGenerator) + { + _currentInvocationImposter.Returns(resultGenerator); + return this; + } + + IGetUtcNowMethodInvocationImposterGroupContinuation IGetUtcNowMethodInvocationImposterGroup.Returns(global::System.DateTime value) + { + _currentInvocationImposter.Returns(value); + return this; + } + + IGetUtcNowMethodInvocationImposterGroup IGetUtcNowMethodInvocationImposterGroupContinuation.Then() + { + this._currentInvocationImposter = _invocationImposterGroup.AddInvocationImposter(); + return this; + } + + void GetUtcNowInvocationVerifier.Called(global::Imposter.Abstractions.Count count) + { + var invocationCount = _getUtcNowMethodInvocationHistoryCollection.Count(); + if (!count.Matches(invocationCount)) + { + throw new global::Imposter.Abstractions.VerificationFailedException(count, invocationCount, _getUtcNowMethodInvocationHistoryCollection.ToString()); + } + } + } + } + + public IMyClockImposter(global::Imposter.Abstractions.ImposterMode invocationBehavior = global::Imposter.Abstractions.ImposterMode.Implicit) + { + this._getNowMethodImposter = new GetNowMethodImposter(_getNowMethodInvocationHistoryCollection, invocationBehavior); + this._getUtcNowMethodImposter = new GetUtcNowMethodImposter(_getUtcNowMethodInvocationHistoryCollection, invocationBehavior); + this._imposterInstance = new ImposterTargetInstance(this); + this._invocationBehavior = invocationBehavior; + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + class ImposterTargetInstance : global::MockData.IMyClock + { + private readonly IMyClockImposter _imposter; + public ImposterTargetInstance(IMyClockImposter _imposter) + { + this._imposter = _imposter; + } + + public global::System.DateTime GetNow() + { + return _imposter._getNowMethodImposter.Invoke(); + } + + public global::System.DateTime GetUtcNow() + { + return _imposter._getUtcNowMethodImposter.Invoke(); + } + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Imposter.CodeGenerator", "0.1.4.0")] + public static class IMyClockImposterExtensions + { + extension(global::MockData.IMyClock imposter) + { + public static global::MockData.IMyClockImposter Imposter(global::Imposter.Abstractions.ImposterMode invocationBehavior = global::Imposter.Abstractions.ImposterMode.Implicit) => new global::MockData.IMyClockImposter(invocationBehavior); + } + } +} +#nullable restore +#pragma warning restore + +``` + + + + +## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project Imposter ](/sources/Imposter.zip) + +::: + + +### Share Imposter + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter + + + diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index f47c84c99..9dccad6d4 100644 --- a/v2/rscg_examples_site/docs/RSCG-Examples/index.md +++ b/v2/rscg_examples_site/docs/RSCG-Examples/index.md @@ -1,7 +1,7 @@ --- sidebar_position: 30 -title: 245 RSCG list by category -description: 245 RSCG list by category +title: 246 RSCG list by category +description: 246 RSCG list by category slug: /rscg-examples --- @@ -1468,7 +1468,7 @@ import DocCardList from '@theme/DocCardList'; ## Tests
- Expand Tests =>examples:6 + Expand Tests =>examples:7 @@ -1499,6 +1499,11 @@ import DocCardList from '@theme/DocCardList'; [TUnit](/docs/TUnit) + + + +[Imposter](/docs/Imposter) +
@@ -2023,6 +2028,8 @@ flowchart LR; Tests--> TUnit((TUnit)) + Tests--> Imposter((Imposter)) + Validator--> validly((validly)) WinAPI--> Com((Com)) diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index 904a77709..740ac833a 100644 --- a/v2/rscg_examples_site/docs/about.md +++ b/v2/rscg_examples_site/docs/about.md @@ -6,7 +6,7 @@ title: About ## Content You will find here code examples -of 245 Roslyn Source Code Generator (RSCG) +of 246 Roslyn Source Code Generator (RSCG) that can be useful for you. That means, you will write more elegant and concise code - even if the generators code is not always nice to look. ## Are those examples ready for production? diff --git a/v2/rscg_examples_site/docs/indexRSCG.md b/v2/rscg_examples_site/docs/indexRSCG.md index 6da998423..f18c9f45b 100644 --- a/v2/rscg_examples_site/docs/indexRSCG.md +++ b/v2/rscg_examples_site/docs/indexRSCG.md @@ -7,9 +7,9 @@ slug: /List-of-RSCG import useBaseUrl from '@docusaurus/useBaseUrl'; -## 245 RSCG with examples in descending chronological order +## 246 RSCG with examples in descending chronological order -This is the list of 245 ( 16 from Microsoft) RSCG with examples +This is the list of 246 ( 16 from Microsoft) RSCG with examples [See by category](/docs/rscg-examples) [See as json](/exports/RSCG.json) [See as Excel](/exports/RSCG.xlsx) @@ -20,6 +20,7 @@ This is the list of 245 ( 16 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|246| [Imposter by Bitchiko Tchelidze ](/docs/Imposter)|2025-12-13 => 13 December 2025 | [Tests](/docs/Categories/Tests) | |245| [Monify by Paul Martin ](/docs/Monify)|2025-12-12 => 12 December 2025 | [PrimitiveObsession](/docs/Categories/PrimitiveObsession) | |244| [BoolParameterGenerator by Justin Buchanan ](/docs/BoolParameterGenerator)|2025-12-11 => 11 December 2025 | [Bool](/docs/Categories/Bool) | |243| [RSCG_MCP2File by Ignat Andrei ](/docs/RSCG_MCP2File)|2025-11-15 => 15 November 2025 | [MCP](/docs/Categories/MCP) | diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js index 3a4920621..42d50ed24 100644 --- a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js +++ b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js @@ -4,7 +4,7 @@ import styles from './styles.module.css'; const FeatureList = [ { -title: '245 Examples (16 from MSFT)', +title: '246 Examples (16 from MSFT)', Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, description: ( <> diff --git a/v2/rscg_examples_site/static/exports/RSCG.json b/v2/rscg_examples_site/static/exports/RSCG.json index b799df359..6149353ad 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -1961,6 +1961,14 @@ "Source": "https://github.com/MooVC/monify", "Category": "PrimitiveObsession", "AddedOn": "2025-12-12T00:00:00" + }, + { + "Name": "Imposter", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/Imposter", + "NuGet": "https://www.nuget.org/packages/Imposter/", + "Source": "https://github.com/themidnightgospel/Imposter", + "Category": "Tests", + "AddedOn": "2025-12-13T00:00:00" } ] } \ No newline at end of file diff --git a/v2/rscg_examples_site/static/exports/RSCG.xlsx b/v2/rscg_examples_site/static/exports/RSCG.xlsx index 126eb4dd9..4431d5710 100644 Binary files a/v2/rscg_examples_site/static/exports/RSCG.xlsx and b/v2/rscg_examples_site/static/exports/RSCG.xlsx differ diff --git a/v2/rscg_examples_site/static/sources/Imposter.zip b/v2/rscg_examples_site/static/sources/Imposter.zip new file mode 100644 index 000000000..33007020e Binary files /dev/null and b/v2/rscg_examples_site/static/sources/Imposter.zip differ