Как можно тестировать интерпретатор или компилятор?

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

очевидно, что с Brainfuck набор инструкций невелик, но я не могу не думать, что по мере добавления дополнительных инструкций ваш тестовый код будет расти экспоненциально. Во всяком случае, больше, чем обычные тесты.

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

в принципе, где вы даже начать с тестирования на что-то подобное?

6 ответов


тестирование компилятора немного отличается от тестирования некоторых других приложений, потому что для компилятора нормально создавать разные версии сборочного кода программы, если они все делают правильно. Однако, если вы просто тестируете интерпретатор, он почти такой же, как и любое другое текстовое приложение. Вот Unix-ориентированный взгляд:

  1. вы захотите создать регрессионных тестов. Каждый тест должен иметь
    • исходный код вы будете интерпретировать, скажем test001.bf
    • стандартный ввод в программу, которую вы будете интерпретировать, скажем test001.0
    • что вы ожидаете, что интерпретатор произведет на стандартном выходе, скажем test001.1
    • что вы ожидаете, что интерпретатор произведет на стандартной ошибке, скажем test001.2 (вы заботитесь о стандартной ошибке, потому что вы хотите, чтобы проверить сообщения об ошибках переводчика)
  2. вам понадобится скрипт" run test", который делает что-то вроде следующего

    function fail {
      echo "Unexpected differences on :"
      diff  
      exit 1
    }
    
    for testname
    do
      tmp1=$(tempfile)
      tmp2=$(tempfile)
      brainfuck $testname.bf < $testname.0 > $tmp1 2> $tmp2
      [ cmp -s $testname.1 $tmp1 ] || fail "stdout" $testname.1 $tmp1
      [ cmp -s $testname.2 $tmp2 ] || fail "stderr" $testname.2 $tmp2
    done
    
  3. вам будет полезно иметь скрипт" создать тест", который делает что-то вроде

    brainfuck $testname.bf < $testname.0 > $testname.1 2> $testname.2
    

    вы запускаете это только тогда, когда вы полностью уверены, что переводчик работает для этого случая.

  4. вы держите свой набор тестов под контролем источника.

  5. удобно украсить ваш тестовый скрипт, чтобы вы могли оставить файлы, которые ожидалось, что будет пусто.

  6. каждый раз, когда что-то меняется, вы повторно запускаете все тесты. Вероятно, вы также повторно запускаете их все по ночам через работу cron.

  7. наконец, вы хотите добавить достаточно тестов, чтобы получить хороший покрытие тестами в исходном коде компилятора. Качество инструментов покрытия варьируется в широких пределах, но GNU Gcov является адекватным инструментом покрытия.

удачи с вашим переводчиком! Если вы хотите увидеть любовно созданную, но не очень хорошо документированную инфраструктуру тестирования, посмотрите на на быстрый C -- компилятор.


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

Как и любой сложный программный объект, будет много путей кода, но поскольку все это очень ориентировано на данные (текст, текст и байты), это просто для авторских тестов.


Я написал статью о тестировании компилятора, первоначальный вывод которой (слегка смягченный для публикации) был: морально неправильно изобретать колесо. Если вы уже не знаете все о существующих решениях и у вас есть очень веская причина игнорировать их, вы должны начать с рассмотрения инструментов, которые уже существуют. Самое простое место для начала -Gnu C Пытка, но имейте в виду, что он основан на Deja Gnu, который имеет, скажем так, проблемы. (Мне потребовалось шесть попыток, чтобы заставить сопровождающего разрешить критический отчет об ошибке о примере Hello World в списке рассылки.)

я нескромно предлагаю вам посмотреть на следующее в качестве отправной точки для инструментов для исследования:

  1. программное обеспечение: практика и опыт апреля 2007 года. (Payware, недоступно для широкой публики - - - бесплатный препринт на http://pobox.com / ~flash/Practical_Testing_of_C99.pdf.

  2. http://en.wikipedia.org/wiki/Compiler_correctness#Testing (в основном написано мной.)

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


в случае brainfuck, я думаю, что тестирование должно быть сделано со сценариями brainfuck. Однако я бы проверил следующее:

1: все ячейки равны 0

2: что происходит, когда вы уменьшаете указатель данных, когда он в настоящее время указывает на первую ячейку? Он заворачивается? Указывает ли это на недопустимую память?

3: Что происходит, когда вы инкремент указателя данных, когда он указывает на последнюю ячейку? Он заворачивается? Она указывает неверный память!--1-->

4: Правильно ли работает выход

5: Правильно ли функционирует вход

6: Правильно ли работает [] материал

7: что происходит, когда вы увеличиваете байт более 255 раз, правильно ли он обертывается до 0 или неправильно обрабатывается как целое число или другое значение.

возможны и другие тесты, но, вероятно, я бы начал с этого. Несколько лет назад я написал компилятор BF, и у него было несколько дополнительных тестов. Особенно Я протестировал [] материал сильно, имея много кода внутри блока, так как в ранней версии моего генератора кода были проблемы (на x86 с использованием jxx у меня были проблемы, когда блок произвел более 128 байтов кода или около того, что привело к недопустимому x86 asm).


вы можете протестировать некоторые уже написанные приложения.


секрет в том, что:

  • отдельные проблемы
  • соблюдайте закон Деметры
  • введите свои зависимости

ну, программное обеспечение, которое трудно проверить, является признаком того, что разработчик написал его, как это 1985. Извините, что говорю это, но, используя три принципа, которые я представил здесь, даже строка с номером BASIC была бы проверяемой (можно вводить зависимости в BASIC, потому что вы можете сделать "переменную goto".