@@ -148,6 +148,130 @@ public static partial class GatewayHost
148148 } )
149149 . AssertPassed ( ) ;
150150
151+ [ Scenario ( "Generates Gateway Routing factories for abstract and sealed hosts" ) ]
152+ [ Fact ]
153+ public Task Generates_Gateway_Routing_Factories_For_Abstract_And_Sealed_Hosts ( )
154+ => Given ( "Gateway Routing declarations on abstract and sealed hosts" , ( ) => Compile ( """
155+ using PatternKit.Generators.GatewayRouting;
156+ namespace Demo;
157+ public sealed record GatewayRequest(string Path);
158+ public sealed record GatewayResponse(string Body);
159+
160+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreateAbstract")]
161+ public abstract partial class AbstractGateway
162+ {
163+ [GatewayRoute("inventory")]
164+ private static bool IsInventory(GatewayRequest request) => true;
165+ [GatewayRouteHandler("inventory")]
166+ private static GatewayResponse Inventory(GatewayRequest request) => new("inventory");
167+ [GatewayRouteFallback]
168+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
169+ }
170+
171+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreateSealed")]
172+ public sealed partial class SealedGateway
173+ {
174+ [GatewayRoute("billing")]
175+ private static bool IsBilling(GatewayRequest request) => true;
176+ [GatewayRouteHandler("billing")]
177+ private static GatewayResponse Billing(GatewayRequest request) => new("billing");
178+ [GatewayRouteFallback]
179+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
180+ }
181+ """ ) )
182+ . Then ( "the generated source preserves host shape" , result =>
183+ {
184+ ScenarioExpect . Empty ( result . Diagnostics ) ;
185+ ScenarioExpect . Equal ( 2 , result . GeneratedSources . Count ) ;
186+ var generatedText = string . Join ( Environment . NewLine , result . GeneratedSources ) ;
187+ ScenarioExpect . Contains ( "public abstract partial class AbstractGateway" , generatedText ) ;
188+ ScenarioExpect . Contains ( "CreateAbstract()" , generatedText ) ;
189+ ScenarioExpect . Contains ( "public sealed partial class SealedGateway" , generatedText ) ;
190+ ScenarioExpect . Contains ( "CreateSealed()" , generatedText ) ;
191+ ScenarioExpect . True ( result . EmitSuccess , string . Join ( Environment . NewLine , result . EmitDiagnostics ) ) ;
192+ } )
193+ . AssertPassed ( ) ;
194+
195+ [ Scenario ( "Generates Gateway Routing source for struct and nested accessibility variants" ) ]
196+ [ Fact ]
197+ public Task Generates_Gateway_Routing_Source_For_Struct_And_Nested_Accessibility_Variants ( )
198+ => Given ( "Gateway Routing declarations with struct and nested host accessibility" , ( ) => CompileWithoutEmit ( """
199+ using PatternKit.Generators.GatewayRouting;
200+ namespace Demo;
201+ public sealed record GatewayRequest(string Path);
202+ public sealed record GatewayResponse(string Body);
203+
204+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreateInternal")]
205+ internal partial struct InternalGateway
206+ {
207+ [GatewayRoute("internal")]
208+ private static bool IsInternal(GatewayRequest request) => true;
209+ [GatewayRouteHandler("internal")]
210+ private static GatewayResponse Handle(GatewayRequest request) => new("internal");
211+ [GatewayRouteFallback]
212+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
213+ }
214+
215+ public partial class Outer
216+ {
217+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreatePrivate")]
218+ private partial class PrivateGateway
219+ {
220+ [GatewayRoute("private")]
221+ private static bool IsPrivate(GatewayRequest request) => true;
222+ [GatewayRouteHandler("private")]
223+ private static GatewayResponse Handle(GatewayRequest request) => new("private");
224+ [GatewayRouteFallback]
225+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
226+ }
227+
228+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreateProtected")]
229+ protected partial class ProtectedGateway
230+ {
231+ [GatewayRoute("protected")]
232+ private static bool IsProtected(GatewayRequest request) => true;
233+ [GatewayRouteHandler("protected")]
234+ private static GatewayResponse Handle(GatewayRequest request) => new("protected");
235+ [GatewayRouteFallback]
236+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
237+ }
238+
239+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreateProtectedInternal")]
240+ protected internal partial class ProtectedInternalGateway
241+ {
242+ [GatewayRoute("protected-internal")]
243+ private static bool IsProtectedInternal(GatewayRequest request) => true;
244+ [GatewayRouteHandler("protected-internal")]
245+ private static GatewayResponse Handle(GatewayRequest request) => new("protected-internal");
246+ [GatewayRouteFallback]
247+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
248+ }
249+
250+ [GenerateGatewayRouting(typeof(GatewayRequest), typeof(GatewayResponse), FactoryMethodName = "CreatePrivateProtected")]
251+ private protected partial class PrivateProtectedGateway
252+ {
253+ [GatewayRoute("private-protected")]
254+ private static bool IsPrivateProtected(GatewayRequest request) => true;
255+ [GatewayRouteHandler("private-protected")]
256+ private static GatewayResponse Handle(GatewayRequest request) => new("private-protected");
257+ [GatewayRouteFallback]
258+ private static GatewayResponse Fallback(GatewayRequest request) => new("fallback");
259+ }
260+ }
261+ """ ) )
262+ . Then ( "the generated source preserves accessibility" , result =>
263+ {
264+ ScenarioExpect . Empty ( result . Diagnostics ) ;
265+ ScenarioExpect . Equal ( 5 , result . GeneratedSources . Count ) ;
266+ var generatedText = string . Join ( Environment . NewLine , result . GeneratedSources ) ;
267+ ScenarioExpect . Contains ( "internal partial struct InternalGateway" , generatedText ) ;
268+ ScenarioExpect . Contains ( "private partial class PrivateGateway" , generatedText ) ;
269+ ScenarioExpect . Contains ( "protected partial class ProtectedGateway" , generatedText ) ;
270+ ScenarioExpect . Contains ( "protected internal partial class ProtectedInternalGateway" , generatedText ) ;
271+ ScenarioExpect . Contains ( "private protected partial class PrivateProtectedGateway" , generatedText ) ;
272+ } )
273+ . AssertPassed ( ) ;
274+
151275 private static GeneratorResult Compile ( string source )
152276 {
153277 var compilation = RoslynTestHelpers . CreateCompilation (
@@ -160,5 +284,16 @@ private static GeneratorResult Compile(string source)
160284 return new ( result . Diagnostics . ToArray ( ) , result . GeneratedSources . Select ( static source => source . SourceText . ToString ( ) ) . ToArray ( ) , emit . Success , emit . Diagnostics . Select ( static diagnostic => diagnostic . ToString ( ) ) . ToArray ( ) ) ;
161285 }
162286
287+ private static GeneratorResult CompileWithoutEmit ( string source )
288+ {
289+ var compilation = RoslynTestHelpers . CreateCompilation (
290+ source ,
291+ "GatewayRoutingGeneratorTests" ,
292+ extra : MetadataReference . CreateFromFile ( typeof ( GatewayRouting < , > ) . Assembly . Location ) ) ;
293+ _ = RoslynTestHelpers . Run ( compilation , new GatewayRoutingGenerator ( ) , out var run , out _ ) ;
294+ var result = run . Results . Single ( ) ;
295+ return new ( result . Diagnostics . ToArray ( ) , result . GeneratedSources . Select ( static source => source . SourceText . ToString ( ) ) . ToArray ( ) , EmitSuccess : true , EmitDiagnostics : [ ] ) ;
296+ }
297+
163298 private sealed record GeneratorResult ( IReadOnlyList < Diagnostic > Diagnostics , IReadOnlyList < string > GeneratedSources , bool EmitSuccess , IReadOnlyList < string > EmitDiagnostics ) ;
164299}
0 commit comments