Permit zero upto max visits per generator

This commit is contained in:
Bhargava Shastry 2021-01-27 14:55:30 +01:00
parent c3f639b355
commit 00a4438f6e
3 changed files with 75 additions and 38 deletions

View File

@ -61,7 +61,7 @@ size_t SolidityCustomMutatorInterface::generate()
{
string testCase = generator->generateTestProgram();
solAssert(
!testCase.empty() && data,
data,
"Solc custom mutator: Invalid mutant or memory pointer"
);
size_t mutantSize = min(testCase.size(), maxMutantSize - 1);

View File

@ -36,14 +36,16 @@ string GeneratorBase::visitChildren()
{
ostringstream os;
// Randomise visit order
vector<GeneratorPtr> randomisedChildren;
vector<std::pair<GeneratorPtr, unsigned>> randomisedChildren;
for (auto const& child: generators)
randomisedChildren.push_back(child);
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist->randomEngine);
for (auto child: randomisedChildren)
os << std::visit(GenericVisitor{
[&](auto const& _item) { return _item->generate(); }
}, child);
for (auto const& child: randomisedChildren)
if (uRandDist->likely(child.second + 1))
for (unsigned i = 0; i < uRandDist->distributionOneToN(child.second); i++)
os << std::visit(GenericVisitor{
[&](auto const& _item) { return _item->generate(); }
}, child.first);
return os.str();
}
@ -96,39 +98,34 @@ string TestState::randomNonCurrentPath() const
void TestCaseGenerator::setup()
{
addGenerators({
mutator->generator<SourceUnitGenerator>()
{mutator->generator<SourceUnitGenerator>(), s_maxSourceUnits}
});
}
string TestCaseGenerator::visit()
{
ostringstream os;
for (unsigned i = 0; i < uRandDist->distributionOneToN(s_maxSourceUnits); i++)
{
string sourcePath = path();
os << "\n"
<< "==== Source: "
<< sourcePath
<< " ===="
<< "\n";
updateSourcePath(sourcePath);
m_numSourceUnits++;
os << visitChildren();
}
return os.str();
return visitChildren();
}
void SourceUnitGenerator::setup()
{
addGenerators({
mutator->generator<ImportGenerator>(),
mutator->generator<PragmaGenerator>()
{mutator->generator<ImportGenerator>(), s_maxImports},
{mutator->generator<PragmaGenerator>(), 1}
});
}
string SourceUnitGenerator::visit()
{
return visitChildren();
state->addSource();
ostringstream os;
os << "\n"
<< "==== Source: "
<< state->currentPath()
<< " ===="
<< "\n";
os << visitChildren();
return os.str();
}
string PragmaGenerator::visit()

View File

