Skip to content

Commit 7601a3f

Browse files
authoredNov 24, 2020
Refactor generator to better handle baseline scenarios & add mechanism to run serializer tests with codegen active (#381)
1 parent da4fe1f commit 7601a3f

36 files changed

+1882
-769
lines changed
 

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/JsonSourceGeneratorTests.cs

+31-13
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System.Collections.Generic;
66
using System.Linq;
7-
using System.Text.Json.Serialization;
87
using JsonCodeGeneration;
98
using Xunit;
109

@@ -69,6 +68,17 @@ public static void RoundTripCollectionsDictionary()
6968
VerifyWeatherForecastWithPOCOs(expected, obj);
7069
}
7170

71+
[Fact]
72+
public static void RoundTripEmptyPoco()
73+
{
74+
EmptyPoco expected = CreateEmptyPoco();
75+
76+
string json = JsonSerializer.Serialize(expected, JsonContext.Instance.EmptyPoco);
77+
EmptyPoco obj = JsonSerializer.Deserialize(json, JsonContext.Instance.EmptyPoco);
78+
79+
VerifyEmptyPoco(expected, obj);
80+
}
81+
7282
[Fact]
7383
public static void RoundTripTypeNameClash()
7484
{
@@ -80,7 +90,7 @@ public static void RoundTripTypeNameClash()
8090
VerifyRepeatedLocation(expected, obj);
8191
}
8292

83-
internal static Location CreateLocation()
93+
private static Location CreateLocation()
8494
{
8595
return new Location
8696
{
@@ -96,7 +106,7 @@ internal static Location CreateLocation()
96106
};
97107
}
98108

99-
internal static void VerifyLocation(Location expected, Location obj)
109+
private static void VerifyLocation(Location expected, Location obj)
100110
{
101111
Assert.Equal(expected.Address1, obj.Address1);
102112
Assert.Equal(expected.Address2, obj.Address2);
@@ -108,7 +118,7 @@ internal static void VerifyLocation(Location expected, Location obj)
108118
Assert.Equal(expected.Country, obj.Country);
109119
}
110120

111-
internal static ActiveOrUpcomingEvent CreateActiveOrUpcomingEvent()
121+
private static ActiveOrUpcomingEvent CreateActiveOrUpcomingEvent()
112122
{
113123
return new ActiveOrUpcomingEvent
114124
{
@@ -123,7 +133,7 @@ internal static ActiveOrUpcomingEvent CreateActiveOrUpcomingEvent()
123133
};
124134
}
125135

