12
12
along with solidity. If not, see <http://www.gnu.org/licenses/>.
13
13
*/
14
14
15
- #include < test/libsolidity/SemanticTest.h>
16
- #include < test/libsolidity/util/BytesUtils.h>
17
- #include < libsolutil/Whiskers.h>
18
- #include < libyul/Exceptions.h>
19
- #include < test/Common.h>
20
15
#include < boost/algorithm/string.hpp>
21
16
#include < boost/algorithm/string/predicate.hpp>
22
17
#include < boost/algorithm/string/trim.hpp>
23
18
#include < boost/throw_exception.hpp>
19
+ #include < libsolutil/Whiskers.h>
20
+ #include < libyul/Exceptions.h>
21
+ #include < test/Common.h>
22
+ #include < test/libsolidity/SemanticTest.h>
23
+ #include < test/libsolidity/util/BytesUtils.h>
24
+
25
+ #include < test/libsolidity/Builtin.h>
26
+ #include < test/libsolidity/TestHook.h>
27
+ #include < test/libsolidity/hooks/SmokeHook.h>
24
28
25
29
#include < algorithm>
26
30
#include < cctype>
@@ -49,14 +53,21 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer
49
53
m_lineOffset(m_reader.lineNumber()),
50
54
m_enforceViaYul(enforceViaYul)
51
55
{
52
- using namespace std ::placeholders;
53
- m_builtins
54
- = {{" smoke" ,
55
- {
56
- {" test0" , {std::bind (&SemanticTest::builtinSmokeTest, this , _1)}},
57
- {" test1" , {std::bind (&SemanticTest::builtinSmokeTest, this , _1)}},
58
- {" test2" , {std::bind (&SemanticTest::builtinSmokeTest, this , _1)}},
59
- }}};
56
+ using namespace placeholders ;
57
+ auto simpleSmokeBuiltin = make_shared<Builtin>(
58
+ bind (&SemanticTest::builtinSmokeTest, this , _1)
59
+ );
60
+ m_builtins = {
61
+ {" smoke" , {
62
+ {" test0" , simpleSmokeBuiltin},
63
+ {" test1" , simpleSmokeBuiltin},
64
+ {" test2" , simpleSmokeBuiltin}
65
+ }
66
+ }
67
+ };
68
+ m_testHooks = {
69
+ make_shared<SmokeHook>()
70
+ };
60
71
61
72
string choice = m_reader.stringSetting (" compileViaYul" , " default" );
62
73
if (choice == " also" )
@@ -130,7 +141,18 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
130
141
return result;
131
142
}
132
143
133
- TestCase::TestResult SemanticTest::runTest (ostream& _stream, string const & _linePrefix, bool _formatted, bool _compileViaYul, bool _compileToEwasm)
144
+ void SemanticTest::addBuiltin (string _module, string _function, std::shared_ptr<Builtin> _builtin)
145
+ {
146
+ m_builtins[_module][_function] = _builtin;
147
+ }
148
+
149
+ TestCase::TestResult SemanticTest::runTest (
150
+ ostream& _stream,
151
+ string const & _linePrefix,
152
+ bool _formatted,
153
+ bool _compileViaYul,
154
+ bool _compileToEwasm
155
+ )
134
156
{
135
157
bool success = true ;
136
158
@@ -160,14 +182,33 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line
160
182
161
183
bool constructed = false ;
162
184
185
+ // Iterate through the test calls and set the previous call.
186
+ TestFunctionCall* previousCall{nullptr };
187
+ for (auto & test: m_tests)
188
+ {
189
+ test.setPreviousCall (previousCall);
190
+ test.setTestHooks (&m_testHooks);
191
+ previousCall = &test;
192
+ }
193
+
194
+ for (auto & hook: m_testHooks)
195
+ hook->beginTestCase ();
196
+
163
197
for (auto & test: m_tests)
164
198
{
199
+ for (auto & hook: m_testHooks)
200
+ hook->beforeFunctionCall (test);
201
+
165
202
if (constructed)
166
203
{
167
- soltestAssert (test.call ().kind != FunctionCall::Kind::Library, " Libraries have to be deployed before any other call." );
204
+ soltestAssert (
205
+ test.call ().kind != FunctionCall::Kind::Library,
206
+ " Libraries have to be deployed before any other call."
207
+ );
168
208
soltestAssert (
169
209
test.call ().kind != FunctionCall::Kind::Constructor,
170
- " Constructor has to be the first function call expect for library deployments." );
210
+ " Constructor has to be the first function call expect for library deployments."
211
+ );
171
212
}
172
213
else if (test.call ().kind == FunctionCall::Kind::Library)
173
214
{
@@ -210,11 +251,11 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line
210
251
output = callLowLevel (test.call ().arguments .rawBytes (), test.call ().value .value );
211
252
else if (test.call ().kind == FunctionCall::Kind::Builtin)
212
253
{
213
- std:: vector<string> builtinPath;
254
+ vector<string> builtinPath;
214
255
boost::split (builtinPath, test.call ().signature , boost::is_any_of (" ." ));
215
256
soltestAssert (builtinPath.size () == 2 , " " );
216
257
auto builtin = m_builtins[builtinPath.front ()][builtinPath.back ()];
217
- std::optional<bytes> builtinOutput{builtin. function (test.call ())};
258
+ std::optional<bytes> builtinOutput{builtin-> builtin (test.call ())};
218
259
if (builtinOutput.has_value ())
219
260
{
220
261
test.setFailure (false );
@@ -241,11 +282,11 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line
241
282
bytes expectationOutput;
242
283
if (test.call ().expectations .builtin )
243
284
{
244
- std:: vector<string> builtinPath;
285
+ vector<string> builtinPath;
245
286
boost::split (builtinPath, test.call ().expectations .builtin ->signature , boost::is_any_of (" ." ));
246
- assert (builtinPath.size () == 2 );
287
+ soltestAssert (builtinPath.size () == 2 , " " );
247
288
auto builtin = m_builtins[builtinPath.front ()][builtinPath.back ()];
248
- std::optional<bytes> builtinResult = builtin. function (*test.call ().expectations .builtin );
289
+ std::optional<bytes> builtinResult = builtin-> builtin (*test.call ().expectations .builtin );
249
290
if (builtinResult.has_value ())
250
291
expectationOutput = builtinResult.value ();
251
292
else
@@ -273,8 +314,29 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line
273
314
test.setRawBytes (std::move (output));
274
315
test.setContractABI (m_compiler.contractABI (m_compiler.lastContractName ()));
275
316
}
317
+
318
+ for (auto & hook: m_testHooks)
319
+ hook->afterFunctionCall (test);
320
+ }
321
+
322
+ // The artificialFunctionCall is an artificially created function call,
323
+ // where it's previous call is pointing to the last call of the test.
324
+ TestFunctionCall artificialFunctionCall (FunctionCall{});
325
+ artificialFunctionCall.setTestHooks (&m_testHooks);
326
+ artificialFunctionCall.setPreviousCall (previousCall);
327
+ for (auto & hook: m_testHooks)
328
+ {
329
+ hook->beforeFunctionCall (artificialFunctionCall);
330
+ hook->afterFunctionCall (artificialFunctionCall);
276
331
}
277
332
333
+ for (auto & hook: m_testHooks)
334
+ hook->endTestCase ();
335
+
336
+ for (auto & test: m_tests)
337
+ for (auto & hook: m_testHooks)
338
+ success &= hook->verifyFunctionCall (test);
339
+
278
340
if (!m_runWithYul && _compileViaYul)
279
341
{
280
342
m_compileViaYulCanBeSet = success;
@@ -391,14 +453,15 @@ void SemanticTest::parseExpectations(istream& _stream)
391
453
{
392
454
TestFileParser parser{_stream, &this ->m_builtins };
393
455
auto functionCalls = parser.parseFunctionCalls (m_lineOffset);
394
- std:: move (functionCalls.begin (), functionCalls.end (), back_inserter (m_tests));
456
+ move (functionCalls.begin (), functionCalls.end (), back_inserter (m_tests));
395
457
}
396
458
397
459
bool SemanticTest::deploy (
398
460
string const & _contractName,
399
461
u256 const & _value,
400
462
bytes const & _arguments,
401
- map<string, solidity::test::Address> const & _libraries)
463
+ map<string, solidity::test::Address> const & _libraries
464
+ )
402
465
{
403
466
auto output = compileAndRunWithoutCheck (m_sources.sources , _value, _contractName, _arguments, _libraries);
404
467
return !output.empty () && m_transactionSuccessful;
0 commit comments