Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable nullable on HtmlLogger #3712

Merged
merged 1 commit into from
Jun 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions TestPlatform.sln
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "testhost.arm64", "src\testh
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DumpMinitool.arm64", "src\DataCollectors\DumpMinitool.arm64\DumpMinitool.arm64.csproj", "{62E9D32B-B989-43CF-81A2-B38B3367FCA3}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.TestPlatform.Nullability", "src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.shproj", "{9DF3BC3C-2A53-46E7-9291-40728ACE5F82}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1023,20 +1025,23 @@ Global
{29270853-90DC-4C39-9621-F47AE40A79B6} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
{186069FE-E1E8-4DE1-BEA4-0FF1484D22D1} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959}
{62E9D32B-B989-43CF-81A2-B38B3367FCA3} = {B705537C-B82C-4A30-AFA5-6244D9A7DAEB}
{9DF3BC3C-2A53-46E7-9291-40728ACE5F82} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0541B30C-FF51-4E28-B172-83F5F3934BCD}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{10b6ade1-f808-4612-801d-4452f5b52242}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{186069fe-e1e8-4de1-bea4-0ff1484d22d1}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.projitems*{236a71e3-01da-4679-9dff-16a8e079acff}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{27dfbd04-64b2-4f1b-82b2-006620cca6f8}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{2c7ce1f8-e73e-4987-8023-b5a0ebac86e8}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.projitems*{61f7f446-9ef3-4768-b33a-4d75f60e1059}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.projitems*{65a25d6e-c9cc-4f45-8925-04087ac82634}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.projitems*{68adc720-316e-4895-9f8e-c3ccadd262be}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{71cb42ff-e750-4a3b-9c3a-ac938853cc89}*SharedItemsImports = 5
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{7f26eda3-c8c4-4b7f-a9b6-d278c2f40a13}*SharedItemsImports = 13
src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.projitems*{9df3bc3c-2a53-46e7-9291-40728ace5f82}*SharedItemsImports = 13
src\Microsoft.TestPlatform.Nullability\Microsoft.TestPlatform.Nullability.projitems*{fbf74c8f-695c-4967-84ac-358eefb1376d}*SharedItemsImports = 5
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
M:System.Diagnostics.Debug.Assert(System.Boolean); Use 'TPDebug.Assert' instead
M:System.Diagnostics.Debug.Assert(System.Boolean,System.String); Use 'TPDebug.Assert' instead
M:System.String.IsNullOrEmpty(System.String); Use 'StringUtils.IsNullOrEmpty' instead
M:System.String.IsNullOrWhiteSpace(System.String); Use 'StringUtils.IsNullOrWhiteSpace' instead
2 changes: 0 additions & 2 deletions src/Microsoft.TestPlatform.Extensions.HtmlLogger/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

using Microsoft.VisualStudio.TestPlatform.ObjectModel;

#nullable disable

namespace Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger;

public static class Constants
Expand Down
32 changes: 16 additions & 16 deletions src/Microsoft.TestPlatform.Extensions.HtmlLogger/Html.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<xsl:stylesheet version="2.0"
xmlns:tp="http://schemas.datacontract.org/2004/07/Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger.ObjectModel"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxs tp">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
Expand Down Expand Up @@ -109,7 +109,7 @@
</xsl:if>
<h2>All Results</h2><xsl:call-template name ="Results"/>
</xsl:template>

<xsl:template match="tp:RunLevelMessageInformational">
<div>
<h2>Informational messages</h2>
Expand All @@ -118,7 +118,7 @@
</xsl:for-each>
</div>
</xsl:template>

<xsl:template match="tp:RunLevelMessageErrorAndWarning">
<div>
<h2>Error and Warning messages</h2>
Expand All @@ -127,7 +127,7 @@
</xsl:for-each>
</div>
</xsl:template>

<xsl:template name ="Results">
<xsl:for-each select ="tp:TestResultCollection">
<xsl:variable name="Source" select="tp:Id" />
Expand All @@ -149,23 +149,23 @@
<xsl:for-each select ="tp:FailedResultList/tp:TestResult"><xsl:call-template name ="TestResult"/></xsl:for-each>
</div>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:for-each>
</xsl:template>

