Skip to content

Commit d4bd44e

Browse files
committed
test: harden composite and flyweight generator coverage
1 parent 9d1d2ca commit d4bd44e

3 files changed

Lines changed: 214 additions & 1 deletion

File tree

src/PatternKit.Generators/Composite/CompositeGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ private static string RenderComposite(INamedTypeSymbol component, string compone
131131
sb.AppendLine("{");
132132
foreach (var property in GetContractProperties(component))
133133
{
134-
sb.Append(" public abstract ").Append(property.Type.ToDisplayString(TypeFormat)).Append(' ').Append(property.Name).Append(" { get; }").AppendLine();
134+
sb.Append(component.TypeKind == TypeKind.Class ? " public abstract override " : " public abstract ")
135+
.Append(property.Type.ToDisplayString(TypeFormat)).Append(' ').Append(property.Name).Append(" { get; }").AppendLine();
135136
sb.AppendLine();
136137
}
137138
sb.AppendLine(" public virtual bool IsLeaf => true;");

test/PatternKit.Generators.Tests/CompositeGeneratorTests.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,47 @@ public sealed class CategoryNode : CategoryCompositeBase
5151
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
5252
}
5353

54+
[Scenario("GeneratesCompositeBasesForAbstractClassWithCustomNames")]
55+
[Fact]
56+
public void GeneratesCompositeBasesForAbstractClassWithCustomNames()
57+
{
58+
const string source = """
59+
using PatternKit.Generators.Composite;
60+
61+
namespace TestNamespace;
62+
63+
[CompositeComponent(
64+
ComponentBaseName = "MenuItemBase",
65+
CompositeBaseName = "MenuGroupBase",
66+
ChildrenPropertyName = "Items")]
67+
public abstract partial class MenuItem
68+
{
69+
public abstract string Name { get; }
70+
71+
[CompositeIgnore]
72+
public abstract int SortOrder { get; }
73+
}
74+
""";
75+
76+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(GeneratesCompositeBasesForAbstractClassWithCustomNames));
77+
var gen = new CompositeGenerator();
78+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out var updated);
79+
80+
ScenarioExpect.All(result.Results, r => ScenarioExpect.Empty(r.Diagnostics));
81+
82+
var generated = ScenarioExpect.Single(result.Results.SelectMany(r => r.GeneratedSources));
83+
var text = generated.SourceText.ToString();
84+
ScenarioExpect.Equal("MenuItem.Composite.g.cs", generated.HintName);
85+
ScenarioExpect.Contains("public abstract partial class MenuItemBase : global::TestNamespace.MenuItem", text);
86+
ScenarioExpect.Contains("public virtual global::System.Collections.Generic.IReadOnlyList<global::TestNamespace.MenuItem> Items", text);
87+
ScenarioExpect.Contains("public abstract override string Name { get; }", text);
88+
ScenarioExpect.DoesNotContain("SortOrder", text);
89+
ScenarioExpect.Contains("public abstract partial class MenuGroupBase : MenuItemBase", text);
90+
91+
var emit = updated.Emit(Stream.Null);
92+
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
93+
}
94+
5495
[Scenario("ReportsDiagnosticWhenComponentIsNotPartial")]
5596
[Fact]
5697
public void ReportsDiagnosticWhenComponentIsNotPartial()
@@ -97,4 +138,55 @@ public partial class Category
97138
var diags = result.Results.SelectMany(r => r.Diagnostics);
98139
ScenarioExpect.Contains(diags, d => d.Id == "PKCMP002");
99140
}
141+
142+
[Scenario("ReportsDiagnosticWhenCompositeContractHasEvent")]
143+
[Fact]
144+
public void ReportsDiagnosticWhenCompositeContractHasEvent()
145+
{
146+
const string source = """
147+
using System;
148+
using PatternKit.Generators.Composite;
149+
150+
namespace TestNamespace;
151+
152+
[CompositeComponent]
153+
public partial interface ICategory
154+
{
155+
event EventHandler? Changed;
156+
}
157+
""";
158+
159+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(ReportsDiagnosticWhenCompositeContractHasEvent));
160+
var gen = new CompositeGenerator();
161+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out _);
162+
163+
var diags = result.Results.SelectMany(r => r.Diagnostics);
164+
ScenarioExpect.Contains(diags, d => d.Id == "PKCMP004");
165+
}
166+
167+
[Scenario("ReportsDiagnosticWhenCompositeGeneratedNameConflicts")]
168+
[Fact]
169+
public void ReportsDiagnosticWhenCompositeGeneratedNameConflicts()
170+
{
171+
const string source = """
172+
using PatternKit.Generators.Composite;
173+
174+
namespace TestNamespace;
175+
176+
public abstract class CategoryComponentBase;
177+
178+
[CompositeComponent]
179+
public partial interface ICategory
180+
{
181+
string Name { get; }
182+
}
183+
""";
184+
185+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(ReportsDiagnosticWhenCompositeGeneratedNameConflicts));
186+
var gen = new CompositeGenerator();
187+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out _);
188+
189+
var diags = result.Results.SelectMany(r => r.Diagnostics);
190+
ScenarioExpect.Contains(diags, d => d.Id == "PKCMP003");
191+
}
100192
}

test/PatternKit.Generators.Tests/FlyweightGeneratorTests.cs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,39 @@ public readonly partial record struct Glyph(char Value)
3737
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
3838
}
3939

