Skip to content

Latest commit

 

History

History
83 lines (54 loc) · 6.62 KB

File metadata and controls

83 lines (54 loc) · 6.62 KB

UtBot-Python

Общая задача: написать utbot для языка Python, использующий fuzzing при генерации тестов.

Основные подзадачи:

  • Получить функции, которые нужно протестировать
  • Сгенерировать значения для аргументов
  • Вычислить значения функции на этих аргументах
  • Отрендерить тесты для функций

Получение функций

Список функций формируется через UI (Intellij IDEA / консоль).

Данные о функциях, которые должны передаваться:

  • название
  • список аргументов
  • код функции
  • аннотации типов аргументов (опционально)
  • аннотация типа возвращаемого значения (опционально)

Генерация тестовых данных

Хотим генерировать значения для всех аргументов функции.

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

Проблема: как сузить значения при генерации для аргумента без аннотации?

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

Для сложных / пользовательских классов без представителей нужно рекурсивно для каждого поля создать представителя. Это может быть достаточно сложно, так как не все поля могут иницализироваться в __init__ и для получения данных о них нужно проанализировать все методы исходного класса. Первым шагом здесь будет случай, когда все поля можно получить из функции инициализации и они имеют примитивные типы.

Проверять можно только те типы, которые доступны (импортированы) в содержащем файле.

Чтобы получить требования к методам аргумента, нужно построить дерево исполнения функции, конечные методы в каждой ветке будут соответствовать одному из подходящих вариантов. Для этого есть несколько библиотек на Python:

  • pycallgraph (очень старая, есть более новая версия pycallgraph2: июль 2019) динамический анализ
  • pyan (последний релиз: февраль 2021) статический, но неполный
  • Jonga (релиз: ноябрь 2018) динамический анализ

Либо можно делать это самостоятельно.

Информация о типах

Для описанного выше алгоритма необходимо составить большую базу о встроенных типах. Их много поэтому, возможно, придется автоматизировать этот процесс.

Составлять можно либо по коду CPython (можно по тестам), либо по коду GraalPython, либо руками.

Данные о типе

О каждом типе нужно хранить следующие данные:

  • имя
  • методы: имя + аргументы (+аннотации)
  • базовые поля?
  • доступ к конструктору

Два последних поля скорее всего не нужны, и сложно определяются для built-in типов. Мы будем создавать тестовые экземляры руками.

Примеры можно брать из cpyhton/Lib/test.

Поддерживаемые операции:

  • Генерировать объект с дефолтными значениями
  • Генерировать с константами из кода

Данные о функции

  • имя
  • аргументы с аннотациями
  • где лежит

Запуск функции с полученными аргументами

Для каждого типа мы должны уметь создавать представителей, можно хранить код для этого в текстовом виде.

Пока что проводим запуск функции непосредственно через запуск python в отдельном процессе. Для этого нужно сгенерировать код, который будет содержать код функции / умеет ее импортировать и сохранять в восстанавливаемом формате (можно попробовать json, для некоторых типов есть сериализатор по умолчанию, для остальных придется писать самим, но это должно быть проще, чем писать польностью свой код).

Некоторые типы очень сложно (невозможно) сохранить и создать такой же, будем считать, что такие типы не можем обрабатывать как результат функции. Пример: socket.

Генерация тестов

Сначала нужно построить AST того кода, который мы хотим выполнять, далее сгенерировать соответствующий код. Нужно либо пользоваться ANTLR, либо написать самостоятельно.

Потом нужно записать этот код в правильный файл.