<xsl:template name="TestResult" match="tp:TestResult">
<xsl:variable name="TestResultId" select="tp:TestResultId" />

<xsl:if test ="tp:InnerTestResults!=''">
<div class ="row" onclick="ToggleClass('{concat($TestResultId,'-',name(..))}')"><xsl:call-template name = "Result" /></div>
<a Id="{concat($TestResultId,'-',name(..))}" style="display:none;"><xsl:apply-templates select = "tp:InnerTestResults" /></a>
</xsl:if>
</xsl:if>

<xsl:if test ="tp:InnerTestResults=''">
<div class ="leaf-division"><xsl:call-template name = "Result" /></div>
</xsl:if>
</xsl:if>

</xsl:template>

<xsl:template match="tp:InnerTestResults">
<div class ="inner-row"><xsl:apply-templates select = "tp:TestResult" /></div>
</xsl:template>
Expand All @@ -176,12 +176,12 @@
<xsl:apply-templates select = "tp:DisplayName" />
<div class="duration"><xsl:apply-templates select = "tp:Duration" /></div>
</div>
<div class="error-info">
<div class="error-info">
<xsl:if test ="tp:ErrorMessage!=''"><xsl:apply-templates select = "tp:ErrorMessage" /></xsl:if>
<xsl:if test ="tp:ErrorStackTrace!=''"><xsl:apply-templates select = "tp:ErrorStackTrace" /></xsl:if>
</div>
</xsl:template>

<xsl:template match = "tp:ErrorMessage">
Error: <span class="error-message"><pre><xsl:value-of select = "." /></pre></span><br />
</xsl:template>
Expand Down Expand Up @@ -223,7 +223,7 @@
<xsl:template match = "tp:Duration">
<span><xsl:value-of select = "." /></span><br />
</xsl:template>

<xsl:template match = "tp:DisplayName">
<span>&#160;<xsl:value-of select = "." />&#8203;</span>
</xsl:template>
Expand Down
60 changes: 34 additions & 26 deletions src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
Expand All @@ -22,8 +23,6 @@
using HtmlLoggerConstants = Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger.Constants;
using HtmlResource = Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger.Resources.Resources;

#nullable disable

namespace Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger;

/// <summary>
Expand All @@ -37,7 +36,7 @@ public class HtmlLogger : ITestLoggerWithParameters
private readonly XmlObjectSerializer _xmlSerializer;
private readonly IHtmlTransformer _htmlTransformer;
private static readonly object FileCreateLockObject = new();
private Dictionary<string, string> _parametersDictionary;
private Dictionary<string, string?>? _parametersDictionary;

