/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 #include #include using namespace solidity::test::fuzzer; using namespace solidity::util; using namespace std; using PrngUtil = solidity::test::fuzzer::GenerationProbability; GeneratorBase::GeneratorBase(std::shared_ptr _mutator) { mutator = std::move(_mutator); rand = mutator->randomEngine(); } string GeneratorBase::visitChildren() { ostringstream os; // Randomise visit order vector randomisedChildren; for (auto child: generators) randomisedChildren.push_back(child); shuffle(randomisedChildren.begin(), randomisedChildren.end(), *rand); for (auto child: randomisedChildren) os << std::visit(GeneratorVisitor{}, child); return os.str(); } void TestCaseGenerator::setup() { addGenerators( { mutator->generator() } ); } string TestCaseGenerator::visit() { ostringstream os; for (unsigned i = 0; i < PrngUtil{}.distributionOneToN(s_maxSourceUnits, rand); i++) { string sourcePath = path(); os << "\n" << "==== Source: " << sourcePath << " ====" << "\n"; m_numSourceUnits++; os << visitChildren(); generator()->reset(); } return os.str(); } void SourceUnitGenerator::setup() { addGenerators( { mutator->generator(), } ); } string SourceUnitGenerator::visit() { string sourceUnit = visitChildren(); reset(); return sourceUnit; } void SourceUnitGenerator::reset() { for (auto& g: generators) std::visit(ResetVisitor{}, g); } string PragmaGenerator::visit() { static constexpr const char* preamble = R"( pragma solidity >= 0.0.0; pragma experimental SMTChecker; )"; // Choose equally at random from coder v1 and v2 string abiPragma = "pragma abicoder v" + to_string(PrngUtil{}.distributionOneToN(2, rand)) + ";\n"; return preamble + abiPragma; } template shared_ptr SolidityGenerator::generator() { for (auto& g: m_generators) if (holds_alternative>(g)) return get>(g); solAssert(false, ""); } SolidityGenerator::SolidityGenerator(unsigned _seed) { m_rand = make_shared(_seed); m_generators = {}; } template void SolidityGenerator::createGenerators() { if constexpr (I < std::variant_size_v) { createGenerator>(); createGenerators(); } } string SolidityGenerator::generateTestProgram() { createGenerators(); for (auto& g: m_generators) std::visit(AddDependenciesVisitor{}, g); string program = generator()->visit(); destroyGenerators(); return program; }