add Backend.Translations.Tests
This commit is contained in:
parent
83a10be7e9
commit
d265fb4373
4
build/run.backend.translations.tests.bat
Normal file
4
build/run.backend.translations.tests.bat
Normal file
@ -0,0 +1,4 @@
|
||||
PUSHD %~dp0..
|
||||
set dir=%~dp0..
|
||||
echo %dir%
|
||||
dotnet test common\Tests\Backend.Translations.Tests\Backend.Translations.Tests.csproj -l:html --environment "BASE_DIR=%dir%" --results-directory "%dir%/TestsResults"
|
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2" />
|
||||
<PackageReference Include="ResXResourceReader.NetStandard" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33213.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend.Translations.Tests", "Backend.Translations.Tests.csproj", "{77474278-2624-496C-B5DB-BDDB9622FA70}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{77474278-2624-496C-B5DB-BDDB9622FA70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77474278-2624-496C-B5DB-BDDB9622FA70}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77474278-2624-496C-B5DB-BDDB9622FA70}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{77474278-2624-496C-B5DB-BDDB9622FA70}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {07AB23F0-190B-4AE7-B4AB-ED8380DB1988}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
174
common/Tests/Backend.Translations.Tests/CheckRules.cs
Normal file
174
common/Tests/Backend.Translations.Tests/CheckRules.cs
Normal file
@ -0,0 +1,174 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Backend.Translations.Tests;
|
||||
public static class CheckRules
|
||||
{
|
||||
public static bool CompliesToRulePunctuationLead(string? neutralValue, string? value)
|
||||
{
|
||||
var reference = GetPunctuationSequence(neutralValue).ToArray();
|
||||
|
||||
var array = GetPunctuationSequence(value);
|
||||
return !reference.SequenceEqual(array);
|
||||
}
|
||||
|
||||
public static bool CompliesToRulePunctuationTail(string? neutralValue, string? value)
|
||||
{
|
||||
var reference = GetPunctuationSequence(neutralValue, true).ToArray();
|
||||
|
||||
var array = GetPunctuationSequence(value, true);
|
||||
return !reference.SequenceEqual(array);
|
||||
}
|
||||
|
||||
public static bool CompliesToRuleWhiteSpaceLead(string? neutralValue, string? value)
|
||||
{
|
||||
var reference = GetWhiteSpaceSequence(neutralValue);
|
||||
|
||||
var array = GetWhiteSpaceSequence(value);
|
||||
return !reference.SequenceEqual(array);
|
||||
}
|
||||
|
||||
public static bool CompliesToRuleWhiteSpaceTail(string? neutralValue, string? value)
|
||||
{
|
||||
var reference = GetWhiteSpaceSequence(neutralValue, true);
|
||||
|
||||
var array = GetWhiteSpaceSequence(value, true);
|
||||
return !reference.SequenceEqual(array);
|
||||
}
|
||||
|
||||
public static bool CompliesToRuleStringFormat(string? neutralValue, string? value)
|
||||
{
|
||||
var allValues = new[] { neutralValue, value }.ToList();
|
||||
|
||||
var indexedComply = GetStringFormatByIndexFlags(neutralValue) == GetStringFormatByIndexFlags(value);
|
||||
|
||||
var namedComply = GetStringFormatByPlaceholdersFingerprint(neutralValue) == GetStringFormatByPlaceholdersFingerprint(value);
|
||||
|
||||
return !(indexedComply && namedComply);
|
||||
}
|
||||
|
||||
private static string GetStringFormatByPlaceholdersFingerprint(string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return string.Empty;
|
||||
|
||||
return string.Join("|", ExtractPlaceholders(value).OrderBy(item => item));
|
||||
}
|
||||
|
||||
private static readonly Regex _formatPlaceholderExpression = new(@"\$\{\s*(\w[.\w\d_]*)\s*\}");
|
||||
public static IEnumerable<string> ExtractPlaceholders(string text)
|
||||
{
|
||||
var placeholders = _formatPlaceholderExpression.Matches(text)
|
||||
.OfType<Match>()
|
||||
.Select(m => m.Groups[1].Value)
|
||||
.Distinct();
|
||||
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
private static readonly Regex _getStringFormatByIndexExpression = new(@"\{([0-9]+)(?:,-?[0-9]+)?(?::[^\}]+)?\}", RegexOptions.CultureInvariant | RegexOptions.Compiled);
|
||||
|
||||
private static long GetStringFormatByIndexFlags(string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return 0;
|
||||
|
||||
return _getStringFormatByIndexExpression.Matches(value)
|
||||
.Cast<Match>()
|
||||
.Where(m => m.Success)
|
||||
.Aggregate(0L, (a, match) => a | ParseMatch(match));
|
||||
}
|
||||
|
||||
private static long ParseMatch(Match match)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||
return 1L << value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static IEnumerable<char> GetWhiteSpaceSequence(string? value, bool revers = false)
|
||||
{
|
||||
return GetCharIterator(value, revers).TakeWhile(char.IsWhiteSpace);
|
||||
}
|
||||
|
||||
private static IEnumerable<char> GetCharIterator(string value, bool revers) => revers ? value.Reverse() : value;
|
||||
|
||||
private static IEnumerable<char> GetPunctuationSequence(string? value, bool revers = false)
|
||||
{
|
||||
return GetCharIterator(NormalizeUnicode(value), revers)
|
||||
.SkipWhile(char.IsWhiteSpace).
|
||||
TakeWhile(IsPunctuation).
|
||||
Select(NormalizePunctuation);
|
||||
}
|
||||
|
||||
private static char NormalizePunctuation(char value)
|
||||
{
|
||||
switch ((int)value)
|
||||
{
|
||||
case 0x055C: return '!'; // ARMENIAN EXCLAMATION MARK
|
||||
case 0x055D: return ','; // ARMENIAN COMMA
|
||||
case 0x055E: return '?'; // ARMENIAN QUESTION MARK
|
||||
case 0x0589: return '.'; // ARMENIAN FULL STOP
|
||||
case 0x07F8: return ','; // NKO COMMA
|
||||
case 0x07F9: return '!'; // NKO EXCLAMATION MARK
|
||||
case 0x1944: return '!'; // LIMBU EXCLAMATION MARK
|
||||
case 0x1945: return '?'; // LIMBU QUESTION MARK
|
||||
case 0x3001: return ','; // IDEOGRAPHIC COMMA
|
||||
case 0x3002: return '.'; // IDEOGRAPHIC FULL STOP
|
||||
case 0xFF01: return '!'; // FULLWIDTH EXCLAMATION MARK
|
||||
case 0xFF0C: return ','; // FULLWIDTH COMMA
|
||||
case 0xFF0E: return '.'; // FULLWIDTH FULL STOP
|
||||
case 0xFF1A: return ':'; // FULLWIDTH COLON
|
||||
case 0xFF1B: return ';'; // FULLWIDTH SEMICOLON
|
||||
case 0xFF1F: return '?'; // FULLWIDTH QUESTION MARK
|
||||
case 0x061F: return '?'; // ARABIC QUESTION MARK
|
||||
default: return value;
|
||||
}
|
||||
}
|
||||
|
||||
private static string NormalizeUnicode(string? value) => value?.Normalize() ?? string.Empty;
|
||||
|
||||
private static bool IsPunctuation(char value)
|
||||
{
|
||||
// exclude quotes, special chars (\#), hot-key prefixes (&_), language specifics with no common equivalent (¡¿).
|
||||
const string excluded = "'\"\\#&_¡¿";
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (char.GetUnicodeCategory(value))
|
||||
{
|
||||
case UnicodeCategory.OtherPunctuation:
|
||||
return !excluded.Contains(value, StringComparison.Ordinal);
|
||||
case UnicodeCategory.DashPunctuation:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
87
common/Tests/Backend.Translations.Tests/CultureHelper.cs
Normal file
87
common/Tests/Backend.Translations.Tests/CultureHelper.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace ResXManager.Infrastructure;
|
||||
|
||||
public static class CultureHelper
|
||||
{
|
||||
public static bool IsValidCultureName(string? languageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(languageName))
|
||||
return false;
|
||||
|
||||
// pseudo-locales:
|
||||
if (languageName.StartsWith("qps-", StringComparison.Ordinal))
|
||||
return true;
|
||||
|
||||
// #376: support Custom dialect resource
|
||||
var culture = new CultureInfo(languageName);
|
||||
while (!culture.IsNeutralCulture)
|
||||
{
|
||||
culture = culture.Parent;
|
||||
}
|
||||
|
||||
return WellKnownNeutralCultures.Contains(culture.Name);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class WellKnownNeutralCultures
|
||||
{
|
||||
private static readonly string[] _sortedNeutralCultureNames = GetSortedNeutralCultureNames();
|
||||
|
||||
public static bool Contains(string cultureName)
|
||||
{
|
||||
return Array.BinarySearch(_sortedNeutralCultureNames, cultureName, StringComparer.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static string[] GetSortedNeutralCultureNames()
|
||||
{
|
||||
var allCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
|
||||
|
||||
var cultureNames = allCultures.Select(culture => culture.IetfLanguageTag)
|
||||
.Concat(allCultures.Select(culture => culture.Name))
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
Array.Sort(cultureNames, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return cultureNames;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all system specific cultures.
|
||||
/// </summary>
|
||||
public static IEnumerable<CultureInfo> SpecificCultures => WellKnownSpecificCultures.Value;
|
||||
|
||||
private static class WellKnownSpecificCultures
|
||||
{
|
||||
public static readonly CultureInfo[] Value = GetSpecificCultures();
|
||||
|
||||
private static CultureInfo[] GetSpecificCultures()
|
||||
{
|
||||
var specificCultures = CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||
.Where(c => c.GetAncestors().Any())
|
||||
.OrderBy(c => c.DisplayName)
|
||||
.ToArray();
|
||||
|
||||
return specificCultures;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<CultureInfo> GetAncestors(this CultureInfo self)
|
||||
{
|
||||
var item = self.Parent;
|
||||
|
||||
while (!string.IsNullOrEmpty(item.Name))
|
||||
{
|
||||
yield return item;
|
||||
item = item.Parent;
|
||||
}
|
||||
}
|
||||
}
|
304
common/Tests/Backend.Translations.Tests/Tests.cs
Normal file
304
common/Tests/Backend.Translations.Tests/Tests.cs
Normal file
@ -0,0 +1,304 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using System.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using ResXManager.Infrastructure;
|
||||
|
||||
namespace Backend.Translations.Tests;
|
||||
|
||||
public class Tests
|
||||
{
|
||||
private Dictionary<FileInfo, IEnumerable<FileInfo>> _resources;
|
||||
private readonly HashSet<string> _excludedDirectories = new(new[] { "bin", "obj", "node_modules", "thirdparty", "migration" }, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var basePath = Environment.GetEnvironmentVariable("BASE_DIR") ?? Path.GetFullPath("../../../../../../");
|
||||
|
||||
var directory = new DirectoryInfo(basePath);
|
||||
var resources = GetResources(directory);
|
||||
var netralresources = resources.Where(f => IsNetral(f.Name));
|
||||
_resources = new Dictionary<FileInfo, IEnumerable<FileInfo>>();
|
||||
foreach(var resource in netralresources)
|
||||
{
|
||||
var nameWithoutExt = resource.FullName.Substring(0, resource.FullName.Length - 5);
|
||||
_resources.Add(resource, resources.Where(r => r.FullName.StartsWith(nameWithoutExt)));
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsNetral(string fileName)
|
||||
{
|
||||
var split = fileName.Split('.');
|
||||
if (split.Length == 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var valid = CultureHelper.IsValidCultureName(split[split.Length - 2]);
|
||||
return !valid;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<FileInfo> GetResources(DirectoryInfo directory)
|
||||
{
|
||||
foreach (var file in directory.EnumerateFiles())
|
||||
{
|
||||
if (IsResourceFile(file.Name))
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var subDirectory in directory.EnumerateDirectories())
|
||||
{
|
||||
var name = subDirectory.Name;
|
||||
if (name.StartsWith(".", StringComparison.Ordinal) || _excludedDirectories.Contains(name))
|
||||
continue;
|
||||
|
||||
foreach (var file in GetResources(subDirectory))
|
||||
{
|
||||
if (IsResourceFile(file.Name))
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsResourceFile(string filePath, string? extension = null)
|
||||
{
|
||||
extension ??= Path.GetExtension(filePath);
|
||||
|
||||
if (extension == ".resx")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Test, Order(1)]
|
||||
public void ResourceFilesExist()
|
||||
{
|
||||
var all = new HashSet<string>();
|
||||
var groupByFile = new Dictionary<FileInfo, HashSet<string>>();
|
||||
var allExist = true;
|
||||
var message = "resource files is not exist: \n";
|
||||
foreach(var pair in _resources)
|
||||
{
|
||||
var resources = pair.Value;
|
||||
var set = new HashSet<string>();
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
var split = resource.Name.Split('.');
|
||||
if (split.Length == 2)
|
||||
{
|
||||
all.Add("netral");
|
||||
set.Add("netral");
|
||||
}
|
||||
else
|
||||
{
|
||||
var culture = split[split.Length - 2];
|
||||
var valid = CultureHelper.IsValidCultureName(split[split.Length - 2]);
|
||||
if (valid)
|
||||
{
|
||||
all.Add(culture);
|
||||
set.Add(culture);
|
||||
}
|
||||
else
|
||||
{
|
||||
all.Add("netral");
|
||||
set.Add("netral");
|
||||
}
|
||||
}
|
||||
}
|
||||
groupByFile.Add(pair.Key, set);
|
||||
}
|
||||
|
||||
foreach(var pair in groupByFile)
|
||||
{
|
||||
var notExist = all.Where(l => !pair.Value.Contains(l));
|
||||
if(notExist.Count() > 0)
|
||||
{
|
||||
allExist = false;
|
||||
message += $"{pair.Key.Name}: \n";
|
||||
message += string.Join(',', notExist) + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
Assert.True(allExist, message);
|
||||
}
|
||||
|
||||
[Test, Order(2)]
|
||||
public void ResoureFilesFilled()
|
||||
{
|
||||
var all = new Dictionary<FileInfo, HashSet<string>>();
|
||||
var groupByFile = new Dictionary<FileInfo, Dictionary<FileInfo, HashSet<string>>>();
|
||||
var allExist = true;
|
||||
var message = "Next resources filled less then 100%: \n";
|
||||
|
||||
foreach (var pair in _resources)
|
||||
{
|
||||
var set = new HashSet<string>();
|
||||
var dictionary = new Dictionary<FileInfo, HashSet<string>>();
|
||||
foreach (var resource in pair.Value)
|
||||
{
|
||||
var innerSet = new HashSet<string>();
|
||||
foreach (var entry in CreateTranslateDictionary(resource.FullName))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(entry.Value.ToString()))
|
||||
{
|
||||
set.Add(entry.Key.ToString());
|
||||
innerSet.Add(entry.Key.ToString());
|
||||
}
|
||||
}
|
||||
dictionary.Add(resource, innerSet);
|
||||
}
|
||||
groupByFile.Add(pair.Key, dictionary);
|
||||
all.Add(pair.Key, set);
|
||||
}
|
||||
|
||||
foreach(var pair in groupByFile)
|
||||
{
|
||||
foreach(var keyValue in pair.Value)
|
||||
{
|
||||
var notExist = all[pair.Key].Where(l => !keyValue.Value.Contains(l));
|
||||
if (notExist.Count() > 0)
|
||||
{
|
||||
allExist = false;
|
||||
var x = notExist.Count();
|
||||
var y = all[pair.Key].Count();
|
||||
var percent = (int)((double)(y - x) / y * 100);
|
||||
|
||||
message += $"{keyValue.Key.Name}: {percent}%\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert.True(allExist, message);
|
||||
}
|
||||
|
||||
[Test, Order(3)]
|
||||
public void CompliesToRulePunctuationLead()
|
||||
{
|
||||
CompliesToRule("The punctuation at the start of the messages doesn't match up:\n", CheckRules.CompliesToRulePunctuationLead);
|
||||
}
|
||||
|
||||
[Test, Order(4)]
|
||||
public void CompliesToRulePunctuationTail()
|
||||
{
|
||||
CompliesToRule("The punctuation at the end of the messages doesn't match up:\n", CheckRules.CompliesToRulePunctuationTail);
|
||||
}
|
||||
|
||||
[Test, Order(5)]
|
||||
public void CompliesToRuleWhiteSpaceLead()
|
||||
{
|
||||
CompliesToRule("The whitespaces at the start of the sequence don't match up:\n", CheckRules.CompliesToRuleWhiteSpaceLead);
|
||||
}
|
||||
|
||||
[Test, Order(6)]
|
||||
public void CompliesToRuleWhiteSpaceTail()
|
||||
{
|
||||
CompliesToRule("The whitespaces at the end of the sequence don't match up:\n", CheckRules.CompliesToRuleWhiteSpaceTail);
|
||||
}
|
||||
|
||||
[Test, Order(7)]
|
||||
public void CompliesToRuleWhiteStringFormat()
|
||||
{
|
||||
CompliesToRule("This items contains string format parameter mismatches:\n", CheckRules.CompliesToRuleStringFormat);
|
||||
}
|
||||
|
||||
private void CompliesToRule(string message, Func<string, string, bool> compliesToRile)
|
||||
{
|
||||
var allRuleCheck = true;
|
||||
foreach (var pair in _resources)
|
||||
{
|
||||
var netral = CreateTranslateDictionary(pair.Key.FullName);
|
||||
foreach (var resource in pair.Value)
|
||||
{
|
||||
var list = new List<string>();
|
||||
foreach (var entry in CreateTranslateDictionary(resource.FullName))
|
||||
{
|
||||
if (netral.TryGetValue(entry.Key, out var value))
|
||||
{
|
||||
if (compliesToRile(value, entry.Value))
|
||||
{
|
||||
list.Add(entry.Key);
|
||||
allRuleCheck = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list.Count > 0)
|
||||
{
|
||||
message += $"\n{resource.Name}: \n";
|
||||
message += string.Join(',', list) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.True(allRuleCheck, message);
|
||||
}
|
||||
|
||||
private Dictionary<string, string> CreateTranslateDictionary(string filePath)
|
||||
{
|
||||
var dictionary = new Dictionary<string, string>();
|
||||
var name = "";
|
||||
using (var reader = XmlReader.Create(filePath))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element:
|
||||
if (reader.Name == "data" && string.IsNullOrEmpty(reader["type"]))
|
||||
{
|
||||
name = reader["name"] ?? "";
|
||||
}
|
||||
break;
|
||||
case XmlNodeType.Text:
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
dictionary.Add(name, reader.Value);
|
||||
name = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user