@@ -1111,4 +1111,150 @@ private Response Terminal(in Request req)
11111111 ScenarioExpect . Equal ( "PKCOM006" , diagnostic . Id ) ;
11121112 ScenarioExpect . Contains ( "Step" , diagnostic . GetMessage ( ) , StringComparison . Ordinal ) ;
11131113 }
1114+
1115+ [ Scenario ( "GenerateAsyncFalse WithAsyncStep ReportsDiagnostic" ) ]
1116+ [ Fact ]
1117+ public void GenerateAsyncFalse_WithAsyncStep_ReportsDiagnostic ( )
1118+ {
1119+ var source = """
1120+ using System;
1121+ using System.Threading.Tasks;
1122+ using PatternKit.Generators.Composer;
1123+
1124+ public readonly record struct Request(string Path);
1125+ public readonly record struct Response(int Status);
1126+
1127+ [Composer(GenerateAsync = false)]
1128+ public partial class RequestPipeline
1129+ {
1130+ [ComposeStep(0)]
1131+ private ValueTask<Response> StepAsync(Request req, Func<Request, ValueTask<Response>> next)
1132+ => next(req);
1133+
1134+ [ComposeTerminal]
1135+ private Response Terminal(in Request req) => new(200);
1136+ }
1137+ """ ;
1138+
1139+ var comp = RoslynTestHelpers . CreateCompilation ( source , nameof ( GenerateAsyncFalse_WithAsyncStep_ReportsDiagnostic ) ) ;
1140+ var gen = new ComposerGenerator ( ) ;
1141+ _ = RoslynTestHelpers . Run ( comp , gen , out var result , out _ ) ;
1142+
1143+ var diagnostic = ScenarioExpect . Single ( result . Results . SelectMany ( r => r . Diagnostics ) ) ;
1144+ ScenarioExpect . Equal ( "PKCOM008" , diagnostic . Id ) ;
1145+ ScenarioExpect . Contains ( "StepAsync" , diagnostic . GetMessage ( ) , StringComparison . Ordinal ) ;
1146+ }
1147+
1148+ [ Scenario ( "NamedOrderAndIgnoredStep GenerateDeterministicPipeline" ) ]
1149+ [ Fact ]
1150+ public void NamedOrderAndIgnoredStep_GenerateDeterministicPipeline ( )
1151+ {
1152+ var source = """
1153+ using System;
1154+ using PatternKit.Generators.Composer;
1155+
1156+ public readonly record struct Request(string Path);
1157+ public readonly record struct Response(int Status);
1158+
1159+ [Composer]
1160+ public partial class RequestPipeline
1161+ {
1162+ [ComposeStep(99, Order = 2, Name = "Audit")]
1163+ private Response Audit(in Request req, Func<Request, Response> next) => next(req);
1164+
1165+ [ComposeStep(1)]
1166+ private Response Auth(in Request req, Func<Request, Response> next) => next(req);
1167+
1168+ [ComposeStep(0)]
1169+ [ComposeIgnore]
1170+ private Response Ignored(in Request req, Func<Request, Response> next) => next(req);
1171+
1172+ [ComposeTerminal]
1173+ private Response Terminal(in Request req) => new(200);
1174+ }
1175+ """ ;
1176+
1177+ var comp = RoslynTestHelpers . CreateCompilation ( source , nameof ( NamedOrderAndIgnoredStep_GenerateDeterministicPipeline ) ) ;
1178+ var gen = new ComposerGenerator ( ) ;
1179+ _ = RoslynTestHelpers . Run ( comp , gen , out var result , out var updated ) ;
1180+
1181+ ScenarioExpect . All ( result . Results , r => ScenarioExpect . Empty ( r . Diagnostics ) ) ;
1182+
1183+ var generatedSource = result . Results . SelectMany ( r => r . GeneratedSources ) . Single ( ) . SourceText . ToString ( ) ;
1184+ ScenarioExpect . Contains ( "Audit(in arg, pipeline)" , generatedSource ) ;
1185+ ScenarioExpect . Contains ( "Auth(in arg, pipeline)" , generatedSource ) ;
1186+ ScenarioExpect . DoesNotContain ( "Ignored" , generatedSource ) ;
1187+
1188+ var emit = updated . Emit ( Stream . Null ) ;
1189+ ScenarioExpect . True ( emit . Success , string . Join ( "\n " , emit . Diagnostics ) ) ;
1190+ }
1191+
1192+ [ Scenario ( "StructAsyncTerminalWithoutCancellationToken GeneratesAsyncPipeline" ) ]
1193+ [ Fact ]
1194+ public void StructAsyncTerminalWithoutCancellationToken_GeneratesAsyncPipeline ( )
1195+ {
1196+ var source = """
1197+ using System;
1198+ using System.Threading.Tasks;
1199+ using PatternKit.Generators.Composer;
1200+
1201+ public readonly record struct Request(string Path);
1202+ public readonly record struct Response(int Status);
1203+
1204+ [Composer]
1205+ public partial struct RequestPipeline
1206+ {
1207+ [ComposeStep(0)]
1208+ private Response Audit(in Request req, Func<Request, Response> next) => next(req);
1209+
1210+ [ComposeTerminal]
1211+ private ValueTask<Response> TerminalAsync(Request req)
1212+ => new(new Response(200));
1213+ }
1214+ """ ;
1215+
1216+ var comp = RoslynTestHelpers . CreateCompilation ( source , nameof ( StructAsyncTerminalWithoutCancellationToken_GeneratesAsyncPipeline ) ) ;
1217+ var gen = new ComposerGenerator ( ) ;
1218+ _ = RoslynTestHelpers . Run ( comp , gen , out var result , out var updated ) ;
1219+
1220+ ScenarioExpect . All ( result . Results , r => ScenarioExpect . Empty ( r . Diagnostics ) ) ;
1221+
1222+ var generatedSource = result . Results . SelectMany ( r => r . GeneratedSources ) . Single ( ) . SourceText . ToString ( ) ;
1223+ ScenarioExpect . Contains ( "terminalFunc" , generatedSource ) ;
1224+ ScenarioExpect . Contains ( "self.TerminalAsync(arg)" , generatedSource ) ;
1225+
1226+ var emit = updated . Emit ( Stream . Null ) ;
1227+ ScenarioExpect . True ( emit . Success , string . Join ( "\n " , emit . Diagnostics ) ) ;
1228+ }
1229+
1230+ [ Scenario ( "InvalidStep WithFunctionPointerNext ReportsDiagnostic" ) ]
1231+ [ Fact ]
1232+ public void InvalidStep_WithFunctionPointerNext_ReportsDiagnostic ( )
1233+ {
1234+ var source = """
1235+ using PatternKit.Generators.Composer;
1236+
1237+ public readonly record struct Request(string Path);
1238+ public readonly record struct Response(int Status);
1239+
1240+ [Composer]
1241+ public partial class RequestPipeline
1242+ {
1243+ [ComposeStep(0)]
1244+ private unsafe Response Step(in Request req, delegate*<Request, Response> next)
1245+ => new(200);
1246+
1247+ [ComposeTerminal]
1248+ private Response Terminal(in Request req) => new(200);
1249+ }
1250+ """ ;
1251+
1252+ var comp = RoslynTestHelpers . CreateCompilation ( source , nameof ( InvalidStep_WithFunctionPointerNext_ReportsDiagnostic ) ) ;
1253+ var gen = new ComposerGenerator ( ) ;
1254+ _ = RoslynTestHelpers . Run ( comp , gen , out var result , out _ ) ;
1255+
1256+ var diagnostic = ScenarioExpect . Single ( result . Results . SelectMany ( r => r . Diagnostics ) ) ;
1257+ ScenarioExpect . Equal ( "PKCOM006" , diagnostic . Id ) ;
1258+ ScenarioExpect . Contains ( "Step" , diagnostic . GetMessage ( ) , StringComparison . Ordinal ) ;
1259+ }
11141260}
0 commit comments