70 lines
2.7 KiB
C++
70 lines
2.7 KiB
C++
#include <clang/Frontend/ASTUnit.h>
|
|
#include <clang/Tooling/Tooling.h>
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "fold/detect/class_dup.hpp"
|
|
#include "fold/report/finding.hpp"
|
|
#include "fold/symbolic/budget.hpp"
|
|
|
|
namespace {
|
|
|
|
std::unique_ptr<clang::ASTUnit> parse(const std::string& code) {
|
|
return clang::tooling::buildASTFromCodeWithArgs(code, {"-std=c++20"}, "input.cpp");
|
|
}
|
|
|
|
std::vector<fold::Finding> runClassDup(const std::string& code, double threshold = 0.7) {
|
|
auto unit = parse(code);
|
|
REQUIRE(unit);
|
|
fold::SolverBudget b;
|
|
fold::SolverStats s;
|
|
fold::ClassDupOptions opts;
|
|
opts.similarity_threshold = threshold;
|
|
opts.min_methods = 2;
|
|
return fold::detectDuplicateClassesInContext(unit->getASTContext(), b, s, opts);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("classes with equivalent methods are flagged", "[class-dup]") {
|
|
auto findings = runClassDup("class CalcA { public:"
|
|
" int twice(int x){ return x + x; }"
|
|
" int square(int x){ return x * x; }"
|
|
"};"
|
|
"class CalcB { public:"
|
|
" int twice(int y){ return y * 2; }"
|
|
" int square(int y){ return y * y; }"
|
|
"};");
|
|
REQUIRE(findings.size() == 1);
|
|
REQUIRE(findings[0].kind == fold::FindingKind::ClassDup);
|
|
}
|
|
|
|
TEST_CASE("classes with distinct semantics are not flagged", "[class-dup][negative]") {
|
|
auto findings = runClassDup("class A { public:"
|
|
" int adjust(int x){ return x + 10; }"
|
|
" int weight(int x){ return x * 3; }"
|
|
"};"
|
|
"class B { public:"
|
|
" int adjust(int x){ return x - 10; }"
|
|
" int weight(int x){ return x * 5; }"
|
|
"};");
|
|
REQUIRE(findings.empty());
|
|
}
|
|
|
|
TEST_CASE("threshold gates partial overlap", "[class-dup][threshold]") {
|
|
// One of two methods is equivalent; with threshold 0.7 we expect NO flag,
|
|
// with threshold 0.4 we expect ONE flag.
|
|
const char* code = "class A { public:"
|
|
" int twice(int x){ return x + x; }"
|
|
" int weight(int x){ return x * 3; }"
|
|
"};"
|
|
"class B { public:"
|
|
" int twice(int y){ return y * 2; }"
|
|
" int weight(int y){ return y * 7; }"
|
|
"};";
|
|
REQUIRE(runClassDup(code, 0.7).empty());
|
|
REQUIRE(runClassDup(code, 0.4).size() == 1);
|
|
}
|