Web: Tests:

+ Added new SpellCheckTest() and submodule (common/Tests/Frontend.Translations.Tests/dictionaries)
+ Split tests on categories FastRunning|LongRunning
+ Added new build/run.translations.spellcheck.test.bat
This commit is contained in:
Alexey Safronov 2021-12-21 16:59:04 +03:00
parent 649e1b420a
commit 4274e3a581
9 changed files with 222 additions and 2 deletions

3
.gitmodules vendored
View File

@ -2,3 +2,6 @@
path = products/ASC.Files/Server/DocStore
url = https://github.com/ONLYOFFICE/document-templates
branch = main/community-server
[submodule "common/Tests/Frontend.Translations.Tests/dictionaries"]
path = common/Tests/Frontend.Translations.Tests/dictionaries
url = https://github.com/ONLYOFFICE/dictionaries

View File

@ -0,0 +1,2 @@
PUSHD %~dp0..
dotnet test common\Tests\Frontend.Translations.Tests\Frontend.Translations.Tests.csproj --filter Name~SpellCheckTest -l:html -r TestsResults

View File

@ -1,2 +1,2 @@
PUSHD %~dp0..
dotnet test common\Tests\Frontend.Translations.Tests\Frontend.Translations.Tests.csproj -l:html -r TestsResults
dotnet test common\Tests\Frontend.Translations.Tests\Frontend.Translations.Tests.csproj --filter "TestCategory=FastRunning" -l:html -r TestsResults

View File

@ -11,6 +11,7 @@
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="UTF.Unknown" Version="2.5.0" />
<PackageReference Include="WeCantSpell.Hunspell" Version="3.0.1" />
</ItemGroup>
</Project>

View File

