Skip to content

Commit fb38d9b

Browse files
committed
Merge branch 'maintenance/code-analysis' into develop
In centralizing the common properties, we introduced both nullability context and code analysis to the unit test and `Host` projects. These previously didn't include these properties. This isn't strictly necessary, but helps us maintain consistent code and best practices. It also helps better expose potential issues in our nullability context early on when writing tests. This obviously exposed a lot of code analysis warnings, necessitating updating these projects to ensure they're both annotated for nullability and also adhering to consistent coding conventions.
2 parents 172feed + 16c5668 commit fb38d9b

10 files changed

Lines changed: 107 additions & 48 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*==============================================================================================================================
2+
| Author Ignia, LLC
3+
| Client Ignia, LLC
4+
| Project Topics Library
5+
\=============================================================================================================================*/
6+
using System;
7+
using System.Runtime.InteropServices;
8+
9+
/*==============================================================================================================================
10+
| DEFINE ASSEMBLY ATTRIBUTES
11+
>===============================================================================================================================
12+
| Declare and define attributes used in the compiling of the finished assembly.
13+
\-----------------------------------------------------------------------------------------------------------------------------*/
14+
[assembly: ComVisible(false)]
15+
[assembly: CLSCompliant(false)]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*==============================================================================================================================
2+
| Author Ignia, LLC
3+
| Client Ignia, LLC
4+
| Project Topics Library
5+
\=============================================================================================================================*/
6+
using System;
7+
using System.Runtime.InteropServices;
8+
9+
/*==============================================================================================================================
10+
| DEFINE ASSEMBLY ATTRIBUTES
11+
>===============================================================================================================================
12+
| Declare and define attributes used in the compiling of the finished assembly.
13+
\-----------------------------------------------------------------------------------------------------------------------------*/
14+
[assembly: ComVisible(false)]
15+
[assembly: CLSCompliant(false)]

