|
Программирование >> Разработка устойчивых систем
long getNumPassedO const { return nPass: } long getNumFailedO const { return nFail: } const ostream* getStreamO const { return osptr; } void setStreamCostream* osptr) { this->osptr = osptr: } void succeed () { ++nPass: } long reportО const: virtual void resetO { nPass = nFail = 0: } } namespace TestSuite #endif TEST H /:- Класс Test содержит три виртуальные функции: виртуальный деструктор; функцию reset(); чисто виртуальную функцию run(). Как объяснялось в первом томе, удаление объекта производного класса через указатель на базовый класс является ошибкой, если у базового класса нет виртуального деструктора. Любой класс, который предполагается использовать в качестве базового (на что, очевидно, указывает присутствие хотя бы одной обычной виртуальной функции), должен иметь виртуальный деструктор. По умолчанию Test::reset() обнуляет счетчики успешных и неудачных проверок. Возможно, вы захотите переопределить эту функцию и организовать сброс данных в производном объекте; только не забудьте явно вызвать функцию Test::reset() из переопределенной версии, чтобы сбросить счетчики. Функция Test::run() является чисто виртуальной, поэтому ее переопределение в производном классе обязательно. Макросы test () и faiLO могут включать информацию об имени файла и номере строки, полученную от препроцессора. Изначально символы подчеркивания в этих именах отсутствовали, но макрос fa1l() конфликтовал с ios::fa1l() и вызывал ошибки компиляции. Далее приведена реализация остальных функций Test: : TestSuite:Test.срр {0} #include Test.h #incl ude <iostream> #include <typeinfo> Примечание: для Visual С++ необходим ключ /GR using namespace std; using namespace TestSuite: void Test::do test(bool cond. const std::string& Ibl. const char* fname. long lineno) { if (Icond) do fail(lbl. fname. lineno); else succeed (); void Test::do faiКconst std::strings Ibl. const char* fname. long lineno) { ++nFai1; if (osptr) { *osptr typeid(*this).nameO failure: ( Ibl ) . fname (line lineno ) endl long Test::reportО const { if (osptr) { *osptr Test \ typeid(*this).name() \ :\n\tPassed: nPass \tFailed: nFail endl: return nFail: } /:- Класс Test хранит информацию о количестве успешных и неудачных проверок, атакже выходной поток, в который функция Test::report() должна выводить результаты. Макросы test () и fail () получают текущие имя файла и номер строки от препроцессора; имя файла передается do test(), а номер строки - do fail(). Эти функции занимаются непосредственным выводом сообщений и обновлением счетчиков. Трудно представить, кому и зачем могло бы понадобиться копировать и присваивать объекты Test, поэтому мы запретили эти операции. Для этого их прототипы объявлены закрытыми, а тела функций не определяются. : TestSuite:Suite.h #ifndef SUITE H #define SUITE H #include <vector> #include <stdexcept> #include ../TestSuite/Test.h using std::vector: usi ng std::1ogi c error: namespace TestSuite { class TestSuiteError : public logic error { public: TestSuiteError(const strings s = ) : logic error(s) {} class Suite { string name: ostream* osptr: vector<Test*> tests: void resetO: Запрещенные операции: Suite(const Suites): Suites operator=(const SuiteS): public: Suite(const strings name, ostream* osptr = Scout) : name(name) { this->osptr = osptr: } string getNameO const { return name: } long getNumPassedO const: long getNumFailedO const: const ostream* getStreamO const { return osptr: } void setStream(ostream* osptr) { this->osptr = osptr; } void addTest(Test* t) throw (TestSuiteError); void addSuite(const SuiteS); long Suite::report0 const { if (osptr) { long totFail = 0: *osptr Suite \ name \ \n====== : void runO: Многократно вызывает Test::run() long reportО const: void freeO: Уничтожает объекты тестов } namespace TestSuite #endif SUITE H /:- Класс Suite хранит указатели на объекты Test в векторе. Обратите внимание на спецификацию исключенир! в объявлении функции addTest(). При включении нового объекта теста в KOHTeiinep функция Suite::addTest() убеждается в том, что переданный указатель отличен от null; в противном случае генерируется исключение TestSuite Error. Поскольку это делает невозможным добавление null-указателя в контейнер, addSuite() проверяет это условие в каждой из своих проверок; то же происходит и в других функциях, перебирающих вектор с объектами тестов (см. реализацию ниже). Как и в классе Test, операции копирования и присваивания в классе Suite запрещены. : TestSuite:Suite.cpp {0} #include Suite.h #i nclude <iostream> #i nclude <cassert> #i nclude <cstddef> using namespace std: using namespace TestSuite: void Suite::addTest(Test* t) throw(TestSuiteError) { Проверка действительности теста и наличия выходного потока: if (t == 0) throw TestSuiteErrorCNull test in Suite::addTest ): else if (osptr && !t->getStream()) t->setStream(osptr): tests.push back(t): t->reset(): void Suite::addSuite(const SuiteS s) { for (size t i = 0: i < s.tests.sizeO: ++i) { assert(tests[i]): addTest(s.tests[i]): void Suite::free() { for (size t i = 0: i < tests.sizeO: ++i) { delete tests[i]: tests[i] = 0: void Suite::run() { resetO: for (size t i = 0: i < tests.size(): ++i) { assert(tests[i]): tests[i]->run():
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |