Библиотеки и тестирование
Сборка библиотек
libtool — инструмент для кроссплатформенной сборки и тестирования библиотек.
Пример:
lib.c
libg.c
lib.h
main.c
Makefile к ним
А теперь с Libtool:
Makefile:
1 CFLAGS = -g -O 2 LTFLAGS = --tag=CC 3 4 all: inc 5 6 %.lo: %.c 7 libtool --mode=compile $(LTFLAGS) $(CC) -c $< 8 9 libinc.la: lib.lo libg.lo 10 libtool --mode=link $(LTFLAGS) $(CC) -o $@ $^ -rpath /usr/lib64 11 12 inc: main.o libinc.la 13 libtool --mode=link $(LTFLAGS) $(CC) -o $@ $^ 14 15 check: inc 16 ./$< 123 17 18 clean: 19 rm -rf *.so inc .libs *.l? *.o
Особенности:
- Сборка двух вариантов библиотек
Использование RPATH
Использование shell-обёрток для подгрузки .so
Версионирование библиотек
-version-info current:revision:age
current — +1 при любом вмешательстве в ABI
revision — +1 при каждом выпуске, не меняющем ABI, 0 при вмешательстве в ABI (т. е. изменении current)
age — +1 при добавлении в ABI, 0 при изменении или удалении (не должно быть больше current)
SONAME: version.minor.subminor
Особенность библиотек: обратно совместимы при добавлении ABI, не совместимы при удалении/изменении
Например, добавление поля в конец структуры при определённых дисциплинах программирования на Си не ломает ABI
vresion = current - age
minor = age
subminor = revision
⇒ Можно поддерживать несколько вариантов интерфейсов, от current - age до current
⇒ «Версия» как таковая отсутствует, version растёт неравномерно
Семантическое версионирование Версия: MAJOR.MINOR.PATCH:
Обратно несовместимые изменения ABI (удаление / изменение сигнатур) — MAJOR++.MINOR=0.PATCH=0
Обратно совместимые изменения ABI 9добавление) — MAJOR.MINOR++.PATCH=0
Обратно совместимые багфиксы ABI и изменения, не затрагивающие ABI — MAJOR.MINOR.PATCH++
В работе:
- Можно добавлять ещё чиселок — для пре-релизов и/иили номеров сборки
-release MAJOR.MINOR.PATCH
TODO как подсовывать SONAME в libtool
Тестирование
Целесообразно начать с преобразования исходного текста — это шаг №0 репозитория с примером
- в действительности — шесть шагов).
TODO возможно, в этот раз нужен пример попроще. Да хоть этот самый libinc?
Коротко о видах тестирования
- модульное → системное → (интеграционное) → приёмочное
Модульное: тысячи их
Модульное, XUnit
- Немного терминологии
- Runner: кто запускает тесты
- Иерархия test → case → suite
Каждый test может завершиться успехом или неуспехом
Если все тесты из case успешны, нечто считается оттестированным
Для разных случаев / подсистем / etc некоторые случаи объединяются в suit
- Fixture: подготовка (set up) и последующая ликвидация (tear down) окружения, которое нужно тестировать
- (например, изготовление специальных тестовых объектов)
- Coverage: насколько полно оттестирована программа
- Системное и далее — слишком много методологий
- CI — не рассматриваем, хотя, возможно, стоило бы
Check
- ЯП — C
Поддержка TAP и др.
- Поддержка pkgconfig (⇒ autotools, cmake и т. п.)
Meson: похоже, нет: в Meson любойтест — это отдельная программа, а что в ней, ему не интересно.
Check + autotools
За основу взят https://github.com/skeeto/fantasyname/tree/master/c
- (это довольно безумная генерилка несуществующих имен с непростым синтаксисом шаблонов)
- Автор — адепт учения «include-библиотеки», придётся превратить в классическую библиотеку
Лицензия у него: The Unlicense
Этапы разработки:
- Предварительные шаги
Импорт, организация autotools-проекта и выделение кода библиотеки в отдельный файл
Простой тест. Здесь и далее раннером работает shell-perl-… начинка ./test-driver, поставляемая с autotools.
Авторские тесты удалены из основной прогарммы и переписаны на checkmk
Поскольку runner-ом у нас всё ещё работает ./test-driver, с его точки зрения это один тест, все подробности про внутренние suite и cases libcheck-а ему неизвестны.
TODO Возможно, стоит прикрутить к этому Test_Anything_Protocol, поддержка есть и в autotools, и в check
Небольшая плюшка — просмотр журнала тестирования
Как минимум, CK_VERBOSITY=verbose make check и grep "" *.log
TODO добавить фикстуру
странное для checkmk TODO а пользоваться-то этим как?
Тестовое покрытие
- Запускаются все тесты со сбором статистики:
- Какие строчки кода сколько раз выполнялись
- В какую сторону и сколько раз ветвились условия
- … (см. по ссылке)
- Составляется БД с этой статистикой
- Инструменты анализа и просмотра
- Самый частый критерий: проценты покрытия кода
Опять-таки тысячи их, посмотрим GCov
Встроен в gcc ⇒ требует специальной пересборки
Понятно, что эксплуатировать такие бинарники не надо
В тестовом репозитории:
в частности, просто make check; cd src; gcov -o .libs libnamegen (
libnamegen — это название базы, собранной при make check.
CMake / CTest / …
(Не успеем)
CMake: add_tests
CMake + check: CMake + check
CMAke + CTest: короткая статья, в документации, руководство
CMake + CTest + coverage: в документации, в руководстве по CTest
Meson / Gcovr
(Не успеем)
-Db_coverage=true на этапе configure (абзац в документации Meson)
Gcovr — python-обёртка над gcov
Д/З
- Изучить выбранный вами фреймворк тестов для Си
Например, check, autotools и пример из лекции
- В ALT Linux понадобятся:
make, automake, autoconf
libtool
libcheck-devel, check
- (кажется, всё?)
- В ALT Linux понадобятся:
Взять за основу Growable Memory Buffers for C99
- Превратить в библиотеку
Функция в ней всего одна, остальное макросы, и переделывать это не надо
Все макросы уезжают в .h-файл
Приложение-пример можно не писать
Тесты взять из авторского файла tests.c
Тесты на память с setjmp() можно выкинуть.
- Оформить их сообразно правилам фреймворка в несколько отдельных тестов
(необязательно) попробовать добиться как можно более полного покрытия (предельные тексты, например, с помощью prlimit)
- Сделать примитивную поддержку проверки покрытия (чтобы проценты показывало)
- Превратить в библиотеку
В репозитории с домашними заданиями создать подкаталог 10_LibTesting и положить решение туда