126-
internal static void VerifyActiveOrUpcomingEvent(ActiveOrUpcomingEvent expected, ActiveOrUpcomingEvent obj)
136+
private static void VerifyActiveOrUpcomingEvent(ActiveOrUpcomingEvent expected, ActiveOrUpcomingEvent obj)
127137
{
128138
Assert.Equal(expected.CampaignManagedOrganizerName, obj.CampaignManagedOrganizerName);
129139
Assert.Equal(expected.CampaignName, obj.CampaignName);
@@ -135,7 +145,7 @@ internal static void VerifyActiveOrUpcomingEvent(ActiveOrUpcomingEvent expected,
135145
Assert.Equal(expected.StartDate, obj.StartDate);
136146
}
137147

138-
internal static CampaignSummaryViewModel CreateCampaignSummaryViewModel()
148+
private static CampaignSummaryViewModel CreateCampaignSummaryViewModel()
139149
{
140150
return new CampaignSummaryViewModel
141151
{
@@ -148,7 +158,7 @@ internal static CampaignSummaryViewModel CreateCampaignSummaryViewModel()
148158
};
149159
}
150160

151-
internal static void VerifyCampaignSummaryViewModel(CampaignSummaryViewModel expected, CampaignSummaryViewModel obj)
161+
private static void VerifyCampaignSummaryViewModel(CampaignSummaryViewModel expected, CampaignSummaryViewModel obj)
152162
{
153163
Assert.Equal(expected.Description, obj.Description);
154164
Assert.Equal(expected.Headline, obj.Headline);
@@ -158,7 +168,7 @@ internal static void VerifyCampaignSummaryViewModel(CampaignSummaryViewModel exp
158168
Assert.Equal(expected.Title, obj.Title);
159169
}
160170

161-
internal static IndexViewModel CreateIndexViewModel()
171+
private static IndexViewModel CreateIndexViewModel()
162172
{
163173
return new IndexViewModel
164174
{
@@ -188,7 +198,7 @@ internal static IndexViewModel CreateIndexViewModel()
188198
};
189199
}
190200

191-
internal static void VerifyIndexViewModel(IndexViewModel expected, IndexViewModel obj)
201+
private static void VerifyIndexViewModel(IndexViewModel expected, IndexViewModel obj)
192202
{
193203
Assert.Equal(expected.ActiveOrUpcomingEvents.Count, obj.ActiveOrUpcomingEvents.Count);
194204
for (int i = 0; i < expected.ActiveOrUpcomingEvents.Count; i++)
@@ -201,7 +211,7 @@ internal static void VerifyIndexViewModel(IndexViewModel expected, IndexViewMode
201211
Assert.Equal(expected.IsNewAccount, obj.IsNewAccount);
202212
}
203213

204-
internal static WeatherForecastWithPOCOs CreateWeatherForecastWithPOCOs()
214+
private static WeatherForecastWithPOCOs CreateWeatherForecastWithPOCOs()
205215
{
206216
return new WeatherForecastWithPOCOs
207217
{
@@ -235,7 +245,7 @@ internal static WeatherForecastWithPOCOs CreateWeatherForecastWithPOCOs()
235245
};
236246
}
237247

238-
internal static void VerifyWeatherForecastWithPOCOs(WeatherForecastWithPOCOs expected, WeatherForecastWithPOCOs obj)
248+
private static void VerifyWeatherForecastWithPOCOs(WeatherForecastWithPOCOs expected, WeatherForecastWithPOCOs obj)
239249
{
240250
Assert.Equal(expected.Date, obj.Date);
241251
Assert.Equal(expected.TemperatureCelsius, obj.TemperatureCelsius);
@@ -261,7 +271,7 @@ internal static void VerifyWeatherForecastWithPOCOs(WeatherForecastWithPOCOs exp
261271
}
262272
}
263273

264-
internal static RepeatedTypes.Location CreateRepeatedLocation()
274+
private static RepeatedTypes.Location CreateRepeatedLocation()
265275
{
266276
return new RepeatedTypes.Location
267277
{
@@ -276,7 +286,7 @@ internal static RepeatedTypes.Location CreateRepeatedLocation()
276286
FakeCountry = "The Greatest"
277287
};
278288
}
279-
internal static void VerifyRepeatedLocation(RepeatedTypes.Location expected, RepeatedTypes.Location obj)
289+
private static void VerifyRepeatedLocation(RepeatedTypes.Location expected, RepeatedTypes.Location obj)
280290
{
281291
Assert.Equal(expected.FakeAddress1, obj.FakeAddress1);
282292
Assert.Equal(expected.FakeAddress2, obj.FakeAddress2);
@@ -287,5 +297,13 @@ internal static void VerifyRepeatedLocation(RepeatedTypes.Location expected, Rep
287297
Assert.Equal(expected.FakePhoneNumber, obj.FakePhoneNumber);
288298
Assert.Equal(expected.FakeCountry, obj.FakeCountry);
289299
}
300+
301+
private static EmptyPoco CreateEmptyPoco() => new EmptyPoco();
302+
303+
private static void VerifyEmptyPoco(EmptyPoco expected, EmptyPoco obj)
304+
{
305+
Assert.NotNull(expected);
306+
Assert.NotNull(obj);
307+
}
290308
}
291309
}

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkCurrent)</TargetFrameworks>
4+
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
45
</PropertyGroup>
56

67
<ItemGroup>

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/TestClasses.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
[module: JsonSerializable(typeof(TestsNamespace.CampaignSummaryViewModel))]
1010
[module: JsonSerializable(typeof(TestsNamespace.IndexViewModel))]
1111
[module: JsonSerializable(typeof(TestsNamespace.WeatherForecastWithPOCOs))]
12+
[module: JsonSerializable(typeof(TestsNamespace.EmptyPoco))]
1213

13-
// TODO: fix bug where ArgumentException is thrown because HighLowTemps already exists in object graph of previously type
14-
// (https://github.com/dotnet/runtimelab/issues/329).
15-
// [module: JsonSerializable(typeof(TestsNamespace.HighLowTemps))]
14+
// Ensure no errors when type of member in previously specified object graph is passed as input type to generator.
15+
[module: JsonSerializable(typeof(TestsNamespace.HighLowTemps))]
1616

1717
namespace System.Text.Json.SourceGeneration.Tests.RepeatedTypes
1818
{
@@ -93,4 +93,7 @@ public class HighLowTemps
9393
public int Low { get; set; }
9494
}
9595

96+
public class EmptyPoco
97+
{
98+
}
9699
}

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorDiagnosticsTests.cs

+23-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Collections.Immutable;
6-
using System.Collections.Generic;
76
using System.Linq;
87
using Microsoft.CodeAnalysis;
98
using Xunit;
@@ -55,9 +54,9 @@ public class IndexViewModel
5554

