DocSpace-client/common/Tests/Backend.Translations.Tests/Tests.cs

398 lines
13 KiB
C#

// (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.Text;
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 neutralresources = resources.Where(f => IsNeutral(f.Name));
_resources = new Dictionary<FileInfo, IEnumerable<FileInfo>>();
foreach (var resource in neutralresources)
{
var nameWithoutExt = resource.FullName.Substring(0, resource.FullName.Length - 5);
_resources.Add(resource, resources.Where(r => r.FullName.StartsWith(nameWithoutExt)));
}
}
private bool IsNeutral(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 LanguageTranslatedPercentTest()
{
var all = 0;
var setByCulture = new Dictionary<string, int>();
var allExist = true;
var message = new StringBuilder("Next languages translated less then 100%:\n\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 culture = GetCulture(resource.Name);
var valid = CultureHelper.IsValidCultureName(culture);
if (valid && !setByCulture.ContainsKey(culture))
{
setByCulture.Add(culture, 0);
}
foreach (var entry in CreateTranslateDictionary(resource.FullName))
{
if (!string.IsNullOrEmpty(entry.Value.ToString()))
{
set.Add(entry.Key.ToString());
if (valid)
{
setByCulture[culture] += 1;
}
}
}
}
all += set.Count;
}
var counter = 0;
foreach (var pair in setByCulture.Where(r => r.Value != all).OrderByDescending(r => Math.Round((r.Value * 100.0) / all, 1)))
{
allExist = false;
message.AppendLine($"{++counter}. Language '{pair.Key}' translated by '{Math.Round((pair.Value * 100.0) / all, 1)}%'");
}
Assert.True(allExist, message.ToString());
}
[Test, Order(2)]
public void NotAllLanguageTranslatedTest()
{
var all = new HashSet<string>();
var groupByFile = new Dictionary<FileInfo, HashSet<string>>();
var allExist = true;
var message = new StringBuilder("Next languages are missing from files: \n\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("en");
set.Add("en");
}
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("en");
set.Add("en");
}
}
}
groupByFile.Add(pair.Key, set);
}
var counter = 0;
foreach (var culture in all)
{
var notExist = groupByFile.Where(l => !l.Value.Contains(culture)).ToList();
if (notExist.Any())
{
allExist = false;
message.AppendLine($"{++counter}. Language '{culture}'. Not found files: \n");
foreach (var f in notExist)
{
message.AppendLine($"{f.Key.FullName}");
}
message.AppendLine();
}
}
Assert.True(allExist, message.ToString());
}
[Test, Order(3)]
public void NotTranslatedKeysTest()
{
var all = new Dictionary<FileInfo, HashSet<string>>();
var groupByFile = new Dictionary<FileInfo, Dictionary<FileInfo, HashSet<string>>>();
var allExist = true;
var message = new StringBuilder("Next languages do not have all keys:\n\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);
}
var counter = 0;
foreach (var pair in groupByFile)
{
foreach (var keyValue in pair.Value)
{
var notExist = all[pair.Key].Where(l => !keyValue.Value.Contains(l)).ToList();
if (notExist.Any())
{
allExist = false;
var x = notExist.Count;
var y = all[pair.Key].Count();
var culture = GetCulture(keyValue.Key.Name);
message.AppendLine($"{++counter}. Language ('{culture}'={y - x}/'all keys'={y}). Path '{pair.Key.FullName}' Not found keys:");
message.AppendLine();
foreach (var key in notExist)
{
message.AppendLine($"{key}");
}
message.AppendLine();
}
}
}
Assert.True(allExist, message.ToString());
}
/*[Test, Order(4)]
public void CompliesToRulePunctuationLead()
{
CompliesToRule("The punctuation at the start of the messages doesn't match up:\n", CheckRules.CompliesToRulePunctuationLead);
}
[Test, Order(5)]
public void CompliesToRulePunctuationTail()
{
CompliesToRule("The punctuation at the end of the messages doesn't match up:\n", CheckRules.CompliesToRulePunctuationTail);
}
*/
[Test, Order(6)]
public void CompliesToRuleWhiteSpaceLead()
{
CompliesToRule("The whitespaces at the start of the sequence don't match up:\n", CheckRules.CompliesToRuleWhiteSpaceLead);
}
[Test, Order(7)]
public void CompliesToRuleWhiteSpaceTail()
{
CompliesToRule("The whitespaces at the end of the sequence don't match up:\n", CheckRules.CompliesToRuleWhiteSpaceTail);
}
[Test, Order(8)]
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 result = new StringBuilder(message);
var counter = 0;
var allRuleCheck = true;
foreach (var pair in _resources)
{
var neutral = CreateTranslateDictionary(pair.Key.FullName);
foreach (var resource in pair.Value)
{
var list = new Dictionary<string, (string, string)>();
foreach (var entry in CreateTranslateDictionary(resource.FullName))
{
if (neutral.TryGetValue(entry.Key, out var value))
{
if (compliesToRile(value, entry.Value))
{
list.Add(entry.Key, (value, entry.Value));
allRuleCheck = false;
}
}
}
if (list.Count > 0)
{
var culture = GetCulture(resource.Name);
result.AppendLine();
foreach (var item in list)
{
result.AppendLine($"{++counter}. {resource.FullName}\n");
result.AppendLine($"key:{item.Key}\n");
result.AppendLine($"'en':{item.Value.Item1}\n");
result.AppendLine($"'{culture}':{item.Value.Item2}\n");
}
}
}
}
Assert.True(allRuleCheck, result.ToString());
}
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;
}
private string GetCulture(string fullName)
{
var split = fullName.Split('.');
if (split.Count() == 3) {
return split[split.Length - 2];
}
else
{
return "en";
}
}
}