Архив рубрики: рабочее

Тестирование PHP-приложений из Geany

Когда-то я настраивал запуск тестов перловых Mojolicious-приложений прямо из IDE Geany. Потом довелось попробовать микрофреймворк Slim для PHP — ну да, работает, хотя тесты там более многословные по сравнению с перловыми.

А теперь попробуем настроить Geany для запуска тестов в современных PHP-приложениях — например, для использующих уже упомянутый Slim. Для запуска тестов в PHP существует PHPUnit — это не единственный инструмент, хоть и весьма популярный. Настройки тестирования зависят от проекта — в каждом проекте они могут быть своими. В Geany 1.27 настройки вызываются через меню: Project → Properties → вкладка Build либо Build → Set Build Commands:

  1. Задаём имя команды, под которым она будет отображаться в меню — нажимаем на пустую кнопку в столбце Label (в моём примере это была вторая сверху кнопка, на которой теперь написано Test).
  2. Указываем в столбце Command путь к PHPUnit — он может лежать, например, в подкаталоге vendor/bin относительно корня приложения. В случае, если он лежит внутри проекта, базовый путь проекта можно записать как %p.
  3. В столбце Working directory указываем путь к корневой папке приложения.
  4. В строке Error regular expression указываем регулярное выражение для поиска ошибок:
    ^(.+):(\d+)$
    PHPUnit выводит в сообщении об ошибке разделённые двоеточием полный путь к файлу и номер строки с ошибкой. Если даблкликнуть^W дважды щёлкнуть по сообщению, можно быстро перейти к соответствующей строке, кроме того, все строки, вызвавшие ошибки тестирования, выделяются подчёркиванием красной волнистой линией.

После настройки тесты можно будет запускать кучей разных способов: через меню, кликом по кнопке с кирпичом, а также с клавиатуры (по умолчанию — клавишей F9).

Подсчёт числа DOM-элементов при тестировании через Test::Mojo

Модуль Test::Mojo позволяет проверить, нашлось ли нужное количество DOM-элементов:

$t = $t->element_count_is('div.foo[x=y]', 5);
$t = $t->element_count_is('html body div', 30, 'thirty elements');

Но так можно проверить лишь равенство ожидаемого и полученного, в то время как иногда нужны другие операции.

$t->get_ok("$ROOT/some.xml");
my @items = $t->tx->res->dom->find('rss channel item')->each;
ok scalar @items > 42, 'More than 42 items in some.xml';

Один белый, другой синий — два слона весёлых

Пробую вышедший недавно четвёртый pgAdmin — а это (внезапно!) веб-приложение, как сейчас модно. Ладно хоть, не тащит за собой ни хром, ни мозиллу, а запускается в новой вкладке существующего браузера. Написано на питоне, весит 22 МБ, из коих половина — картинки, клиентские скрипты, шрифты да переводы.

Аська выступает

ICQ (точнее, Mail.ru Group), похоже, хочет заставить пользователей переползти на использование нового клиента. Мне кажется, эффект будет обратным — народ разбежится.

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

Разрешаем Имиджмеджику делать PDF

ImageMagick позволяет собирать многостраничный PDF-файл из нескольких растровых картинок, но не всегда — на некоторых компьютерах выдаёт ошибку

convert: not authorized `result.pdf' @ error/constitute.c/WriteImage/1028.

Причина — в том, что в конкретном экземпляре может быть запрещено создавать PDF, но есть рецепт, как это исправить: в файле /etc/ImageMagick-6/policy.xml надо включить нужное разрешение — строку

<policy domain="coder" rights="none" pattern="PDF" />

надо заменить на 

<policy domain="coder" rights="read|write" pattern="PDF" />

После этого PDF-файл будет нормально создаваться.

Теперь осталось понять, почему же готовый файл вдвое тяжелее суммы исходных. Добавление в команду преобразования параметров -dither none -colors 2 на размер готового файла практически не влияет.

Правильный тип для офисных файлов

Перловый микрофреймворк Mojolicious::Lite умеет сам выдавать существующие файлы, но при этом не все из них получают верный тип содержимого Content-type: некоторые файлы прикидываются обычными текстовыми (text/plain), другие же вообще не имеют никакого типа — браузер такие файлы может воспринимать как угодно. В состав фреймворка входит модуль Mojolicious::Types, в котором определены MIME-типы для наиболее популярных (most common) расширений файлов:

appcache -> text/cache-manifest
atom     -> application/atom+xml
bin      -> application/octet-stream
css      -> text/css
gif      -> image/gif
gz       -> application/x-gzip
htm      -> text/html
html     -> text/html;charset=UTF-8
ico      -> image/x-icon
jpeg     -> image/jpeg
jpg      -> image/jpeg
js       -> application/javascript
json     -> application/json;charset=UTF-8
mp3      -> audio/mpeg
mp4      -> video/mp4
ogg      -> audio/ogg
ogv      -> video/ogg
pdf      -> application/pdf
png      -> image/png
rss      -> application/rss+xml
svg      -> image/svg+xml
txt      -> text/plain;charset=UTF-8
webm     -> video/webm
woff     -> font/woff
woff2    -> font/woff2
xml      -> application/xml,text/xml
zip      -> application/zip

странно, но среди них нет ни одного, относящегося к офисным пакетам. На сайте Microsoft | Developer можно найти список типов — Office 2007 File Format MIME Types for HTTP Content Streaming. Чтобы не задумываться, какие же из этих типов брать, можно сохранить все — если есть какой-нибудь конфигурационный файл, он вполне подойдёт для хранения такого списка. В моём случае конфигурационные файлы обычно в формате YAML — это удобно.

---
# ... ещё какие-нибудь параметры

# MS Office types
types:
    rtf:    application/rtf
    doc:    application/msword
    dot:    application/msword
    docx:   application/vnd.openxmlformats-officedocument.wordprocessingml.document

Где-нибудь перед запуском приложения надо добавить типы (допустим, конфигурация приложения доступна через $config)

while ( my ( $ext, $type ) = each %{ $config->{'types'} } ) {
    app->types->type($ext => $type);
}

Правда, при выдаче файла тип его содержимого придётся всё-таки указать явно, иначе Mojolicious вернёт тип только для знакомых файлов, а для офисных будет undef

my $type = $self->app->types->mapping->{$ext}->[0];
if (my $asset = $self->app->static->file("/$path/$id.$ext")) {
    $self->res->headers->content_type($type);
    return $self->reply->asset($asset);
}
else {
    return $self->reply->not_found;
}

Теперь и офисные файлы возвращаются нормально.

Регистрозависимая сортировка

Линуксовая команда sort (во всяком случае, в Ubuntu 16.04 LTS) почему-то сразу сортирует без учёта регистра, хотя такое поведение должно включаться специальным ключом -f либо --ignore-case. Ключа --no-ignore-case для выключения такого поведения нет. Выход — сортировать перловым однострочником


perl -0777 -ne 'print join "\n", sort split "\n"'