Тестирование кода

Рейтинг: -2Ответов: 1Опубликовано: 16.06.2023

Всем доброго дня! Хочу автоматизировать проверку программ на языке С++. Допустим есть 20 файлов .cpp (полученных от учеников:) ) выполняющих одно и то же, но написанных совершенно в разном стиле и т.п. Можно ли написать программу, которая будет тестировать на заданных тестах, некоторый исходник? Представим, что есть код:

#include <iostream>
#include <cmath>
 
int main()
{
  int a, b;
  cin >> a >> b;
  if(b == 0)
  {  
    cout << "ERROR";
    return 1;
  }
  cout << log(a) << endl;
  cout << a / b;
  return 0;
}

Для него есть текстовый файл с тестами:

1 2
0 0 //<- результат

2 5
0.30102 0.4

0 4
ERROR //т.е. программа должна вывести сообщение об ошибке

3 0
ERROR

Запустив проверку программы на выходе будем иметь что-то вроде этого:

Test #1
OK

Test #2
OK

Test #3
Fail

Test #4
OK

Собственно проблема в том, что нет идей как это сделать. Буду благодарен за любую помощь!

Ответы

▲ 1

Ну... Без костылей не обойтесь(

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std::string_literals;

const std::string TESTS_FILENAME = "tests.txt"s;

struct Test {
  std::string input;
  std::string expecting;
};

int main(int argc, char** argv)
{
  if (argc < 2)
  {
    std::cerr << "usage: " << argv[0] << " PROGRAM\n";
    return 1;
  }
  std::ifstream tests_file;
  tests_file.open(TESTS_FILENAME, std::ios::in);
  if (tests_file.fail())
  {
    std::cerr << "error when opening tests: " << std::strerror(errno) << '\n';
    return 2;
  }
  std::vector<Test> tests;
  std::string line;
  for (;;)
  {
    if (!std::getline(tests_file, line))
      break;
    if (line.empty())
      continue;
    Test test;
    test.input = line;
    if (!std::getline(tests_file, line))
      break;
    if (line.empty())
      continue;
    test.expecting = line;
    tests.push_back(test);
  }
  size_t i = 0;
  for (const auto& test : tests)
  {
    if (i++ > 0)
    {
      std::cout << '\n';
    }
    std::cout << "Test #" << i << '\n';
    char proc_buffer[128];
    sprintf(proc_buffer, "bash -c '%s <<< \"%s\"'\n", argv[1], test.input.c_str());
    FILE* process = popen(proc_buffer, "r");
    if (process == nullptr)
    {
      std::cerr << "error when opening process: " << std::strerror(errno) << '\n';
      tests_file.close();
      return 3;
    }
    std::string output;
    int c;
    while ((c = getc(process)) != EOF)
    {
      if (c == '\n')
      {
        c = ' ';
      }
      output.append(1, (unsigned char)c);
    }
    if (output != test.expecting)
    {
      std::cout << "Fail\n";
    }
    else
    {
      std::cout << "OK\n";
    }
  }
  return 0;
}