mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-24 18:23:01 +08:00
297 lines
10 KiB
C#
297 lines
10 KiB
C#
using AtomUI.Build.Tasks;
|
|
using Microsoft.Build.Framework;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace AtomUI.Build.Tasks.Tests;
|
|
|
|
public class ValidateLanguageFilesTaskTests : IDisposable
|
|
{
|
|
private readonly string _directory = Path.Combine(
|
|
Path.GetTempPath(),
|
|
$"atomui-localization-task-tests-{Guid.NewGuid():N}");
|
|
|
|
public ValidateLanguageFilesTaskTests()
|
|
{
|
|
Directory.CreateDirectory(_directory);
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Reports_Xliff_Parse_Errors_With_Source_Location()
|
|
{
|
|
var path = Write("invalid.xlf", CreateXliff(version: "2.0"));
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles = [Item(path, "ModuleBuiltIn")]
|
|
};
|
|
|
|
task.Execute().ShouldBeFalse();
|
|
|
|
var error = engine.Errors.ShouldHaveSingleItem();
|
|
error.Code.ShouldBe("ATOMUILOC005");
|
|
error.File.ShouldBe(path);
|
|
error.LineNumber.ShouldBeGreaterThan(0);
|
|
error.Message.ShouldNotBeNull().ShouldContain("version");
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Requires_Complete_Module_Bundles_But_Allows_Partial_Overrides()
|
|
{
|
|
var source = Write("en-US.xlf", CreateXliff(targetLanguage: null));
|
|
var target = Write("zh-CN.xlf", CreateXliff(targetLanguage: "zh-CN", includeSecondTarget: false));
|
|
var partialOverride = Write(
|
|
"zh-CN.override.xlf",
|
|
CreateXliff(targetLanguage: "zh-CN", includeSecondUnit: false));
|
|
var moduleEngine = new RecordingBuildEngine();
|
|
var moduleTask = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = moduleEngine,
|
|
LanguageFiles =
|
|
[
|
|
Item(source, "ModuleBuiltIn"),
|
|
Item(target, "ModuleBuiltIn")
|
|
]
|
|
};
|
|
|
|
moduleTask.Execute().ShouldBeFalse();
|
|
moduleEngine.Errors.Any(error =>
|
|
error.Code == "ATOMUILOC007" &&
|
|
error.Message?.Contains("unit '2'", StringComparison.Ordinal) == true)
|
|
.ShouldBeTrue();
|
|
|
|
var overrideEngine = new RecordingBuildEngine();
|
|
var overrideTask = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = overrideEngine,
|
|
LanguageFiles =
|
|
[
|
|
Item(source, "ModuleBuiltIn"),
|
|
Item(partialOverride, "ApplicationOverride")
|
|
]
|
|
};
|
|
|
|
overrideTask.Execute().ShouldBeTrue();
|
|
overrideEngine.Errors.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Rejects_Duplicate_Translation_Sources_At_The_Same_Priority()
|
|
{
|
|
var first = Write("first.xlf", CreateXliff(targetLanguage: "zh-CN"));
|
|
var second = Write("second.xlf", CreateXliff(targetLanguage: "zh-CN"));
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles =
|
|
[
|
|
Item(first, "StaticLanguagePack", "Pack.One"),
|
|
Item(second, "StaticLanguagePack", "Pack.Two")
|
|
]
|
|
};
|
|
|
|
task.Execute().ShouldBeFalse();
|
|
var error = engine.Errors.ShouldHaveSingleItem();
|
|
error.Code.ShouldBe("ATOMUILOC006");
|
|
error.Message.ShouldNotBeNull().ShouldContain("same priority");
|
|
error.Message.ShouldNotBeNull().ShouldContain("Pack.One");
|
|
error.Message.ShouldNotBeNull().ShouldContain("Pack.Two");
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Accepts_Disjoint_Application_Override_Fragments()
|
|
{
|
|
var source = Write("en-US.xlf", CreateXliff(targetLanguage: null));
|
|
var titleOverride = Write(
|
|
"title.override.xlf",
|
|
CreateXliff(targetLanguage: "zh-CN", includeSecondUnit: false));
|
|
var bodyOverride = Write(
|
|
"body.override.xlf",
|
|
CreateXliff(targetLanguage: "zh-CN", includeFirstUnit: false));
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles =
|
|
[
|
|
Item(source, "ModuleBuiltIn"),
|
|
Item(titleOverride, "ApplicationOverride", "TestApp.Title"),
|
|
Item(bodyOverride, "ApplicationOverride", "TestApp.Body")
|
|
]
|
|
};
|
|
|
|
task.Execute().ShouldBeTrue();
|
|
engine.Errors.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Rejects_Overlapping_Application_Override_Units()
|
|
{
|
|
var source = Write("en-US.xlf", CreateXliff(targetLanguage: null));
|
|
var first = Write(
|
|
"first.override.xlf",
|
|
CreateXliff(targetLanguage: "zh-CN", includeSecondUnit: false));
|
|
var second = Write(
|
|
"second.override.xlf",
|
|
CreateXliff(targetLanguage: "zh-CN", includeSecondUnit: false));
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles =
|
|
[
|
|
Item(source, "ModuleBuiltIn"),
|
|
Item(first, "ApplicationOverride", "TestApp.One"),
|
|
Item(second, "ApplicationOverride", "TestApp.Two")
|
|
]
|
|
};
|
|
|
|
task.Execute().ShouldBeFalse();
|
|
var error = engine.Errors.ShouldHaveSingleItem();
|
|
error.Code.ShouldBe("ATOMUILOC006");
|
|
error.Message.ShouldNotBeNull().ShouldContain("unit '1'");
|
|
error.Message.ShouldNotBeNull().ShouldContain("TestApp.One");
|
|
error.Message.ShouldNotBeNull().ShouldContain("TestApp.Two");
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Accepts_A_Complete_Publishable_Bundle()
|
|
{
|
|
var source = Write("en-US.xlf", CreateXliff(targetLanguage: null));
|
|
var target = Write("zh-CN.xlf", CreateXliff(targetLanguage: "zh-CN"));
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles =
|
|
[
|
|
Item(source, "ModuleBuiltIn"),
|
|
Item(target, "ModuleBuiltIn")
|
|
]
|
|
};
|
|
|
|
task.Execute().ShouldBeTrue();
|
|
engine.Errors.ShouldBeEmpty();
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("<target state=\"translated\">标题</target>", "<target state=\"translated\"> </target>")]
|
|
[InlineData("<target state=\"translated\">标题</target>", "<target state=\"translated\" subState=\"needs-review\">标题</target>")]
|
|
public void Execute_Rejects_Unpublishable_Target_Content_Or_SubState(
|
|
string currentTarget,
|
|
string invalidTarget)
|
|
{
|
|
var source = Write("en-US.xlf", CreateXliff(targetLanguage: null));
|
|
var target = Write(
|
|
"zh-CN.xlf",
|
|
CreateXliff(targetLanguage: "zh-CN").Replace(currentTarget, invalidTarget));
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles =
|
|
[
|
|
Item(source, "ModuleBuiltIn"),
|
|
Item(target, "ModuleBuiltIn")
|
|
]
|
|
};
|
|
|
|
task.Execute().ShouldBeFalse();
|
|
engine.Errors.Any(error =>
|
|
error.Code == "ATOMUILOC007" &&
|
|
(error.Message ?? string.Empty).Contains("non-empty target", StringComparison.Ordinal))
|
|
.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_Accepts_An_Empty_English_Source_Unit()
|
|
{
|
|
var source = Write(
|
|
"en-US-empty.xlf",
|
|
"""
|
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.1" srcLang="en-US">
|
|
<file id="Test.Product.CalendarLangResourceKind">
|
|
<unit id="1" name="YearSuffix">
|
|
<segment><source></source></segment>
|
|
</unit>
|
|
</file>
|
|
</xliff>
|
|
""");
|
|
var engine = new RecordingBuildEngine();
|
|
var task = new ValidateLanguageFilesTask
|
|
{
|
|
BuildEngine = engine,
|
|
LanguageFiles = [Item(source, "ModuleBuiltIn")]
|
|
};
|
|
|
|
task.Execute().ShouldBeTrue();
|
|
engine.Errors.ShouldBeEmpty();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Directory.Delete(_directory, recursive: true);
|
|
}
|
|
|
|
private TestTaskItem Item(
|
|
string path,
|
|
string sourceKind,
|
|
string sourceIdentity = "Test.Product")
|
|
{
|
|
return new TestTaskItem(
|
|
path,
|
|
("AtomUILanguageModuleId", "Test.Product"),
|
|
("AtomUILanguageSourceKind", sourceKind),
|
|
("AtomUILanguageSourceIdentity", sourceIdentity));
|
|
}
|
|
|
|
private string Write(string fileName, string content)
|
|
{
|
|
var path = Path.Combine(_directory, fileName);
|
|
File.WriteAllText(path, content);
|
|
return path;
|
|
}
|
|
|
|
private static string CreateXliff(
|
|
string? targetLanguage = "zh-CN",
|
|
bool includeSecondTarget = true,
|
|
bool includeSecondUnit = true,
|
|
string version = "2.1",
|
|
bool includeFirstUnit = true)
|
|
{
|
|
var targetAttribute = targetLanguage is null ? string.Empty : $" trgLang=\"{targetLanguage}\"";
|
|
var firstTarget = targetLanguage is null
|
|
? string.Empty
|
|
: "<target state=\"translated\">标题</target>";
|
|
var secondTarget = targetLanguage is null || !includeSecondTarget
|
|
? string.Empty
|
|
: "<target state=\"reviewed\">正文</target>";
|
|
var secondUnit = includeSecondUnit
|
|
? $$"""
|
|
<unit id="2" name="Body">
|
|
<segment><source>Body</source>{{secondTarget}}</segment>
|
|
</unit>
|
|
"""
|
|
: string.Empty;
|
|
var firstUnit = includeFirstUnit
|
|
? $$"""
|
|
<unit id="1" name="Title">
|
|
<segment><source>Title</source>{{firstTarget}}</segment>
|
|
</unit>
|
|
"""
|
|
: string.Empty;
|
|
return $$"""
|
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0"
|
|
version="{{version}}"
|
|
srcLang="en-US"{{targetAttribute}}>
|
|
<file id="Test.Product.LoginLangResourceKind">
|
|
{{firstUnit}}
|
|
{{secondUnit}}
|
|
</file>
|
|
</xliff>
|
|
""";
|
|
}
|
|
}
|