Initial unit tests

This commit is contained in:
Erki 2021-03-07 15:58:45 +02:00
parent 326decd3de
commit 6e27e99735
5 changed files with 180 additions and 3 deletions

View File

@ -15,7 +15,10 @@ if (NOT LLVM_ENABLE_RTTI)
endif ()
add_executable(op-finder-tests
main.cpp basic_operations.cpp fixtures/RunOnCodeFixture.cpp fixtures/RunOnCodeFixture.hpp)
main.cpp
fixtures/RunOnCodeFixture.cpp
basic_operations.cpp
branches.cpp)
target_link_libraries(op-finder-tests
PUBLIC

View File

@ -51,3 +51,45 @@ TEST_CASE("Find unary operations", "[basic_operation]")
REQUIRE(op->type_rhs.empty());
REQUIRE(op->type_result == "int");
}
TEST_CASE("Find subscript operation", "[basic_operation]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a[4]; (void)a[4]; }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 1);
const OperationLog& log = operations.front();
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
REQUIRE(op->operation_name == "subscript");
REQUIRE(op->type_lhs == "int *");
REQUIRE(op->type_rhs == "int");
REQUIRE(op->type_result == "int");
}
TEST_CASE("Find subscript operation reversed", "[basic_operation]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a[4]; (void)4[a]; }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 1);
const OperationLog& log = operations.front();
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
REQUIRE(op->operation_name == "subscript");
REQUIRE(op->type_lhs == "int *");
REQUIRE(op->type_rhs == "int");
REQUIRE(op->type_result == "int");
}

View File

@ -0,0 +1,125 @@
//
// Created by erki on 07.03.21.
//
#include <catch2/catch.hpp>
#include "fixtures/RunOnCodeFixture.hpp"
TEST_CASE("For loop without header", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (;;) {} }";
REQUIRE(fixture.runCode(code));
REQUIRE(fixture.storage.getOperations().empty());
}
TEST_CASE("For loop with init only.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (a = 4;;) {} }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 1);
const OperationLog& log = operations.front();
REQUIRE(log.branch_number == 1);
}
TEST_CASE("For loop with init & cond.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (a = 4; a < 4;) {} }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 2);
const OperationLog& log_init = operations.at(0);
REQUIRE(log_init.branch_number == 1);
const OperationLog& log_cond = operations.at(1);
REQUIRE(log_cond.branch_number == 2);
}
TEST_CASE("For loop with init & inc.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (a = 4;;a++) {} }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 2);
const OperationLog& log_init = operations.at(0);
REQUIRE(log_init.branch_number == 1);
const OperationLog& log_inc = operations.at(1);
REQUIRE(log_inc.branch_number == 2);
}
TEST_CASE("For loop with full header.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (a = 4; a < 4 ;a++) {} }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 3);
const OperationLog& log_init = operations.at(0);
REQUIRE(log_init.branch_number == 1);
const OperationLog& log_cond = operations.at(1);
REQUIRE(log_cond.branch_number == 2);
const OperationLog& log_inc = operations.at(2);
REQUIRE(log_inc.branch_number == 2);
}
TEST_CASE("For loop without init.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (;a < 4 ;a++) {} }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 2);
const OperationLog& log_cond = operations.at(0);
REQUIRE(log_cond.branch_number == 0);
const OperationLog& log_inc = operations.at(1);
REQUIRE(log_inc.branch_number == 0);
}
TEST_CASE("For loop closes branches inside the loop.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (a = 4; a < 4 ; a++) { a = 5; } }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 4);
const OperationLog& log_inner = operations.back();
REQUIRE(log_inner.branch_number == 0);
}
TEST_CASE("For loop closes branches outside the loop.", "[branches][for_loops]")
{
RunOnCodeFixture fixture;
const std::string code = "int main() { int a; for (a = 4; a < 4 ; a++) {} a = 5; }";
const auto& operations = fixture(code);
REQUIRE(operations.size() == 4);
const OperationLog& log_outer = operations.back();
REQUIRE(log_outer.branch_number == 0);
}

View File

@ -14,13 +14,18 @@ RunOnCodeFixture::RunOnCodeFixture()
, action(&finder)
{ }
const std::vector<OperationLog>& RunOnCodeFixture::operator()(const std::string& code)
bool RunOnCodeFixture::runCode(const std::string& code)
{
const bool success = clang::tooling::runToolOnCode(
return clang::tooling::runToolOnCode(
clang::tooling::newFrontendActionFactory(&action)->create(),
code,
RunOnCodeFixture::INPUT_FILE
);
}
const std::vector<OperationLog>& RunOnCodeFixture::operator()(const std::string& code)
{
const bool success = runCode(code);
REQUIRE(success);

View File

@ -19,6 +19,8 @@ struct RunOnCodeFixture
RunOnCodeFixture();
bool runCode(const std::string& code);
const std::vector<OperationLog>& operator()(const std::string& code);
};