40+
[Scenario("GeneratesFlyweightCacheWithoutTryGet")]
41+
[Fact]
42+
public void GeneratesFlyweightCacheWithoutTryGet()
43+
{
44+
const string source = """
45+
using PatternKit.Generators.Flyweight;
46+
47+
namespace TestNamespace;
48+
49+
[Flyweight(typeof(string), CacheTypeName = "TokenCache", GenerateTryGet = false)]
50+
public sealed partial record class Token(string Value)
51+
{
52+
[FlyweightFactory]
53+
private static Token Create(string key) => new(key);
54+
}
55+
""";
56+
57+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(GeneratesFlyweightCacheWithoutTryGet));
58+
var gen = new FlyweightGenerator();
59+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out var updated);
60+
61+
ScenarioExpect.All(result.Results, r => ScenarioExpect.Empty(r.Diagnostics));
62+
63+
var generated = result.Results.SelectMany(r => r.GeneratedSources).Single(s => s.HintName == "Token.Flyweight.g.cs").SourceText.ToString();
64+
ScenarioExpect.Contains("partial record class Token", generated);
65+
ScenarioExpect.Contains("public sealed partial class TokenCache", generated);
66+
ScenarioExpect.Contains("public global::TestNamespace.Token Get(string key)", generated);
67+
ScenarioExpect.DoesNotContain("public bool TryGet(", generated);
68+
69+
var emit = updated.Emit(Stream.Null);
70+
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
71+
}
72+
4073
[Scenario("ReportsMissingFactory")]
4174
[Fact]
4275
public void ReportsMissingFactory()
@@ -83,6 +116,61 @@ public readonly partial record struct Glyph(char Value)
83116
ScenarioExpect.Contains(diags, d => d.Id == "PKFLY006");
84117
}
85118

119+
[Scenario("ReportsMultipleFlyweightFactories")]
120+
[Fact]
121+
public void ReportsMultipleFlyweightFactories()
122+
{
123+
const string source = """
124+
using PatternKit.Generators.Flyweight;
125+
126+
namespace TestNamespace;
127+
128+
[Flyweight(typeof(string))]
129+
public readonly partial record struct Glyph(char Value)
130+
{
131+
[FlyweightFactory]
132+
private static Glyph Create(string key) => new(key[0]);
133+
134+
[FlyweightFactory]
135+
private static Glyph CreateAlternate(string key) => new(key[^1]);
136+
}
137+
""";
138+
139+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(ReportsMultipleFlyweightFactories));
140+
var gen = new FlyweightGenerator();
141+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out _);
142+
143+
var diags = result.Results.SelectMany(r => r.Diagnostics);
144+
ScenarioExpect.Contains(diags, d => d.Id == "PKFLY003");
145+
}
146+
147+
[Scenario("ReportsFlyweightCacheNameConflict")]
148+
[Fact]
149+
public void ReportsFlyweightCacheNameConflict()
150+
{
151+
const string source = """
152+
using PatternKit.Generators.Flyweight;
153+
154+
namespace TestNamespace;
155+
156+
public sealed class GlyphFlyweightCache;
157+
158+
[Flyweight(typeof(string))]
159+
public readonly partial record struct Glyph(char Value)
160+
{
161+
[FlyweightFactory]
162+
private static Glyph Create(string key) => new(key[0]);
163+
}
164+
""";
165+
166+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(ReportsFlyweightCacheNameConflict));
167+
var gen = new FlyweightGenerator();
168+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out _);
169+
170+
var diags = result.Results.SelectMany(r => r.Diagnostics);
171+
ScenarioExpect.Contains(diags, d => d.Id == "PKFLY005");
172+
}
173+
86174
[Scenario("ReportsNonPartialAndNonStaticFactory")]
87175
[Fact]
88176
public void ReportsNonPartialAndNonStaticFactory()
@@ -115,4 +203,36 @@ public readonly partial record struct NonStaticFactoryGlyph(char Value)
115203
ScenarioExpect.Contains(diags, d => d.Id == "PKFLY001");
116204
ScenarioExpect.Contains(diags, d => d.Id == "PKFLY004");
117205
}
206+
207+
[Scenario("ReportsInvalidFlyweightFactoryForWrongKeyAndReturnTypes")]
208+
[Fact]
209+
public void ReportsInvalidFlyweightFactoryForWrongKeyAndReturnTypes()
210+
{
211+
const string source = """
212+
using PatternKit.Generators.Flyweight;
213+
214+
namespace TestNamespace;
215+
216+
[Flyweight(typeof(string))]
217+
public readonly partial record struct WrongKeyGlyph(char Value)
218+
{
219+
[FlyweightFactory]
220+
private static WrongKeyGlyph Create(int key) => new((char)key);
221+
}
222+
223+
[Flyweight(typeof(string))]
224+
public readonly partial record struct WrongReturnGlyph(char Value)
225+
{
226+
[FlyweightFactory]
227+
private static string Create(string key) => key;
228+
}
229+
""";
230+
231+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(ReportsInvalidFlyweightFactoryForWrongKeyAndReturnTypes));
232+
var gen = new FlyweightGenerator();
233+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out _);
234+
235+
var diags = result.Results.SelectMany(r => r.Diagnostics).ToArray();
236+
ScenarioExpect.Equal(2, diags.Count(d => d.Id == "PKFLY004"));
237+
}
118238
}

0 commit comments

Comments
 (0)