@@ -101,6 +101,56 @@ private static ValueTask PriorityAudit(Message<Order> message, MessageContext co
101101 ScenarioExpect . True ( emit . Success , string . Join ( "\n " , emit . Diagnostics ) ) ;
102102 }
103103
104+ [ Scenario ( "Generates recipient-list factories for global struct with sync and async recipients" ) ]
105+ [ Fact ]
106+ public void GeneratesRecipientListFactoriesForGlobalStructWithSyncAndAsyncRecipients ( )
107+ {
108+ var source = """
109+ using System.Threading;
110+ using System.Threading.Tasks;
111+ using PatternKit.Generators.Messaging;
112+ using PatternKit.Messaging;
113+
114+ public sealed record Order(string Channel);
115+
116+ [GenerateRecipientList(typeof(Order), FactoryName = "BuildSync", AsyncFactoryName = "BuildAsync")]
117+ public partial struct OrderRecipients
118+ {
119+ private static bool IsRetail(Message<Order> message, MessageContext context)
120+ => message.Payload.Channel == "retail";
121+
122+ private static ValueTask<bool> IsPriority(Message<Order> message, MessageContext context, CancellationToken cancellationToken)
123+ => ValueTask.FromResult(message.Payload.Channel == "priority");
124+
125+ [RecipientListRecipient("retail\"audit", 10, nameof(IsRetail))]
126+ private static void RetailAudit(Message<Order> message, MessageContext context) { }
127+
128+ [RecipientListRecipient("priority-audit", 20, nameof(IsPriority))]
129+ private static ValueTask PriorityAudit(Message<Order> message, MessageContext context, CancellationToken cancellationToken)
130+ => ValueTask.CompletedTask;
131+ }
132+ """ ;
133+
134+ var comp = CreateCompilation ( source , nameof ( GeneratesRecipientListFactoriesForGlobalStructWithSyncAndAsyncRecipients ) ) ;
135+ var gen = new RecipientListGenerator ( ) ;
136+ _ = RoslynTestHelpers . Run ( comp , gen , out var run , out var updated ) ;
137+
138+ ScenarioExpect . All ( run . Results , result => ScenarioExpect . Empty ( result . Diagnostics ) ) ;
139+
140+ var generated = ScenarioExpect . Single ( run . Results . SelectMany ( result => result . GeneratedSources ) ) ;
141+ var text = generated . SourceText . ToString ( ) ;
142+ ScenarioExpect . Equal ( "OrderRecipients.RecipientList.g.cs" , generated . HintName ) ;
143+ ScenarioExpect . DoesNotContain ( "namespace " , text ) ;
144+ ScenarioExpect . Contains ( "partial struct OrderRecipients" , text ) ;
145+ ScenarioExpect . Contains ( "BuildSync()" , text ) ;
146+ ScenarioExpect . Contains ( "BuildAsync()" , text ) ;
147+ ScenarioExpect . Contains ( ".When(\" retail\\ \" audit\" , IsRetail).Then(RetailAudit)" , text ) ;
148+ ScenarioExpect . Contains ( ".When(\" priority-audit\" , IsPriority).Then(PriorityAudit)" , text ) ;
149+
150+ var emit = updated . Emit ( Stream . Null ) ;
151+ ScenarioExpect . True ( emit . Success , string . Join ( "\n " , emit . Diagnostics ) ) ;
152+ }
153+
104154 [ Scenario ( "Reports diagnostic for non-partial recipient list" ) ]
105155 [ Fact ]
106156 public void ReportsDiagnosticForNonPartialRecipientList ( )
@@ -184,6 +234,46 @@ public static partial class OrderRecipients
184234 ScenarioExpect . Equal ( "PKRL003" , diagnostic . Id ) ;
185235 }
186236
237+ [ Scenario ( "Reports diagnostics for invalid recipient-list recipient shapes" ) ]
238+ [ Fact ]
239+ public void ReportsDiagnosticsForInvalidRecipientListRecipientShapes ( )
240+ {
241+ var source = """
242+ using PatternKit.Generators.Messaging;
243+ using PatternKit.Messaging;
244+
245+ namespace MyApp;
246+
247+ public sealed record Order(string Channel);
248+
249+ [GenerateRecipientList(typeof(Order))]
250+ public static partial class OrderRecipients
251+ {
252+ private static bool IsRetail(Message<Order> message, MessageContext context) => true;
253+ private static int InvalidPredicate(Message<Order> message, MessageContext context) => 1;
254+
255+ [RecipientListRecipient(" ", 10, nameof(IsRetail))]
256+ private static void BlankName(Message<Order> message, MessageContext context) { }
257+
258+ [RecipientListRecipient("missing-predicate", 20, "Missing")]
259+ private static void MissingPredicate(Message<Order> message, MessageContext context) { }
260+
261+ [RecipientListRecipient("invalid-predicate", 30, nameof(InvalidPredicate))]
262+ private static void InvalidPredicateRecipient(Message<Order> message, MessageContext context) { }
263+
264+ [RecipientListRecipient("instance", 40, nameof(IsRetail))]
265+ private void Instance(Message<Order> message, MessageContext context) { }
266+ }
267+ """ ;
268+
269+ var comp = CreateCompilation ( source , nameof ( ReportsDiagnosticsForInvalidRecipientListRecipientShapes ) ) ;
270+ var gen = new RecipientListGenerator ( ) ;
271+ _ = RoslynTestHelpers . Run ( comp , gen , out var run , out _ ) ;
272+
273+ var diagnostics = run . Results . SelectMany ( result => result . Diagnostics ) . ToArray ( ) ;
274+ ScenarioExpect . Equal ( 4 , diagnostics . Count ( diagnostic => diagnostic . Id == "PKRL003" ) ) ;
275+ }
276+
187277 [ Scenario ( "Reports diagnostic for duplicate recipient name or order" ) ]
188278 [ Fact ]
189279 public void ReportsDiagnosticForDuplicateRecipientNameOrOrder ( )
0 commit comments