Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google test gen #5

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@

.idea
cmake-build-*
llvm-project
16 changes: 13 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
cmake_minimum_required(VERSION 3.12)
project(fuzz VERSION 0.1)

add_library(fuzz src/test.cpp src/test.h src/test_main.h src/test_main.cpp)
list(APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/llvm-project/llvm/cmake/modules"
"${CMAKE_CURRENT_SOURCE_DIR}/llvm-project/clang/cmake/modules")

if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(LLVM_TARGETS_TO_BUILD "X86")
endif()

include(AddLLVM)
include(AddClang)

add_library(fuzz src/test.cpp src/test.h src/test_main.h src/test_main.cpp src/printer.cpp src/subprocess.cpp src/subprocess.h)
add_library(fuzz::fuzz ALIAS fuzz)
target_include_directories(fuzz PUBLIC src/)

target_compile_features(fuzz PUBLIC cxx_std_17)

add_subdirectory(examples)


set(LLVM_LINK_COMPONENTS support)
set(CMAKE_CXX_STANDARD 17)

Expand All @@ -26,4 +36,4 @@ target_link_libraries(test-builder
clangASTMatchers
)

include_directories(src)
include_directories(src)
45 changes: 7 additions & 38 deletions TestBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,28 +112,11 @@ class FunctionTestBuilder : public MatchFinder::MatchCallback
}
};

std::vector<Test> tests;

void construct_tests()
{
std::random_device rd;

std::mt19937 generator(rd());


for(const auto &i: test_signatures)
{
tests.emplace_back(Test::generate(generator, i.name, i));
}
}


[[nodiscard]] auto generate_tests_and_signatures(auto Tool)
[[nodiscard]] std::vector<TestSignature> generate_test_signatures(auto Tool)
{
DeclarationMatcher Matcher = functionDecl().bind("FunctionDecl");



// FunctionArgsPrinter Printer;
FunctionTestBuilder Builder;
MatchFinder Finder;
Expand All @@ -142,9 +125,7 @@ void construct_tests()

assert(! Tool.run(newFrontendActionFactory(&Finder).get()));

construct_tests();

return std::pair{test_signatures, tests};
return test_signatures;
}

} // namespace GenerateTest
Expand All @@ -160,25 +141,13 @@ int main(int argc, char **argv)
OptionsParser.getSourcePathList());


auto [s, t] = GenerateTest::generate_tests_and_signatures(Tool);

auto tst = t.at(0);
auto sign = s.at(0);

// std::cout << tst.print() << std::endl << std::endl;
auto signatures = GenerateTest::generate_test_signatures(Tool);

TestMain test_main(1, argv);

test_main.fuzz(sign, 5).run();


// // test_main.add(tst);
// for(auto tst: t)
// test_main.add(tst);

// test_main.run();


for (auto sign : signatures) {
test_main.fuzz(std::make_shared<TestSignature>(sign), 5).run();
}

return 0;
}
}
6 changes: 3 additions & 3 deletions examples/fib_generator.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#include "test_main.h"

int main(int argc, char **argv) {
auto n = primitiveType(PrimitiveType::INT, 0, 10);
auto n = primitiveType(PrimitiveType::INT, 0, 20);
auto tInt = primitiveType(PrimitiveType::INT);
TestSignature fib{ "fib", { n }, tInt };
TestSignature fib{ "fib", { n }, tInt, "../examples/fib.cpp" };

TestMain(argc, argv)
.fuzz(fib, 5)
.fuzz(&fib, 5)
.run();
return 0;
}
69 changes: 69 additions & 0 deletions src/printer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "test.h"

struct TypePrinter {
std::string s;

void visitPrimitiveType(PrimitiveType x) {
s = printPrimitiveType(x);
}

void visitPointerTo(const PointerTo& x) {
s = printType(*x.type) + "*";
}

void visitInRange(const InRange& x) {
s = printType(*x.type);
}
};

std::string printType(const Type &type) {
TypePrinter typePrinter;
type.accept(typePrinter);
return typePrinter.s;
}

