Порядок выполнения зависимостей в модуле Boost Unit Test Framework

Я пытаюсь установить зависимости в платформе Boost Unit Testing Framework. Я обнаружил, что этот поток tbat имеет пример того, как использовать метод test_unit::depen_on(). Пока все хорошо, я могу написать магию вокруг этого, чтобы сгладить это. Однако UTF не учитывает тестовые зависимости во время выполнения.

Сценарий: BOOST_AUTO_TEST_CASE A объявляется перед другим (B), и A depen_on() B Ожидаемый (желательный) результат: среда определяет сначала зависимость и запускает B, а затем A, если B преуспел. Фактический результат: A пропускается, потому что B, который еще не запущен, "провалился" (т. Е. Пока нет / ложный результат).

Теперь моя идея состояла в том, чтобы выполнить топологическую сортировку тестовых наборов / наборов, а затем запустить их в отсортированном порядке. Для этого я создал test_tree_visitor, чтобы пройтись по наборам и определить порядок члена m_members test_suite.

Однако m_members защищен и недоступен через методы. Поскольку я не могу изменить заголовки (это усложнит обновление до более новой версии и т. Д. И т. Д.), А макросы BOOST_* "жестко кодируют" класс как test_suite, я подумал о следующей хакерской атаке:

class member_accessible_test_suite : public test_suite
{
public:
    const std::vector<test_unit_id> *get_members() const { return &m_members; }
};

class dependency_order_visitor : public test_tree_visitor
{
public:
    virtual void visit( test_case const& tu)
    {}

    virtual bool test_suite_start( test_suite const& tu)
    {
        const member_accessible_test_suite *psuite(reinterpret_cast<const member_accessible_test_suite*>(&tu));
        const std::vector<test_unit_id> *pmembers(psuite->get_members());
        /* do something with pmembers */
        return true;
    }

    virtual void test_suite_finish( test_suite const& tu)
    {}

};

Смотрите разбавленную версию на Coliru

Итак, теперь на мои вопросы:

  1. Библиотеки буста, как правило, хорошо спроектированы - я делаю фундаментальную ошибку из-за неправильного понимания дизайна модульного тестирования, требуя эту функцию?

  2. Так как member_accessible_test_suite не имеет данных и добавляет только функции, является ли reinterpret_cast() безопасным или быстрым переулком на землю UB? В любом случае, я боюсь использовать такой ужасный хак в производстве.

  3. Есть ли лучший способ, и если да, то в какой момент это превратилось в проблему XY?

1 ответ

Решение

Следующий способ кажется наиболее подходящим при работе с членами базового класса, которые не предоставляются каким-либо механизмом (но к ним необходимо получить доступ для некоторой близкой функциональности, а базовый класс нельзя изменять):

Ссылка: доступ к закрытым переменным-членам

Обоснование этой идеи относительно того, почему это работает, можно найти в 14.7.2p8 стандарта:

Обычные правила проверки доступа не применяются к именам, используемым для указания явных экземпляров. В частности, аргументы и имена шаблонов, используемые в деклараторе функции (включая типы параметров, типы возвращаемых данных и спецификации исключений), могут быть закрытыми типами или объектами, которые обычно недоступны, а шаблон может быть шаблоном-членом или функцией-членом, которая не будет обычно быть доступным.]

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

Как и все эти обходные пути - используйте с умом!

/* The ROB_PRIVATE_MEMBER_INST() macro should be used for explicit instantiation of the template at the appropriate source/compilation unit
   The ROB_PRIVATE_MEMBER_ACCESS() macro should be used for access to the variable where required
*/
#define ROB_PRIVATE_MEMBER_INST(CLASS, TYPE, MEMBER)    \
template<typename T>                                    \
struct CLASS##_##MEMBER##_rob_tag {                     \
  typedef T CLASS::*type;                               \
  friend type get(CLASS##_##MEMBER##_rob_tag);          \
};                                                      \
template<typename Tag, typename Tag::type M>            \
struct CLASS##_##MEMBER##_rob_private                   \
{                                                       \
    friend typename Tag::type get(Tag) { return M; }    \
};                                                      \
template struct CLASS##_##MEMBER##_rob_private<         \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>;     \
/**/

#define ROB_PRIVATE_MEMBER_ACCESS(CLASS, INSTANCE, TYPE, MEMBER) \
    (INSTANCE.*get(CLASS##_##MEMBER##_rob_tag<TYPE>()))          \
/**/
Другие вопросы по тегам