Skip to content

Commit

Permalink
C# Files need to be UTF-8 (#58)
Browse files Browse the repository at this point in the history
* Add initial part

* Disable codefix test as the fix breaks the tests

* Improve error message & taking in account bin/obj folder

* Fix unit test

* Fix SonarCloud remark

* Update to latest version of FileSystem NuGet

* Using the CICD.Parsers

* CR remark
  • Loading branch information
MichielOda authored Jun 21, 2024
1 parent a7797b2 commit 245a222
Show file tree
Hide file tree
Showing 33 changed files with 800 additions and 8 deletions.
1 change: 1 addition & 0 deletions Common/Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Skyline.DataMiner.CICD.FileSystem" Version="1.0.6" />
<PackageReference Include="Skyline.DataMiner.CICD.Models.Protocol" Version="1.0.11" />
<PackageReference Include="Skyline.DataMiner.XmlSchemas.Protocol" Version="1.0.4" />
</ItemGroup>
Expand Down
5 changes: 5 additions & 0 deletions Protocol/Common/ValidatorContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@ public ValidatorContext(IProtocolInputData input, ValidatorSettings validatorSet
public CrossData.CrossData CrossData { get; } = new CrossData.CrossData();

internal HelperCollection Helpers { get; }

public bool HasQActionsAndIsSolution =>
ProtocolModel?.Protocol?.QActions != null &&
InputData?.QActionCompilationModel?.IsSolutionBased == true &&
CompiledQActions != null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// <auto-generated>This is auto-generated code by Validator Management Tool. Do not modify.</auto-generated>
namespace Skyline.DataMiner.CICD.Validators.Protocol.Tests.Protocol.QActions.QAction.CheckFileEncoding
{
using System;
using System.Collections.Generic;

using Skyline.DataMiner.CICD.Models.Protocol.Read;
using Skyline.DataMiner.CICD.Validators.Common.Interfaces;
using Skyline.DataMiner.CICD.Validators.Common.Model;
using Skyline.DataMiner.CICD.Validators.Protocol.Common;
using Skyline.DataMiner.CICD.Validators.Protocol.Interfaces;

internal static class Error
{
public static IValidationResult InvalidFileEncoding(IValidate test, IReadable referenceNode, IReadable positionNode, string invalidFileEncoding, string fileName, string qactionId)
{
return new ValidationResult
{
Test = test,
CheckId = CheckId.CheckFileEncoding,
ErrorId = ErrorIds.InvalidFileEncoding,
FullId = "3.40.1",
Category = Category.QAction,
Severity = Severity.Minor,
Certainty = Certainty.Certain,
Source = Source.Validator,
FixImpact = FixImpact.NonBreaking,
GroupDescription = "",
Description = String.Format("Invalid file encoding '{0}' detected in file '{1}'. QAction ID '{2}'.", invalidFileEncoding, fileName, qactionId),
HowToFix = "",
ExampleCode = "",
Details = "Each file in a QAction needs to be UTF-8 as otherwise certain characters could be converted to invalid characters.",
HasCodeFix = true,

PositionNode = positionNode,
ReferenceNode = referenceNode,
};
}
}

internal static class ErrorIds
{
public const uint InvalidFileEncoding = 1;
}

/// <summary>
/// Contains the identifiers of the checks.
/// </summary>
public static class CheckId
{
/// <summary>
/// The check identifier.
/// </summary>
public const uint CheckFileEncoding = 40;
}
}
25 changes: 25 additions & 0 deletions Protocol/ErrorMessages.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12128,6 +12128,31 @@
</ErrorMessage>
</ErrorMessages>
</Check>
<Check id="40">
<Name namespace="Protocol.QActions.QAction">CheckFileEncoding</Name>
<ErrorMessages>
<ErrorMessage id="1">
<Name>InvalidFileEncoding</Name>
<GroupDescription />
<Description>
<Format>Invalid file encoding '{0}' detected in file '{1}'. QAction ID '{2}'.</Format>
<InputParameters>
<InputParameter id="0">invalidFileEncoding</InputParameter>
<InputParameter id="1">fileName</InputParameter>
<InputParameter id="2">qactionId</InputParameter>
</InputParameters>
</Description>
<Severity>Minor</Severity>
<Certainty>Certain</Certainty>
<Source>Validator</Source>
<FixImpact>NonBreaking</FixImpact>
<HasCodeFix>True</HasCodeFix>
<HowToFix><![CDATA[]]></HowToFix>
<ExampleCode><![CDATA[]]></ExampleCode>
<Details><![CDATA[Each file in a QAction needs to be UTF-8 as otherwise certain characters could be converted to invalid characters.]]></Details>
</ErrorMessage>
</ErrorMessages>
</Check>
</Checks>
</Category>
<Category id="4">
Expand Down
5 changes: 1 addition & 4 deletions Protocol/Tests/Protocol/QActions/CheckAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ public List<IValidationResult> Validate(ValidatorContext context)
{
List<IValidationResult> results = new List<IValidationResult>();

if (context?.ProtocolModel?.Protocol?.QActions == null ||
context.InputData?.QActionCompilationModel == null ||
!context.InputData.QActionCompilationModel.IsSolutionBased ||
context.CompiledQActions == null)
if (!context.HasQActionsAndIsSolution)
{
// Early skip when no QActions are present or when it is not solution based.
return results;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ public List<IValidationResult> Validate(ValidatorContext context)
{
List<IValidationResult> results = new List<IValidationResult>();

if (context?.ProtocolModel?.Protocol?.QActions == null ||
context.InputData?.QActionCompilationModel == null ||
!context.InputData.QActionCompilationModel.IsSolutionBased ||
context.CompiledQActions == null)
if (!context.HasQActionsAndIsSolution)
{
// Early skip when no QActions are present or when it is not solution based.
return results;
Expand Down
124 changes: 124 additions & 0 deletions Protocol/Tests/Protocol/QActions/QAction/CheckFileEncoding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
namespace Skyline.DataMiner.CICD.Validators.Protocol.Tests.Protocol.QActions.QAction.CheckFileEncoding
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using Skyline.DataMiner.CICD.FileSystem;
using Skyline.DataMiner.CICD.Models.Protocol;
using Skyline.DataMiner.CICD.Models.Protocol.Read;
using Skyline.DataMiner.CICD.Parsers.Common.VisualStudio.Projects;
using Skyline.DataMiner.CICD.Validators.Common.Interfaces;
using Skyline.DataMiner.CICD.Validators.Common.Model;
using Skyline.DataMiner.CICD.Validators.Protocol.Common;
using Skyline.DataMiner.CICD.Validators.Protocol.Common.Attributes;
using Skyline.DataMiner.CICD.Validators.Protocol.Common.Extensions;
using Skyline.DataMiner.CICD.Validators.Protocol.Interfaces;

[Test(CheckId.CheckFileEncoding, Category.QAction)]
internal class CheckFileEncoding : IValidate, ICodeFix/*, ICompare*/
{
public List<IValidationResult> Validate(ValidatorContext context)
{
List<IValidationResult> results = new List<IValidationResult>();

if (!context.HasQActionsAndIsSolution)
{
// Early skip when no QActions are present or when it is not solution based.
return results;
}

foreach ((CompiledQActionProject projectData, IQActionsQAction qaction) in context.EachQActionProject(true))
{
try
{
Project project = Project.Load(projectData.Project.FilePath, projectData.Project.Name);
string projectDirectory = FileSystem.Instance.Path.GetDirectoryName(project.Path);
foreach (ProjectFile file in project.Files)
{
string csharpFile = FileSystem.Instance.Path.Combine(projectDirectory, file.Name);
using (StreamReader sr = new StreamReader(csharpFile))
{
// Have a look in the file, so it can detect the encoding.
sr.Peek();

if (!sr.CurrentEncoding.Equals(Encoding.UTF8))
{
string fileName = FileSystem.Instance.Path.GetFileName(csharpFile);
results.Add(Error.InvalidFileEncoding(this, qaction, qaction, sr.CurrentEncoding.EncodingName, fileName, qaction.Id.RawValue)
.WithExtraData(ExtraData.InvalidFileEncoding, csharpFile));
}
}
}
}
catch (FileNotFoundException)
{
// Can happen in legacy style projects. In case the file mentioned in the csproj does not exist.
}
}

return results;
}

public ICodeFixResult Fix(CodeFixContext context)
{
CodeFixResult result = new CodeFixResult();
var fs = FileSystem.Instance;

switch (context.Result.ErrorId)
{
case ErrorIds.InvalidFileEncoding:
if (context.Result.ExtraData.TryGetValue(ExtraData.InvalidFileEncoding, out object csharpFile) &&
csharpFile is string filePath &&
fs.File.Exists(filePath))
{
string tempPath = fs.Path.Combine(fs.Path.GetTempPath(), fs.Path.GetRandomFileName());
using (StreamReader sr = new StreamReader(filePath))
using (StreamWriter sw = new StreamWriter(tempPath, false, Encoding.UTF8))
{
// Have a look in the file, so it can detect the encoding.
sr.Peek();

int charsRead;
char[] buffer = new char[128 * 1024];
while ((charsRead = sr.ReadBlock(buffer, 0, buffer.Length)) > 0)
{
sw.Write(buffer, 0, charsRead);
}
}

fs.File.Delete(filePath);
fs.File.Move(tempPath, filePath);

result.Success = true;
}
else
{
result.Message = "Unable to locate file.";
}

break;

default:
result.Message = $"This error ({context.Result.ErrorId}) isn't implemented.";
break;
}

return result;
}

////public List<IValidationResult> Compare(MajorChangeCheckContext context)
////{
//// List<IValidationResult> results = new List<IValidationResult>();

//// return results;
////}
}

internal enum ExtraData
{
InvalidFileEncoding,
}
}
Loading

0 comments on commit 245a222

Please sign in to comment.