5655
// Expected info logs.
5756
string[] expectedInfoDiagnostics = new string[] {
58-
"Generated type class ActiveOrUpcomingEvent for root type IndexViewModel",
59-
"Generated type class CampaignSummaryViewModel for root type IndexViewModel",
60-
"Generated type class IndexViewModel for root type IndexViewModel",
57+
"Generated serialization metadata for type ActiveOrUpcomingEvent",
58+
"Generated serialization metadata for type CampaignSummaryViewModel",
59+
"Generated serialization metadata for type IndexViewModel",
6160
};
6261

6362
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, expectedInfoDiagnostics);
@@ -66,7 +65,7 @@ public class IndexViewModel
6665
}
6766

6867
[Fact]
69-
public void UnSuccessfulSourceGeneration()
68+
public void UnsuccessfulSourceGeneration()
7069
{
7170
// Compile the referenced assembly first.
7271
Compilation campaignCompilation = CompilationHelper.CreateCampaignSummaryViewModelCompilation();
@@ -106,10 +105,16 @@ public class IndexViewModel
106105

107106
CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);
108107

108+
// Expected success info logs.
109+
string[] expectedInfoDiagnostics = new string[] {
110+
"Generated serialization metadata for type IndexViewModel",
111+
"Generated serialization metadata for type CampaignSummaryViewModel"
112+
};
113+
109114
// Expected warning logs.
110-
string[] expectedWarningDiagnostics = new string[] { "Failed in sourcegenerating nested type ISet`1 for root type IndexViewModel" };
115+
string[] expectedWarningDiagnostics = new string[] { "Did not generate serialization metadata for type ISet<ReferencedAssembly.ActiveOrUpcomingEvent>" };
111116

112-
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, new string[] { });
117+
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, expectedInfoDiagnostics);
113118
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics);
114119
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, new string[] { });
115120
}
@@ -125,11 +130,12 @@ public void NameClashSourceGeneration()
125130

126131
// Expected info logs.
127132
string[] expectedInfoDiagnostics = new string[] {
128-
"Generated type class Location for root type Location",
129-
"Generated type class TestAssemblyLocation for root type Location",
133+
"Generated serialization metadata for type Location",
134+
"Generated serialization metadata for type HelloWorld.Location",
130135
};
131136
// Expected warning logs.
132-
string[] expectedWarningDiagnostics = new string[] { "Changed name type Location to TestAssemblyLocation. To use please call `JsonContext.Instance.TestAssemblyLocation`" };
137+
string[] expectedWarningDiagnostics = new string[] {
138+
"Duplicate type name detected. Setting the JsonTypeInfo<T> property for type HelloWorld.Location in assembly TestAssembly to HelloWorldLocation. To use please call JsonContext.Instance.HelloWorldLocation" };
133139

134140
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, expectedInfoDiagnostics);
135141
CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics);
@@ -138,7 +144,13 @@ public void NameClashSourceGeneration()
138144

139145
private void CheckDiagnosticMessages(ImmutableArray<Diagnostic> diagnostics, DiagnosticSeverity level, string[] expectedMessages)
140146
{
141-
Assert.Equal(expectedMessages, diagnostics.Where(diagnostic => diagnostic.Severity == level ).Select(diagnostic => diagnostic.GetMessage()).ToArray());
147+
string[] actualMessages = diagnostics.Where(diagnostic => diagnostic.Severity == level).Select(diagnostic => diagnostic.GetMessage()).ToArray();
148+
149+
// Can't depending on reflection order when generating type metadata.
150+
Array.Sort(actualMessages);
151+
Array.Sort(expectedMessages);
152+
153+
Assert.Equal(expectedMessages, actualMessages);
142154
}
143155
}
144156
}

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs

+12-11
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public void UsePrivates()
5757
CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());
5858

5959
// Check base functionality of found types.
60-
Assert.Equal(1, generator.FoundTypes.Count);
61-
Type myType = generator.FoundTypes["HelloWorld.MyType"];
60+
Assert.Equal(1, generator.SerializableTypes.Count);
61+
Type myType = generator.SerializableTypes["HelloWorld.MyType"];
6262
Assert.Equal("HelloWorld.MyType", myType.FullName);
6363

6464
// Check for received fields, properties and methods in created type.
@@ -123,9 +123,9 @@ public void UsePrivates()
123123
CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());
124124

125125
// Check base functionality of found types.
126-
Assert.Equal(2, generator.FoundTypes.Count);
127-
Type myType = generator.FoundTypes["HelloWorld.MyType"];
128-
Type notMyType = generator.FoundTypes["ReferencedAssembly.Location"];
126+
Assert.Equal(2, generator.SerializableTypes.Count);
127+
Type myType = generator.SerializableTypes["HelloWorld.MyType"];
128+
Type notMyType = generator.SerializableTypes["ReferencedAssembly.Location"];
129129

