Skip to content

Commit 5bba037

Browse files
committed
Add enumListSetting()/enumSetSetting() and use them for output lists
1 parent fc66d33 commit 5bba037

File tree

5 files changed

+136
-51
lines changed

5 files changed

+136
-51
lines changed

Diff for: test/TestCaseReader.h

+57
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@
2222

2323
#include <test/libsolidity/util/SoltestErrors.h>
2424

25+
#include <libsolutil/CommonData.h>
2526
#include <libsolutil/StringUtils.h>
2627

28+
#include <boost/algorithm/string/split.hpp>
29+
#include <boost/algorithm/string/trim.hpp>
2730
#include <boost/filesystem.hpp>
2831
#include <boost/throw_exception.hpp>
2932

3033
#include <fmt/format.h>
3134

35+
#include <range/v3/range/conversion.hpp>
3236
#include <range/v3/view/map.hpp>
37+
#include <range/v3/view/transform.hpp>
3338

3439
#include <fstream>
3540
#include <map>
@@ -73,6 +78,10 @@ class TestCaseReader
7378

7479
template <typename E>
7580
E enumSetting(std::string const& _name, std::map<std::string, E> const& _choices, std::string const& _defaultChoice);
81+
template <typename E>
82+
std::vector<E> enumListSetting(std::string const& _name, std::map<E, std::string> const& _choices, std::vector<E> const& _defaultValue);
83+
template <typename E>
84+
std::set<E> enumSetSetting(std::string const& _name, std::map<E, std::string> const& _choices, std::set<E> const& _defaultValue);
7685

7786
void ensureAllSettingsRead() const;
7887

@@ -105,4 +114,52 @@ E TestCaseReader::enumSetting(std::string const& _name, std::map<std::string, E>
105114
return _choices.at(value);
106115
}
107116

117+
template <typename E>
118+
std::vector<E> TestCaseReader::enumListSetting(std::string const& _name, std::map<E, std::string> const& _choices, std::vector<E> const& _defaultValue)
119+
{
120+
std::map<std::string, E> const labelToItem = util::invertMap(_choices);
121+
auto const translateToLabel = [&](E _item) { return _choices.at(_item); };
122+
123+
for (std::string const& label: labelToItem | ranges::views::keys)
124+
soltestAssert(label.find(",") == std::string::npos && boost::algorithm::trim_copy(label) == label);
125+
126+
for (E item: _defaultValue)
127+
soltestAssert(_choices.contains(item));
128+
129+
std::string value = stringSetting(
130+
_name,
131+
util::joinHumanReadable(_defaultValue | ranges::views::transform(translateToLabel) | ranges::to<std::vector>)
132+
);
133+
134+
std::vector<std::string> selectedLabels;
135+
boost::split(selectedLabels, value, boost::is_any_of(","));
136+
137+
std::vector<E> selectedItems;
138+
std::vector<std::string> invalidLabels;
139+
for (std::string const& label: selectedLabels)
140+
{
141+
std::string trimmedLabel = boost::trim_copy(label);
142+
if (labelToItem.contains(trimmedLabel))
143+
selectedItems.push_back(labelToItem.at(trimmedLabel));
144+
else
145+
invalidLabels.push_back(trimmedLabel);
146+
}
147+
148+
if (!invalidLabels.empty())
149+
solThrow(solidity::test::ValidationError, fmt::format(
150+
"Invalid choices in '{}' setting: {}.\nAvailable choices: {}.",
151+
_name,
152+
util::joinHumanReadable(invalidLabels),
153+
util::joinHumanReadable(labelToItem | ranges::views::keys)
154+
));
155+
156+
return selectedItems;
157+
}
158+
159+
template <typename E>
160+
std::set<E> TestCaseReader::enumSetSetting(std::string const& _name, std::map<E, std::string> const& _choices, std::set<E> const& _defaultValue)
161+
{
162+
return enumListSetting(_name, _choices, _defaultValue | ranges::to<std::vector>) | ranges::to<std::set>;
163+
}
164+
108165
}