@ -14,6 +14,8 @@ using NUnit.Framework;
using UtfUnknown;
using WeCantSpell.Hunspell;
namespace Frontend.Translations.Tests
{
public class Tests
@ -246,12 +248,70 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void ParseJsonTest()
{
Assert.AreEqual(0, ParseJsonErrors.Count, string.Join("\r\n", ParseJsonErrors.Select(e => $"File path = '{e.Path}' failed to parse with error: '{e.Exception.Message}'")));
}
[Test]
[Category("LongRunning")]
public void SpellCheckTest()
{
const string dictionariesPath = @"..\..\..\dictionaries";
var i = 0;
var errorsCount = 0;
var message = $"Next keys have spell check issues:\r\n\r\n";
var groupByLng = TranslationFiles
.GroupBy(t => t.Language)
.Select(g => new
{
Language = g.Key,
Files = g.ToList()
})
.ToList();
foreach (var group in groupByLng)
{
try
{
var language = SpellCheck.GetDictionaryLanguage(group.Language);
using (var dictionaryStream = File.OpenRead(Path.Combine(dictionariesPath, language, $"{language}.dic")))
using (var affixStream = File.OpenRead(Path.Combine(dictionariesPath, language, $"{language}.aff")))
{
var dictionary = WordList.CreateFromStreams(dictionaryStream, affixStream);
foreach (var g in group.Files)
{
foreach (var item in g.Translations)
{
var result = SpellCheck.HasSpellIssues(item.Value, dictionary);
if (result.HasProblems)
{
message += $"{++i}. lng='{group.Language}' file='{g.FilePath}'\r\nkey='{item.Key}' value='{item.Value}'\r\nIncorrect words:\r\n{string.Join("\r\n", result.SpellIssues.Select(issue => $"'{issue.Word}' Suggestion: '{issue.Suggestions.FirstOrDefault()}'"))}\r\n\r\n";
errorsCount++;
}
}
}
}
}
catch (NotSupportedException)
{
// Skip not supported
continue;
}
}
Assert.AreEqual(0, errorsCount, message);
}
[Test]
[Category("FastRunning")]
public void DublicatesFilesByMD5HashTest()
{
var duplicatesByMD5 = TranslationFiles
@ -261,10 +321,11 @@ namespace Frontend.Translations.Tests
.OrderByDescending(itm => itm.Count)
.ToList();
Assert.AreEqual(0, duplicatesByMD5.Count, "Dublicates by MD5 hash:\r\n" + string.Join("\r\n", duplicatesByMD5.Select(d => $"\r\nMD5='{d.Key}\r\n{string.Join("\r\n", d.Paths.Select(p => p))}'")));
Assert.AreEqual(0, duplicatesByMD5.Count, "Dublicates by MD5 hash:\r\n" + string.Join("\r\n", duplicatesByMD5.Select(d => $"\r\nMD5='{d.Key}':\r\n{string.Join("\r\n", d.Paths.Select(p => p))}'")));
}
[Test]
[Category("FastRunning")]
public void FullEnDublicatesTest()
{
var fullEnDuplicates = TranslationFiles
@ -281,6 +342,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void EnDublicatesByContentTest()
{
var allRuTranslations = TranslationFiles
@ -359,6 +421,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void NotAllLanguageTranslatedTest()
{
var groupedByLng = TranslationFiles
@ -435,6 +498,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void NotTranslatedKeysTest()
{
var message = $"Next languages are not equal 'en' by translated keys count:\r\n\r\n";
@ -481,6 +545,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void NotFoundKeysTest()
{
var allEnKeys = TranslationFiles
@ -502,6 +567,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void UselessTranslationKeysTest()
{
var allEnKeys = TranslationFiles
@ -524,6 +590,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void UselessModuleTranslationKeysTest()
{
var notFoundi18nKeys = new List<KeyValuePair<string, List<string>>>();
@ -605,6 +672,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void NotTranslatedCommonKeysTest()
{
var message = $"Some i18n-keys are not found in COMMON translations: \r\nKeys: \r\n\r\n";
@ -703,6 +771,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void EmptyValueKeysTest()
{
// Uncomment if new keys are available
@ -806,6 +875,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void LanguageTranslatedPercentTest()
{
var message = $"Next languages translated less then 100%:\r\n\r\n";
@ -852,6 +922,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void NotTranslatedToastsTest()
{
var message = $"Next text not translated in toasts:\r\n\r\n";
@ -874,6 +945,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void WrongTranslationVariablesTest()
{
var message = $"Next keys have wrong variables:\r\n\r\n";
@ -951,6 +1023,7 @@ namespace Frontend.Translations.Tests
}
[Test]
[Category("FastRunning")]
public void TranslationsEncodingTest()
{
/*//Convert to UTF-8

View File

@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Frontend.Translations.Tests.Models
{
public class SpellCheckResult
{
private Regex wordRegex = new Regex(@"\p{L}+", RegexOptions.Multiline | RegexOptions.Compiled);
public SpellCheckResult(string text)
{
Text = text;
Words = wordRegex.Matches(text).Select(m => m.Value)
.Where(w => !string.IsNullOrEmpty(w))
.Where(w => !w.StartsWith("{{"))
.ToList();
SpellIssues = new List<SpellIssue>();
}
public string Text { get; }
public List<string> Words { get; }
public List<SpellIssue> SpellIssues { get; set; }
public bool HasProblems
{
get
{
return SpellIssues.Any(issue => issue.Suggestions.Any());
}
}
}
}

View File

@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace Frontend.Translations.Tests.Models
{
public class SpellIssue
{
public SpellIssue(string word, IEnumerable<string> suggestions)
{
Word = word;
Suggestions = suggestions;
}
public string Word { get; }
public IEnumerable<string> Suggestions { get; }
}
}

View File

@ -0,0 +1,88 @@
using System;
using WeCantSpell.Hunspell;
namespace Frontend.Translations.Tests
{
public static class SpellCheck
{
public static Models.SpellCheckResult HasSpellIssues(string text, WordList dictionary)
{
var result = new Models.SpellCheckResult(text);
foreach (var word in result.Words)
{
if (!dictionary.Check(word))
{
result.SpellIssues.Add(new Models.SpellIssue(word, dictionary.Suggest(word)));
}
}
return result;
}
public static string GetDictionaryLanguage(string lng)
{
// az,bg,cs,de,el,en,en-US,es,fi,fr,it,ja,ko,lo,lv,nl,pl,pt,pt-BR,ro,ru,sk,sl,tr,uk,vi,zh-CN
switch (lng)
{
case "az":
return "az_Latn_AZ";
case "bg":
return "bg_BG";
case "cs":
return "cs_CZ";
case "de":
return "de_DE";
case "el":
return "el_GR";
case "en":
return "en_GB";
case "en-US":
return "en_US";
case "es":
return "es_ES";
//case "fi":
// return "";
case "fr":
return "fr_FR";
case "it":
return "it_IT";
//case "ja":
// return "";
case "ko":
return "ko_KR";
//case "lo":
// return "";
case "lv":
return "lv_LV";
case "nl":
return "nl_NL";
case "pl":
return "pl_PL";
case "pt":
return "pt_PT";
case "pt-BR":
return "pt_BR";
case "ro":
return "ro_RO";
case "ru":
return "ru_RU";
case "sk":
return "sk_SK";
case "sl":
return "sl_SI";
case "tr":
return "tr_TR";
case "uk":
return "uk_UA";
case "vi":
return "vi_VN";
//case "zh-CN":
// return "";
default:
throw new NotSupportedException();
}
}
}
}

@ -0,0 +1 @@
Subproject commit 8222c8ca5d017973a76197551958f4aac0f75f71