Telegram Group & Telegram Channel
#compiler

Простые тесты для C++ кода на Python 🍄🍄🍄🍄🍄

Часто хочется покрыть тестами код на C++ в проекте - не логику, которую описывает код, а сам исходный код. Сейчас для этого есть приличное количество чекеров в clang-tidy. Можно написать свой чекер, который все равно будут ревьюить много месяцев и КПД всего этого занятия близок к нулю. Для специфических проверок надо что-то колхозить самому.

Примерных проверок может быть много:
1️⃣ Запрет на использование typeid(x).name(), потому что он дает mangled имя, с советом использовать костыль, который отдаст demangled имя.
2️⃣ Запрет на использование старого API в новом коде во время масштабного рефакторинга.
3️⃣ Проверка, что в начале каждого файла находится копипаста лицензии проекта.

Можно придумать проверку на примере лямбд 😊 Пусть у нас есть такой код:
    int counter = 15;
const auto addEvent = [&counter](int number) {
if (counter > 0) {
// do something...
--counter;
}
};
// ... call the lambda
addEvent(1337);
В этом примере лямбда использует внешнюю переменную, которая влияет на логику.
Если переменная используется только внутри лямбды, то ее можно вкостылить прямо в capture list. Тогда вместо двух верхних строк примера будет такая строка, дающая аналогичный результат:
    auto addEvent = [counter = 15](int number) mutable {
Такой же подход работает для переменных любых типов. Если интересно, что происходит внутри лямбд, то можно почитать целую книгу про них.

Попробуем сделать тест на такие кейсы 😁 Если мы для этого используем библиотеки clang, то логика такая:
1️⃣ Получаем AST (Abstract Syntax Tree) из исходного кода.
2️⃣ Лямбды в AST это вершины LambdaExpr.
3️⃣ "Объявление переменной" в AST это вершина VarDecl.
4️⃣ "Использование переменной" (в каком-то месте) это вершина DeclRefExpr.
5️⃣ Если все "использования переменной" находятся внутри какого-то одного и того же LambdaExpr, а "объявление переменной" находится вне этого LambdaExpr, то тест должен упасть, потому что данную переменную можно всунуть в capture list лямбды.
6️⃣ Делаем рекурсивный обход AST с корня и держанием указателя на "текущую лямбду", и делаем проверку на пункт 5.

Этот тест можно сделать на 👩‍💻 C++: вкостылить новый чекер в локальной сборке clang-tidy или просто сделать программу на libclang. Но можно сделать то же самое на 👩‍💻 Python и кода будет меньше в несколько раз, и это делается быстрее - менее муторно. Python хорошо подходит для быстрого написания разных тестов.

Поддерживается libclang в Python, и после просмотра примеров можно поставить его себе:
    pip install pytest
pip install clang
pip install libclang
и сделать такой простой тест, где реализуется описанная проверка для лямбд. Можно в директории рядом сохранить тестовый файл source.cpp и проверить, что тест падает:
    python3 -m pytest test.py

Вывод:
E           Failed: These variables can be declared in lambda capture: 
E "counter" (at source.cpp:3:44), to lambda at source.cpp:4:88

libclang на Python выглядит нормально, но неприятно то, что для понятия "нода AST" не к месту придумали новый термин "курсор".
Также не хватает некоторых очевидных фичей, например получения родительской ноды: в курсорах есть пара ссылок на другие курсоры (типа родительские, двух видов), но они работают неправильно.

Кроме тестов можно писать другие тулзы, например "кодогенераторы" - которые сгенерируют какой-нибудь исходник на основе существующего кода. Про кодогенераторы можно почитать лонгрид.

Еще можно делать "исправляторы" исходников - которые берут AST, что-то туда дописывают и сохраняют в другой файл, а компилятор имеет дело с уже поправленным AST (то есть с этим другим файлом).
Please open Telegram to view this post
VIEW IN TELEGRAM



group-telegram.com/cxx95/106
Create:
Last Update:

#compiler

Простые тесты для C++ кода на Python 🍄🍄🍄🍄🍄

Часто хочется покрыть тестами код на C++ в проекте - не логику, которую описывает код, а сам исходный код. Сейчас для этого есть приличное количество чекеров в clang-tidy. Можно написать свой чекер, который все равно будут ревьюить много месяцев и КПД всего этого занятия близок к нулю. Для специфических проверок надо что-то колхозить самому.

Примерных проверок может быть много:
1️⃣ Запрет на использование typeid(x).name(), потому что он дает mangled имя, с советом использовать костыль, который отдаст demangled имя.
2️⃣ Запрет на использование старого API в новом коде во время масштабного рефакторинга.
3️⃣ Проверка, что в начале каждого файла находится копипаста лицензии проекта.

Можно придумать проверку на примере лямбд 😊 Пусть у нас есть такой код:

    int counter = 15;
const auto addEvent = [&counter](int number) {
if (counter > 0) {
// do something...
--counter;
}
};
// ... call the lambda
addEvent(1337);
В этом примере лямбда использует внешнюю переменную, которая влияет на логику.
Если переменная используется только внутри лямбды, то ее можно вкостылить прямо в capture list. Тогда вместо двух верхних строк примера будет такая строка, дающая аналогичный результат:
    auto addEvent = [counter = 15](int number) mutable {
Такой же подход работает для переменных любых типов. Если интересно, что происходит внутри лямбд, то можно почитать целую книгу про них.

Попробуем сделать тест на такие кейсы 😁 Если мы для этого используем библиотеки clang, то логика такая:
1️⃣ Получаем AST (Abstract Syntax Tree) из исходного кода.
2️⃣ Лямбды в AST это вершины LambdaExpr.
3️⃣ "Объявление переменной" в AST это вершина VarDecl.
4️⃣ "Использование переменной" (в каком-то месте) это вершина DeclRefExpr.
5️⃣ Если все "использования переменной" находятся внутри какого-то одного и того же LambdaExpr, а "объявление переменной" находится вне этого LambdaExpr, то тест должен упасть, потому что данную переменную можно всунуть в capture list лямбды.
6️⃣ Делаем рекурсивный обход AST с корня и держанием указателя на "текущую лямбду", и делаем проверку на пункт 5.

Этот тест можно сделать на 👩‍💻 C++: вкостылить новый чекер в локальной сборке clang-tidy или просто сделать программу на libclang. Но можно сделать то же самое на 👩‍💻 Python и кода будет меньше в несколько раз, и это делается быстрее - менее муторно. Python хорошо подходит для быстрого написания разных тестов.

Поддерживается libclang в Python, и после просмотра примеров можно поставить его себе:
    pip install pytest
pip install clang
pip install libclang
и сделать такой простой тест, где реализуется описанная проверка для лямбд. Можно в директории рядом сохранить тестовый файл source.cpp и проверить, что тест падает:
    python3 -m pytest test.py

Вывод:
E           Failed: These variables can be declared in lambda capture: 
E "counter" (at source.cpp:3:44), to lambda at source.cpp:4:88

libclang на Python выглядит нормально, но неприятно то, что для понятия "нода AST" не к месту придумали новый термин "курсор".
Также не хватает некоторых очевидных фичей, например получения родительской ноды: в курсорах есть пара ссылок на другие курсоры (типа родительские, двух видов), но они работают неправильно.

Кроме тестов можно писать другие тулзы, например "кодогенераторы" - которые сгенерируют какой-нибудь исходник на основе существующего кода. Про кодогенераторы можно почитать лонгрид.

Еще можно делать "исправляторы" исходников - которые берут AST, что-то туда дописывают и сохраняют в другой файл, а компилятор имеет дело с уже поправленным AST (то есть с этим другим файлом).

BY C++95


Warning: Undefined variable $i in /var/www/group-telegram/post.php on line 260

Share with your friend now:
group-telegram.com/cxx95/106

View MORE
Open in Telegram


Telegram | DID YOU KNOW?

Date: |

There was another possible development: Reuters also reported that Ukraine said that Belarus could soon join the invasion of Ukraine. However, the AFP, citing a Pentagon official, said the U.S. hasn’t yet seen evidence that Belarusian troops are in Ukraine. In a message on his Telegram channel recently recounting the episode, Durov wrote: "I lost my company and my home, but would do it again – without hesitation." Apparently upbeat developments in Russia's discussions with Ukraine helped at least temporarily send investors back into risk assets. Russian President Vladimir Putin said during a meeting with his Belarusian counterpart Alexander Lukashenko that there were "certain positive developments" occurring in the talks with Ukraine, according to a transcript of their meeting. Putin added that discussions were happening "almost on a daily basis." A Russian Telegram channel with over 700,000 followers is spreading disinformation about Russia's invasion of Ukraine under the guise of providing "objective information" and fact-checking fake news. Its influence extends beyond the platform, with major Russian publications, government officials, and journalists citing the page's posts. Recently, Durav wrote on his Telegram channel that users' right to privacy, in light of the war in Ukraine, is "sacred, now more than ever."
from de


Telegram C++95
FROM American