Diff for: test/libevmasm/EVMAssemblyTest.cpp

+24-26
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include <libevmasm/EVMAssemblyStack.h>
2626

2727
#include <boost/algorithm/string/predicate.hpp>
28-
#include <boost/algorithm/string/split.hpp>
2928
#include <boost/algorithm/string/trim.hpp>
3029

3130
#include <range/v3/view/map.hpp>
@@ -40,12 +39,12 @@ using namespace solidity::frontend::test;
4039
using namespace solidity::langutil;
4140
using namespace solidity::util;
4241

43-
std::vector<std::string> const EVMAssemblyTest::c_outputLabels = {
44-
"InputAssemblyJSON",
45-
"Assembly",
46-
"Bytecode",
47-
"Opcodes",
48-
"SourceMappings",
42+
std::map<EVMAssemblyTest::Output, std::string> const EVMAssemblyTest::c_outputLabels = {
43+
{EVMAssemblyTest::Output::InputAssemblyJSON, "InputAssemblyJSON"},
44+
{EVMAssemblyTest::Output::Assembly, "Assembly"},
45+
{EVMAssemblyTest::Output::Bytecode, "Bytecode"},
46+
{EVMAssemblyTest::Output::Opcodes, "Opcodes"},
47+
{EVMAssemblyTest::Output::SourceMappings, "SourceMappings"},
4948
};
5049

5150
std::unique_ptr<TestCase> EVMAssemblyTest::create(Config const& _config)
@@ -66,7 +65,11 @@ EVMAssemblyTest::EVMAssemblyTest(std::string const& _filename):
6665
else
6766
solThrow(ValidationError, "Not an assembly test: \"" + _filename + "\". Allowed extensions: .asm, .asmjson.");
6867

69-
m_selectedOutputs = m_reader.stringSetting("outputs", "Assembly,Bytecode,Opcodes,SourceMappings");
68+
m_selectedOutputs = m_reader.enumSetSetting(
69+
"outputs",
70+
c_outputLabels,
71+
{Output::Assembly, Output::Bytecode, Output::Opcodes, Output::SourceMappings}
72+
);
7073
OptimisationPreset optimizationPreset = m_reader.enumSetting<OptimisationPreset>(
7174
"optimizationPreset",
7275
{
@@ -145,34 +148,29 @@ TestCase::TestResult EVMAssemblyTest::run(std::ostream& _stream, std::string con
145148
}
146149
soltestAssert(evmAssemblyStack.compilationSuccessful());
147150

148-
auto const produceOutput = [&](std::string const& _output) {
149-
if (_output == "InputAssemblyJSON")
150-
return assemblyJSON;
151-
if (_output == "Assembly")
152-
return evmAssemblyStack.assemblyString({{m_reader.fileName().filename().string(), m_source}});
153-
if (_output == "Bytecode")
154-
return util::toHex(evmAssemblyStack.object().bytecode);
155-
if (_output == "Opcodes")
156-
return disassemble(evmAssemblyStack.object().bytecode, CommonOptions::get().evmVersion());
157-
if (_output == "SourceMappings")
158-
return evmAssemblyStack.sourceMapping();
159-
soltestAssert(false);
151+
auto const produceOutput = [&](Output _output) {
152+
switch (_output)
153+
{
154+
case Output::InputAssemblyJSON: return assemblyJSON;
155+
case Output::Assembly: return evmAssemblyStack.assemblyString({{m_reader.fileName().filename().string(), m_source}});
156+
case Output::Bytecode: return util::toHex(evmAssemblyStack.object().bytecode);
157+
case Output::Opcodes: return disassemble(evmAssemblyStack.object().bytecode, CommonOptions::get().evmVersion());
158+
case Output::SourceMappings: return evmAssemblyStack.sourceMapping();
159+
}
160160
unreachable();
161161
};
162162

163-
std::set<std::string> selectedOutputSet;
164-
boost::split(selectedOutputSet, m_selectedOutputs, boost::is_any_of(","));
165-
for (std::string const& output: c_outputLabels)
166-
if (selectedOutputSet.contains(output))
163+
for (Output output: c_outputLabels | ranges::views::keys)
164+
if (m_selectedOutputs.contains(output))
167165
{
168166
if (!m_obtainedResult.empty() && m_obtainedResult.back() != '\n')
169167
m_obtainedResult += "\n";
170168

171169
// Don't trim on the left to avoid stripping indentation.
172170
std::string content = produceOutput(output);
173171
boost::trim_right(content);
174-
std::string separator = (content.empty() ? "" : (output == "Assembly" ? "\n" : " "));
175-
m_obtainedResult += output + ":" + separator + content;
172+
std::string separator = (content.empty() ? "" : (output == Output::Assembly ? "\n" : " "));
173+
m_obtainedResult += c_outputLabels.at(output) + ":" + separator + content;
176174
}
177175

178176
return checkResult(_stream, _linePrefix, _formatted);

Diff for: test/libevmasm/EVMAssemblyTest.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@
2424

2525
#include <libevmasm/Assembly.h>
2626

27+
#include <map>
2728
#include <memory>
2829
#include <ostream>
30+
#include <set>
2931
#include <string>
30-
#include <vector>
3132

3233
namespace solidity::evmasm::test
3334
{
@@ -48,10 +49,19 @@ class EVMAssemblyTest: public frontend::test::EVMVersionRestrictedTestCase
4849
Plain,
4950
};
5051

51-
static std::vector<std::string> const c_outputLabels;
52+
enum class Output
53+
{
54+
InputAssemblyJSON,
55+
Assembly,
56+
Bytecode,
57+
Opcodes,
58+
SourceMappings,
59+
};
60+
61+
static std::map<Output, std::string> const c_outputLabels;
5262

5363
AssemblyFormat m_assemblyFormat{};
54-
std::string m_selectedOutputs;
64+
std::set<Output> m_selectedOutputs;
5565
evmasm::Assembly::OptimiserSettings m_optimizerSettings;
5666
};
5767

Diff for: test/libyul/ObjectCompilerTest.cpp

+31-21
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ using namespace solidity::frontend;
4444
using namespace solidity::frontend::test;
4545
using namespace solidity::test;
4646

47+
std::map<ObjectCompilerTest::Output, std::string> const ObjectCompilerTest::c_outputLabels = {
48+
{ObjectCompilerTest::Output::Assembly, "Assembly"},
49+
{ObjectCompilerTest::Output::Bytecode, "Bytecode"},
50+
{ObjectCompilerTest::Output::Opcodes, "Opcodes"},
51+
{ObjectCompilerTest::Output::SourceMappings, "SourceMappings"},
52+
};
53+
4754
ObjectCompilerTest::ObjectCompilerTest(std::string const& _filename):
4855
EVMVersionRestrictedTestCase(_filename)
4956
{
@@ -59,11 +66,11 @@ ObjectCompilerTest::ObjectCompilerTest(std::string const& _filename):
5966
"minimal"
6067
);
6168

62-
constexpr std::array allowedOutputs = {"Assembly", "Bytecode", "Opcodes", "SourceMappings"};
63-
boost::split(m_outputSetting, m_reader.stringSetting("outputs", "Assembly,Bytecode,Opcodes,SourceMappings"), boost::is_any_of(","));
64-
for (auto const& output: m_outputSetting)
65-
if (std::find(allowedOutputs.begin(), allowedOutputs.end(), output) == allowedOutputs.end())
66-
solThrow(ValidationError, "Invalid output type: \"" + output + "\"");
69+
m_selectedOutputs = m_reader.enumSetSetting(
70+
"outputs",
71+
c_outputLabels,
72+
c_outputLabels | ranges::views::keys | ranges::to<std::set>
73+
);
6774

6875
m_expectation = m_reader.simpleExpectations();
6976
}
@@ -86,26 +93,29 @@ TestCase::TestResult ObjectCompilerTest::run(std::ostream& _stream, std::string
8693
solAssert(obj.bytecode);
8794
solAssert(obj.sourceMappings);
8895

89-
if (std::find(m_outputSetting.begin(), m_outputSetting.end(), "Assembly") != m_outputSetting.end())
90-
m_obtainedResult = "Assembly:\n" + obj.assembly->assemblyString(yulStack.debugInfoSelection());
91-
if (obj.bytecode->bytecode.empty())
92-
m_obtainedResult += "-- empty bytecode --\n";
93-
else
94-
{
95-
if (std::find(m_outputSetting.begin(), m_outputSetting.end(), "Bytecode") != m_outputSetting.end())
96-
m_obtainedResult += "Bytecode: " + util::toHex(obj.bytecode->bytecode);
97-
if (std::find(m_outputSetting.begin(), m_outputSetting.end(), "Opcodes") != m_outputSetting.end())
96+
auto const produceOutput = [&](Output _output) {
97+
switch (_output)
9898
{
99-
m_obtainedResult += (!m_obtainedResult.empty() && m_obtainedResult.back() != '\n') ? "\n" : "";
100-
m_obtainedResult += "Opcodes: " +
101-
boost::trim_copy(evmasm::disassemble(obj.bytecode->bytecode, CommonOptions::get().evmVersion()));
99+
case Output::Assembly: return obj.assembly->assemblyString(yulStack.debugInfoSelection());
100+
case Output::Bytecode: return util::toHex(obj.bytecode->bytecode);
101+
case Output::Opcodes: return evmasm::disassemble(obj.bytecode->bytecode, CommonOptions::get().evmVersion());
102+
case Output::SourceMappings: return *obj.sourceMappings;
102103
}
103-
if (std::find(m_outputSetting.begin(), m_outputSetting.end(), "SourceMappings") != m_outputSetting.end())
104+
unreachable();
105+
};
106+
107+
for (Output output: c_outputLabels | ranges::views::keys)
108+
if (m_selectedOutputs.contains(output))
104109
{
105-
m_obtainedResult += (!m_obtainedResult.empty() && m_obtainedResult.back() != '\n') ? "\n" : "";
106-
m_obtainedResult += "SourceMappings:" + (obj.sourceMappings->empty() ? "" : " " + *obj.sourceMappings) + "\n";
110+
if (!m_obtainedResult.empty() && m_obtainedResult.back() != '\n')
111+
m_obtainedResult += "\n";
112+
113+
// Don't trim on the left to avoid stripping indentation.
114+
std::string content = produceOutput(output);
115+
boost::trim_right(content);
116+
std::string separator = (content.empty() ? "" : (output == Output::Assembly ? "\n" : " "));
117+
m_obtainedResult += c_outputLabels.at(output) + ":" + separator + content;
107118
}
108-
}
109119

110120
return checkResult(_stream, _linePrefix, _formatted);
111121
}

Diff for: test/libyul/ObjectCompilerTest.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,20 @@ class ObjectCompilerTest: public solidity::frontend::test::EVMVersionRestrictedT
5151
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
5252

5353
private:
54+
enum class Output
55+
{
56+
Assembly,
57+
Bytecode,
58+
Opcodes,
59+
SourceMappings,
60+
};
61+
5462
void disambiguate();
5563

64+
static std::map<Output, std::string> const c_outputLabels;
65+
5666
frontend::OptimisationPreset m_optimisationPreset;
57-
std::vector<std::string> m_outputSetting;
67+
std::set<Output> m_selectedOutputs;
5868
};
5969

6070
}

0 commit comments

Comments
 (0)