Skip to content

Commit af32f59

Browse files
rainsxngdariusclayRussKie
authored
Additional tests to the logging generator (#5704)
* TypeSymbolExtensions tests * Added explaining comment * Update test cases * Add tests for the IConvertable and ISpanFormattable interfaces * Attempt to test the special types * Check special types * HasCustomToString tests * Extra InlineData for the tests * GetPossiblyNullWrappedType tests * Fixed a typo * Simplify HasCustomToString tests * Updated test cases * Fix lint * Removed extra method override from the tests --------- Co-authored-by: Darius Letterman <[email protected]> Co-authored-by: Igor Velikorossov <[email protected]>
1 parent a23a7a9 commit af32f59

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
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 Microsoft.CodeAnalysis;
7+
using Microsoft.Gen.Logging.Parsing;
8+
using Xunit;
9+
10+
namespace Microsoft.Gen.Logging.Test;
11+
12+
public class TypeSymbolExtensionsTests
13+
{
14+
private readonly Action<DiagnosticDescriptor, Location?, object
15+
?[]?> _diagCallback = (_, __, ___) => { };
16+
17+
[Theory]
18+
[InlineData("TestEnumerableInt : List<int>", "TestEnumerableInt", true)]
19+
[InlineData("TestEnumerable<T> : List<T>", "TestEnumerable<object>", true)]
20+
[InlineData("NotUsed", "IEnumerable<string>", true)]
21+
[InlineData("TestClass", "NonEnumerable", false)]
22+
[InlineData("TestClassDerived : NonEnumerable", "TestClassDerived", false)]
23+
[InlineData("NotUsed", "bool", false)]
24+
public void ValidateIsEnumerable(string classDefinition, string typeReference, bool expectedResult)
25+
{
26+
// Generate the code
27+
string source = $@"
28+
namespace Test
29+
{{
30+
using System.Collections.Generic;
31+
using Microsoft.Extensions.Logging;
32+
33+
class {classDefinition} {{ }}
34+
35+
class NonEnumerable {{ }}
36+
37+
partial class C
38+
{{
39+
[LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
40+
static partial void M1(ILogger logger, {typeReference} property);
41+
}}
42+
}}";
43+
44+
// Create compilation and extract symbols
45+
Compilation compilation = CompilationHelper.CreateCompilation(source);
46+
SymbolHolder? symbolHolder = SymbolLoader.LoadSymbols(compilation, _diagCallback);
47+
48+
IEnumerable<ISymbol> methodSymbols = compilation.GetSymbolsWithName("M1", SymbolFilter.Member);
49+
50+
// Assert
51+
Assert.NotNull(symbolHolder);
52+
ISymbol symbol = Assert.Single(methodSymbols);
53+
var methodSymbol = Assert.IsAssignableFrom<IMethodSymbol>(symbol);
54+
var parameterSymbol = Assert.Single(methodSymbol.Parameters, p => p.Name == "property");
55+
56+
Assert.Equal(expectedResult, parameterSymbol.Type.IsEnumerable(symbolHolder));
57+
}
58+
59+
[Theory]
60+
[InlineData("TestFormattable", "TestFormattable", true)]
61+
[InlineData("TestFormattable : IFormattable", "TestFormattable", true)]
62+
[InlineData("TestFormattable", "NonFormattable", false)]
63+
public void ValidateImplementsIFormattable(string classDefinition, string typeReference, bool expectedResult)
64+
{
65+
// Generate the code
66+
string source = $@"
67+
namespace Test
68+
{{
69+
using System;
70+
using Microsoft.Extensions.Logging;
71+
72+
class {classDefinition}
73+
{{
74+
public string ToString(string? format, IFormatProvider? formatProvider)
75+
{{
76+
throw new NotImplementedException();
77+
}}
78+
}}
79+
80+
class NonFormattable {{ }}
81+
82+
partial class C
83+
{{
84+
[LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
85+
static partial void M1(ILogger logger, {typeReference} property);
86+
}}
87+
}}";
88+
89+
// Create compilation and extract symbols
90+
Compilation compilation = CompilationHelper.CreateCompilation(source);
91+
SymbolHolder? symbolHolder = SymbolLoader.LoadSymbols(compilation, _diagCallback);
92+
IEnumerable<ISymbol> methodSymbols = compilation.GetSymbolsWithName("M1", SymbolFilter.Member);
93+
94+
// Assert
95+
Assert.NotNull(symbolHolder);
96+
ISymbol symbol = Assert.Single(methodSymbols);
97+
var methodSymbol = Assert.IsAssignableFrom<IMethodSymbol>(symbol);
98+
var parameterSymbol = Assert.Single(methodSymbol.Parameters, p => p.Name == "property");
99+
100+
Assert.Equal(expectedResult, parameterSymbol.Type.ImplementsIFormattable(symbolHolder));
101+
}
102+
103+
[Theory]
104+
[InlineData("TestConvertible", "TestConvertible", true)]
105+
[InlineData("TestConvertible : IConvertible", "TestConvertible", true)]
106+
[InlineData("TestConvertible", "NonConvertible", false)]
107+
public void ValidateImplementsIConvertible(string classDefinition, string typeReference, bool expectedResult)
108+
{
109+
// Generate the code
110+
string source = $@"
111+
namespace Test
112+
{{
113+
using System;
114+
using Microsoft.Extensions.Logging;
115+
116+
class {classDefinition}
117+
{{
118+
public string ToString(IFormatProvider? formatProvider)
119+
{{
120+
throw new NotImplementedException();
121+
}}
122+
}}
123+
124+
class NonConvertible {{ }}
125+
126+
partial class C
127+
{{
128+
[LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
129+
static partial void M1(ILogger logger, {typeReference} property);
130+
}}
131+
}}";
132+
133+
// Create compilation and extract symbols
134+
Compilation compilation = CompilationHelper.CreateCompilation(source);
135+
SymbolHolder? symbolHolder = SymbolLoader.LoadSymbols(compilation, _diagCallback);
136+
IEnumerable<ISymbol> methodSymbols = compilation.GetSymbolsWithName("M1", SymbolFilter.Member);
137+
138+
// Assert
139+
Assert.NotNull(symbolHolder);
140+
ISymbol symbol = Assert.Single(methodSymbols);
141+
var methodSymbol = Assert.IsAssignableFrom<IMethodSymbol>(symbol);
142+
var parameterSymbol = Assert.Single(methodSymbol.Parameters, p => p.Name == "property");
143+
144+
Assert.Equal(expectedResult, parameterSymbol.Type.ImplementsIConvertible(symbolHolder));
145+
}
146+
147+
[Theory]
148+
[InlineData("TestISpanFormattable : ISpanFormattable", "TestISpanFormattable", true)]
149+
[InlineData("TestISpanFormattable", "NonConvertible", false)]
150+
public void ValidateImplementsISpanFormattable(string classDefinition, string typeReference, bool expectedResult)
151+
{
152+
// Generate the code
153+
string source = $@"
154+
namespace Test
155+
{{
156+
using System;
157+
using Microsoft.Extensions.Logging;
158+
159+
class {classDefinition}
160+
{{
161+
public string ToString(string? format, IFormatProvider? formatProvider)
162+
{{
163+
throw new NotImplementedException();
164+
}}
165+
166+
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
167+
{{
168+
throw new NotImplementedException();
169+
}}
170+
}}
171+
172+
class NonSpanFormattable {{ }}
173+
174+
partial class C
175+
{{
176+
[LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
177+
static partial void M1(ILogger logger, {typeReference} property);
178+
}}
179+
}}";
180+
181+
// Create compilation and extract symbols
182+
Compilation compilation = CompilationHelper.CreateCompilation(source);
183+
SymbolHolder? symbolHolder = SymbolLoader.LoadSymbols(compilation, _diagCallback);
184+
IEnumerable<ISymbol> methodSymbols = compilation.GetSymbolsWithName("M1", SymbolFilter.Member);
185+
186+
// Assert
187+
Assert.NotNull(symbolHolder);
188+
ISymbol symbol = Assert.Single(methodSymbols);
189+
var methodSymbol = Assert.IsAssignableFrom<IMethodSymbol>(symbol);
190+
var parameterSymbol = Assert.Single(methodSymbol.Parameters, p => p.Name == "property");
191+
192+
Assert.Equal(expectedResult, parameterSymbol.Type.ImplementsISpanFormattable(symbolHolder));
193+
}
194+
195+
[Theory]
196+
[InlineData("string", true)]
197+
[InlineData("bool", true)]
198+
[InlineData("int", true)]
199+
[InlineData("NonSpecialType", false)]
200+
[InlineData("TestClassDerived", false)]
201+
[InlineData("TimeSpan", false)]
202+
[InlineData("Uri", false)]
203+
public void ValidateIsSpecialType(string typeReference, bool expectedResult)
204+
{
205+
// Generate the code
206+
string source = $@"
207+
namespace Test
208+
{{
209+
using System.Collections.Generic;
210+
using Microsoft.Extensions.Logging;
211+
212+
class NonSpecialType {{ }}
213+
214+
class TestClassDerived: NonSpecialType {{ }}
215+
216+
partial class C
217+
{{
218+
[LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
219+
static partial void M1(ILogger logger, {typeReference} property);
220+
}}
221+
}}";
222+
223+
// Create compilation and extract symbols
224+
Compilation compilation = CompilationHelper.CreateCompilation(source);
225+
SymbolHolder? symbolHolder = SymbolLoader.LoadSymbols(compilation, _diagCallback);
226+
227+
IEnumerable<ISymbol> methodSymbols = compilation.GetSymbolsWithName("M1", SymbolFilter.Member);
228+
229+
// Assert
230+
Assert.NotNull(symbolHolder);
231+
ISymbol symbol = Assert.Single(methodSymbols);
232+
var methodSymbol = Assert.IsAssignableFrom<IMethodSymbol>(symbol);
233+
var parameterSymbol = Assert.Single(methodSymbol.Parameters, p => p.Name == "property");
234+
235+
Assert.Equal(expectedResult, parameterSymbol.Type.IsSpecialType(symbolHolder));
236+
}
237+
238+
[Theory]
239+
[InlineData("ToString", true)]
240+
[InlineData("RandomMethod", false)]
241+
[InlineData("ToooooString", false)]
242+
public void ValidateHasCustomToString(string methodName, bool expectedResult)
243+
{
244+
// Generate the code
245+
string source = $@"
246+
namespace Test
247+
{{
248+
using System;
249+
using Microsoft.Extensions.Logging;
250+
251+
class Test
252+
{{
253+
public override string {methodName}()
254+
{{
255+
throw new NotImplementedException();
256+
}}
257+
}}
258+
259+
class NonConvertible {{ }}
260+
261+
partial class C
262+
{{
263+
[LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
264+
static partial void M1(ILogger logger, Test property);
265+
}}
266+
}}";
267+
268+
// Create compilation and extract symbols
269+
Compilation compilation = CompilationHelper.CreateCompilation(source);
270+
SymbolHolder? symbolHolder = SymbolLoader.LoadSymbols(compilation, _diagCallback);
271+
IEnumerable<ISymbol> methodSymbols = compilation.GetSymbolsWithName("M1", SymbolFilter.Member);
272+
273+
// Assert
274+
Assert.NotNull(symbolHolder);
275+
ISymbol symbol = Assert.Single(methodSymbols);
276+
var methodSymbol = Assert.IsAssignableFrom<IMethodSymbol>(symbol);
277+
var parameterSymbol = Assert.Single(methodSymbol.Parameters, p => p.Name == "property");
278+
279+
Assert.Equal(expectedResult, parameterSymbol.Type.HasCustomToString());
280+
}
281+
282+
[Fact]
283+
public void GetPossiblyNullWrappedType_NullableT_ReturnsT()
284+
{
285+
Compilation compilation = CompilationHelper.CreateCompilation("public class TestClass { }");
286+
INamedTypeSymbol nullableType = compilation.GetSpecialType(SpecialType.System_Nullable_T);
287+
INamedTypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
288+
INamedTypeSymbol nullableIntType = nullableType.Construct(intType);
289+
var result = nullableIntType.GetPossiblyNullWrappedType();
290+
Assert.Equal(intType, result);
291+
}
292+
293+
[Fact]
294+
public void GetPossiblyNullWrappedType_ListT_ReturnsListT()
295+
{
296+
Compilation compilation = CompilationHelper.CreateCompilation("using System.Collections.Generic; public class TestClass { }");
297+
INamedTypeSymbol listType = compilation.GetTypeByMetadataName("System.Collections.Generic.List`1")!;
298+
INamedTypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
299+
INamedTypeSymbol listIntType = listType.Construct(intType);
300+
var result = listIntType.GetPossiblyNullWrappedType();
301+
Assert.Equal(listIntType, result);
302+
}
303+
304+
[Fact]
305+
public void GetPossiblyNullWrappedType_T_ReturnsT()
306+
{
307+
Compilation compilation = CompilationHelper.CreateCompilation("public class TestClass { }");
308+
INamedTypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
309+
var result = intType.GetPossiblyNullWrappedType();
310+
Assert.Equal(intType, result);
311+
}
312+
}

0 commit comments

Comments
 (0)