Skip to content

Commit 09e30c9

Browse files
authored
Updated to NLog v5.2 with RegisterWindowsForms (#141)
1 parent 5c41a46 commit 09e30c9

File tree

7 files changed

+456
-23
lines changed

7 files changed

+456
-23
lines changed
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
namespace NLog.Windows.Forms.Tests
2+
{
3+
using System;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Collections.Generic;
7+
using System.Reflection;
8+
using NLog.Config;
9+
using NLog.LayoutRenderers;
10+
using Xunit;
11+
12+
/// <summary>
13+
/// Test the characteristics of the API. Config of the API is tested in <see cref="NLog.UnitTests.Config.ConfigApiTests"/>
14+
/// </summary>
15+
public class ApiTests
16+
{
17+
private readonly Type[] allTypes;
18+
private readonly Assembly nlogExtensionAssembly = typeof(RichTextBoxTarget).Assembly;
19+
private readonly Dictionary<Type, int> typeUsageCount = new Dictionary<Type, int>();
20+
21+
public ApiTests()
22+
{
23+
allTypes = nlogExtensionAssembly.GetTypes();
24+
}
25+
26+
[Fact]
27+
public void PublicEnumsTest()
28+
{
29+
foreach (Type type in allTypes)
30+
{
31+
if (!type.IsPublic)
32+
{
33+
continue;
34+
}
35+
36+
if (type.IsEnum || type.IsInterface)
37+
{
38+
typeUsageCount[type] = 0;
39+
}
40+
}
41+
42+
typeUsageCount[typeof(IInstallable)] = 1;
43+
44+
foreach (Type type in allTypes)
45+
{
46+
if (type.IsGenericTypeDefinition)
47+
{
48+
continue;
49+
}
50+
51+
if (type.BaseType != null)
52+
{
53+
IncrementUsageCount(type.BaseType);
54+
}
55+
56+
foreach (var iface in type.GetInterfaces())
57+
{
58+
IncrementUsageCount(iface);
59+
}
60+
61+
foreach (var method in type.GetMethods())
62+
{
63+
if (method.IsGenericMethodDefinition)
64+
{
65+
continue;
66+
}
67+
68+
// Console.WriteLine(" {0}", method.Name);
69+
try
70+
{
71+
IncrementUsageCount(method.ReturnType);
72+
73+
foreach (var p in method.GetParameters())
74+
{
75+
IncrementUsageCount(p.ParameterType);
76+
}
77+
}
78+
catch (Exception ex)
79+
{
80+
// this sometimes throws on .NET Compact Framework, but is not fatal
81+
Console.WriteLine("EXCEPTION {0}", ex);
82+
}
83+
}
84+
}
85+
86+
var unusedTypes = new List<Type>();
87+
StringBuilder sb = new StringBuilder();
88+
89+
foreach (var kvp in typeUsageCount)
90+
{
91+
if (kvp.Value == 0)
92+
{
93+
Console.WriteLine("Type '{0}' is not used.", kvp.Key);
94+
unusedTypes.Add(kvp.Key);
95+
sb.Append(kvp.Key.FullName).Append("\n");
96+
}
97+
}
98+
99+
Assert.Empty(unusedTypes);
100+
}
101+
102+
private void IncrementUsageCount(Type type)
103+
{
104+
if (type.IsArray)
105+
{
106+
type = type.GetElementType();
107+
}
108+
109+
if (type.IsGenericType && !type.IsGenericTypeDefinition)
110+
{
111+
IncrementUsageCount(type.GetGenericTypeDefinition());
112+
foreach (var parm in type.GetGenericArguments())
113+
{
114+
IncrementUsageCount(parm);
115+
}
116+
return;
117+
}
118+
119+
if (type.Assembly != nlogExtensionAssembly)
120+
{
121+
return;
122+
}
123+
124+
if (typeUsageCount.ContainsKey(type))
125+
{
126+
typeUsageCount[type]++;
127+
}
128+
}
129+
130+
[Fact]
131+
public void TypesInInternalNamespaceShouldBeInternalTest()
132+
{
133+
var notInternalTypes = allTypes
134+
.Where(t => t.Namespace != null && t.Namespace.Contains(".Internal"))
135+
.Where(t => !t.IsNested && (t.IsVisible || t.IsPublic))
136+
.Select(t => t.FullName)
137+
.ToList();
138+
139+
Assert.Empty(notInternalTypes);
140+
}
141+
142+
[Fact]
143+
public void AppDomainFixedOutput_Attribute_EnsureThreadAgnostic()
144+
{
145+
foreach (Type type in allTypes)
146+
{
147+
var appDomainFixedOutputAttribute = type.GetCustomAttribute<AppDomainFixedOutputAttribute>();
148+
if (appDomainFixedOutputAttribute != null)
149+
{
150+
var threadAgnosticAttribute = type.GetCustomAttribute<ThreadAgnosticAttribute>();
151+
Assert.True(!(threadAgnosticAttribute is null), $"{type.ToString()} is missing [ThreadAgnostic] attribute");
152+
}
153+
}
154+
}
155+
156+
[Fact]
157+
public void WrapperLayoutRenderer_EnsureThreadAgnostic()
158+
{
159+
foreach (Type type in allTypes)
160+
{
161+
if (typeof(NLog.LayoutRenderers.Wrappers.WrapperLayoutRendererBase).IsAssignableFrom(type))
162+
{
163+
if (type.IsAbstract || !type.IsPublic)
164+
continue; // skip non-concrete types, enumerations, and private nested types
165+
166+
Assert.True(type.IsDefined(typeof(ThreadAgnosticAttribute), true), $"{type.ToString()} is missing [ThreadAgnostic] attribute.");
167+
}
168+
}
169+
}
170+
171+
[Fact]
172+
public void RequiredConfigOptionMustBeClass()
173+
{
174+
foreach (Type type in allTypes)
175+
{
176+
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
177+
foreach (var prop in properties)
178+
{
179+
var requiredParameter = prop.GetCustomAttribute<NLog.Config.RequiredParameterAttribute>();
180+
if (requiredParameter != null)
181+
{
182+
Assert.True(prop.PropertyType.IsClass, prop.Name);
183+
}
184+
}
185+
}
186+
}
187+
188+
[Fact]
189+
public void SingleDefaultConfigOption()
190+
{
191+
string prevDefaultPropertyName = null;
192+
193+
foreach (Type type in allTypes)
194+
{
195+
prevDefaultPropertyName = null;
196+
197+
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
198+
foreach (var prop in properties)
199+
{
200+
var defaultParameter = prop.GetCustomAttribute<DefaultParameterAttribute>();
201+
if (defaultParameter != null)
202+
{
203+
Assert.True(prevDefaultPropertyName == null, prevDefaultPropertyName?.ToString());
204+
prevDefaultPropertyName = prop.Name;
205+
Assert.True(type.IsSubclassOf(typeof(NLog.LayoutRenderers.LayoutRenderer)), type.ToString());
206+
}
207+
}
208+
}
209+
}
210+
211+
[Fact]
212+
public void ValidateLayoutRendererTypeAlias()
213+
{
214+
// These class-names should be repaired with next major version bump
215+
// Do NOT add more incorrect class-names to this exlusion-list
216+
HashSet<string> oldFaultyClassNames = new HashSet<string>()
217+
{
218+
"RichTextBoxLinkLayoutRenderer",
219+
};
220+
foreach (Type type in allTypes)
221+
{
222+
if (type.IsSubclassOf(typeof(LayoutRenderer)))
223+
{
224+
var layoutRendererAttributes = type.GetCustomAttributes<LayoutRendererAttribute>()?.ToArray() ?? new LayoutRendererAttribute[0];
225+
if (layoutRendererAttributes.Length == 0)
226+
{
227+
Assert.True(type.IsAbstract, $"{type} without LayoutRendererAttribute must be abstract");
228+
}
229+
else
230+
{
231+
Assert.False(type.IsAbstract, $"{type} with LayoutRendererAttribute cannot be abstract");
232+
233+
if (!oldFaultyClassNames.Contains(type.Name))
234+
{
235+
var typeAlias = layoutRendererAttributes.First().Name.Replace("-", "");
236+
Assert.Equal(typeAlias + "LayoutRenderer", type.Name, StringComparer.OrdinalIgnoreCase);
237+
}
238+
}
239+
240+
Assert.Equal("NLog.Windows.Forms", type.Namespace);
241+
}
242+
}
243+
}
244+
245+
[Fact]
246+
public void ValidateConfigurationItemFactory()
247+
{
248+
ConfigurationItemFactory.Default = null; // Reset
249+
250+
LogManager.Setup().SetupExtensions(ext => ext.RegisterWindowsForms());
251+
252+
var missingTypes = new List<string>();
253+
254+
foreach (Type type in allTypes)
255+
{
256+
if (!type.IsPublic || !type.IsClass || type.IsAbstract)
257+
continue;
258+
259+
if (typeof(NLog.Targets.Target).IsAssignableFrom(type))
260+
{
261+
var configAttribs = type.GetCustomAttributes<NLog.Targets.TargetAttribute>(false);
262+
Assert.NotEmpty(configAttribs);
263+
264+
foreach (var configName in configAttribs)
265+
{
266+
if (!ConfigurationItemFactory.Default.TargetFactory.TryCreateInstance(configName.Name, out var target))
267+
{
268+
Console.WriteLine(configName.Name);
269+
missingTypes.Add(configName.Name);
270+
}
271+
else if (type != target.GetType())
272+
{
273+
Console.WriteLine(type.Name);
274+
missingTypes.Add(type.Name);
275+
}
276+
}
277+
}
278+
else if (typeof(NLog.Layouts.Layout).IsAssignableFrom(type))
279+
{
280+
var configAttribs = type.GetCustomAttributes<NLog.Layouts.LayoutAttribute>(false);
281+
Assert.NotEmpty(configAttribs);
282+
283+
foreach (var configName in configAttribs)
284+
{
285+
if (!ConfigurationItemFactory.Default.LayoutFactory.TryCreateInstance(configName.Name, out var layout))
286+
{
287+
Console.WriteLine(configName.Name);
288+
missingTypes.Add(configName.Name);
289+
}
290+
else if (type != layout.GetType())
291+
{
292+
Console.WriteLine(type.Name);
293+
missingTypes.Add(type.Name);
294+
}
295+
}
296+
}
297+
else if (typeof(NLog.LayoutRenderers.LayoutRenderer).IsAssignableFrom(type))
298+
{
299+
var configAttribs = type.GetCustomAttributes<NLog.LayoutRenderers.LayoutRendererAttribute>(false);
300+
Assert.NotEmpty(configAttribs);
301+
302+
foreach (var configName in configAttribs)
303+
{
304+
if (!ConfigurationItemFactory.Default.LayoutRendererFactory.TryCreateInstance(configName.Name, out var layoutRenderer))
305+
{
306+
Console.WriteLine(configName.Name);
307+
missingTypes.Add(configName.Name);
308+
}
309+
else if (type != layoutRenderer.GetType())
310+
{
311+
Console.WriteLine(type.Name);
312+
missingTypes.Add(type.Name);
313+
}
314+
}
315+
316+
if (typeof(NLog.LayoutRenderers.Wrappers.WrapperLayoutRendererBase).IsAssignableFrom(type))
317+
{
318+
var wrapperAttribs = type.GetCustomAttributes<NLog.LayoutRenderers.AmbientPropertyAttribute>(false);
319+
if (wrapperAttribs?.Any() == true)
320+
{
321+
foreach (var ambientName in wrapperAttribs)
322+
{
323+
if (!ConfigurationItemFactory.Default.AmbientRendererFactory.TryCreateInstance(ambientName.Name, out var layoutRenderer))
324+
{
325+
Console.WriteLine(ambientName.Name);
326+
missingTypes.Add(ambientName.Name);
327+
}
328+
else if (type != layoutRenderer.GetType())
329+
{
330+
Console.WriteLine(type.Name);
331+
missingTypes.Add(type.Name);
332+
}
333+
}
334+
}
335+
}
336+
}
337+
}
338+
339+
Assert.Empty(missingTypes);
340+
}
341+
}
342+
}

0 commit comments

Comments
 (0)