OnTopic.AspNetCore.Mvc.Host/SampleActivator.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using OnTopic.AspNetCore.Mvc.Host.Components;
1212
using OnTopic.Data.Caching;
1313
using OnTopic.Data.Sql;
14+
using OnTopic.Internal.Diagnostics;
1415
using OnTopic.Lookup;
1516
using OnTopic.Mapping;
1617
using OnTopic.Mapping.Hierarchical;
@@ -31,15 +32,15 @@ public class SampleActivator : IControllerActivator, IViewComponentActivator {
3132
/*==========================================================================================================================
3233
| PRIVATE INSTANCES
3334
\-------------------------------------------------------------------------------------------------------------------------*/
34-
private readonly ITypeLookupService _typeLookupService = null;
35-
private readonly ITopicMappingService _topicMappingService = null;
36-
private readonly ITopicRepository _topicRepository = null;
35+
private readonly ITypeLookupService _typeLookupService;
36+
private readonly ITopicMappingService _topicMappingService;
37+
private readonly ITopicRepository _topicRepository;
3738
private DateTime _cacheLastUpdated = DateTime.UtcNow;
3839

3940
/*==========================================================================================================================
4041
| HIERARCHICAL TOPIC MAPPING SERVICE
4142
\-------------------------------------------------------------------------------------------------------------------------*/
42-
private readonly IHierarchicalTopicMappingService<NavigationTopicViewModel> _hierarchicalMappingService = null;
43+
private readonly IHierarchicalTopicMappingService<NavigationTopicViewModel> _hierarchicalMappingService;
4344

4445
/*==========================================================================================================================
4546
| CONSTRUCTOR
@@ -90,6 +91,11 @@ public SampleActivator(string connectionString) {
9091
/// <returns>A concrete instance of an <see cref="IController"/>.</returns>
9192
public object Create(ControllerContext context) {
9293

94+
/*------------------------------------------------------------------------------------------------------------------------
95+
| Validate parameters
96+
\-----------------------------------------------------------------------------------------------------------------------*/
97+
Contract.Requires(context, nameof(context));
98+
9399
/*------------------------------------------------------------------------------------------------------------------------
94100
| Determine controller type
95101
\-----------------------------------------------------------------------------------------------------------------------*/
@@ -100,7 +106,7 @@ public object Create(ControllerContext context) {
100106
\-----------------------------------------------------------------------------------------------------------------------*/
101107
if (DateTime.UtcNow > _cacheLastUpdated.AddMinutes(1)) {
102108
var currentUpdate = DateTime.UtcNow;
103-
_topicRepository.Refresh(_topicRepository.Load(), _cacheLastUpdated);
109+
_topicRepository.Refresh(_topicRepository.Load()!, _cacheLastUpdated);
104110
_cacheLastUpdated = currentUpdate;
105111
}
106112

@@ -125,6 +131,11 @@ public object Create(ControllerContext context) {
125131
/// <returns>A concrete instance of an <see cref="IController"/>.</returns>
126132
public object Create(ViewComponentContext context) {
127133

134+
/*------------------------------------------------------------------------------------------------------------------------
135+
| Validate parameters
136+
\-----------------------------------------------------------------------------------------------------------------------*/
137+
Contract.Requires(context, nameof(context));
138+
128139
/*------------------------------------------------------------------------------------------------------------------------
129140
| Determine view component type
130141
\-----------------------------------------------------------------------------------------------------------------------*/

OnTopic.AspNetCore.Mvc.Host/Views/Shared/Components/Menu/Default.cshtml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<h2>Menu</h2>
44
<nav id="PrimaryNavigationSmallScreen" role="navigation" vocab="http://schema.org" typeof="SiteNavigationElement">
55
<ul>
6-
@foreach (var topic in Model.NavigationRoot.Children) {
6+
@foreach (var topic in Model.NavigationRoot!.Children) {
77
@WriteMenu(topic);
88
}
99
</ul>
@@ -12,7 +12,7 @@
1212

1313
@{
1414

15-
IHtmlContent Body(Func<object, IHtmlContent> body) => body(null);
15+
IHtmlContent Body(Func<object?, IHtmlContent> body) => body(null);
1616

1717
IHtmlContent WriteMenu(NavigationTopicViewModel topic, int indentLevel = 1) => Body(
1818

OnTopic.AspNetCore.Mvc.Tests/OnTopic.AspNetCore.Mvc.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<TargetFrameworks>net5.0</TargetFrameworks>
55
<IsPackable>false</IsPackable>
6+
<NoWarn>CA1707</NoWarn>
67
</PropertyGroup>
78

89
<ItemGroup>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*==============================================================================================================================
2+
| Author Ignia, LLC
3+
| Client Ignia, LLC
4+
| Project Topics Library
5+
\=============================================================================================================================*/
6+
using System;
7+
using System.Runtime.InteropServices;
8+
9+
/*==============================================================================================================================
10+
| DEFINE ASSEMBLY ATTRIBUTES
11+
>===============================================================================================================================
12+
| Declare and define attributes used in the compiling of the finished assembly.
13+
\-----------------------------------------------------------------------------------------------------------------------------*/
14+
[assembly: ComVisible(false)]
15+
[assembly: CLSCompliant(false)]

OnTopic.AspNetCore.Mvc.Tests/TopicControllerTest.cs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ public async Task TopicController_IndexAsync_ReturnsTopicViewResult() {
9191
};
9292

9393
var result = await controller.IndexAsync(_topic.GetWebPath()).ConfigureAwait(false) as TopicViewResult;
94-
var model = result.Model as PageTopicViewModel;
94+
var model = result?.Model as PageTopicViewModel;
9595

9696
controller.Dispose();
9797

9898
Assert.IsNotNull(model);
99-
Assert.AreEqual<string>("Web_0_1_1", model.Title);
99+
Assert.AreEqual<string?>("Web_0_1_1", model?.Title);
100100

101101
}
102102

@@ -115,8 +115,8 @@ public void RedirectController_TopicRedirect_ReturnsRedirectResult() {
115115
controller.Dispose();
116116

117117
Assert.IsNotNull(result);
118-
Assert.IsTrue(result.Permanent);
119-
Assert.AreEqual<string>("/Web/Web_1/Web_1_1/Web_1_1_1/", result.Url);
118+
Assert.IsTrue(result?.Permanent?? false);
119+
Assert.AreEqual<string?>("/Web/Web_1/Web_1_1/Web_1_1_1/", result?.Url);
120120

121121
}
122122

@@ -138,13 +138,13 @@ public void SitemapController_Index_ReturnsSitemapXml() {
138138
ControllerContext = new(actionContext)
139139
};
140140
var result = controller.Index() as ContentResult;
141-
var model = result.Content as string;
141+
var model = result?.Content as string;
142142

143143
controller.Dispose();
144144

145145
Assert.IsNotNull(model);
146-
Assert.IsTrue(model.StartsWith("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>"));
147-
Assert.IsTrue(model.Contains("/Web/Web_1/Web_1_1/Web_1_1_1/</loc>"));
146+
Assert.IsTrue(model!.StartsWith("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>", StringComparison.Ordinal));
147+
Assert.IsTrue(model!.Contains("/Web/Web_1/Web_1_1/Web_1_1_1/</loc>", StringComparison.Ordinal));
148148

149149
}
150150

@@ -177,20 +177,20 @@ public void SitemapController_Index_ExcludesContentTypes() {
177177
ControllerContext = new(actionContext)
178178
};
179179
var result = controller.Index(false, true) as ContentResult;
180-
var model = result.Content as string;
180+
var model = result?.Content as string;
181181

182182
controller.Dispose();
183183

184184
Assert.IsNotNull(model);
185-
Assert.IsTrue(model.Contains("<DataObject type=\"Attributes\">"));
186-
Assert.IsFalse(model.Contains("<DataObject type=\"List\">"));
187-
Assert.IsFalse(model.Contains("<DataObject type=\"Container\">"));
188-
Assert.IsFalse(model.Contains("<DataObject type=\"PageGroup\">"));
189-
Assert.IsTrue(model.Contains("/Web/Web_0/Web_0_0/Web_0_0_1/</loc>"));
190-
Assert.IsTrue(model.Contains("/Web/Web_1/Web_1_1/Web_1_1_0/</loc>"));
191-
Assert.IsFalse(model.Contains("/Web/Web_1/Web_1_0/Web_1_0_0/</loc>"));
192-
Assert.IsFalse(model.Contains("/Web/Web_1/Web_1_1/Web_1_1_1/</loc>"));
193-
Assert.IsFalse(model.Contains("/Web/Web_0/Web_0_0/</loc>"));
185+
Assert.IsTrue(model!.Contains("<DataObject type=\"Attributes\">", StringComparison.Ordinal));
186+
Assert.IsFalse(model!.Contains("<DataObject type=\"List\">", StringComparison.Ordinal));
187+
Assert.IsFalse(model!.Contains("<DataObject type=\"Container\">", StringComparison.Ordinal));
188+
Assert.IsFalse(model!.Contains("<DataObject type=\"PageGroup\">", StringComparison.Ordinal));
189+
Assert.IsTrue(model!.Contains("/Web/Web_0/Web_0_0/Web_0_0_1/</loc>", StringComparison.Ordinal));
190+
Assert.IsTrue(model!.Contains("/Web/Web_1/Web_1_1/Web_1_1_0/</loc>", StringComparison.Ordinal));
191+
Assert.IsFalse(model!.Contains("/Web/Web_1/Web_1_0/Web_1_0_0/</loc>", StringComparison.Ordinal));
192+
Assert.IsFalse(model!.Contains("/Web/Web_1/Web_1_1/Web_1_1_1/</loc>", StringComparison.Ordinal));
193+
Assert.IsFalse(model!.Contains("/Web/Web_0/Web_0_0/</loc>", StringComparison.Ordinal));
194194

195195
}
196196

@@ -220,15 +220,15 @@ public void SitemapController_Index_ExcludesAttributes() {
220220
ControllerContext = new(actionContext)
221221
};
222222
var result = controller.Index(false, true) as ContentResult;
223-
var model = result.Content as string;
223+
var model = result?.Content as string;
224224

225225
controller.Dispose();
226226

227227
Assert.IsNotNull(model);
228-
Assert.IsTrue(model.Contains("<Attribute name=\"Title\">"));
229-
Assert.IsTrue(model.Contains("<Attribute name=\"LastModified\">"));
230-
Assert.IsFalse(model.Contains("<Attribute name=\"Body\">"));
231-
Assert.IsFalse(model.Contains("<Attribute name=\"IsHidden\">"));
228+
Assert.IsTrue(model!.Contains("<Attribute name=\"Title\">", StringComparison.Ordinal));
229+
Assert.IsTrue(model!.Contains("<Attribute name=\"LastModified\">", StringComparison.Ordinal));
230+
Assert.IsFalse(model!.Contains("<Attribute name=\"Body\">", StringComparison.Ordinal));
231+
Assert.IsFalse(model!.Contains("<Attribute name=\"IsHidden\">", StringComparison.Ordinal));
232232

233233
}
234234

OnTopic.AspNetCore.Mvc.Tests/TopicRepositoryExtensionsTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void Load_ByRoute_ReturnsTopic() {
6161

6262
Assert.IsNotNull(currentTopic);
6363
Assert.ReferenceEquals(topic, currentTopic);
64-
Assert.AreEqual<string>("Web_0_1_1", currentTopic.Key);
64+
Assert.AreEqual<string?>("Web_0_1_1", currentTopic?.Key);
6565

6666
}
6767

@@ -83,7 +83,7 @@ public void Load_ByRoute_ReturnsRootTopic() {
8383

8484
Assert.IsNotNull(currentTopic);
8585
Assert.ReferenceEquals(topic, currentTopic);
86-
Assert.AreEqual<string>("Root", currentTopic.Key);
86+
Assert.AreEqual<string?>("Root", currentTopic?.Key);
8787

8888
}
8989

OnTopic.AspNetCore.Mvc.Tests/TopicViewComponentTest.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class TopicViewComponentTest {
4141
/*==========================================================================================================================
4242
| HIERARCHICAL TOPIC MAPPING SERVICE
4343
\-------------------------------------------------------------------------------------------------------------------------*/
44-
private readonly IHierarchicalTopicMappingService<NavigationTopicViewModel> _hierarchicalMappingService = null;
44+
private readonly IHierarchicalTopicMappingService<NavigationTopicViewModel> _hierarchicalMappingService;
4545

4646
/*==========================================================================================================================
4747
| CONSTRUCTOR
@@ -110,13 +110,13 @@ public async Task Menu_Invoke_ReturnsNavigationViewModel() {
110110

111111
var result = await viewComponent.InvokeAsync().ConfigureAwait(false);
112112
var concreteResult = result as ViewViewComponentResult;
113-
var model = concreteResult.ViewData.Model as NavigationViewModel<NavigationTopicViewModel>;
113+
var model = concreteResult?.ViewData.Model as NavigationViewModel<NavigationTopicViewModel>;
114114

115115
Assert.IsNotNull(model);
116-
Assert.AreEqual<string>(_topic.GetUniqueKey(), model.CurrentKey);
117-
Assert.AreEqual<string>("Root:Web", model.NavigationRoot.UniqueKey);
118-
Assert.AreEqual<int>(3, model.NavigationRoot.Children.Count);
119-
Assert.IsTrue(model.NavigationRoot.IsSelected(_topic.GetUniqueKey()));
116+
Assert.AreEqual<string?>(_topic.GetUniqueKey(), model?.CurrentKey);
117+
Assert.AreEqual<string?>("Root:Web", model?.NavigationRoot?.UniqueKey);
118+
Assert.AreEqual<int?>(3, model?.NavigationRoot?.Children.Count);
119+
Assert.IsTrue(model?.NavigationRoot?.IsSelected(_topic.GetUniqueKey())?? false);
120120

121121
}
122122

@@ -135,13 +135,13 @@ public async Task PageLevelNavigation_Invoke_ReturnsNavigationViewModel() {
135135

136136
var result = await viewComponent.InvokeAsync().ConfigureAwait(false);
137137
var concreteResult = result as ViewViewComponentResult;
138-
var model = concreteResult.ViewData.Model as NavigationViewModel<NavigationTopicViewModel>;
138+
var model = concreteResult?.ViewData.Model as NavigationViewModel<NavigationTopicViewModel>;
139139

140140
Assert.IsNotNull(model);
141-
Assert.AreEqual<string>(_topic.GetUniqueKey(), model.CurrentKey);
142-
Assert.AreEqual<string>("Root:Web:Web_3", model.NavigationRoot.UniqueKey);
143-
Assert.AreEqual<int>(2, model.NavigationRoot.Children.Count);
144-
Assert.IsTrue(model.NavigationRoot.IsSelected(_topic.GetUniqueKey()));
141+
Assert.AreEqual<string?>(_topic.GetUniqueKey(), model?.CurrentKey);
142+
Assert.AreEqual<string?>("Root:Web:Web_3", model?.NavigationRoot?.UniqueKey);
143+
Assert.AreEqual<int?>(2, model?.NavigationRoot?.Children.Count);
144+
Assert.IsTrue(model?.NavigationRoot?.IsSelected(_topic.GetUniqueKey())?? false);
145145

146146
}
147147

OnTopic.AspNetCore.Mvc.Tests/ValidateTopicAttributeTest.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public static ActionExecutingContext GetActionExecutingContext(Controller contro
6161
/// <summary>
6262
/// Generates a barebones <see cref="ControllerContext"/> for testing a controller.
6363
/// </summary>
64+
#pragma warning disable CA1024 // Use properties where appropriate
6465
public static ControllerContext GetControllerContext() =>
6566
new(
6667
new() {
@@ -69,14 +70,15 @@ public static ControllerContext GetControllerContext() =>
6970
ActionDescriptor = new ControllerActionDescriptor()
7071
}
7172
);
73+
#pragma warning restore CA1024 // Use properties where appropriate
7274

7375
/*==========================================================================================================================
7476
| METHOD: GET TOPIC CONTROLLER
7577
\-------------------------------------------------------------------------------------------------------------------------*/
7678
/// <summary>
7779
/// Generates a barebones <see cref="ControllerContext"/> for testing a controller.
7880
/// </summary>
79-
public static TopicController GetTopicController(Topic topic) =>
81+
public static TopicController GetTopicController(Topic? topic) =>
8082
new(
8183
new DummyTopicRepository(),
8284
new DummyTopicMappingService()
@@ -127,7 +129,7 @@ public void NullTopic_ReturnsNotFound() {
127129

128130
controller.Dispose();
129131

130-
Assert.AreEqual(typeof(NotFoundObjectResult), context.Result.GetType());
132+
Assert.AreEqual(typeof(NotFoundObjectResult), context.Result?.GetType());
131133

132134
}
133135

@@ -151,7 +153,7 @@ public void DisabledTopic_ReturnsNotFound() {
151153

152154
controller.Dispose();
153155

154-
Assert.AreEqual(typeof(UnauthorizedResult), context.Result.GetType());
156+
Assert.AreEqual(typeof(UnauthorizedResult), context.Result?.GetType());
155157

156158
}
157159

@@ -176,7 +178,7 @@ public void TopicWithUrl_ReturnsRedirect() {
176178

177179
controller.Dispose();
178180

179-
Assert.AreEqual(typeof(RedirectResult), context.Result.GetType());
181+
Assert.AreEqual(typeof(RedirectResult), context.Result?.GetType());
180182

181183
}
182184

@@ -202,7 +204,7 @@ public void NestedTopic_Returns403() {
202204
var result = context.Result as StatusCodeResult;
203205

204206
Assert.IsNotNull(result);
205-
Assert.AreEqual(403, result.StatusCode);
207+
Assert.AreEqual(403, result?.StatusCode);
206208

207209
}
208210

@@ -227,7 +229,7 @@ public void PageGroupTopic_ReturnsRedirect() {
227229

228230
controller.Dispose();
229231

230-
Assert.AreEqual(typeof(RedirectResult), context.Result.GetType());
232+
Assert.AreEqual(typeof(RedirectResult), context.Result?.GetType());
231233

232234
}
233235

0 commit comments

Comments
 (0)