@ -68,15 +68,24 @@ struct UniformRandomDistribution
/// uniformly at random.
[[nodiscard]] size_t distributionOneToN(size_t _n) const
{
solAssert(_n > 0, "");
return Distribution(1, _n)(*randomEngine);
}
/// @returns true with a probability of 1/(@param _n), false otherwise.
/// @param _n must be non zero.
/// @param _n > 1.
[[nodiscard]] bool probable(size_t _n) const
{
solAssert(_n > 0, "");
solAssert(_n > 1, "");
return distributionOneToN(_n) == 1;
}
/// @returns true with a probability of 1 - 1/(@param _n),
/// false otherwise.
/// @param _n > 1.
[[nodiscard]] bool likely(size_t _n) const
{
solAssert(_n > 1, "");
return !probable(_n);
}
std::unique_ptr<RandomEngine> randomEngine;
};
@ -85,7 +94,8 @@ struct TestState
explicit TestState(std::shared_ptr<UniformRandomDistribution> _urd):
sourceUnitPaths({}),
currentSourceUnitPath({}),
uRandDist(std::move(_urd))
uRandDist(std::move(_urd)),
numSourceUnits(0)
{}
/// Adds @param _path to @name sourceUnitPaths updates
/// @name currentSourceUnitPath.
@ -94,24 +104,49 @@ struct TestState
sourceUnitPaths.insert(_path);
currentSourceUnitPath = _path;
}
/// @returns true if @name sourceUnitPaths is empty,
/// Returns true if @name sourceUnitPaths is empty,
/// false otherwise.
[[nodiscard]] bool empty() const
{
return sourceUnitPaths.empty();
}
/// @returns the number of items in @name sourceUnitPaths.
/// Returns the number of items in @name sourceUnitPaths.
[[nodiscard]] size_t size() const
{
return sourceUnitPaths.size();
}
/// Returns a new source path name that is formed by concatenating
/// a static prefix @name m_sourceUnitNamePrefix, a monotonically
/// increasing counter starting from 0 and the postfix (extension)
/// ".sol".
[[nodiscard]] std::string newPath() const
{
return sourceUnitNamePrefix + std::to_string(numSourceUnits) + ".sol";
}
[[nodiscard]] std::string currentPath() const
{
solAssert(numSourceUnits > 0, "");
return currentSourceUnitPath;
}
/// Adds @param _path to list of source paths in global test
/// state and increments @name m_numSourceUnits.
void updateSourcePath(std::string const& _path)
{
addSourceUnit(_path);
numSourceUnits++;
}
/// Adds a new source unit to test case.
void addSource()
{
updateSourcePath(newPath());
}
/// Prints test state to @param _os.
void print(std::ostream& _os) const;
/// @returns a randomly chosen path from @param _sourceUnitPaths.
/// Returns a randomly chosen path from @param _sourceUnitPaths.
[[nodiscard]] std::string randomPath(std::set<std::string> const& _sourceUnitPaths) const;
/// @returns a randomly chosen path from @name sourceUnitPaths.
/// Returns a randomly chosen path from @name sourceUnitPaths.
[[nodiscard]] std::string randomPath() const;
/// @returns a randomly chosen non current source unit path.
/// Returns a randomly chosen non current source unit path.
[[nodiscard]] std::string randomNonCurrentPath() const;
/// List of source paths in test input.
std::set<std::string> sourceUnitPaths;
@ -119,6 +154,10 @@ struct TestState
std::string currentSourceUnitPath;
/// Uniform random distribution.
std::shared_ptr<UniformRandomDistribution> uRandDist;
/// Number of source units in test input
size_t numSourceUnits;
/// String prefix of source unit names
std::string const sourceUnitNamePrefix = "su";
};
struct GeneratorBase
@ -128,8 +167,8 @@ struct GeneratorBase
std::shared_ptr<T> generator()
{
for (auto& g: generators)
if (std::holds_alternative<std::shared_ptr<T>>(g))
return std::get<std::shared_ptr<T>>(g);
if (std::holds_alternative<std::shared_ptr<T>>(g.first))
return std::get<std::shared_ptr<T>>(g.first);
solAssert(false, "");
}
/// @returns test fragment created by this generator.
@ -151,7 +190,7 @@ struct GeneratorBase
std::string visitChildren();
/// Adds generators for child grammar elements of
/// this grammar element.
void addGenerators(std::set<GeneratorPtr> _generators)
void addGenerators(std::set<std::pair<GeneratorPtr, unsigned>> _generators)
{
generators += _generators;
}
@ -168,7 +207,7 @@ struct GeneratorBase
/// Shared pointer to the mutator instance
std::shared_ptr<SolidityGenerator> mutator;
/// Set of generators used by this generator.
std::set<GeneratorPtr> generators;
std::set<std::pair<GeneratorPtr, unsigned>> generators;
/// Shared ptr to global test state.
std::shared_ptr<TestState> state;
/// Uniform random distribution
@ -179,8 +218,7 @@ class TestCaseGenerator: public GeneratorBase
{
public:
explicit TestCaseGenerator(std::shared_ptr<SolidityGenerator> _mutator):
GeneratorBase(std::move(_mutator)),
m_numSourceUnits(0)
GeneratorBase(std::move(_mutator))
{}
void setup() override;
std::string visit() override;
@ -221,6 +259,8 @@ public:
void setup() override;
std::string visit() override;
std::string name() override { return "Source unit generator"; }
private:
static unsigned constexpr s_maxImports = 2;
};
class PragmaGenerator: public GeneratorBase