C #: модульный тест для дифференциации CurrentCulture от InvariantCulture - PullRequest
8 голосов
/ 24 апреля 2011

У меня есть метод, который принимает аргумент StringComparison, и ему действительно нужен модульный тест, чтобы доказать, что он выполняет правильный тип сравнения.

Это в основном то, что я имею до сих пор. Он отличает Порядковый от остальных, сравнивая «oe» и «œ» (см. System.String ). Однако я не нашел способа отличить CurrentCulture от InvariantCulture.

using System;
using NUnit.Framework;
using System.Threading;
using System.Globalization;

namespace NUnitTests
{
    [TestFixture]
    public class IndexOfTests
    {
        [Test]
        public void IndexOf_uses_specified_comparison_type()
        {
            StringComparison comparisonTypePerformed;

            result = TestComparisonType(StringComparison.CurrentCulture);
            Assert.AreEqual(StringComparison.CurrentCulture, comparisonTypePerformed);

            result = TestComparisonType(StringComparison.InvariantCulture);
            Assert.AreEqual(StringComparison.CurrentCulture, comparisonTypePerformed);

            result = TestComparisonType(StringComparison.Ordinal);
            Assert.AreEqual(StringComparison.CurrentCulture, comparisonTypePerformed);
        }

        bool TestComparisonType(StringComparison comparisonType)
        {
            int result;

            // Ensure the current culture is consistent for test
            var prevCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);

            try
            {
                result = IndexOf("oe", "œ", comparisonType);
                if (result == 0)
                {
                    // The comparison type performed was either CurrentCulture,
                    // InvariantCulture, or one of the case-insensitive variants.

                    // TODO: Add test to differentiate between CurrentCulture and InvariantCulture
                    throw new NotImplementedException();
                    result = IndexOf("???????", "???????", StringComparison.CurrentCulture);

                    //...
                }
                else // result == -1
                {
                    // The comparison type performed was either Ordinal or OrdinalIgnoreCase

                    result = IndexOf("a", "A", StringComparison.CurrentCulture);
                    if (result)
                        Console.WriteLine("Comparison type was OrdinalIgnoreCase");
                    else
                        Console.WriteLine("Comparison type was Ordinal");
                }
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = prevCulture;
            }
        }
    }
}

Я подумал об использовании турецкой задачи путем сравнения «i» и «I», но это работает только для сравнения без учета регистра.

Я осмотрелся и не смог найти случай, когда InvariantCulture отличается от других культур в тесте на равенство строк (только порядок сортировки и синтаксический анализ / сериализация). Например, в зависимости от культуры «ô» и «o» сортируются по-разному, но все культуры возвращают один и тот же результат в тестах на равенство.

Существует ли тест на равенство, чтобы отличить InvariantCulture от любой другой культуры?

EDIT: Немецкие "ß" и "ss" дают одинаковый результат для всех культур, поэтому они не будут работать.

EDIT: На самом деле все, что нужно, - это две строки, считающиеся равными в одной культуре и неравными в другой.

Ответы [ 3 ]

3 голосов
/ 30 апреля 2011

Образец MSDN для CultureInfo содержит пример с различными порядками сортировки в зависимости от культуры.Я думаю, что это ваша наиболее вероятная ставка на стартовое место.Однако вы можете воспользоваться некоторыми сведениями ниже, если это не сработает.

Похоже, аналогичный набор тестов выполняется на String.Compare MSDNстр.В этом примере, однако, это в ан-американской культуре.

Если вы посмотрите на страницу CultureInfo.InvarientCulture, вы заметите, что InvarientCulture основан на английском языке, но без какой-либо региональной или национальной кодировки.А на странице StringComparison упоминается, что дефисы имеют разный вес в зависимости от языка.Вы можете воспользоваться этим, найдя язык, который весит дефисы не так, как английский.

В Википедии есть несколько интересных заметок по сортировке в статье collation , которые также могут быть полезны.Посмотрите конкретно через сортировку по алфавиту, а затем посмотрите на испанские заметки.

