gTest и

    Написал недавно пост про " По рзелульаттам илссеовадний одонго анлигйсокго унвиертисета, не иеемт занчнеия, в кокам пряокде рсапожолены бкувы в солве..."?
    Очень меня заинтересовало — правда это или нет, а тут еще захотелось gTest поизучать и заодно попрактиковаться в Программировании через тестирование, так что написал я программку, которая таким вот образом коверкает слова.
    И действительно, это правило отлично работает — тексты, исковерканные моей программой, достаточно свободно читаются.
    Кому интересно самому поиграться, могут скачать программу тут:
    ScrambleStrings.rar — там можно вставить любой текст в верхний EditBox и нажать на «Создать». Получившийся текст можно скопировать в буфер обмена кнопкой «Копировать» и вставить куда хочешь.



    gTest оказался жутко удобной библиотекой. Почти не пришлось тратить время на его подключение — только пара ошибок линкования была и та из-за конфликтов с MFC. Использование gTest — это всего 2 строки для старта тестов, причем ими еще и через командную строку можно управлять.
    Сами тесты тоже создавать предельно просто (в конце поста будет код — можно заценить).
    Я решил написать эту утилитку по правилу «Сначала тест — потом код» и не пожалел.
    Придумал вначале несколько тестовых случаев, написал их — это помогло продумать интерфейс функции для переворачивания строки, которую я сначала хотел сделать в классе, но оказалось, что гораздо удобнее сделать просто 1 функцию.
    Как ни странно, но все те тесты, что в итоге были написаны, удалось написать сразу с первой попытки. Новых тестов придумывать не пришлось — хватило этих.
    Когда тесты готовы — тупо пишешь реализацию, компилируешь, запускаешь тесты, смотришь ошибки и исправляешь.
    Когда все заработало в тестах — только тогда запустил саму программу с GUI, она тоже уже сразу заработала :)
    На все ушло около 2 часов, из которых около часа — на разборки с MFC и SetClipboardData.
    Задачи сделать оптимально по быстродействию не стояло — просто делал быстро и чтобы работало правильно.

    Надо сказать, что я до этого использовал CppUnit в нескольких проектах и был им доволен. Но gTest показался мне более простым и удобным. К тому же он Open Source и будет постоянно дорабатываться. Мой выбор теперь — gTest.

    Собственно код тестов:

    #include «stdafx.h»
    #include <gtest/gtest.h>

    #include «StringScrambler.h»


    TEST(StringScramblerTest, TestNoChangeCases)
    {
    std::string testCases[] = {
    "",
    " ",
    «I»,
    «In»,
    «Ink»,
    " I ",
    «I am Ink»,
    ".I, ;am:-\'\" ?Ink!",
    " Are you Ink? ",
    " \n\r\n\n\r\r Are you Ink? I use tab and car ret\n\r",
    " \n\r\n\n\r\r ",
    «Arrrrrrrrrrrrrrrrrrrrrre»
    };
    for (int i = 0; i < sizeof(testCases)/sizeof(testCases[0]); ++i)
    {
    EXPECT_STREQ(testCases[i].c_str(), StringScrambler::ScrambleString(testCases[i]).c_str());
    }
    }


    TEST(StringScramblerTest, TestGoodOneWordCases)
    {
    std::string testCases[] = {«Перевернул», «Переворот», «Война», «Всегда», «Плохо», «Независимо», «Целей»};
    std::string ret;
    for (int i = 0; i < sizeof(testCases)/sizeof(testCases[0]); ++i)
    {
    ret = StringScrambler::ScrambleString(testCases[i]);
    EXPECT_STRNE(ret.c_str(), testCases[i].c_str());
    assert(ret != testCases[i]);
    EXPECT_EQ(testCases[i][0], ret[0]);
    EXPECT_EQ(testCases[i][testCases[i].length() — 1], ret[ret.length() — 1]);
    EXPECT_EQ(testCases[i].length(), ret.length());
    }
    }

    TEST(StringScramblerTest, TestSeveralWords)
    {
    std::string checkPhraze = «которое попадается им на пути»;
    std::string ret = StringScrambler::ScrambleString(checkPhraze);
    EXPECT_STRNE(ret.c_str(), checkPhraze.c_str());

    EXPECT_EQ(checkPhraze[0], ret[0]);
    EXPECT_EQ(checkPhraze[checkPhraze.length() — 1], ret[ret.length() — 1]);
    EXPECT_EQ(checkPhraze.length(), ret.length());

    EXPECT_EQ(checkPhraze[6], ret[6]);
    EXPECT_EQ(checkPhraze[8], ret[8]);
    EXPECT_EQ(checkPhraze[17], ret[17]);
    EXPECT_EQ(checkPhraze[25], ret[25]);
    }

    TEST(StringScramblerTest, TestSeveralWords2)
    {
    std::string checkPhraze = «преувеличение, потому что Грузия не входит в состав Европы»;
    std::string ret = StringScrambler::ScrambleString(checkPhraze);
    EXPECT_STRNE(ret.c_str(), checkPhraze.c_str());

    EXPECT_EQ(checkPhraze[0], ret[0]);
    EXPECT_EQ(checkPhraze[checkPhraze.length() — 1], ret[ret.length() — 1]);
    EXPECT_EQ(checkPhraze.length(), ret.length());


    EXPECT_EQ(checkPhraze[12], ret[12]);
    EXPECT_EQ(checkPhraze[15], ret[15]);
    EXPECT_EQ(checkPhraze[20], ret[20]);
    EXPECT_EQ(checkPhraze[26], ret[26]);
    EXPECT_EQ(checkPhraze[31], ret[31]);
    EXPECT_EQ(checkPhraze[36], ret[36]);
    }


    Код функции перемешивания строки, если кому надо (еще раз повторюсь, что не было задачи сделать это наиболее оптимально и красиво. Но если будут коментарии и предложения — с удовольствием почитаю):
    bool isItDelimiter(char sym)
    {
    char delimiters[] = {' ', '\t', ' ', '\r', '\n', '.', ',', '!', '?', ';', ':', '\'', '\"', '-', ')', '(', '[', ']', '{', '}'};
    for(int i = 0; i < sizeof(delimiters)/sizeof(delimiters[0]); ++i)
    if (sym == delimiters[i])
    return true;

    return false;
    }

    void scramble(const char* sourceStart, const char* sourceEnd, char* to)
    {
    int numSymbols = (int)(sourceEnd — sourceStart);
    if (numSymbols < 4)
    return;
    bool stringFromOneSymbol = true;
    for(const char* s = sourceStart + 1; s < sourceEnd — 2; ++s)
    if (*s != *(s+1))
    {
    stringFromOneSymbol = false;
    break;
    }
    if (stringFromOneSymbol)
    return;

    int numChanges = numSymbols/3 + 2;
    while(numChanges-- > 0)
    {
    int posFrom = rand()%(numSymbols — 2) + 1;
    int posTo= rand()%(numSymbols — 2) + 1;
    char t = to[posTo];
    to[posTo] = to[posFrom];
    to[posFrom] = t;
    }

    if (strncmp(sourceStart, to, numSymbols) == 0)
    scramble(sourceStart, sourceEnd, to);
    }

    const char* findAndScrambleNextString(const char* from, char* &to)
    {
    if (*from == 0)
    return from;
    const char* prevNotDelimiter = 0;

    while(*from)
    {
    *to = *from;
    if (isItDelimiter(*from))
    {
    if (prevNotDelimiter != 0)
    scramble(prevNotDelimiter, from, to — (from — prevNotDelimiter));

    prevNotDelimiter = 0;
    }
    else
    {
    if (prevNotDelimiter == 0)
    prevNotDelimiter = from;
    }
    ++from;
    ++to;
    }
    if (prevNotDelimiter != 0)
    scramble(prevNotDelimiter, from, to — (from — prevNotDelimiter));
    return from;
    }

    std::string StringScrambler::ScrambleString(const std::string& source)
    {
    if (source.length() < 4)
    return source;

    char* str = new char[source.length() + 1];
    char* strStart = str;
    strcpy_s(str, source.length() + 1, source.c_str());

    const char* from = source.c_str();
    while(*from)
    {
    from = findAndScrambleNextString(from, str);
    }

    std::string ret = strStart;
    delete []strStart;

    return ret;
    }

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 3

      0
      Код нечитаем, IDE под рукой нет. Может быть, стоит пропустить через Хабраредактор?
        0
        Странно, у меня читается отлично.
        >>Может быть, стоит пропустить через Хабраредактор?
        научите, как?

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

    Самое читаемое