public HtmlLogger()
: this(new FileHelper(), new HtmlTransformer(), new DataContractSerializer(typeof(TestRunDetails)))
Expand All @@ -55,23 +54,23 @@ public HtmlLogger(IFileHelper fileHelper, IHtmlTransformer htmlTransformer,
/// <summary>
/// Gets the directory under which default html file and test results attachments should be saved.
/// </summary>
public string TestResultsDirPath { get; private set; }
public string? TestResultsDirPath { get; private set; }

/// <summary>
/// Total results are stored in sequential order
/// </summary>
/// <returns></returns>
public ConcurrentDictionary<Guid, ObjectModel.TestResult> Results { get; private set; }
public ConcurrentDictionary<Guid, ObjectModel.TestResult>? Results { get; private set; }

/// <summary>
///
/// </summary>
public ConcurrentDictionary<string, TestResultCollection> ResultCollectionDictionary { get; private set; }
public ConcurrentDictionary<string, TestResultCollection>? ResultCollectionDictionary { get; private set; }

/// <summary>
/// Test results stores all the summary and the details of every results in hierarchical order.
/// </summary>
public TestRunDetails TestRunDetails { get; private set; }
public TestRunDetails? TestRunDetails { get; private set; }

/// <summary>
/// Total passed tests in the test results.
Expand All @@ -96,14 +95,15 @@ public HtmlLogger(IFileHelper fileHelper, IHtmlTransformer htmlTransformer,
/// <summary>
/// Path to the xml file.
/// </summary>
public string XmlFilePath { get; private set; }
public string? XmlFilePath { get; private set; }

/// <summary>
/// path to html file.
/// </summary>
public string HtmlFilePath { get; private set; }
public string? HtmlFilePath { get; private set; }

/// <inheritdoc/>
[MemberNotNull(nameof(TestResultsDirPath), nameof(TestRunDetails), nameof(Results), nameof(ResultCollectionDictionary))]
public void Initialize(TestLoggerEvents events, string testResultsDirPath)
{
ValidateArg.NotNull(events, nameof(events));
Expand All @@ -124,7 +124,8 @@ public void Initialize(TestLoggerEvents events, string testResultsDirPath)
}

/// <inheritdoc/>
public void Initialize(TestLoggerEvents events, Dictionary<string, string> parameters)
[MemberNotNull(nameof(_parametersDictionary))]
public void Initialize(TestLoggerEvents events, Dictionary<string, string?> parameters)
{
ValidateArg.NotNull(parameters, nameof(parameters));
if (parameters.Count == 0)
Expand All @@ -140,19 +141,20 @@ public void Initialize(TestLoggerEvents events, Dictionary<string, string> param
throw new ArgumentException(htmlParameterErrorMsg);
}

Initialize(events, parameters[DefaultLoggerParameterNames.TestRunDirectory]);
Initialize(events, parameters[DefaultLoggerParameterNames.TestRunDirectory]!);
}

/// <summary>
/// Handles the message level information like warnings, errors etc..
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void TestMessageHandler(object sender, TestRunMessageEventArgs e)
public void TestMessageHandler(object? sender, TestRunMessageEventArgs e)
{
ValidateArg.NotNull(sender, nameof(sender));
ValidateArg.NotNull(e, nameof(e));

TPDebug.Assert(TestRunDetails != null, "Initialize must be called before this method.");

switch (e.Level)
{
case TestMessageLevel.Informational:
Expand Down Expand Up @@ -184,11 +186,12 @@ public void TestMessageHandler(object sender, TestRunMessageEventArgs e)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void TestResultHandler(object sender, TestResultEventArgs e)
public void TestResultHandler(object? sender, TestResultEventArgs e)
{
ValidateArg.NotNull(sender, nameof(sender));
ValidateArg.NotNull(e, nameof(e));

TPDebug.Assert(ResultCollectionDictionary != null && TestRunDetails != null && Results != null, "Initialize must be called before this method.");

var testResult = new ObjectModel.TestResult
{
DisplayName = e.Result.DisplayName ?? e.Result.TestCase.FullyQualifiedName,
Expand All @@ -212,7 +215,7 @@ public void TestResultHandler(object sender, TestResultEventArgs e)
FailedResultList = new List<ObjectModel.TestResult>(),
};
ResultCollectionDictionary.TryAdd(e.Result.TestCase.Source, testResultCollection);
TestRunDetails.ResultCollectionList.Add(testResultCollection);
TestRunDetails.ResultCollectionList!.Add(testResultCollection);
}

TotalTests++;
Expand All @@ -238,10 +241,10 @@ public void TestResultHandler(object sender, TestResultEventArgs e)
{
if (e.Result.Outcome == TestOutcome.Failed)
{
testResultCollection.FailedResultList.Add(testResult);
testResultCollection.FailedResultList!.Add(testResult);
}

testResultCollection.ResultList.Add(testResult);
testResultCollection.ResultList!.Add(testResult);
}
else
{
Expand All @@ -251,6 +254,9 @@ public void TestResultHandler(object sender, TestResultEventArgs e)

private void AddToParentResult(Guid parentExecutionId, ObjectModel.TestResult testResult)
{
TPDebug.Assert(Results != null, "Initialize must be called before this method.");


if (Results.TryGetValue(parentExecutionId, out var parentTestResult))
{
if (parentTestResult.InnerTestResults == null)
Expand All @@ -265,8 +271,10 @@ private void AddToParentResult(Guid parentExecutionId, ObjectModel.TestResult te
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void TestRunCompleteHandler(object sender, TestRunCompleteEventArgs e)
public void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e)
{
TPDebug.Assert(TestRunDetails != null && _parametersDictionary != null, "Initialize must be called before this method.");

TestRunDetails.Summary = new TestRunSummary
{
FailedTests = FailedTests,
Expand All @@ -276,7 +284,7 @@ public void TestRunCompleteHandler(object sender, TestRunCompleteEventArgs e)
PassPercentage = TotalTests == 0 ? 0 : PassedTests * 100 / TotalTests,
TotalRunTime = GetFormattedDurationString(e.ElapsedTimeInRunningTests),
};
if (_parametersDictionary.TryGetValue(HtmlLoggerConstants.LogFilePrefixKey, out string logFilePrefixValue) && !string.IsNullOrWhiteSpace(logFilePrefixValue))
if (_parametersDictionary.TryGetValue(HtmlLoggerConstants.LogFilePrefixKey, out string? logFilePrefixValue) && !logFilePrefixValue.IsNullOrWhiteSpace())
{
var framework = _parametersDictionary[DefaultLoggerParameterNames.TargetFramework];
if (framework != null)
Expand All @@ -290,7 +298,7 @@ public void TestRunCompleteHandler(object sender, TestRunCompleteEventArgs e)
}
else
{
if (_parametersDictionary.TryGetValue(HtmlLoggerConstants.LogFileNameKey, out string logFileNameValue) && !string.IsNullOrWhiteSpace(logFileNameValue))
if (_parametersDictionary.TryGetValue(HtmlLoggerConstants.LogFileNameKey, out string? logFileNameValue) && !logFileNameValue.IsNullOrWhiteSpace())
{
HtmlFilePath = Path.Combine(TestResultsDirPath, logFileNameValue);
}
Expand All @@ -314,7 +322,7 @@ private void PopulateHtmlFile()
_xmlSerializer.WriteObject(xmlStream, TestRunDetails);
}

if (string.IsNullOrEmpty(HtmlFilePath))
if (HtmlFilePath.IsNullOrEmpty())
{
HtmlFilePath = GenerateUniqueFilePath(fileName, HtmlLoggerConstants.HtmlFileExtension);
}
Expand Down Expand Up @@ -361,7 +369,7 @@ private string GenerateUniqueFilePath(string fileName, string fileExtension)
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, HtmlResource.CannotGenerateUniqueFilePath, fileName, TestResultsDirPath));
}

private string FormatDateTimeForRunName(DateTime timeStamp)
private static string FormatDateTimeForRunName(DateTime timeStamp)
{
return timeStamp.ToString("yyyyMMdd_HHmmss", DateTimeFormatInfo.InvariantInfo);
}
Expand All @@ -371,7 +379,7 @@ private string FormatDateTimeForRunName(DateTime timeStamp)
/// </summary>
/// <param name="testResult"></param>
/// <returns></returns>
private Guid GetParentExecutionId(TestPlatform.ObjectModel.TestResult testResult)
private static Guid GetParentExecutionId(TestPlatform.ObjectModel.TestResult testResult)
{
var parentExecutionIdProperty = testResult.Properties.FirstOrDefault(property =>
property.Id.Equals(HtmlLoggerConstants.ParentExecutionIdPropertyIdentifier));
Expand All @@ -385,7 +393,7 @@ private Guid GetParentExecutionId(TestPlatform.ObjectModel.TestResult testResult
/// </summary>
/// <param name="testResult"></param>
/// <returns></returns>
private Guid GetExecutionId(TestPlatform.ObjectModel.TestResult testResult)
private static Guid GetExecutionId(TestPlatform.ObjectModel.TestResult testResult)
{
var executionIdProperty = testResult.Properties.FirstOrDefault(property =>
property.Id.Equals(HtmlLoggerConstants.ExecutionIdPropertyIdentifier));
Expand All @@ -404,7 +412,7 @@ private Guid GetExecutionId(TestPlatform.ObjectModel.TestResult testResult)
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
internal string GetFormattedDurationString(TimeSpan duration)
internal static string? GetFormattedDurationString(TimeSpan duration)
{
if (duration == default)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
using System.Xml;
using System.Xml.Xsl;

#nullable disable

namespace Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#nullable disable

namespace Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger;

public interface IHtmlTransformer
Expand Down
Loading