struct ValuePrinter {
std::string value, s;

void visitPrimitiveType(PrimitiveType x) {
s = "static_cast<" + printPrimitiveType(x) + ">(" + value + ")";
}

void visitPointerTo(const PointerTo& x) {
s = "new " + printType(*x.type) + "{" + printValue(*x.type, value) + "}";
}

void visitInRange(const InRange& x) {
s = printValue(*x.type, value);
}
};

std::string printValue(const Type &type, const std::string &value) {
ValuePrinter valuePrinter;
valuePrinter.value = value;
type.accept(valuePrinter);
return valuePrinter.s;
}

struct ValueSerializer {
std::string value, s;

void visitPrimitiveType(PrimitiveType x) {
s = "std::cout << static_cast<" + printPrimitiveType(x) + ">(" + value + ");\n";
}

void visitPointerTo(const PointerTo& x) {
s = printValueSerializer(*x.type, value);
}

void visitInRange(const InRange& x) {
s = printValueSerializer(*x.type, value);
}
};

std::string printValueSerializer(const Type &type, const std::string &value) {
ValueSerializer valueSerializer;
valueSerializer.value = value;
type.accept(valueSerializer);
return valueSerializer.s;
}
97 changes: 97 additions & 0 deletions src/subprocess.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "subprocess.h"
#include <utility>
#include <array>
#include <cstring>
#include <iostream>
#include <system_error>
#include <unistd.h>
#include <sys/wait.h>

Subprocess::Subprocess(std::vector<std::string> cmd) : cmd(std::move(cmd)), exitCode(0) {}

Subprocess &Subprocess::run(const std::string& input) {
exitCode = -1;
capturedStdout.clear();

std::array<char, 4096> buf;

int inputPipe[2];
int outputPipe[2];
int statusPipe[2];

if (pipe(inputPipe) != 0) {
throw std::system_error(errno, std::generic_category());
}

if (pipe(outputPipe) != 0) {
throw std::system_error(errno, std::generic_category());
}

if (pipe(statusPipe) != 0) {
throw std::system_error(errno, std::generic_category());
}

pid_t pid = fork();

if (pid < 0) {
throw std::system_error(errno, std::generic_category());
}

int ready = 0;

if (pid == 0) {
// child
close(inputPipe[1]);
close(outputPipe[0]);
close(statusPipe[1]);

read(statusPipe[0], &ready, sizeof(ready));
close(statusPipe[0]);

dup2(inputPipe[0], 0); // remap stdin
dup2(outputPipe[1], 1); // remap stdout

std::vector<char*> argv;
for (auto s : cmd) {
argv.push_back(strdup(s.c_str()));
}

execvp(cmd[0].c_str(), argv.data());
}

// parent

close(outputPipe[1]);
close(inputPipe[0]);
close(statusPipe[0]);
write(inputPipe[1], input.data(), input.size());
close(inputPipe[1]);
write(statusPipe[1], &ready, sizeof(ready));
close(statusPipe[1]);

int stat;
waitpid(pid, &stat, 0);

if (WIFEXITED(stat)) {
exitCode = WEXITSTATUS(stat);
} else if (WIFSIGNALED(stat)) {
exitCode = -WTERMSIG(stat);
}

int rd;
while ((rd = read(outputPipe[0], buf.data(), buf.size())) > 0) {
std::copy(buf.begin(), buf.begin() + rd, std::back_inserter(capturedStdout));
}

close(outputPipe[0]);

return *this;
}

std::string Subprocess::output() const {
return capturedStdout;
}

Subprocess::operator bool() const {
return exitCode == 0;
}
18 changes: 18 additions & 0 deletions src/subprocess.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <vector>
#include <string>

class Subprocess {
private:
std::vector<std::string> cmd;
std::string capturedStdout;
int exitCode;

public:
explicit Subprocess(std::vector<std::string> cmd);
explicit operator bool() const;

Subprocess &run(const std::string &input);
[[nodiscard]] std::string output() const;
};
Loading