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:
parent
649e1b420a
commit
4274e3a581
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
2
build/run.translations.spellcheck.test.bat
Normal file
2
build/run.translations.spellcheck.test.bat
Normal 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
|
@ -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
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
88
common/Tests/Frontend.Translations.Tests/SpellCheck.cs
Normal file
88
common/Tests/Frontend.Translations.Tests/SpellCheck.cs
Normal 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
|
Loading…
Reference in New Issue
Block a user