С.В. Герасимов, И.В. Машечкин, М.И. Петровский и др. Инструментальные средства разработки ПО в ОС UNIX (1114660), страница 9
Текст из файла (страница 9)
Возвращает индекс (начинаяс 0) найденного элементалибо -1. В случае нескольких вхождений одного и того же элемента,возвращается индекспроизвольного.При отсутствии искомого элемента в массиве через posBeforeвозвращается индекс ближайшегоэлемента, меньшего искомого */int _bsearch (int * array, int len, int elem, int * posBefore){int low = 0, high = len - 1;while(low <= high){int mid = (low + high) / 2;if (elem == array[mid])return mid;else if (elem < array[mid])55high = mid - 1;elselow = mid + 1;}if(NULL != posBefore)*posBefore = high;return -1;}int contains(Set * set, int elem){return indexOf(set, elem) != -1;}int indexOf(Set * set, int elem){return _bsearch(set->data, set->size - 1, elem, NULL);}Result insert(Set * set, int elem){int index, posBefore;index = _bsearch(set->data, set->size, elem, &posBefore);if(index != -1)return FAIL;set->data = realloc(set->data, sizeof(int) * (set->size + 1));memmove(set->data + posBefore + 2, set->data + posBefore + 1,sizeof(int) * (set->size - posBefore - 1));set->data[posBefore + 1] = elem;set->size++;return SUCCESS;}Result remove(Set * set, int elem){int index, posBefore;index = _bsearch(set->data, set->size, elem, &posBefore);if(index == -1)return FAIL;set->data = realloc(set->data, sizeof(int) * (set->size - 1));memmove(set->data + index, set->data + index + 1, sizeof(int) *(set->size - index - 1));set->size--;return SUCCESS;56}Автоматические тесты могут созданы как на функции интерфейсабиблиотеки:void test1(void){Set s = {0};CU_ASSERT_EQUAL(s.size, 0);insert(&s, 3);CU_ASSERT_EQUAL(s.size, 1);insert(&s, 1);CU_ASSERT_EQUAL(s.size, 2);CU_ASSERT_EQUAL(s.data[0], 1);CU_ASSERT_EQUAL(s.data[1], 3);}void test2(void){Set s = {0};CU_ASSERT_EQUAL(insert(&s, 1), SUCCESS);CU_ASSERT_EQUAL(insert(&s, 1), FAIL);}void test3(void){Set s = {0};insert(&s, 1);CU_ASSERT_EQUAL(remove(&s, 2), FAIL);CU_ASSERT_EQUAL(remove(&s, 1), SUCCESS);}, так и на функцию _bsearch, используемую реализацией библиотеки:void test4(){int array[] = {1, 3, 5, 11};int size = sizeof(array) / sizeof(int);int posBefore;57CU_ASSERT_EQUAL(_bsearch(array, size, 4, &posBefore),-1);CU_ASSERT_EQUAL(posBefore, 1);CU_ASSERT_EQUAL(_bsearch(array, size, 19,&posBefore), -1);CU_ASSERT_EQUAL(posBefore, 3);CU_ASSERT_EQUAL(_bsearch(array, size, 5, &posBefore),2);}Следует отметить, что в реальных программах обычно создаетсябольшее число тестов, чем в рассмотренном примере.
Тестовоепокрытие должно по возможности описывать все многообразиеситуаций,вкоторыхотфункциихочетсяожидатьдетерминированный результат. Например, «пустые» параметры,граничные точки, вообще говоря, любые параметры, обладающиесвойствами, прямо или косвенно используемыми реализацией(например, четность/нечетность числа элементов массива в_bsearch). Иногда бывает полезно включить в тестовый набор тесты,проверяющие обработку функцией входных некорректныхпараметров.Пример кода помещения тестов в набор и их автоматическогозапуска:#include <CUnit/Basic.h>int main(){CU_pSuite suite;CU_initialize_registry();suite = CU_add_suite("main_suite", NULL, NULL);CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,test1);test2);test3);test4);CU_basic_run_tests();58CU_cleanup_registry();return CU_get_error();}Данная тестирующая программа, скомпилированная в исполняемыйфайл testrunner в последствии может стать отдельной цельюMakefile:test:testrunnerПример запуска среды интерактивной проверки CUnit:#include <CUnit/Console.h>int main(){CU_pSuite suite;CU_initialize_registry();suite = CU_add_suite("main_suite", NULL, NULL);CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,test1);test2);test3);test4);CU_console_run_tests();CU_cleanup_registry();return 0;}Документирование исходных использованием Doxygen текстов программ с Возвращаясь к примеру функции _bsearch из предыдущегораздела, реализующей бинарный поиск, следует обратить вниманиена тот факт, что имея перед глазами один только прототип этойфункцииint _bsearch (int * array, int len, int elem, int *posBefore)59, сложно догадаться о смысле некоторых параметров, например,параметра posBefore.
Конечно же, можно заглянуть в реализациюфункции, однако это требует дополнительного времени, сил исопряжено с ошибками интерпретации кода. Кроме этого, не во всехслучаях исходный текст реализации доступен программисту.Помочь решить проблему может документирование данной функции– снабжение ее текстом, описывающим семантику параметров ивозвращаемого значения. Документирование, как правило,производится в исходном тексте программы, используяспециальнымобразомразмеченныйкомментарийязыкапрограммирования,расположенныйнепосредственнопередописываемым элементом программы: типом либо функцией.Системы генерации документации позволяют упроститьпроцесс документирования.Основной их задачей являетсяавтоматическоепостроениефайловдокументацииподокументирующимкомментариям.Принимаянавходдокументированные исходные тексты программы, генератордокументации сопоставляет документирующие комментарии сдокументируемыми элементами программы, осуществляет разбор иконтроль корректности разметки и формирует итоговуюдокументацию в одном из популярных текстовых форматов.Кросс-платформенная система генерации документацииподдерживаетязыкиDoxygen(http://www.doxygen.org)программирования Си++, Си, Objective-C, Python, Java, IDL, PHP,C#, Fortran, VHDL, D и генерирует документацию на основе набораисходных текстов, содержащих документирующие комментарии встиле Си/Си++.
Кроме этого Doxygen может быть использован дляизвлечения структуры программы из недокументированныхисходных кодов. Возможно автоматическое составление диаграммклассов и графов зависимостей сущностей программы. Doxygenподдерживает генерацию документации в форматах HTML, LATEX,man, RTF и XML.Doxygen является консольной программой.
Параметрыпостроения документации хранятся в конфигурационном файле,имеющем текстовый формат.60Документирование исходного кода Блоки комментариев Для документирования исходного кода используются блокикомментариев в стиле Си/Си++ с использованием дополнительнойразметки. Для каждой сущности программы могут быть заданыописания двух типов: подробное и краткое (для функций такжесуществует третий тип описания – «в теле»).
Краткое описание –однострочное, подробное – более детализированное многострочное,описание «в теле», как правило, используется для описанияреализации функции.Существует несколько способов отметить блок комментариякак подробное описание:1.
Многострочный комментарий, начинающийся с двух или более«*», т.н. JavaDoc стиль описания:/*** Подробное* описание*/Промежуточные ‘*’ не обязательны:/**Подробноеописание*/2. Многострочный комментарий, начинающийся с «/!*». Описаниев стиле QT./*!* Подробное* описание*/3.
Три или более однострочных комментария Си/Си++, где каждаястрока начинается с «///» или «//!»:////// Подробное/// описание///и:61//!//! Текст//!4. Более выделенные в исходном коде блоки комментариев:/********** Подробное* описание**********/и://////////////////////// Подробное/// описание/////////////////////Способы создания краткого описания:1. Использование команды brief:/*** @brief Краткое* описание** Полное описание*/В данном случае краткое и полное описания разделяются пустойстрокой.2.
Использованиережимаконфигурационном файле.JAVADOC_AUTOBRIEF=YESвВ данном режиме краткое описание не требует отдельной команды изавершается точкой либо новой строкой:/*** Краткое описание. Полное описание*/3. Разделение на несколько блоков:/// Краткое описание/*** Полное* описание*/62или:/// Краткое описание/// Полное/// описаниеОбязательна пустая строка между кратким и полным описанием.Документирование функций Для документирования параметров функции используется командаparam, возвращаемых значений - return:/*** Двоичный поиск в упорядоченном массиве.** В случае нескольких вхождение одного и того же элемента,возвращается индекс произвольного.** @param[in] array массив чисел* @param[in] len длина массива* @param[in] elem искомый элемент* @param[out] posBefore при отсутствии искомого элемента в массиве* через posBefore возвращается индекс ближайшего** @return Индекс (начиная с 0) найденного элемента либо -1.*/int _bsearch (int * array, int len, int elem, int * posBefore);Задавать тип параметра in (входной) / out (выходной) необязательно.Фрагмент сгенерированного Doxygen описания данной функции (сдиаграммой вызова данной функции):63Запуск Doxygen В результате выполнения командыdoxygen –g <имя конфигурационного файла>Doxygenсоздастновыйконфигурационныйконфигурационного файла по умолчанию Doxygen.файл.ИмяДля использования Doxygen при документировании исходныхфайловнаСиможетпригодитьсяопция«OPTIMIZE_OUTPUT_FOR_C = YES».
Также может быть полезнаопция «JAVADOC_AUTOBRIEF = YES» для интерпретации первойстроки комментария как краткого комментария без указаниякоманды @brief. Для выбора кодировки исходных текстов илокализации файла документации существуют параметры«INPUT_ENCODING» и «OUTPUT_LANGUAGE».После редактирования файла можно использовать командуdoxygen <имя конфигурационного файла>для генерации документации.64В Makefile может быть создана соответствующая цель,отвечающая за генерацию документации:doc:doxygenДля визуального редактирования опций конфигурационногофайла и запуска генерации документации в состав Doxygen входитграфическая утилита doxywizard:Полныйпереченькомандразметкииопцийконфигурационного файла можно найти в документации Doxygen.65.