From 2d399b927837c3fde8b424a3eb060de0789567c6 Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Wed, 4 Nov 2020 18:39:07 +0300 Subject: [PATCH 1/8] Fix test generator --- src/test.cpp | 1 + src/test.h | 2 ++ src/test_main.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/src/test.cpp b/src/test.cpp index 6ee1545..60e4ecc 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -73,6 +73,7 @@ std::string quote(const std::string& s) { std::string Test::print() const { std::stringstream ss; auto call = printFunctionCall(); + ss << signature.print() << "\n"; ss << "TEST(" << signature.name << "Test, " << name << ") {\n"; ss << " ASSERT_EQ(" << call; ss << ", " << signature.returnType->printValue('\0' + call + '\0') << ");\n"; diff --git a/src/test.h b/src/test.h index 95df47b..35f4e79 100644 --- a/src/test.h +++ b/src/test.h @@ -94,3 +94,5 @@ struct Test return test; } }; + +std::string quote(const std::string& s); diff --git a/src/test_main.cpp b/src/test_main.cpp index 2e5fda5..5b67620 100644 --- a/src/test_main.cpp +++ b/src/test_main.cpp @@ -29,6 +29,7 @@ void TestMain::run() { std::cout << test.signature.print(); } std::cout << "int main() {\n"; + std::cout << "std::cout << " << quote("#include \n") << ";\n"; for (const auto& test : tests) { std::cout << test.printGenerator(); } From db58c4bf633aa170226518ca743a0e54a0780840 Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Wed, 18 Nov 2020 13:08:17 +0300 Subject: [PATCH 2/8] Fix error in CMakeLists.txt --- .gitignore | 1 + CMakeLists.txt | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9f5ce17..0f77964 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ .idea cmake-build-* +llvm-project diff --git a/CMakeLists.txt b/CMakeLists.txt index dbb617f..14cbdf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,12 @@ cmake_minimum_required(VERSION 3.12) project(fuzz VERSION 0.1) +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/llvm-project/llvm/cmake/modules" + "${CMAKE_CURRENT_SOURCE_DIR}/llvm-project/clang/cmake/modules") +include(AddLLVM) +include(AddClang) + add_library(fuzz src/test.cpp src/test.h src/test_main.h src/test_main.cpp) add_library(fuzz::fuzz ALIAS fuzz) target_include_directories(fuzz PUBLIC src/) @@ -9,7 +15,6 @@ target_compile_features(fuzz PUBLIC cxx_std_17) add_subdirectory(examples) - set(LLVM_LINK_COMPONENTS support) set(CMAKE_CXX_STANDARD 17) @@ -26,4 +31,4 @@ target_link_libraries(test-builder clangASTMatchers ) -include_directories(src) \ No newline at end of file +include_directories(src) From e4909b9be937df1138b68d9c23fd677fa96a2237 Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Mon, 30 Nov 2020 20:09:50 +0300 Subject: [PATCH 3/8] work --- CMakeLists.txt | 2 +- TestBuilder.cpp | 45 ++++++-------------------------------- examples/fib_generator.cpp | 2 +- src/test.cpp | 12 ++++++---- src/test.h | 10 +++++---- src/test_main.cpp | 7 +++--- src/test_main.h | 4 +++- src/test_rt.h | 36 ++++++++++++++++++++++++++++++ 8 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 src/test_rt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 14cbdf0..eaf97b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ list(APPEND CMAKE_MODULE_PATH include(AddLLVM) include(AddClang) -add_library(fuzz src/test.cpp src/test.h src/test_main.h src/test_main.cpp) +add_library(fuzz src/test.cpp src/test.h src/test_main.h src/test_main.cpp src/test_rt.h) add_library(fuzz::fuzz ALIAS fuzz) target_include_directories(fuzz PUBLIC src/) diff --git a/TestBuilder.cpp b/TestBuilder.cpp index d01689c..9593bbf 100644 --- a/TestBuilder.cpp +++ b/TestBuilder.cpp @@ -112,28 +112,11 @@ class FunctionTestBuilder : public MatchFinder::MatchCallback } }; -std::vector 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 generate_test_signatures(auto Tool) { DeclarationMatcher Matcher = functionDecl().bind("FunctionDecl"); - - // FunctionArgsPrinter Printer; FunctionTestBuilder Builder; MatchFinder Finder; @@ -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 @@ -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(sign), 5).run(); + } return 0; -} \ No newline at end of file +} diff --git a/examples/fib_generator.cpp b/examples/fib_generator.cpp index f63cc08..9f675f9 100644 --- a/examples/fib_generator.cpp +++ b/examples/fib_generator.cpp @@ -6,7 +6,7 @@ int main(int argc, char **argv) { TestSignature fib{ "fib", { n }, tInt }; TestMain(argc, argv) - .fuzz(fib, 5) + .fuzz(&fib, 5) .run(); return 0; } diff --git a/src/test.cpp b/src/test.cpp index 60e4ecc..042944a 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -73,10 +73,10 @@ std::string quote(const std::string& s) { std::string Test::print() const { std::stringstream ss; auto call = printFunctionCall(); - ss << signature.print() << "\n"; - ss << "TEST(" << signature.name << "Test, " << name << ") {\n"; + ss << signature->print() << "\n"; + ss << "TEST(" << signature->name << "Test, " << name << ") {\n"; ss << " ASSERT_EQ(" << call; - ss << ", " << signature.returnType->printValue('\0' + call + '\0') << ");\n"; + ss << ", " << signature->returnType->printValue('\0' + call + '\0') << ");\n"; ss << "}\n"; return ss.str(); } @@ -87,7 +87,7 @@ std::string Test::printGenerator() const { std::string Test::printFunctionCall() const { std::string res; - res += signature.name + "("; + res += signature->name + "("; bool first = true; @@ -148,3 +148,7 @@ std::string TestSignature::print() const { res += ");\n"; return res; } + +std::string TestSignature::printInteractor() const { + +} diff --git a/src/test.h b/src/test.h index 35f4e79..57b71e1 100644 --- a/src/test.h +++ b/src/test.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -52,6 +53,7 @@ struct TestSignature { Type::ptr returnType; [[nodiscard]] std::string print() const; + [[nodiscard]] std::string printInteractor() const; }; struct Value { @@ -71,7 +73,7 @@ struct Value { struct Test { std::string name; - TestSignature signature; + TestSignature *signature; std::vector arguments; // after test launch @@ -82,12 +84,12 @@ struct Test [[nodiscard]] std::string printFunctionCall() const; template - static Test generate(Generator &gen, std::string name, TestSignature signature) { + static Test generate(Generator &gen, std::string name, TestSignature *signature) { Test test; test.name = std::move(name); - test.signature = std::move(signature); + test.signature = signature; - for (const auto &type : test.signature.parameterTypes) { + for (const auto &type : test.signature->parameterTypes) { test.arguments.push_back(Value::generate(gen, type)); } diff --git a/src/test_main.cpp b/src/test_main.cpp index 5b67620..eb6ddc4 100644 --- a/src/test_main.cpp +++ b/src/test_main.cpp @@ -10,6 +10,7 @@ TestMain::TestMain(int argc, char **argv) : gen { std::random_device{}() } { } TestMain &TestMain::add(Test test) { + signatures.insert(test.signature); tests.push_back(std::move(test)); return *this; } @@ -25,8 +26,8 @@ void TestMain::run() { } std::cout << "#include \n"; - for (const auto& test : tests) { - std::cout << test.signature.print(); + for (auto signature : signatures) { + std::cout << signature->print(); } std::cout << "int main() {\n"; std::cout << "std::cout << " << quote("#include \n") << ";\n"; @@ -36,7 +37,7 @@ void TestMain::run() { std::cout << "}\n"; } -TestMain &TestMain::fuzz(const TestSignature& testSignature, int n) { +TestMain &TestMain::fuzz(TestSignature *testSignature, int n) { for (int i = 0; i < n; ++i) { add(Test::generate(gen, "test_" + std::to_string(i), testSignature)); } diff --git a/src/test_main.h b/src/test_main.h index ee0427c..353a534 100644 --- a/src/test_main.h +++ b/src/test_main.h @@ -3,11 +3,13 @@ #include "test.h" #include #include +#include class TestMain { private: std::vector args; std::vector tests; + std::unordered_set signatures; std::mt19937 gen; private: @@ -17,6 +19,6 @@ class TestMain { TestMain(int argc, char **argv); TestMain &add(Test test); - TestMain &fuzz(const TestSignature& testSignature, int n); + TestMain &fuzz(TestSignature *testSignature, int n); void run(); }; diff --git a/src/test_rt.h b/src/test_rt.h new file mode 100644 index 0000000..966fad4 --- /dev/null +++ b/src/test_rt.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace test_rt { +static inline void writeHex(const void *ptr, std::size_t size) { + std::stringstream ss; + + ss << std::setw(2) << std::setfill('0') << std::hex; + + for (std::size_t i = 0; i < size; ++i) { + unsigned byte = static_cast(ptr)[i]; + ss << byte; + } + + std::cout << ss.str(); +} + +static inline void readHex(void *ptr, std::size_t size) +{ + for (std::size_t i = 0; i < size; ++i) { + char s[3]; + std::cin >> s[0] >> s[1]; + s[2] = 0; + unsigned byte = std::strtol(s, nullptr, 16); + static_cast(ptr)[i] = byte; + } +} +} + +#define READ(name, type) auto name = type{}; test_rt::readHex(&name, sizeof(name));1z From be8a23b43766c5448d557ecc6a415cc3d6cb2854 Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Wed, 2 Dec 2020 15:39:45 +0300 Subject: [PATCH 4/8] Implement subprocess --- CMakeLists.txt | 7 +++- src/printer.cpp | 46 +++++++++++++++++++++++ src/subprocess.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++ src/subprocess.h | 20 ++++++++++ src/test.cpp | 30 ++------------- src/test.h | 16 +++++++- src/test_rt.h | 36 ------------------ 7 files changed, 180 insertions(+), 66 deletions(-) create mode 100644 src/printer.cpp create mode 100644 src/subprocess.cpp create mode 100644 src/subprocess.h delete mode 100644 src/test_rt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eaf97b8..f4f0c79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,15 @@ project(fuzz VERSION 0.1) 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/test_rt.h) +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/) diff --git a/src/printer.cpp b/src/printer.cpp new file mode 100644 index 0000000..fe80118 --- /dev/null +++ b/src/printer.cpp @@ -0,0 +1,46 @@ +#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; +} diff --git a/src/subprocess.cpp b/src/subprocess.cpp new file mode 100644 index 0000000..4820ab9 --- /dev/null +++ b/src/subprocess.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include + +class Subprocess { +private: + std::vector cmd; + std::string capturedStdout; + int exitCode; + +public: + explicit Subprocess(std::vector cmd); + explicit operator bool() const { + return exitCode == 0; + } + + Subprocess &run(std::string input); + [[nodiscard]] std::string output() const; +}; + +Subprocess::Subprocess(std::vector cmd) : cmd(std::move(cmd)), exitCode(0) {} + +Subprocess &Subprocess::run(std::string input) { + exitCode = -1; + capturedStdout.clear(); + + int inputPipe[2]; + int outputPipe[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()); + } + + pid_t pid = fork(); + + if (pid < 0) { + throw std::system_error(errno, std::generic_category()); + } + + if (pid == 0) { + // child + close(inputPipe[1]); + close(outputPipe[0]); + dup2(0, inputPipe[0]); // remap stdin + dup2(1, outputPipe[1]); // remap stdout + + std::vector argv; + for (auto s : cmd) { + argv.push_back(s.data()); + } + + execvp(cmd[0].c_str(), argv.data()); + + } + + // parent + + close(outputPipe[1]); + write(inputPipe[0], input.data(), input.size()); + close(inputPipe[0]); + + int stat; + waitpid(pid, &stat, 0); + + if (WIFEXITED(stat)) { + exitCode = WEXITSTATUS(stat); + } else if (WIFSIGNALED(stat)) { + exitCode = -WTERMSIG(stat); + } + + std::array buf; + int rd; + + while ((rd = read(outputPipe[0], buf.data(), buf.size())) > 0) { + std::copy(buf.begin(), buf.begin() + rd, std::back_inserter(capturedStdout)); + } + + return *this; +} + +std::string Subprocess::output() const { + return capturedStdout; +} diff --git a/src/subprocess.h b/src/subprocess.h new file mode 100644 index 0000000..f4c8ef9 --- /dev/null +++ b/src/subprocess.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +class Subprocess { +private: + std::vector cmd; + std::string capturedStdout; + int exitCode; + +public: + explicit Subprocess(std::vector cmd); + explicit operator bool() const { + return exitCode == 0; + } + + Subprocess &run(std::string input); + [[nodiscard]] std::string output() const; +}; diff --git a/src/test.cpp b/src/test.cpp index 042944a..7588ff5 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -3,31 +3,7 @@ #include std::string Value::print() const { - return type->printValue(std::to_string(value)); -} - -std::string Type::print() const { - if (auto primitiveType = std::get_if(&type)) { - return printPrimitiveType(*primitiveType); - } else if (auto pointerTo = std::get_if(&type)) { - return pointerTo->type->print() + "*"; - } else if (auto inRange = std::get_if(&type)) { - return inRange->type->print(); - } - - return ""; -} - -std::string Type::printValue(const std::string& value) const { - if (auto primitiveType = std::get_if(&type)) { - return "static_cast<" + print() + ">(" + value + ")"; - } else if (auto pointerTo = std::get_if(&type)) { - return "new " + pointerTo->type->print() + "{" + pointerTo->type->printValue(value) + "}"; - } else if (auto inRange = std::get_if(&type)) { - return inRange->type->printValue(value); - } - - return ""; + return printValue(*type, std::to_string(value)); } std::pair Type::getRange() const { @@ -132,7 +108,7 @@ Type::ptr pointerTo(Type::ptr type) { } std::string TestSignature::print() const { - std::string res = returnType->print() + " " + name; + std::string res = printType(*returnType) + " " + name; res += "("; bool first = true; @@ -142,7 +118,7 @@ std::string TestSignature::print() const { res += ", "; } first = false; - res += type->print(); + res += printType(*type); } res += ");\n"; diff --git a/src/test.h b/src/test.h index 57b71e1..dcaa838 100644 --- a/src/test.h +++ b/src/test.h @@ -38,11 +38,23 @@ struct Type { using ptr = std::shared_ptr; - [[nodiscard]] std::string print() const; - [[nodiscard]] std::string printValue(const std::string &value) const; [[nodiscard]] std::pair getRange() const; + + template + void accept(Visitor &visitor) const { + if (auto primitiveType = std::get_if(&type)) { + visitor.visitPrimitiveType(type); + } else if (auto pointerTo = std::get_if(&type)) { + visitor.visitPointerTo(pointerTo); + } else if (auto inRange = std::get_if(&type)) { + visitor.visitInRange(inRange); + } + } }; +std::string printType(const Type &type); +std::string printValue(const Type &type, const std::string &value); + [[nodiscard]] Type::ptr primitiveType(PrimitiveType type); [[nodiscard]] Type::ptr primitiveType(PrimitiveType type, PrimitiveInteger min, PrimitiveInteger max); [[nodiscard]] Type::ptr pointerTo(Type::ptr type); diff --git a/src/test_rt.h b/src/test_rt.h deleted file mode 100644 index 966fad4..0000000 --- a/src/test_rt.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace test_rt { -static inline void writeHex(const void *ptr, std::size_t size) { - std::stringstream ss; - - ss << std::setw(2) << std::setfill('0') << std::hex; - - for (std::size_t i = 0; i < size; ++i) { - unsigned byte = static_cast(ptr)[i]; - ss << byte; - } - - std::cout << ss.str(); -} - -static inline void readHex(void *ptr, std::size_t size) -{ - for (std::size_t i = 0; i < size; ++i) { - char s[3]; - std::cin >> s[0] >> s[1]; - s[2] = 0; - unsigned byte = std::strtol(s, nullptr, 16); - static_cast(ptr)[i] = byte; - } -} -} - -#define READ(name, type) auto name = type{}; test_rt::readHex(&name, sizeof(name));1z From 1ce2aa1f3a544d1841d701314c5dc9bb64d1f88e Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Wed, 2 Dec 2020 17:21:11 +0300 Subject: [PATCH 5/8] Implement invocation API --- examples/fib_generator.cpp | 6 +++- src/printer.cpp | 23 ++++++++++++++++ src/subprocess.cpp | 56 +++++++++++++++++++++----------------- src/subprocess.h | 4 +-- src/test.cpp | 52 +++++++++++++++++++++++++++++++++-- src/test.h | 20 +++++++++----- src/test_main.h | 2 +- 7 files changed, 123 insertions(+), 40 deletions(-) diff --git a/examples/fib_generator.cpp b/examples/fib_generator.cpp index 9f675f9..583622e 100644 --- a/examples/fib_generator.cpp +++ b/examples/fib_generator.cpp @@ -1,9 +1,13 @@ #include "test_main.h" +#include int main(int argc, char **argv) { auto n = primitiveType(PrimitiveType::INT, 0, 10); auto tInt = primitiveType(PrimitiveType::INT); - TestSignature fib{ "fib", { n }, tInt }; + TestSignature fib{ "fib", { n }, tInt, "/home/tsarn/Coding/UnitTestFuzzerCPP/examples/fib.cpp" }; + + std::cout << fib.callSerialized("15") << std::endl; + return 0; TestMain(argc, argv) .fuzz(&fib, 5) diff --git a/src/printer.cpp b/src/printer.cpp index fe80118..9f0d719 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -44,3 +44,26 @@ std::string printValue(const Type &type, const std::string &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; +} diff --git a/src/subprocess.cpp b/src/subprocess.cpp index 4820ab9..5448dd4 100644 --- a/src/subprocess.cpp +++ b/src/subprocess.cpp @@ -1,35 +1,23 @@ -#include +#include "subprocess.h" #include -#include #include +#include +#include #include #include #include -class Subprocess { -private: - std::vector cmd; - std::string capturedStdout; - int exitCode; - -public: - explicit Subprocess(std::vector cmd); - explicit operator bool() const { - return exitCode == 0; - } - - Subprocess &run(std::string input); - [[nodiscard]] std::string output() const; -}; - Subprocess::Subprocess(std::vector cmd) : cmd(std::move(cmd)), exitCode(0) {} Subprocess &Subprocess::run(std::string input) { exitCode = -1; capturedStdout.clear(); + std::array buf; + int inputPipe[2]; int outputPipe[2]; + int statusPipe[2]; if (pipe(inputPipe) != 0) { throw std::system_error(errno, std::generic_category()); @@ -39,33 +27,47 @@ Subprocess &Subprocess::run(std::string input) { 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]); - dup2(0, inputPipe[0]); // remap stdin - dup2(1, outputPipe[1]); // remap stdout + 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 argv; for (auto s : cmd) { - argv.push_back(s.data()); + argv.push_back(strdup(s.c_str())); } execvp(cmd[0].c_str(), argv.data()); - } // parent close(outputPipe[1]); - write(inputPipe[0], input.data(), input.size()); 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); @@ -76,16 +78,20 @@ Subprocess &Subprocess::run(std::string input) { exitCode = -WTERMSIG(stat); } - std::array buf; 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; +} diff --git a/src/subprocess.h b/src/subprocess.h index f4c8ef9..67daba6 100644 --- a/src/subprocess.h +++ b/src/subprocess.h @@ -11,9 +11,7 @@ class Subprocess { public: explicit Subprocess(std::vector cmd); - explicit operator bool() const { - return exitCode == 0; - } + explicit operator bool() const; Subprocess &run(std::string input); [[nodiscard]] std::string output() const; diff --git a/src/test.cpp b/src/test.cpp index 7588ff5..8e00986 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,9 +1,11 @@ #include "test.h" +#include "subprocess.h" #include +#include std::string Value::print() const { - return printValue(*type, std::to_string(value)); + return printValue(*type, value); } std::pair Type::getRange() const { @@ -52,7 +54,7 @@ std::string Test::print() const { ss << signature->print() << "\n"; ss << "TEST(" << signature->name << "Test, " << name << ") {\n"; ss << " ASSERT_EQ(" << call; - ss << ", " << signature->returnType->printValue('\0' + call + '\0') << ");\n"; + ss << ", " << printValue(*signature->returnType, '\0' + call + '\0') << ");\n"; ss << "}\n"; return ss.str(); } @@ -125,6 +127,50 @@ std::string TestSignature::print() const { return res; } -std::string TestSignature::printInteractor() const { +std::string TestSignature::printInvoker() const { + std::string res = "#include\n"; + res += print(); + res += "int main() {\n"; + int i = 0; + Test test; + test.signature = this; + + for (auto param : parameterTypes) { + std::string paramName = "arg" + std::to_string(i); + res += "long " + paramName + "; std::cin >> " + paramName + ";\n"; + test.arguments.push_back(Value { param, paramName }); + } + + res += "auto retval = " + test.printFunctionCall() + ";\n"; + res += printValueSerializer(*returnType, "retval"); + res += "return 0;\n}\n"; + + return res; +} + +std::string TestSignature::getInvoker() const { + if (!pathToInvoker.empty()) { + return pathToInvoker; + } + + std::string path = "/tmp/UnitTestFuzzerInvoker_" + name; + + Subprocess compiler{{"g++", "-std=c++17", "-o", path, linkWith, "-x", "c++", "-"}}; + if (!compiler.run(printInvoker())) { + throw std::runtime_error("Failed to compile invoker"); + } + + return pathToInvoker = path; +} + +std::string TestSignature::callSerialized(std::string args) const { + std::string path = getInvoker(); + Subprocess prog{{path}}; + + if (!prog.run(std::move(args))) { + throw std::runtime_error("Failed to run invoker"); + } + + return prog.output(); } diff --git a/src/test.h b/src/test.h index dcaa838..b951d57 100644 --- a/src/test.h +++ b/src/test.h @@ -43,17 +43,18 @@ struct Type { template void accept(Visitor &visitor) const { if (auto primitiveType = std::get_if(&type)) { - visitor.visitPrimitiveType(type); + visitor.visitPrimitiveType(*primitiveType); } else if (auto pointerTo = std::get_if(&type)) { - visitor.visitPointerTo(pointerTo); + visitor.visitPointerTo(*pointerTo); } else if (auto inRange = std::get_if(&type)) { - visitor.visitInRange(inRange); + visitor.visitInRange(*inRange); } } }; std::string printType(const Type &type); std::string printValue(const Type &type, const std::string &value); +std::string printValueSerializer(const Type &type, const std::string &value); [[nodiscard]] Type::ptr primitiveType(PrimitiveType type); [[nodiscard]] Type::ptr primitiveType(PrimitiveType type, PrimitiveInteger min, PrimitiveInteger max); @@ -63,14 +64,19 @@ struct TestSignature { std::string name; std::vector parameterTypes; Type::ptr returnType; + std::string linkWith; + + mutable std::string pathToInvoker; [[nodiscard]] std::string print() const; - [[nodiscard]] std::string printInteractor() const; + [[nodiscard]] std::string printInvoker() const; + [[nodiscard]] std::string getInvoker() const; + [[nodiscard]] std::string callSerialized(std::string args) const; }; struct Value { Type::ptr type; - PrimitiveInteger value; + std::string value; [[nodiscard]] std::string print() const; @@ -78,14 +84,14 @@ struct Value { static Value generate(Generator& gen, const Type::ptr& type) { auto [a, b] = type->getRange(); std::uniform_int_distribution distribution{a, b}; - return Value { type, distribution(gen) }; + return Value { type, std::to_string(distribution(gen)) }; } }; struct Test { std::string name; - TestSignature *signature; + const TestSignature *signature; std::vector arguments; // after test launch diff --git a/src/test_main.h b/src/test_main.h index 353a534..c8febe1 100644 --- a/src/test_main.h +++ b/src/test_main.h @@ -9,7 +9,7 @@ class TestMain { private: std::vector args; std::vector tests; - std::unordered_set signatures; + std::unordered_set signatures; std::mt19937 gen; private: From 59c1c9c9aa7e4d1d85c6c8da695f87db5af46d5d Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Wed, 2 Dec 2020 18:51:50 +0300 Subject: [PATCH 6/8] Unlink temporary files on exit --- examples/fib_generator.cpp | 6 +-- src/subprocess.cpp | 2 +- src/subprocess.h | 2 +- src/test.cpp | 83 ++++++++++++++++++++++---------------- src/test.h | 43 ++++++++++++-------- src/test_main.cpp | 9 ++--- 6 files changed, 82 insertions(+), 63 deletions(-) diff --git a/examples/fib_generator.cpp b/examples/fib_generator.cpp index 583622e..9500833 100644 --- a/examples/fib_generator.cpp +++ b/examples/fib_generator.cpp @@ -1,14 +1,10 @@ #include "test_main.h" -#include 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, "/home/tsarn/Coding/UnitTestFuzzerCPP/examples/fib.cpp" }; - std::cout << fib.callSerialized("15") << std::endl; - return 0; - TestMain(argc, argv) .fuzz(&fib, 5) .run(); diff --git a/src/subprocess.cpp b/src/subprocess.cpp index 5448dd4..3f9dfce 100644 --- a/src/subprocess.cpp +++ b/src/subprocess.cpp @@ -9,7 +9,7 @@ Subprocess::Subprocess(std::vector cmd) : cmd(std::move(cmd)), exitCode(0) {} -Subprocess &Subprocess::run(std::string input) { +Subprocess &Subprocess::run(const std::string& input) { exitCode = -1; capturedStdout.clear(); diff --git a/src/subprocess.h b/src/subprocess.h index 67daba6..13a9ff4 100644 --- a/src/subprocess.h +++ b/src/subprocess.h @@ -13,6 +13,6 @@ class Subprocess { explicit Subprocess(std::vector cmd); explicit operator bool() const; - Subprocess &run(std::string input); + Subprocess &run(const std::string &input); [[nodiscard]] std::string output() const; }; diff --git a/src/test.cpp b/src/test.cpp index 8e00986..4ef21c2 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -3,6 +3,7 @@ #include #include +#include std::string Value::print() const { return printValue(*type, value); @@ -23,46 +24,16 @@ std::pair Type::getRange() const { return { 0, 0 }; } -std::string quote(const std::string& s) { - std::stringstream ss; - - ss << '"'; - bool inEscape = false; - - for (char c : s) { - if (c == '\n') ss << "\\n"; - else if (c == '\t') ss << "\\t"; - else if (c == '"') ss << "\\\""; - else if (c == '\0') { - inEscape = !inEscape; - if (inEscape) { - ss << "\" << "; - } else { - ss << " << \""; - } - } else ss << c; - } - - ss << '"'; - - return ss.str(); -} - std::string Test::print() const { std::stringstream ss; auto call = printFunctionCall(); - ss << signature->print() << "\n"; ss << "TEST(" << signature->name << "Test, " << name << ") {\n"; ss << " ASSERT_EQ(" << call; - ss << ", " << printValue(*signature->returnType, '\0' + call + '\0') << ");\n"; + ss << ", " << signature->call(arguments).print() << ");\n"; ss << "}\n"; return ss.str(); } -std::string Test::printGenerator() const { - return "std::cout << " + quote(print()) + ";\n"; -} - std::string Test::printFunctionCall() const { std::string res; res += signature->name + "("; @@ -136,7 +107,7 @@ std::string TestSignature::printInvoker() const { Test test; test.signature = this; - for (auto param : parameterTypes) { + for (const auto& param : parameterTypes) { std::string paramName = "arg" + std::to_string(i); res += "long " + paramName + "; std::cin >> " + paramName + ";\n"; test.arguments.push_back(Value { param, paramName }); @@ -164,13 +135,57 @@ std::string TestSignature::getInvoker() const { return pathToInvoker = path; } -std::string TestSignature::callSerialized(std::string args) const { +std::string TestSignature::callSerialized(const std::string& args) const { std::string path = getInvoker(); Subprocess prog{{path}}; - if (!prog.run(std::move(args))) { + if (!prog.run(args)) { throw std::runtime_error("Failed to run invoker"); } return prog.output(); } + +Value TestSignature::call(const std::vector& args) const { + std::string serialized; + for (const auto &val : args) { + serialized += val.value; + serialized += '\n'; + } + + auto ret = callSerialized(serialized); + return Value { returnType, ret }; +} + +TestSignature::TestSignature(TestSignature &&that) noexcept { + swap(that); +} + +TestSignature &TestSignature::operator=(TestSignature &&that) noexcept { + swap(that); + return *this; +} + +void TestSignature::swap(TestSignature &that) noexcept { + std::swap(name, that.name); + std::swap(parameterTypes, that.parameterTypes); + std::swap(returnType, that.returnType); + std::swap(linkWith, that.linkWith); + std::swap(pathToInvoker, that.pathToInvoker); +} + +TestSignature::~TestSignature() { + if (!pathToInvoker.empty()) { + unlink(pathToInvoker.c_str()); + } +} + +TestSignature::TestSignature(std::string name, + std::vector parameterTypes, + Type::ptr returnType, + std::string linkWith) : + name(std::move(name)), + parameterTypes(std::move(parameterTypes)), + returnType(std::move(returnType)), + linkWith(std::move(linkWith)) +{} diff --git a/src/test.h b/src/test.h index b951d57..84bc124 100644 --- a/src/test.h +++ b/src/test.h @@ -60,20 +60,6 @@ std::string printValueSerializer(const Type &type, const std::string &value); [[nodiscard]] Type::ptr primitiveType(PrimitiveType type, PrimitiveInteger min, PrimitiveInteger max); [[nodiscard]] Type::ptr pointerTo(Type::ptr type); -struct TestSignature { - std::string name; - std::vector parameterTypes; - Type::ptr returnType; - std::string linkWith; - - mutable std::string pathToInvoker; - - [[nodiscard]] std::string print() const; - [[nodiscard]] std::string printInvoker() const; - [[nodiscard]] std::string getInvoker() const; - [[nodiscard]] std::string callSerialized(std::string args) const; -}; - struct Value { Type::ptr type; std::string value; @@ -88,6 +74,32 @@ struct Value { } }; +struct TestSignature { + std::string name; + std::vector parameterTypes; + Type::ptr returnType; + std::string linkWith; + + mutable std::string pathToInvoker; + + [[nodiscard]] std::string print() const; + [[nodiscard]] std::string printInvoker() const; + [[nodiscard]] std::string getInvoker() const; + [[nodiscard]] std::string callSerialized(const std::string& args) const; + [[nodiscard]] Value call(const std::vector& args) const; + + TestSignature() = default; + TestSignature(std::string name, + std::vector parameterTypes, + Type::ptr returnType, + std::string linkWith); + TestSignature(TestSignature &&that) noexcept; + TestSignature &operator=(TestSignature &&that) noexcept; + ~TestSignature(); + void swap(TestSignature &that) noexcept; +}; + + struct Test { std::string name; @@ -98,7 +110,6 @@ struct Test std::optional returnValue; [[nodiscard]] std::string print() const; - [[nodiscard]] std::string printGenerator() const; [[nodiscard]] std::string printFunctionCall() const; template @@ -114,5 +125,3 @@ struct Test return test; } }; - -std::string quote(const std::string& s); diff --git a/src/test_main.cpp b/src/test_main.cpp index eb6ddc4..8e93002 100644 --- a/src/test_main.cpp +++ b/src/test_main.cpp @@ -25,16 +25,15 @@ void TestMain::run() { usage(); } - std::cout << "#include \n"; + std::cout << "#include \n"; + for (auto signature : signatures) { std::cout << signature->print(); } - std::cout << "int main() {\n"; - std::cout << "std::cout << " << quote("#include \n") << ";\n"; + for (const auto& test : tests) { - std::cout << test.printGenerator(); + std::cout << test.print(); } - std::cout << "}\n"; } TestMain &TestMain::fuzz(TestSignature *testSignature, int n) { From 4025883e91780fba7beb244275bd69fb1b72bb9e Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Tue, 8 Dec 2020 16:54:23 +0300 Subject: [PATCH 7/8] Implement fuzzer driver using libfuzzer --- src/test.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++- src/test.h | 14 +++++--- src/test_main.cpp | 6 ++++ 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/test.cpp b/src/test.cpp index 4ef21c2..5c7a08c 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include std::string Value::print() const { return printValue(*type, value); @@ -127,7 +128,7 @@ std::string TestSignature::getInvoker() const { std::string path = "/tmp/UnitTestFuzzerInvoker_" + name; - Subprocess compiler{{"g++", "-std=c++17", "-o", path, linkWith, "-x", "c++", "-"}}; + Subprocess compiler{{"clang++", "-std=c++17", "-o", path, linkWith, "-x", "c++", "-"}}; if (!compiler.run(printInvoker())) { throw std::runtime_error("Failed to compile invoker"); } @@ -189,3 +190,84 @@ TestSignature::TestSignature(std::string name, returnType(std::move(returnType)), linkWith(std::move(linkWith)) {} + +std::string TestSignature::printStruct(const std::string &structName) const { + std::stringstream ss; + + ss << "struct " << structName << " {\n"; + + int i = 0; + for (const auto& param : parameterTypes) { + std::string paramName = "arg" + std::to_string(i++); + ss << "long " << paramName << ";\n"; + } + + ss << "};\n"; + + return ss.str(); +} + +std::string TestSignature::printFuzzer(int nTests, int interval) const { + std::stringstream ss; + + ss << "#include \n"; + ss << "#include \n"; + ss << "#include \n"; + ss << print(); + ss << printStruct("FuzzArgs"); + ss << "extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n"; + ss << "static long cnt, tests;\n"; + ss << "FuzzArgs args;\n"; + ss << "if (size != sizeof(args)) return 0;\n"; + ss << "memcpy(&args, data, size);\n"; + + int i = 0; + Test test; + test.signature = this; + + for (const auto& param : parameterTypes) { + std::string paramName = "args.arg" + std::to_string(i); + test.arguments.push_back(Value { param, paramName }); + + auto [lo, hi] = param->getRange(); + if (lo != std::numeric_limits::min() || hi != std::numeric_limits::max()) { + PrimitiveIntegerU domain = 1 + hi - lo; + ss << paramName << " = " << "(" << paramName << " % " << domain << " + " << domain << ") % "; + ss << domain << " + " << lo << ";\n"; + } + } + + ss << test.printFunctionCall() << ";\n"; + ss << "if (++cnt % " << interval << " == 0) {\n"; + i = 0; + for (const auto& param : parameterTypes) { + std::string paramName = "args.arg" + std::to_string(i); + ss << "std::cout << \"test \" << " << paramName << " << ' ';\n"; + } + ss << "std::cout << std::endl;\n"; + ss << "if (++tests >= " << nTests << ") {\n"; + ss << "std::cout << \"exit\" << std::endl;\n"; + ss << "exit(0);\n"; + ss << "}\n"; + ss << "}\n"; + ss << "return 0;\n"; + ss << "}\n"; + + std::cerr << ss.str(); + + return ss.str(); +} + +std::string TestSignature::runFuzzer(int nTests) const { + std::string path = "/tmp/UnitTestFuzzerFuzzer_" + name; + + Subprocess compiler{{"clang++", "-g", "-fsanitize=address,fuzzer", "-std=c++17", "-o", path, linkWith, "-x", "c++", "-"}}; + if (!compiler.run(printFuzzer(nTests, 100))) { + throw std::runtime_error("Failed to compile fuzzer"); + } + + Subprocess fuzzer{{path}}; + auto res = fuzzer.run("").output(); + unlink(path.c_str()); + return res; +} diff --git a/src/test.h b/src/test.h index 84bc124..3002b54 100644 --- a/src/test.h +++ b/src/test.h @@ -11,6 +11,7 @@ struct Type; using PrimitiveInteger = long; +using PrimitiveIntegerU = unsigned long; enum class PrimitiveType { CHAR, @@ -80,13 +81,11 @@ struct TestSignature { Type::ptr returnType; std::string linkWith; - mutable std::string pathToInvoker; - [[nodiscard]] std::string print() const; - [[nodiscard]] std::string printInvoker() const; - [[nodiscard]] std::string getInvoker() const; + [[nodiscard]] std::string printStruct(const std::string &structName) const; [[nodiscard]] std::string callSerialized(const std::string& args) const; [[nodiscard]] Value call(const std::vector& args) const; + [[nodiscard]] std::string runFuzzer(int nTests) const; TestSignature() = default; TestSignature(std::string name, @@ -97,6 +96,13 @@ struct TestSignature { TestSignature &operator=(TestSignature &&that) noexcept; ~TestSignature(); void swap(TestSignature &that) noexcept; + +private: + mutable std::string pathToInvoker; + [[nodiscard]] std::string printInvoker() const; + [[nodiscard]] std::string getInvoker() const; + + [[nodiscard]] std::string printFuzzer(int nTests, int interval) const; }; diff --git a/src/test_main.cpp b/src/test_main.cpp index 8e93002..c277759 100644 --- a/src/test_main.cpp +++ b/src/test_main.cpp @@ -25,6 +25,12 @@ void TestMain::run() { usage(); } + for (auto signature : signatures) { + std::cout << signature->runFuzzer(10) << std::endl; + } + + return; + std::cout << "#include \n"; for (auto signature : signatures) { From dae2794b1e7c9b8a370122db5531f61d8089c33f Mon Sep 17 00:00:00 2001 From: Nikita Tsarev Date: Tue, 8 Dec 2020 17:45:30 +0300 Subject: [PATCH 8/8] Use libfuzzer to generate tests --- examples/fib_generator.cpp | 2 +- src/test.cpp | 40 +++++++++++++++++++++++++++---- src/test.h | 49 +++++++++++--------------------------- src/test_main.cpp | 12 +++------- src/test_main.h | 1 - 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/examples/fib_generator.cpp b/examples/fib_generator.cpp index 9500833..3db9dae 100644 --- a/examples/fib_generator.cpp +++ b/examples/fib_generator.cpp @@ -3,7 +3,7 @@ int main(int argc, char **argv) { auto n = primitiveType(PrimitiveType::INT, 0, 20); auto tInt = primitiveType(PrimitiveType::INT); - TestSignature fib{ "fib", { n }, tInt, "/home/tsarn/Coding/UnitTestFuzzerCPP/examples/fib.cpp" }; + TestSignature fib{ "fib", { n }, tInt, "../examples/fib.cpp" }; TestMain(argc, argv) .fuzz(&fib, 5) diff --git a/src/test.cpp b/src/test.cpp index 5c7a08c..380e6c6 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,10 +1,11 @@ #include "test.h" #include "subprocess.h" -#include #include #include #include +#include +#include std::string Value::print() const { return printValue(*type, value); @@ -151,8 +152,9 @@ Value TestSignature::call(const std::vector& args) const { std::string serialized; for (const auto &val : args) { serialized += val.value; - serialized += '\n'; + serialized += ' '; } + serialized += '\n'; auto ret = callSerialized(serialized); return Value { returnType, ret }; @@ -253,8 +255,6 @@ std::string TestSignature::printFuzzer(int nTests, int interval) const { ss << "return 0;\n"; ss << "}\n"; - std::cerr << ss.str(); - return ss.str(); } @@ -266,8 +266,38 @@ std::string TestSignature::runFuzzer(int nTests) const { throw std::runtime_error("Failed to compile fuzzer"); } - Subprocess fuzzer{{path}}; + Subprocess fuzzer{{path, "-verbosity=0"}}; auto res = fuzzer.run("").output(); unlink(path.c_str()); return res; } + +[[nodiscard]] std::vector TestSignature::fuzz(int nTests) const { + std::stringstream ss(runFuzzer(nTests)); + std::vector res; + + int i = 0; + + std::string cmd; + while (ss >> cmd) { + if (cmd == "exit") { + break; + } + + if (cmd == "test") { + Test test; + test.signature = this; + test.name = "test_" + std::to_string(i++); + for (const auto& param : parameterTypes) { + Value value; + value.type = param; + ss >> value.value; + test.arguments.push_back(value); + } + + res.push_back(test); + } + } + + return res; +} diff --git a/src/test.h b/src/test.h index 3002b54..d3e5c41 100644 --- a/src/test.h +++ b/src/test.h @@ -6,7 +6,6 @@ #include #include #include -#include struct Type; @@ -66,15 +65,21 @@ struct Value { std::string value; [[nodiscard]] std::string print() const; +}; - template - static Value generate(Generator& gen, const Type::ptr& type) { - auto [a, b] = type->getRange(); - std::uniform_int_distribution distribution{a, b}; - return Value { type, std::to_string(distribution(gen)) }; - } +struct TestSignature; + +struct Test +{ + std::string name; + const TestSignature *signature; + std::vector arguments; + + [[nodiscard]] std::string print() const; + [[nodiscard]] std::string printFunctionCall() const; }; + struct TestSignature { std::string name; std::vector parameterTypes; @@ -85,7 +90,7 @@ struct TestSignature { [[nodiscard]] std::string printStruct(const std::string &structName) const; [[nodiscard]] std::string callSerialized(const std::string& args) const; [[nodiscard]] Value call(const std::vector& args) const; - [[nodiscard]] std::string runFuzzer(int nTests) const; + [[nodiscard]] std::vector fuzz(int nTests) const; TestSignature() = default; TestSignature(std::string name, @@ -103,31 +108,5 @@ struct TestSignature { [[nodiscard]] std::string getInvoker() const; [[nodiscard]] std::string printFuzzer(int nTests, int interval) const; -}; - - -struct Test -{ - std::string name; - const TestSignature *signature; - std::vector arguments; - - // after test launch - std::optional returnValue; - - [[nodiscard]] std::string print() const; - [[nodiscard]] std::string printFunctionCall() const; - - template - static Test generate(Generator &gen, std::string name, TestSignature *signature) { - Test test; - test.name = std::move(name); - test.signature = signature; - - for (const auto &type : test.signature->parameterTypes) { - test.arguments.push_back(Value::generate(gen, type)); - } - - return test; - } + [[nodiscard]] std::string runFuzzer(int nTests) const; }; diff --git a/src/test_main.cpp b/src/test_main.cpp index c277759..fbb398c 100644 --- a/src/test_main.cpp +++ b/src/test_main.cpp @@ -3,7 +3,7 @@ #include #include -TestMain::TestMain(int argc, char **argv) : gen { std::random_device{}() } { +TestMain::TestMain(int argc, char **argv) { for (int i = 0; i < argc; ++i) { args.emplace_back(argv[i]); } @@ -25,12 +25,6 @@ void TestMain::run() { usage(); } - for (auto signature : signatures) { - std::cout << signature->runFuzzer(10) << std::endl; - } - - return; - std::cout << "#include \n"; for (auto signature : signatures) { @@ -43,8 +37,8 @@ void TestMain::run() { } TestMain &TestMain::fuzz(TestSignature *testSignature, int n) { - for (int i = 0; i < n; ++i) { - add(Test::generate(gen, "test_" + std::to_string(i), testSignature)); + for (const auto &test : testSignature->fuzz(n)) { + add(test); } return *this; diff --git a/src/test_main.h b/src/test_main.h index c8febe1..283173a 100644 --- a/src/test_main.h +++ b/src/test_main.h @@ -10,7 +10,6 @@ class TestMain { std::vector args; std::vector tests; std::unordered_set signatures; - std::mt19937 gen; private: void usage();