解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
10.36 KiB
X
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using NewLife;
using NewLife.Configuration;
using Xunit;

namespace XUnitTest.Common;

/// <summary>语言清单与显示名称测试。用例会临时注册运行时语言,放入串行集合</summary>
[Collection("GlobalState")]
public class LanguageListTests
{
    private const String Key = "Language list probe: {0}.";

    private static LanguageInfo? Find(IList<LanguageInfo> list, String name)
    {
        foreach (var item in list)
        {
            if (item.Name.EqualIgnoreCase(name)) return item;
        }

        return null;
    }

    private static String[] GetLanguageCodes(String text) => Regex.Matches(text, @"\b[a-z]{2}-[A-Za-z]{2,4}\b")
        .Select(m => m.Value)
        .OrderBy(m => m, StringComparer.Ordinal)
        .ToArray();

    private static Boolean CultureAvailable(String name)
    {
        try
        {
            _ = CultureInfo.GetCultureInfo(name);
            return true;
        }
        catch (Exception ex) when (ex is CultureNotFoundException || ex is ArgumentException)
        {
            return false;
        }
    }

    [Fact(DisplayName = "语言清单:内置语言全部在列且顺序固定")]
    public void Builtin()
    {
        var list = Localization.GetLanguages();

        Assert.True(list.Count >= Localization.SupportedCultures.Length);
        Assert.Equal("zh-CN", list[0].Name);
        Assert.Equal("zh-TW", list[1].Name);
        Assert.Equal("en-US", list[2].Name);

        for (var i = 0; i < Localization.SupportedCultures.Length; i++)
        {
            Assert.Equal(Localization.SupportedCultures[i], list[i].Name);
        }
    }

    [Fact(DisplayName = "语言清单:每项都带键、自称与英文名")]
    public void Names()
    {
        foreach (var item in Localization.GetLanguages())
        {
            Assert.False(item.Name.IsNullOrEmpty());
            Assert.False(item.NativeName.IsNullOrEmpty());
            Assert.False(item.EnglishName.IsNullOrEmpty());
        }
    }

    [Fact(DisplayName = "语言名称:英文界面同时显示英文名与自称,中文界面显示自称")]
    public void DisplayName()
    {
        var list = Localization.GetLanguages();
        var zh = Find(list, "zh-CN")!;
        var en = Find(list, "en-US")!;
        var enCulture = CultureInfo.GetCultureInfo("en-US");
        var zhCulture = CultureInfo.GetCultureInfo("zh-CN");

        var prev = CultureInfo.CurrentUICulture;
        try
        {
            // 名称本地化跟随当前界面语言(.NET 区域数据),显式传入的显示语言在非当前界面语言时走词表
            CultureInfo.CurrentUICulture = enCulture;

            Assert.Equal("Chinese (Simplified)", zh.EnglishName);
            Assert.Equal("简体中文", zh.NativeName);
            Assert.Equal("Chinese (Simplified)", zh.GetName(enCulture));
            Assert.Equal("Chinese (Simplified) (简体中文)", zh.GetDisplayName(enCulture));
            Assert.Equal("简体中文", zh.GetName(zhCulture));
            Assert.Equal("简体中文", zh.GetDisplayName(zhCulture));

            Assert.Equal("English", en.GetDisplayName(enCulture));

            // 同属中文的繁体在简体界面直接显示自称
            var tw = Find(list, "zh-TW")!;
            Assert.Equal("Chinese (Traditional) (繁體中文)", tw.GetDisplayName(enCulture));
            Assert.Equal("繁體中文", tw.GetDisplayName(zhCulture));

            // 当前界面语言为中文时,语言名称交给 .NET 区域数据,无需词表
            CultureInfo.CurrentUICulture = zhCulture;

            // 不变量全球化(无 ICU 区域数据)下 .NET 无法按中文显示英文名,退回英文
            var enName = en.GetDisplayName(zhCulture);
            Assert.Equal(TestSetup.HasCultureData ? "英语 (English)" : "English", enName);
            var deName = Find(list, "de-DE")!.GetDisplayName(zhCulture);
            Assert.Equal(TestSetup.HasCultureData ? "德语 (Deutsch)" : "German (Deutsch)", deName);
        }
        finally
        {
            CultureInfo.CurrentUICulture = prev;
        }
    }

    [Fact(DisplayName = "语言名称:词表提供译文时按目标语言显示")]
    public void LocalizedName()
    {
        var zh = CultureInfo.GetCultureInfo("zh-CN");
        var de = Find(Localization.GetLanguages(), "de-DE")!;
        try
        {
            // 语言名称就是普通词条,以英文名称为键登记译文即可本地化
            Localization.Register(zh, new Dictionary<String, String> { [de.EnglishName] = "德语" }, true);

            Assert.Equal("德语", de.GetName(zh));
            Assert.Equal("德语 (Deutsch)", de.GetDisplayName(zh));
        }
        finally
        {
            Localization.Unregister(zh);
        }
    }