Например, 29-буквенный алфавит испанского трактует - как основную букву после n, а ранее трактовал ch и ll какосновные буквы, следующие за c и l соответственно.Буквы Ch и ll по-прежнему считаются буквами, но теперь они расположены в алфавитном порядке как двухбуквенные комбинации.

Я не уверен, насколько это будет полезно, но это может привести к ответу.

2 голосов
/ 11 мая 2011

Благодаря blackSphere мне удалось обнаружить несколько различий между некоторыми культурами и InvariantCulture, как показано в следующем коде:

void Demonstration_For_LL()
{
    int foundPos;

    foundPos = "ll".IndexOf("l", StringComparison.InvariantCulture);
    Assert.AreEqual(0, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sq", false);
    foundPos = "ll".IndexOf("l", StringComparison.CurrentCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sq-AL", false);
    foundPos = "ll".IndexOf("l", StringComparison.CurrentCulture);
    Assert.AreEqual(-1, foundPos);
}

void Demonstration_For_CH()
{
    int foundPos;

    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(0, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("cs", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("cs-CZ", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sk", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sk-SK", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("vi", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("vi-VN", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);
}

К сожалению, метод string.Compare, похоже, непоказать эти различия.Во всяком случае, мой метод испытаний выглядит следующим образом:

class Example
{
    public static void Main()
    {
        var comparisonTypePerformed =
            GetComparisonTypePerformed(
                new TestedMethod(string.IndexOf));

        Console.WriteLine("Comparison type performed was: " + comparisonTypePerformed);
    }

    public static StringComparison GetComparisonTypePerformed(TestedMethod testedMethod)
    {
        StringComparison comparisonTypePerformed;

        var prevCulture = Thread.CurrentThread.CurrentCulture;
        try
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);

            // Check if method performs an Ordinal search
            int result = testedMethod("œ", "oe", 0, 1, comparisonType);

            if (result == StringHelper.NPOS)
            {
                // Check if method performs a case-sensitive search
                result = testedMethod("a", "A", 0, 1, comparisonType);

                if (result == StringHelper.NPOS)
                    comparisonTypePerformed = StringComparison.Ordinal;
                else
                    comparisonTypePerformed = StringComparison.OrdinalIgnoreCase;
            }
            else
            {
                Thread.CurrentThread.CurrentCulture = new CultureInfo("sq-AL", false);

                // Check if method uses CurrentCulture or InvariantCulture
                result = testedMethod("ll", new string[] { "l" }, 0, 2, comparisonType);

                if (result == StringHelper.NPOS)
                {
                    // Check if method performs a case-sensitive search
                    result = testedMethod("a", new string[] { "A" }, 0, 1, comparisonType);

                    if (result == StringHelper.NPOS)
                        comparisonTypePerformed = StringComparison.CurrentCulture;
                    else
                        comparisonTypePerformed = StringComparison.CurrentCultureIgnoreCase;
                }
                else
                {
                    // Check if method performs a case-sensitive search
                    result = testedMethod("a", new string[] { "A" }, 0, 1, comparisonType);

                    if (result == StringHelper.NPOS)
                        comparisonTypePerformed = StringComparison.InvariantCulture;
                    else
                        comparisonTypePerformed = StringComparison.InvariantCultureIgnoreCase;
                }
            }
        }
        finally
        {
            Thread.CurrentThread.CurrentCulture = prevCulture;
        }

        return comparisonTypePerformed;
    }

    delegate int TestedMethod(string source, string value, int startIndex, int count, StringComparison comparisonType);
}
1 голос
/ 24 апреля 2011

Попробуйте Coté и Cote с FR-FR в качестве вашей текущей культуры.

Или используйте этот ресурс MSDN , чтобы найти другие примеры.

Я осмотрелся и не смог найти случай, когда InvariantCulture отличается от других культур сравнением строк (только порядок сортировки и синтаксический анализ / сериализация).

Я не понимаю этот комментарий - конечно, порядок сортировки использует StringComparison.

...