C ++ тест для проверки равенства оператора поддерживается со временем структура - PullRequest
6 голосов
/ 02 мая 2011

Я проголосовал за @TomalakGeretkal за хорошую заметку о контракте;Я не принял ответ, так как мой вопрос заключается в том, как программно проверить функцию равенства.


У меня есть структура POD и оператор равенства, (очень) небольшая часть системы с> 100 инженерами.

Со временем я ожидаю, что структура будет изменена (добавлены / удалены / переупорядочены члены), и я хочу написать тест, чтобы убедиться, что оператор равенства проверяет каждый член структуры (например, поддерживается в актуальном состоянии).по мере изменения структуры).

Как отметил Томалак, комментарии & «по контракту» часто являются лучшим / единственным способом обеспечить это;однако в моей ситуации я ожидаю проблем и хочу выяснить, есть ли какие-либо способы активного улова (хотя бы многих) модификаций.

Я не придумаю удовлетворительный ответ - это лучшее, что яподумал:

-new up two instances struct (x, y), fill each with identical non-zero data.
-check x==y
-modify x "byte by byte"
    -take ptr to be (unsigned char*)&x
    -iterator over ptr (for sizeof(x))
        -increment the current byte
        -check !(x==y)
        -decrement the current byte
        -check x==y

Тест проходит, если оператор равенства перехватывает каждый байт (ПРИМЕЧАНИЕ: это предостережение - не все байты используются в представлении компилятора x, поэтому тест будетнеобходимо пропустить эти байты - например, жесткий код игнорирует байты)

Мой предлагаемый тест имеет существенные проблемы: (по крайней мере) байты «не заботятся» и тот факт, что увеличивается один байт типовв x может не привести к допустимому значению для переменной в этой области памяти.

Есть ли лучшие решения?

(Это не должно иметь значения, но я использую VS2008, rtti выключен, GoogleTest Suite)

Ответы [ 5 ]

6 голосов
/ 02 мая 2011

Хотя соблазнительно сделать код «защищенным от глупостей» с помощью таких самопроверок, мой опыт показывает, что самопроверка сама по себе является надежной, ну, в общем-то, это идиотское поручение.и локализовать влияние любых изменений.Напишите комментарий в определении структуры, пояснив, что оператор равенства также должен быть обновлен, если структура имеет вид;затем, если это не удастся, это просто ошибка программиста.

Я знаю , что это не покажется вам оптимальным, поскольку это оставляет возможность для ошибки пользователя в будущем, но на самом деле выне может обойти это (по крайней мере, не делая ваш код ужасно сложным), и часто это наиболее практично, просто не беспокоиться.

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

Я согласен с (и одобрил) ответом Томалака.Вряд ли вы найдете надежное решение.Тем не менее, одним простым полуавтоматическим подходом может быть проверка ожидаемого размера в операторе равенства:

MyStruct::operator==(const MyStruct &rhs) 
{
  assert(sizeof(MyStruct) == 42);  // reminder to update as new members added

  // actual functionality here ...
}

Таким образом, если добавляются какие-либо новые члены, assert будет срабатывать, пока кто-то не обновит оператор равенства.Это не надежно, конечно.(Членские переменные могут быть заменены чем-то такого же размера и т. Д.) Тем не менее, это относительно простой (одна строка утверждать), у которого есть хороший шанс обнаружить случай ошибки.

0 голосов
/ 02 мая 2011

Согласна с Томалаком и Эриком.Я использовал это для очень похожих проблем.

Assert не работает, если не определен DEBUG, поэтому вы можете выпустить неправильный код.Эти тесты не всегда будут работать надежно.Если структура содержит битовые поля или вставлены элементы, которые занимают место из-за недостатка места, поскольку компилятор выравнивает границы слов, размер не изменится.По этой причине они предлагают ограниченную ценность.например,

struct MyStruct {   
    char a ;
    ulong l ;
}

изменено на

struct MyStruct {   
    char a ;
    char b ;  
    ulong l ;
}

Обе структуры имеют размер 8 байт (в 32-битном Linux x86)

0 голосов
/ 02 мая 2011

это на самом деле сложная проблема, которую нужно решить самостоятельно в ходе самопроверки.

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

некоторые из этих проблем легче поддерживать / проверять с помощью таких подходов, как композиция, а не расширение / подклассы.

0 голосов
/ 02 мая 2011

Я уверен, что за это проголосую, но ...

Как насчет функции равенства шаблонов, которая принимает ссылку на параметр int и два тестируемых объекта.Функция равенства возвращает bool, но увеличивает размер (int) на sizeof (T).

Затем создайте большую тестовую функцию, которая вызывает шаблон для каждого объекта и суммирует общий размерсравните эту сумму с размером объекта.Существование виртуальных функций / наследования и т. Д. Может убить эту идею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...