Skip to content

Commit 678f55b

Browse files
committed
test: harden prototype generator coverage
1 parent 167bee2 commit 678f55b

2 files changed

Lines changed: 150 additions & 2 deletions

File tree

‎src/PatternKit.Generators/PrototypeGenerator.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,8 @@ private bool IsImmutableReferenceType(ITypeSymbol type)
532532
return true;
533533

534534
// Check for known immutable collections (basic check)
535-
var typeName = type.ToDisplayString();
536-
if (typeName.StartsWith("System.Collections.Immutable.", StringComparison.Ordinal))
535+
var typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
536+
if (typeName.Contains("System.Collections.Immutable.", StringComparison.Ordinal))
537537
return true;
538538

539539
// Conservative: assume mutable

‎test/PatternKit.Generators.Tests/PrototypeGeneratorTests.cs‎

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,4 +1074,152 @@ public partial class Snapshot
10741074
var emit = updated.Emit(Stream.Null);
10751075
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
10761076
}
1077+
1078+
[Scenario("MutableRecordPrototype UsesCopyConstructor")]
1079+
[Fact]
1080+
public void MutableRecordPrototype_UsesCopyConstructor()
1081+
{
1082+
const string source = """
1083+
using PatternKit.Generators.Prototype;
1084+
1085+
namespace TestNamespace;
1086+
1087+
[Prototype]
1088+
public partial record class MutableSnapshot
1089+
{
1090+
public string Name { get; set; } = "";
1091+
public int Version { get; set; }
1092+
}
1093+
""";
1094+
1095+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(MutableRecordPrototype_UsesCopyConstructor));
1096+
var gen = new PrototypeGenerator();
1097+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out var updated);
1098+
1099+
ScenarioExpect.All(result.Results, r => ScenarioExpect.DoesNotContain(r.Diagnostics, d => d.Severity == DiagnosticSeverity.Error));
1100+
1101+
var generatedSource = result.Results
1102+
.SelectMany(r => r.GeneratedSources)
1103+
.First(gs => gs.HintName == "MutableSnapshot.Prototype.g.cs")
1104+
.SourceText.ToString();
1105+
1106+
ScenarioExpect.Contains("new global::TestNamespace.MutableSnapshot(this)", generatedSource);
1107+
1108+
var emit = updated.Emit(Stream.Null);
1109+
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
1110+
}
1111+
1112+
[Scenario("MutableRecordStructPrototype UsesParameterlessConstruction")]
1113+
[Fact]
1114+
public void MutableRecordStructPrototype_UsesParameterlessConstruction()
1115+
{
1116+
const string source = """
1117+
using PatternKit.Generators.Prototype;
1118+
1119+
namespace TestNamespace;
1120+
1121+
[Prototype]
1122+
public partial record struct MutablePoint
1123+
{
1124+
public int X { get; set; }
1125+
public int Y { get; set; }
1126+
}
1127+
""";
1128+
1129+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(MutableRecordStructPrototype_UsesParameterlessConstruction));
1130+
var gen = new PrototypeGenerator();
1131+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out var updated);
1132+
1133+
ScenarioExpect.All(result.Results, r => ScenarioExpect.DoesNotContain(r.Diagnostics, d => d.Severity == DiagnosticSeverity.Error));
1134+
1135+
var generatedSource = result.Results
1136+
.SelectMany(r => r.GeneratedSources)
1137+
.First(gs => gs.HintName == "MutablePoint.Prototype.g.cs")
1138+
.SourceText.ToString();
1139+
1140+
ScenarioExpect.Contains("return new global::TestNamespace.MutablePoint", generatedSource);
1141+
ScenarioExpect.Contains("X = this.X", generatedSource);
1142+
ScenarioExpect.Contains("Y = this.Y", generatedSource);
1143+
1144+
var emit = updated.Emit(Stream.Null);
1145+
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
1146+
}
1147+
1148+
[Scenario("ImmutableCollectionDoesNotWarnInShallowWithWarningsMode")]
1149+
[Fact]
1150+
public void ImmutableCollectionDoesNotWarnInShallowWithWarningsMode()
1151+
{
1152+
const string source = """
1153+
using PatternKit.Generators.Prototype;
1154+
1155+
namespace TestNamespace
1156+
{
1157+
[Prototype]
1158+
public partial class ImmutableSnapshot
1159+
{
1160+
public System.Collections.Immutable.ImmutableTags Tags { get; set; } = new();
1161+
}
1162+
}
1163+
1164+
namespace System.Collections.Immutable
1165+
{
1166+
public sealed class ImmutableTags
1167+
{
1168+
}
1169+
}
1170+
""";
1171+
1172+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(ImmutableCollectionDoesNotWarnInShallowWithWarningsMode));
1173+
var gen = new PrototypeGenerator();
1174+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out var updated);
1175+
1176+
var diagnostics = result.Results.SelectMany(r => r.Diagnostics).ToArray();
1177+
ScenarioExpect.DoesNotContain(diagnostics, d => d.Id == "PKPRO003");
1178+
ScenarioExpect.DoesNotContain(diagnostics, d => d.Severity == DiagnosticSeverity.Error);
1179+
1180+
var emit = updated.Emit(Stream.Null);
1181+
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
1182+
}
1183+
1184+
[Scenario("PrototypeIncludesFieldsAndShallowCopyReferenceFallback")]
1185+
[Fact]
1186+
public void PrototypeIncludesFieldsAndShallowCopyReferenceFallback()
1187+
{
1188+
const string source = """
1189+
using PatternKit.Generators.Prototype;
1190+
1191+
namespace TestNamespace;
1192+
1193+
public sealed class Payload
1194+
{
1195+
public string Value { get; set; } = "";
1196+
}
1197+
1198+
[Prototype(Mode = PrototypeMode.Shallow)]
1199+
public partial class Snapshot
1200+
{
1201+
public int Version;
1202+
1203+
[PrototypeStrategy(PrototypeCloneStrategy.ShallowCopy)]
1204+
public Payload Data { get; set; } = new();
1205+
}
1206+
""";
1207+
1208+
var comp = RoslynTestHelpers.CreateCompilation(source, nameof(PrototypeIncludesFieldsAndShallowCopyReferenceFallback));
1209+
var gen = new PrototypeGenerator();
1210+
_ = RoslynTestHelpers.Run(comp, gen, out var result, out var updated);
1211+
1212+
ScenarioExpect.All(result.Results, r => ScenarioExpect.DoesNotContain(r.Diagnostics, d => d.Severity == DiagnosticSeverity.Error));
1213+
1214+
var generatedSource = result.Results
1215+
.SelectMany(r => r.GeneratedSources)
1216+
.First(gs => gs.HintName == "Snapshot.Prototype.g.cs")
1217+
.SourceText.ToString();
1218+
1219+
ScenarioExpect.Contains("Version = this.Version", generatedSource);
1220+
ScenarioExpect.Contains("Data = this.Data", generatedSource);
1221+
1222+
var emit = updated.Emit(Stream.Null);
1223+
ScenarioExpect.True(emit.Success, string.Join("\n", emit.Diagnostics));
1224+
}
10771225
}

0 commit comments

Comments
 (0)