130130
// Check for MyType.
131131
Assert.Equal("HelloWorld.MyType", myType.FullName);
@@ -205,10 +205,10 @@ public void UsePrivates()
205205
CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());
206206

207207
// Check base functionality of found types.
208-
Assert.Equal(2, generator.FoundTypes.Count);
208+
Assert.Equal(2, generator.SerializableTypes.Count);
209209

210210
// Check for MyType.
211-
Assert.Equal("HelloWorld.MyType", generator.FoundTypes["HelloWorld.MyType"].FullName);
211+
Assert.Equal("HelloWorld.MyType", generator.SerializableTypes["HelloWorld.MyType"].FullName);
212212

213213
// Check for received fields, properties and methods for MyType.
214214
string[] expectedFieldNamesMyType = { "PublicChar", "PublicDouble" };
@@ -217,7 +217,7 @@ public void UsePrivates()
217217
CheckFieldsPropertiesMethods("HelloWorld.MyType", ref generator, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType);
218218

219219
// Check for NotMyType.
220-
Assert.Equal("ReferencedAssembly.Location", generator.FoundTypes["ReferencedAssembly.Location"].FullName);
220+
Assert.Equal("ReferencedAssembly.Location", generator.SerializableTypes["ReferencedAssembly.Location"].FullName);
221221

222222
// Check for received fields, properties and methods for NotMyType.
223223
string[] expectedFieldNamesNotMyType = { };
@@ -284,6 +284,7 @@ public class WeatherForecastWithPOCOs
284284
Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);
285285

286286
// Make sure compilation was successful.
287+
287288
CheckCompilationDiagnosticsErrors(generatorDiags);
288289
CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());
289290
}
@@ -295,9 +296,9 @@ private void CheckCompilationDiagnosticsErrors(ImmutableArray<Diagnostic> diagno
295296

296297
private void CheckFieldsPropertiesMethods(string typeName, ref JsonSourceGenerator generator, string[] expectedFields, string[] expectedProperties, string[] expectedMethods)
297298
{
298-
string[] receivedFields = generator.FoundTypes[typeName].GetFields().Select(field => field.Name).OrderBy(s => s).ToArray();
299-
string[] receivedProperties = generator.FoundTypes[typeName].GetProperties().Select(property => property.Name).OrderBy(s => s).ToArray();
300-
string[] receivedMethods = generator.FoundTypes[typeName].GetMethods().Select(method => method.Name).OrderBy(s => s).ToArray();
299+
string[] receivedFields = generator.SerializableTypes[typeName].GetFields().Select(field => field.Name).OrderBy(s => s).ToArray();
300+
string[] receivedProperties = generator.SerializableTypes[typeName].GetProperties().Select(property => property.Name).OrderBy(s => s).ToArray();
301+
string[] receivedMethods = generator.SerializableTypes[typeName].GetMethods().Select(method => method.Name).OrderBy(s => s).ToArray();
301302

302303
Assert.Equal(expectedFields, receivedFields);
303304
Assert.Equal(expectedProperties, receivedProperties);

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkCurrent)</TargetFrameworks>
4+
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
45
</PropertyGroup>
56

67
<ItemGroup>

‎src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/TypeWrapperTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public void MySecondMethod() { }
7272
Assert.Empty(newCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error)));
7373

7474
// Should find both types since compilation above was successful.
75-
Assert.Equal(2, generator.FoundTypes.Count);
75+
Assert.Equal(2, generator.SerializableTypes.Count);
7676
}
7777

7878
[Fact]
@@ -129,8 +129,8 @@ public void MySecondMethod() { }
129129
Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray<Diagnostic> generatorDiags, generator);
130130

131131
// Check base functionality of found types.
132-
Assert.Equal(1, generator.FoundTypes.Count);
133-
Type foundType = generator.FoundTypes.First().Value;
132+
Assert.Equal(1, generator.SerializableTypes.Count);
133+
Type foundType = generator.SerializableTypes.First().Value;
134134

135135
Assert.Equal("HelloWorld.MyType", foundType.FullName);
136136

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
7+
8+
namespace System.Text.Json.SourceGeneration
9+
{
10+
internal enum ClassType
11+
{
12+
TypeUnsupportedBySourceGen = 0,
13+
Object = 1,
14+
KnownType = 2,
15+
TypeWithCustomConverter = 3,
16+
Enumerable = 4,
17+
Dictionary = 5,
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
7+
8+
namespace System.Text.Json.SourceGeneration
9+
{
10+
internal enum CollectionType
11+
{
12+
NotApplicable = 0,
13+
Array = 1,
14+
List = 2,
15+
IEnumerable = 3,
16+
Dictionary = 4
17+
}
18+
}

0 commit comments

Comments
 (0)
Please sign in to comment.