    [Fact(DisplayName = "语言名称:区域数据未本地化时退回英文名,可由词表改写")]
    public void LocalizedName_english_fallback()
    {
        var en = CultureInfo.GetCultureInfo("en-US");
        var de = Find(Localization.GetLanguages(), "de-DE")!;
        var prev = CultureInfo.CurrentUICulture;
        try
        {
            // 英文界面下 .NET 区域名称与英文名一致,不应直接显示区域数据,而是交给词表(无译文时为英文名)
            CultureInfo.CurrentUICulture = en;
            Localization.Register(en, new Dictionary<String, String> { [de.EnglishName] = "German (custom)" }, true);

            Assert.Equal("German (custom)", de.GetName(en));
            Assert.Equal("German (custom) (Deutsch)", de.GetDisplayName(en));
        }
        finally
        {
            CultureInfo.CurrentUICulture = prev;
            Localization.Unregister(en);
        }
    }

    [Fact(DisplayName = "语言清单:运行时注册的语言自动出现,注销后移除")]
    public void Dynamic()
    {
        // 测试程序集自带的 ta.yml 在模块初始化时注册,等价于下游动态新增语言
        if (CultureAvailable("ta")) Assert.NotNull(Find(Localization.GetLanguages(), "ta"));

        var culture = CultureInfo.GetCultureInfo("af-ZA");
        try
        {
            Assert.Null(Find(Localization.GetLanguages(), "af-ZA"));

            Localization.Register(culture, new Dictionary<String, String> { [Key] = "آزمون {0}." });

            var item = Find(Localization.GetLanguages(), "af-ZA");
            Assert.NotNull(item);
            Assert.Equal(culture.NativeName, item.NativeName);
            Assert.Equal("af-ZA", Localization.NormalizeCulture("af-ZA"));
            Assert.Equal("af-ZA", Localization.NormalizeCulture("af"));

            Localization.Unregister(culture);

            Assert.Null(Find(Localization.GetLanguages(), "af-ZA"));
            Assert.Null(Localization.NormalizeCulture("af-ZA"));
        }
        finally
        {
            Localization.Unregister(culture);
        }
    }

    [Fact(DisplayName = "语言清单:旧版别名不重复出现")]
    public void LegacyAlias()
    {
        if (!CultureAvailable("in")) return;

        var culture = CultureInfo.GetCultureInfo("in");
        try
        {
            Localization.Register(culture, new Dictionary<String, String> { [Key] = "Uji {0}." });

            // in/iw/no/mo 是 id/he/nb/ro 的旧名,归一化后与内置区域语言重合,不应单独出现在清单里
            Assert.Null(Find(Localization.GetLanguages(), "in"));
            Assert.Equal("id-ID", Localization.NormalizeCulture("in"));
            Assert.Equal("he-IL", Localization.NormalizeCulture("iw"));
            Assert.Equal("nb-NO", Localization.NormalizeCulture("no"));
            Assert.Equal("ro-RO", Localization.NormalizeCulture("mo"));
        }
        finally
        {
            Localization.Unregister(culture);
        }
    }

    [Fact(DisplayName = "语言选项:键为语言代码,显示名随界面语言本地化")]
    public void Options()
    {
        var prev = Localization.Culture;
        var prevUI = CultureInfo.CurrentUICulture;
        try
        {
            Localization.Culture = CultureInfo.GetCultureInfo("zh-CN");
            CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("zh-CN");

            var options = Localization.GetLanguageOptions();

            Assert.True(options.Count >= Localization.SupportedCultures.Length);
            Assert.Equal("简体中文", options["zh-CN"]);
            // 不变量全球化(无 ICU 区域数据)下区域显示名退回英文名,仅自称仍可用
            Assert.Equal(TestSetup.HasCultureData ? "英语 (English)" : "English", options["en-US"]);
            Assert.Equal(TestSetup.HasCultureData ? "德语 (Deutsch)" : "German (Deutsch)", options["de-DE"]);
            Assert.Equal(TestSetup.HasCultureData ? "日语 (日本語)" : "Japanese (日本語)", options["ja-JP"]);
        }
        finally
        {
            Localization.Culture = prev;
            CultureInfo.CurrentUICulture = prevUI;
        }
    }

    [Fact(DisplayName = "界面语言:Description 与内置语言清单一致")]
    public void DescriptionListsSupportedCultures()
    {
        var property = typeof(Setting).GetProperty(nameof(Setting.Language))!;
        var description = property.GetCustomAttribute<DescriptionAttribute>()?.Description;
        Assert.False(description.IsNullOrEmpty());

        var expected = Localization.SupportedCultures.OrderBy(m => m, StringComparer.Ordinal).ToArray();
        Assert.Equal(expected, GetLanguageCodes(description!));
    }

    [Fact(DisplayName = "配置注释:界面语言列出全部内置语言码")]
    public void ConfigCommentListsSupportedCultures()
    {
        var root = new ConfigSection { Key = "Root", Childs = [] };
        root.MapFrom(new Setting());
        var comment = root.Find("Language")?.Comment;
        Assert.False(comment.IsNullOrEmpty());

        var expected = Localization.SupportedCultures.OrderBy(m => m, StringComparer.Ordinal).ToArray();
        Assert.Equal(expected, GetLanguageCodes(comment!));

        var prev = Localization.LogCulture;
        try
        {
            Localization.LogCulture = CultureInfo.GetCultureInfo("zh-CN");
            Assert.Contains("界面语言", comment!.LocalizeComment());
        }
        finally
        {
            Localization.LogCulture = prev;
        }
    }
}