2017-04-19 14:54:14 +00:00
/*
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 < http : //www.gnu.org/licenses/>.
*/
2020-07-17 14:54:12 +00:00
// SPDX-License-Identifier: GPL-3.0
2017-04-19 14:54:14 +00:00
/**
* @ date 2017
* Unit tests for interface / StandardCompiler . h .
*/
# include <string>
# include <boost/test/unit_test.hpp>
2020-04-24 12:26:31 +00:00
# include <libsolidity/interface/OptimiserSettings.h>
2017-04-19 14:54:14 +00:00
# include <libsolidity/interface/StandardCompiler.h>
2019-05-06 12:31:49 +00:00
# include <libsolidity/interface/Version.h>
2020-01-06 10:52:23 +00:00
# include <libsolutil/JSON.h>
2020-04-24 12:26:31 +00:00
# include <libsolutil/CommonData.h>
2019-02-05 22:04:35 +00:00
# include <test/Metadata.h>
2017-04-19 14:54:14 +00:00
2020-08-20 14:56:25 +00:00
# include <algorithm>
2020-04-24 12:26:31 +00:00
# include <set>
2017-04-19 14:54:14 +00:00
using namespace std ;
2019-12-23 15:50:30 +00:00
using namespace solidity : : evmasm ;
2017-04-19 14:54:14 +00:00
2019-12-23 15:50:30 +00:00
namespace solidity : : frontend : : test
2017-04-19 14:54:14 +00:00
{
namespace
{
/// Helper to match a specific error type and message
bool containsError ( Json : : Value const & _compilerResult , string const & _type , string const & _message )
{
if ( ! _compilerResult . isMember ( " errors " ) )
return false ;
for ( auto const & error : _compilerResult [ " errors " ] )
{
BOOST_REQUIRE ( error . isObject ( ) ) ;
BOOST_REQUIRE ( error [ " type " ] . isString ( ) ) ;
BOOST_REQUIRE ( error [ " message " ] . isString ( ) ) ;
if ( ( error [ " type " ] . asString ( ) = = _type ) & & ( error [ " message " ] . asString ( ) = = _message ) )
return true ;
}
return false ;
}
bool containsAtMostWarnings ( Json : : Value const & _compilerResult )
{
if ( ! _compilerResult . isMember ( " errors " ) )
return true ;
for ( auto const & error : _compilerResult [ " errors " ] )
{
BOOST_REQUIRE ( error . isObject ( ) ) ;
BOOST_REQUIRE ( error [ " severity " ] . isString ( ) ) ;
if ( error [ " severity " ] . asString ( ) ! = " warning " )
return false ;
}
return true ;
}
2017-04-19 17:39:37 +00:00
Json : : Value getContractResult ( Json : : Value const & _compilerResult , string const & _file , string const & _name )
{
if (
! _compilerResult [ " contracts " ] . isObject ( ) | |
! _compilerResult [ " contracts " ] [ _file ] . isObject ( ) | |
! _compilerResult [ " contracts " ] [ _file ] [ _name ] . isObject ( )
)
return Json : : Value ( ) ;
return _compilerResult [ " contracts " ] [ _file ] [ _name ] ;
}
2019-04-06 23:48:37 +00:00
Json : : Value compile ( string _input )
2017-04-19 14:54:14 +00:00
{
StandardCompiler compiler ;
2019-04-06 23:48:37 +00:00
string output = compiler . compile ( std : : move ( _input ) ) ;
2017-04-19 14:54:14 +00:00
Json : : Value ret ;
2019-12-23 15:50:30 +00:00
BOOST_REQUIRE ( util : : jsonParseStrict ( output , ret ) ) ;
2017-04-19 14:54:14 +00:00
return ret ;
}
} // end anonymous namespace
BOOST_AUTO_TEST_SUITE ( StandardCompiler )
BOOST_AUTO_TEST_CASE ( assume_object_input )
{
2017-04-19 16:41:55 +00:00
Json : : Value result ;
/// Use the native JSON interface of StandardCompiler to trigger these
2019-12-23 15:50:30 +00:00
frontend : : StandardCompiler compiler ;
2017-04-19 16:41:55 +00:00
result = compiler . compile ( Json : : Value ( ) ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Input is not a JSON object. " ) ) ;
result = compiler . compile ( Json : : Value ( " INVALID " ) ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Input is not a JSON object. " ) ) ;
/// Use the string interface of StandardCompiler to trigger these
result = compile ( " " ) ;
2018-02-07 01:05:20 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " * Line 1, Column 1 \n Syntax error: value, object or array expected. \n * Line 1, Column 1 \n A valid JSON document must be either an array or an object value. \n " ) ) ;
2017-04-19 14:54:14 +00:00
result = compile ( " invalid " ) ;
2018-02-07 01:05:20 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " * Line 1, Column 1 \n Syntax error: value, object or array expected. \n * Line 1, Column 2 \n Extra non-whitespace after JSON value. \n " ) ) ;
2017-04-19 14:54:14 +00:00
result = compile ( " \" invalid \" " ) ;
2018-02-07 01:05:20 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " * Line 1, Column 1 \n A valid JSON document must be either an array or an object value. \n " ) ) ;
2017-04-19 14:54:14 +00:00
BOOST_CHECK ( ! containsError ( result , " JSONError " , " * Line 1, Column 1 \n Syntax error: value, object or array expected. \n " ) ) ;
result = compile ( " {} " ) ;
BOOST_CHECK ( ! containsError ( result , " JSONError " , " * Line 1, Column 1 \n Syntax error: value, object or array expected. \n " ) ) ;
BOOST_CHECK ( ! containsAtMostWarnings ( result ) ) ;
}
BOOST_AUTO_TEST_CASE ( invalid_language )
{
char const * input = R " (
{
2017-04-21 14:34:40 +00:00
" language " : " INVALID " ,
" sources " : { " name " : { " content " : " abc " } }
2017-04-19 14:54:14 +00:00
}
) " ;
Json : : Value result = compile ( input ) ;
2017-04-21 14:34:40 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " Only \" Solidity \" or \" Yul \" is supported as a language. " ) ) ;
2017-04-19 14:54:14 +00:00
}
BOOST_AUTO_TEST_CASE ( valid_language )
{
char const * input = R " (
{
" language " : " Solidity "
}
) " ;
Json : : Value result = compile ( input ) ;
2017-04-21 14:34:40 +00:00
BOOST_CHECK ( ! containsError ( result , " JSONError " , " Only \" Solidity \" or \" Yul \" is supported as a language. " ) ) ;
2017-04-19 14:54:14 +00:00
}
BOOST_AUTO_TEST_CASE ( no_sources )
{
char const * input = R " (
{
" language " : " Solidity "
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " No input sources specified. " ) ) ;
}
2018-02-13 20:40:16 +00:00
BOOST_AUTO_TEST_CASE ( no_sources_empty_object )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : { }
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " No input sources specified. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( no_sources_empty_array )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : [ ]
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " \" sources \" is not a JSON object. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( sources_is_array )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : [ " aa " , " bb " ]
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " \" sources \" is not a JSON object. " ) ) ;
}
2018-02-07 01:05:20 +00:00
BOOST_AUTO_TEST_CASE ( unexpected_trailing_test )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : {
" A " : {
" content " : " contract A { function f() {} } "
}
}
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " * Line 10, Column 2 \n Extra non-whitespace after JSON value. \n " ) ) ;
}
2017-04-19 14:54:14 +00:00
BOOST_AUTO_TEST_CASE ( smoke_test )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
}
2019-05-30 14:35:42 +00:00
BOOST_AUTO_TEST_CASE ( error_recovery_field )
{
auto input = R " (
{
" language " : " Solidity " ,
" settings " : {
" parserErrorRecovery " : " 1 "
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " \" settings.parserErrorRecovery \" must be a Boolean. " ) ) ;
input = R " (
{
" language " : " Solidity " ,
" settings " : {
" parserErrorRecovery " : true
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
}
2018-09-24 10:48:25 +00:00
BOOST_AUTO_TEST_CASE ( optimizer_enabled_not_boolean )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" optimizer " : {
" enabled " : " wrong "
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
2019-02-21 16:39:47 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " The \" enabled \" setting must be a Boolean. " ) ) ;
2018-09-24 10:48:25 +00:00
}
BOOST_AUTO_TEST_CASE ( optimizer_runs_not_a_number )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" optimizer " : {
" enabled " : true ,
" runs " : " not a number "
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " The \" runs \" setting must be an unsigned number. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( optimizer_runs_not_an_unsigned_number )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" optimizer " : {
" enabled " : true ,
" runs " : - 1
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " The \" runs \" setting must be an unsigned number. " ) ) ;
}
2017-04-19 17:39:37 +00:00
BOOST_AUTO_TEST_CASE ( basic_compilation )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
2017-04-20 22:34:12 +00:00
} ,
" settings " : {
" outputSelection " : {
" fileA " : {
2018-08-08 19:43:44 +00:00
" A " : [ " abi " , " devdoc " , " userdoc " , " evm.bytecode " , " evm.assembly " , " evm.gasEstimates " , " evm.legacyAssembly " , " metadata " ] ,
2017-04-20 22:34:12 +00:00
" " : [ " legacyAST " ]
}
}
2017-04-19 17:39:37 +00:00
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
2017-05-02 14:20:27 +00:00
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2017-05-02 14:20:27 +00:00
BOOST_CHECK ( contract [ " devdoc " ] . isObject ( ) ) ;
2020-06-09 15:30:17 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " devdoc " ] ) , R " ({ " kind " : " dev " , " methods " :{}, " version " :1}) " ) ;
2017-05-02 14:20:27 +00:00
BOOST_CHECK ( contract [ " userdoc " ] . isObject ( ) ) ;
2020-06-09 15:30:17 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " userdoc " ] ) , R " ({ " kind " : " user " , " methods " :{}, " version " :1}) " ) ;
2017-04-19 17:39:37 +00:00
BOOST_CHECK ( contract [ " evm " ] . isObject ( ) ) ;
/// @TODO check evm.methodIdentifiers, legacyAssembly, bytecode, deployedBytecode
2017-04-20 09:29:42 +00:00
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " object " ] . isString ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL (
2019-12-23 15:50:30 +00:00
solidity : : test : : bytecodeSansMetadata ( contract [ " evm " ] [ " bytecode " ] [ " object " ] . asString ( ) ) ,
2019-05-06 12:31:49 +00:00
string ( " 6080604052348015600f57600080fd5b5060 " ) +
2019-12-23 15:50:30 +00:00
( VersionIsRelease ? " 3f " : util : : toHex ( bytes { uint8_t ( 61 + VersionStringStrict . size ( ) ) } ) ) +
2019-05-06 12:31:49 +00:00
" 80601d6000396000f3fe6080604052600080fdfe "
2017-06-14 17:36:05 +00:00
) ;
2017-04-19 17:39:37 +00:00
BOOST_CHECK ( contract [ " evm " ] [ " assembly " ] . isString ( ) ) ;
2017-06-14 19:31:20 +00:00
BOOST_CHECK ( contract [ " evm " ] [ " assembly " ] . asString ( ) . find (
2018-01-04 16:08:47 +00:00
" /* \" fileA \" :0:14 contract A { } */ \n mstore(0x40, 0x80) \n "
2020-05-26 15:24:52 +00:00
" callvalue \n dup1 \n "
" iszero \n tag_1 \n jumpi \n "
" 0x00 \n "
" dup1 \n revert \n "
" tag_1: \n pop \n dataSize(sub_0) \n dup1 \n "
2018-12-05 21:11:31 +00:00
" dataOffset(sub_0) \n 0x00 \n codecopy \n 0x00 \n return \n stop \n \n sub_0: assembly { \n "
2020-05-26 15:24:52 +00:00
" /* \" fileA \" :0:14 contract A { } */ \n mstore(0x40, 0x80) \n "
" 0x00 \n "
" dup1 \n revert \n \n auxdata: 0xa26469706673582212 "
2018-01-04 16:08:47 +00:00
) = = 0 ) ;
2017-04-19 17:39:37 +00:00
BOOST_CHECK ( contract [ " evm " ] [ " gasEstimates " ] . isObject ( ) ) ;
2019-05-06 12:31:49 +00:00
BOOST_CHECK_EQUAL ( contract [ " evm " ] [ " gasEstimates " ] . size ( ) , 1 ) ;
BOOST_CHECK ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] . isObject ( ) ) ;
BOOST_CHECK_EQUAL ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] . size ( ) , 3 ) ;
BOOST_CHECK ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] [ " codeDepositCost " ] . isString ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] [ " executionCost " ] . isString ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] [ " totalCost " ] . isString ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL (
2019-05-06 12:31:49 +00:00
u256 ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] [ " codeDepositCost " ] . asString ( ) ) +
u256 ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] [ " executionCost " ] . asString ( ) ) ,
u256 ( contract [ " evm " ] [ " gasEstimates " ] [ " creation " ] [ " totalCost " ] . asString ( ) )
2017-06-14 17:36:05 +00:00
) ;
2018-08-08 19:43:44 +00:00
// Lets take the top level `.code` section (the "deployer code"), that should expose most of the features of
// the assembly JSON. What we want to check here is Operation, Push, PushTag, PushSub, PushSubSize and Tag.
BOOST_CHECK ( contract [ " evm " ] [ " legacyAssembly " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " legacyAssembly " ] [ " .code " ] . isArray ( ) ) ;
BOOST_CHECK_EQUAL (
2019-12-23 15:50:30 +00:00
util : : jsonCompactPrint ( contract [ " evm " ] [ " legacyAssembly " ] [ " .code " ] ) ,
2020-02-18 09:22:34 +00:00
" [{ \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" source \" :0, \" value \" : \" 80 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" source \" :0, \" value \" : \" 40 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" MSTORE \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" CALLVALUE \" , \" source \" :0}, "
2020-05-26 15:24:52 +00:00
" { \" begin \" :0, \" end \" :14, \" name \" : \" DUP1 \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" ISZERO \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH [tag] \" , \" source \" :0, \" value \" : \" 1 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" JUMPI \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" source \" :0, \" value \" : \" 0 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" DUP1 \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" REVERT \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" tag \" , \" source \" :0, \" value \" : \" 1 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" JUMPDEST \" , \" source \" :0}, "
2020-02-18 09:22:34 +00:00
" { \" begin \" :0, \" end \" :14, \" name \" : \" POP \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH #[$] \" , \" source \" :0, \" value \" : \" 0000000000000000000000000000000000000000000000000000000000000000 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" DUP1 \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH [$] \" , \" source \" :0, \" value \" : \" 0000000000000000000000000000000000000000000000000000000000000000 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" source \" :0, \" value \" : \" 0 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" CODECOPY \" , \" source \" :0}, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" source \" :0, \" value \" : \" 0 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" RETURN \" , \" source \" :0}] "
2018-08-08 19:43:44 +00:00
) ;
2017-04-19 17:39:37 +00:00
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( solidity : : test : : isValidMetadata ( contract [ " metadata " ] . asString ( ) ) ) ;
2017-04-20 09:29:53 +00:00
BOOST_CHECK ( result [ " sources " ] . isObject ( ) ) ;
BOOST_CHECK ( result [ " sources " ] [ " fileA " ] . isObject ( ) ) ;
BOOST_CHECK ( result [ " sources " ] [ " fileA " ] [ " legacyAST " ] . isObject ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL (
2019-12-23 15:50:30 +00:00
util : : jsonCompactPrint ( result [ " sources " ] [ " fileA " ] [ " legacyAST " ] ) ,
2020-08-18 14:23:55 +00:00
" { \" attributes \" :{ \" absolutePath \" : \" fileA \" , \" exportedSymbols \" :{ \" A \" :[1]}}, \" children \" : "
2019-09-19 19:31:42 +00:00
" [{ \" attributes \" :{ \" abstract \" :false, \" baseContracts \" :[null], \" contractDependencies \" :[null], \" contractKind \" : \" contract \" , "
2020-08-18 14:23:55 +00:00
" \" fullyImplemented \" :true, \" linearizedBaseContracts \" :[1], \" name \" : \" A \" , \" nodes \" :[null], \" scope \" :2}, "
2017-06-14 17:36:05 +00:00
" \" id \" :1, \" name \" : \" ContractDefinition \" , \" src \" : \" 0:14:0 \" }], \" id \" :2, \" name \" : \" SourceUnit \" , \" src \" : \" 0:14:0 \" } "
) ;
2017-04-19 17:39:37 +00:00
}
2017-12-18 11:40:06 +00:00
BOOST_AUTO_TEST_CASE ( compilation_error )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : {
" A " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { function } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( result . isMember ( " errors " ) ) ;
BOOST_CHECK ( result [ " errors " ] . size ( ) > = 1 ) ;
for ( auto const & error : result [ " errors " ] )
{
BOOST_REQUIRE ( error . isObject ( ) ) ;
BOOST_REQUIRE ( error [ " message " ] . isString ( ) ) ;
if ( error [ " message " ] . asString ( ) . find ( " pre-release compiler " ) = = string : : npos )
{
BOOST_CHECK_EQUAL (
2019-12-23 15:50:30 +00:00
util : : jsonCompactPrint ( error ) ,
2020-05-29 23:42:36 +00:00
" { \" component \" : \" general \" , \" errorCode \" : \" 2314 \" , \" formattedMessage \" : \" fileA:1:23: ParserError: Expected identifier but got '}' \\ n "
2018-05-02 18:49:36 +00:00
" contract A { function } \\ n ^ \\ n \" , \" message \" : \" Expected identifier but got '}' \" , "
2018-05-09 11:15:27 +00:00
" \" severity \" : \" error \" , \" sourceLocation \" :{ \" end \" :23, \" file \" : \" fileA \" , \" start \" :22}, \" type \" : \" ParserError \" } "
2017-12-18 11:40:06 +00:00
) ;
}
}
}
2017-09-29 18:05:39 +00:00
BOOST_AUTO_TEST_CASE ( output_selection_explicit )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : {
" A " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2017-09-29 18:05:39 +00:00
}
BOOST_AUTO_TEST_CASE ( output_selection_all_contracts )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : {
" * " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2017-09-29 18:05:39 +00:00
}
BOOST_AUTO_TEST_CASE ( output_selection_all_files_single_contract )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" * " : {
" A " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2017-09-29 18:05:39 +00:00
}
BOOST_AUTO_TEST_CASE ( output_selection_all_files_all_contracts )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" * " : {
" * " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2017-09-29 18:05:39 +00:00
}
2017-10-05 08:53:43 +00:00
BOOST_AUTO_TEST_CASE ( output_selection_dependent_contract )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" * " : {
" A " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
2018-07-11 13:57:07 +00:00
" content " : " contract B { } contract A { function f() public { new B(); } } "
2017-10-05 08:53:43 +00:00
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [{ \" inputs \" :[], \" name \" : \" f \" , \" outputs \" :[], \" stateMutability \" : \" nonpayable \" , \" type \" : \" function \" }] " ) ;
2017-10-05 08:53:43 +00:00
}
BOOST_AUTO_TEST_CASE ( output_selection_dependent_contract_with_import )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" * " : {
" A " : [
" abi "
]
}
}
} ,
" sources " : {
" fileA " : {
2018-07-11 13:57:07 +00:00
" content " : " import \" fileB \" ; contract A { function f() public { new B(); } } "
2017-10-05 08:53:43 +00:00
} ,
" fileB " : {
" content " : " contract B { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [{ \" inputs \" :[], \" name \" : \" f \" , \" outputs \" :[], \" stateMutability \" : \" nonpayable \" , \" type \" : \" function \" }] " ) ;
2017-10-05 08:53:43 +00:00
}
2018-01-03 11:34:48 +00:00
BOOST_AUTO_TEST_CASE ( filename_with_colon )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" http://github.com/ethereum/solidity/std/StandardToken.sol " : {
" A " : [
" abi "
]
}
}
} ,
" sources " : {
" http://github.com/ethereum/solidity/std/StandardToken.sol " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " http://github.com/ethereum/solidity/std/StandardToken.sol " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " abi " ] . isArray ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK_EQUAL ( util : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2018-01-03 11:34:48 +00:00
}
2018-01-05 13:24:07 +00:00
BOOST_AUTO_TEST_CASE ( library_filename_with_colon )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : {
" A " : [
" evm.bytecode "
]
}
}
} ,
" sources " : {
" fileA " : {
2018-06-29 14:52:41 +00:00
" content " : " import \" git:library.sol \" ; contract A { function f() public returns (uint) { return L.g(); } } "
2018-01-05 13:24:07 +00:00
} ,
" git:library.sol " : {
2018-06-29 14:52:41 +00:00
" content " : " library L { function g() public returns (uint) { return 1; } } "
2018-01-05 13:24:07 +00:00
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " git:library.sol " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " git:library.sol " ] [ " L " ] . isArray ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " git:library.sol " ] [ " L " ] [ 0 ] . isObject ( ) ) ;
}
2018-02-28 09:36:07 +00:00
BOOST_AUTO_TEST_CASE ( libraries_invalid_top_level )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" libraries " : " 42 "
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " \" libraries \" is not a JSON object. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( libraries_invalid_entry )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" libraries " : {
" L " : " 42 "
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
2018-09-21 13:51:45 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " Library entry is not a JSON object. " ) ) ;
2018-02-28 09:36:07 +00:00
}
2018-02-28 09:44:48 +00:00
BOOST_AUTO_TEST_CASE ( libraries_invalid_hex )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" libraries " : {
" library.sol " : {
" L " : " 0x4200000000000000000000000000000000000xx1 "
}
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Invalid library address ( \" 0x4200000000000000000000000000000000000xx1 \" ) supplied. " ) ) ;
}
2018-02-28 15:57:35 +00:00
BOOST_AUTO_TEST_CASE ( libraries_invalid_length )
2018-02-28 09:36:07 +00:00
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" libraries " : {
" library.sol " : {
2018-02-28 15:57:35 +00:00
" L1 " : " 0x42 " ,
" L2 " : " 0x4200000000000000000000000000000000000001ff "
2018-02-28 09:36:07 +00:00
}
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
2018-02-28 15:57:35 +00:00
BOOST_CHECK ( containsError ( result , " JSONError " , " Library address is of invalid length. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( libraries_missing_hex_prefix )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" libraries " : {
" library.sol " : {
" L " : " 4200000000000000000000000000000000000001 "
}
}
} ,
" sources " : {
" empty " : {
" content " : " "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Library address is not prefixed with \" 0x \" . " ) ) ;
2018-02-28 09:36:07 +00:00
}
BOOST_AUTO_TEST_CASE ( library_linking )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" libraries " : {
" library.sol " : {
" L " : " 0x4200000000000000000000000000000000000001 "
}
} ,
" outputSelection " : {
" fileA " : {
" A " : [
" evm.bytecode "
]
}
}
} ,
" sources " : {
" fileA " : {
2018-06-29 14:52:41 +00:00
" content " : " import \" library.sol \" ; import \" library2.sol \" ; contract A { function f() public returns (uint) { L2.g(); return L.g(); } } "
2018-02-28 09:36:07 +00:00
} ,
" library.sol " : {
2018-06-29 14:52:41 +00:00
" content " : " library L { function g() public returns (uint) { return 1; } } "
2018-02-28 09:36:07 +00:00
} ,
" library2.sol " : {
2018-07-11 13:57:07 +00:00
" content " : " library L2 { function g() public { } } "
2018-02-28 09:36:07 +00:00
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] . isObject ( ) ) ;
BOOST_CHECK ( ! contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " library.sol " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " library2.sol " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " library2.sol " ] [ " L2 " ] . isArray ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " linkReferences " ] [ " library2.sol " ] [ " L2 " ] [ 0 ] . isObject ( ) ) ;
}
2018-01-03 11:34:48 +00:00
2018-02-22 13:47:36 +00:00
BOOST_AUTO_TEST_CASE ( evm_version )
{
auto inputForVersion = [ ] ( string const & _version )
{
return R " (
{
" language " : " Solidity " ,
" sources " : { " fileA " : { " content " : " contract A { } " } } ,
" settings " : {
) " + _version + R " (
" outputSelection " : {
" fileA " : {
" A " : [ " metadata " ]
}
}
}
}
) " ;
} ;
Json : : Value result ;
result = compile ( inputForVersion ( " \" evmVersion \" : \" homestead \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" homestead \" " ) ! = string : : npos ) ;
2018-02-26 18:53:38 +00:00
result = compile ( inputForVersion ( " \" evmVersion \" : \" tangerineWhistle \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" tangerineWhistle \" " ) ! = string : : npos ) ;
result = compile ( inputForVersion ( " \" evmVersion \" : \" spuriousDragon \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" spuriousDragon \" " ) ! = string : : npos ) ;
2018-02-22 13:47:36 +00:00
result = compile ( inputForVersion ( " \" evmVersion \" : \" byzantium \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" byzantium \" " ) ! = string : : npos ) ;
2018-03-12 17:11:08 +00:00
result = compile ( inputForVersion ( " \" evmVersion \" : \" constantinople \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" constantinople \" " ) ! = string : : npos ) ;
2019-02-25 14:51:26 +00:00
result = compile ( inputForVersion ( " \" evmVersion \" : \" petersburg \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" petersburg \" " ) ! = string : : npos ) ;
2019-12-04 09:42:14 +00:00
result = compile ( inputForVersion ( " \" evmVersion \" : \" istanbul \" , " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" istanbul \" " ) ! = string : : npos ) ;
2018-02-22 13:47:36 +00:00
// test default
result = compile ( inputForVersion ( " " ) ) ;
2019-12-04 09:42:14 +00:00
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" istanbul \" " ) ! = string : : npos ) ;
2018-02-22 13:47:36 +00:00
// test invalid
result = compile ( inputForVersion ( " \" evmVersion \" : \" invalid \" , " ) ) ;
BOOST_CHECK ( result [ " errors " ] [ 0 ] [ " message " ] . asString ( ) = = " Invalid EVM version requested. " ) ;
}
2019-02-21 16:39:47 +00:00
BOOST_AUTO_TEST_CASE ( optimizer_settings_default_disabled )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : { " A " : [ " metadata " ] }
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
Json : : Value metadata ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( util : : jsonParseStrict ( contract [ " metadata " ] . asString ( ) , metadata ) ) ;
2019-02-21 16:39:47 +00:00
Json : : Value const & optimizer = metadata [ " settings " ] [ " optimizer " ] ;
BOOST_CHECK ( optimizer . isMember ( " enabled " ) ) ;
BOOST_CHECK ( optimizer [ " enabled " ] . asBool ( ) = = false ) ;
BOOST_CHECK ( ! optimizer . isMember ( " details " ) ) ;
BOOST_CHECK ( optimizer [ " runs " ] . asUInt ( ) = = 200 ) ;
}
BOOST_AUTO_TEST_CASE ( optimizer_settings_default_enabled )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : { " A " : [ " metadata " ] }
} ,
" optimizer " : { " enabled " : true }
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
Json : : Value metadata ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( util : : jsonParseStrict ( contract [ " metadata " ] . asString ( ) , metadata ) ) ;
2019-02-21 16:39:47 +00:00
Json : : Value const & optimizer = metadata [ " settings " ] [ " optimizer " ] ;
BOOST_CHECK ( optimizer . isMember ( " enabled " ) ) ;
BOOST_CHECK ( optimizer [ " enabled " ] . asBool ( ) = = true ) ;
BOOST_CHECK ( ! optimizer . isMember ( " details " ) ) ;
BOOST_CHECK ( optimizer [ " runs " ] . asUInt ( ) = = 200 ) ;
}
BOOST_AUTO_TEST_CASE ( optimizer_settings_details_exactly_as_default_disabled )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : { " A " : [ " metadata " ] }
} ,
" optimizer " : { " details " : {
" constantOptimizer " : false ,
" cse " : false ,
" deduplicate " : false ,
" jumpdestRemover " : true ,
" orderLiterals " : false ,
" peephole " : true
} }
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
Json : : Value metadata ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( util : : jsonParseStrict ( contract [ " metadata " ] . asString ( ) , metadata ) ) ;
2019-02-21 16:39:47 +00:00
Json : : Value const & optimizer = metadata [ " settings " ] [ " optimizer " ] ;
BOOST_CHECK ( optimizer . isMember ( " enabled " ) ) ;
// enabled is switched to false instead!
BOOST_CHECK ( optimizer [ " enabled " ] . asBool ( ) = = false ) ;
BOOST_CHECK ( ! optimizer . isMember ( " details " ) ) ;
BOOST_CHECK ( optimizer [ " runs " ] . asUInt ( ) = = 200 ) ;
}
BOOST_AUTO_TEST_CASE ( optimizer_settings_details_different )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : { " A " : [ " metadata " ] }
} ,
" optimizer " : { " runs " : 600 , " details " : {
" constantOptimizer " : true ,
" cse " : false ,
" deduplicate " : true ,
" jumpdestRemover " : true ,
" orderLiterals " : false ,
" peephole " : true ,
" yul " : true
} }
} ,
" sources " : {
" fileA " : {
" content " : " contract A { } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
Json : : Value metadata ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( util : : jsonParseStrict ( contract [ " metadata " ] . asString ( ) , metadata ) ) ;
2019-02-21 16:39:47 +00:00
Json : : Value const & optimizer = metadata [ " settings " ] [ " optimizer " ] ;
BOOST_CHECK ( ! optimizer . isMember ( " enabled " ) ) ;
BOOST_CHECK ( optimizer . isMember ( " details " ) ) ;
BOOST_CHECK ( optimizer [ " details " ] [ " constantOptimizer " ] . asBool ( ) = = true ) ;
BOOST_CHECK ( optimizer [ " details " ] [ " cse " ] . asBool ( ) = = false ) ;
BOOST_CHECK ( optimizer [ " details " ] [ " deduplicate " ] . asBool ( ) = = true ) ;
BOOST_CHECK ( optimizer [ " details " ] [ " jumpdestRemover " ] . asBool ( ) = = true ) ;
BOOST_CHECK ( optimizer [ " details " ] [ " orderLiterals " ] . asBool ( ) = = false ) ;
BOOST_CHECK ( optimizer [ " details " ] [ " peephole " ] . asBool ( ) = = true ) ;
2019-02-26 18:55:13 +00:00
BOOST_CHECK ( optimizer [ " details " ] [ " yul " ] . asBool ( ) = = true ) ;
2019-02-21 16:39:47 +00:00
BOOST_CHECK ( optimizer [ " details " ] [ " yulDetails " ] . isObject ( ) ) ;
2020-04-24 12:26:31 +00:00
BOOST_CHECK (
util : : convertContainer < set < string > > ( optimizer [ " details " ] [ " yulDetails " ] . getMemberNames ( ) ) = =
( set < string > { " stackAllocation " , " optimizerSteps " } )
) ;
2019-02-26 18:55:13 +00:00
BOOST_CHECK ( optimizer [ " details " ] [ " yulDetails " ] [ " stackAllocation " ] . asBool ( ) = = true ) ;
2020-04-24 12:26:31 +00:00
BOOST_CHECK ( optimizer [ " details " ] [ " yulDetails " ] [ " optimizerSteps " ] . asString ( ) = = OptimiserSettings : : DefaultYulOptimiserSteps ) ;
2019-02-21 16:39:47 +00:00
BOOST_CHECK_EQUAL ( optimizer [ " details " ] . getMemberNames ( ) . size ( ) , 8 ) ;
BOOST_CHECK ( optimizer [ " runs " ] . asUInt ( ) = = 600 ) ;
}
2018-02-22 13:47:36 +00:00
2019-02-28 13:08:21 +00:00
BOOST_AUTO_TEST_CASE ( metadata_without_compilation )
{
// NOTE: the contract code here should fail to compile due to "out of stack"
// If the metadata is successfully returned, that means no compilation was attempted.
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" fileA " : { " A " : [ " metadata " ] }
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A {
function x ( uint a , uint b , uint c , uint d , uint e , uint f , uint g , uint h , uint i , uint j , uint k , uint l , uint m , uint n , uint o , uint p ) pure public { }
function y ( ) pure public {
uint a ; uint b ; uint c ; uint d ; uint e ; uint f ; uint g ; uint h ; uint i ; uint j ; uint k ; uint l ; uint m ; uint n ; uint o ; uint p ;
x ( a , b , c , d , e , f , g , h , i , j , k , l , m , n , o , p ) ;
}
} "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( solidity : : test : : isValidMetadata ( contract [ " metadata " ] . asString ( ) ) ) ;
2019-02-28 13:08:21 +00:00
}
2020-05-13 01:52:33 +00:00
BOOST_AUTO_TEST_CASE ( license_in_metadata )
{
string const input = R " (
{
" language " : " Solidity " ,
" sources " : {
" fileA " : { " content " : " import \" fileB \" ; contract A { } // SPDX-License-Identifier: GPL-3.0 \n " } ,
" fileB " : { " content " : " import \" fileC \" ; /* SPDX-License-Identifier: MIT */ contract B { } " } ,
" fileC " : { " content " : " import \" fileD \" ; /* SPDX-License-Identifier: MIT AND GPL-3.0 */ contract C { } " } ,
" fileD " : { " content " : " // SPDX-License-Identifier: (GPL-3.0+ OR MIT) AND MIT \n import \" fileE \" ; contract D { } " } ,
" fileE " : { " content " : " import \" fileF \" ; /// SPDX-License-Identifier: MIT \n contract E { } " } ,
" fileF " : { " content " : " /* \n * SPDX-License-Identifier: MIT \n */ contract F { } " }
} ,
" settings " : {
" outputSelection " : {
" fileA " : {
" * " : [ " metadata " ]
}
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
Json : : Value metadata ;
BOOST_REQUIRE ( util : : jsonParseStrict ( contract [ " metadata " ] . asString ( ) , metadata ) ) ;
BOOST_CHECK_EQUAL ( metadata [ " sources " ] [ " fileA " ] [ " license " ] , " GPL-3.0 " ) ;
BOOST_CHECK_EQUAL ( metadata [ " sources " ] [ " fileB " ] [ " license " ] , " MIT " ) ;
BOOST_CHECK_EQUAL ( metadata [ " sources " ] [ " fileC " ] [ " license " ] , " MIT AND GPL-3.0 " ) ;
BOOST_CHECK_EQUAL ( metadata [ " sources " ] [ " fileD " ] [ " license " ] , " (GPL-3.0+ OR MIT) AND MIT " ) ;
// This is actually part of the docstring, but still picked up
// because the source location of the contract does not cover the docstring.
BOOST_CHECK_EQUAL ( metadata [ " sources " ] [ " fileE " ] [ " license " ] , " MIT " ) ;
BOOST_CHECK_EQUAL ( metadata [ " sources " ] [ " fileF " ] [ " license " ] , " MIT " ) ;
}
2019-02-28 13:08:21 +00:00
BOOST_AUTO_TEST_CASE ( common_pattern )
{
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" outputSelection " : {
" * " : {
" * " : [ " evm.bytecode.object " , " metadata " ]
}
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A { function f() pure public {} } "
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_CHECK ( contract . isObject ( ) ) ;
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( solidity : : test : : isValidMetadata ( contract [ " metadata " ] . asString ( ) ) ) ;
2019-02-28 13:08:21 +00:00
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " object " ] . isString ( ) ) ;
}
2019-03-11 16:54:01 +00:00
BOOST_AUTO_TEST_CASE ( use_stack_optimization )
{
// NOTE: the contract code here should fail to compile due to "out of stack"
// If we enable stack optimization, though, it will compile.
char const * input = R " (
{
" language " : " Solidity " ,
" settings " : {
" optimizer " : { " enabled " : true , " details " : { " yul " : true } } ,
" outputSelection " : {
" fileA " : { " A " : [ " evm.bytecode.object " ] }
}
} ,
" sources " : {
" fileA " : {
" content " : " contract A {
function y ( ) public {
assembly {
function fun ( ) - > a3 , b3 , c3 , d3 , e3 , f3 , g3 , h3 , i3 , j3 , k3 , l3 , m3 , n3 , o3 , p3
{
let a : = 1
let b : = 1
let z3 : = 1
sstore ( a , b )
sstore ( add ( a , 1 ) , b )
sstore ( add ( a , 2 ) , b )
sstore ( add ( a , 3 ) , b )
sstore ( add ( a , 4 ) , b )
sstore ( add ( a , 5 ) , b )
sstore ( add ( a , 6 ) , b )
sstore ( add ( a , 7 ) , b )
sstore ( add ( a , 8 ) , b )
sstore ( add ( a , 9 ) , b )
sstore ( add ( a , 10 ) , b )
sstore ( add ( a , 11 ) , b )
sstore ( add ( a , 12 ) , b )
}
let a1 , b1 , c1 , d1 , e1 , f1 , g1 , h1 , i1 , j1 , k1 , l1 , m1 , n1 , o1 , p1 : = fun ( )
let a2 , b2 , c2 , d2 , e2 , f2 , g2 , h2 , i2 , j2 , k2 , l2 , m2 , n2 , o2 , p2 : = fun ( )
sstore ( a1 , a2 )
}
}
} "
}
}
}
) " ;
Json : : Value parsedInput ;
2019-12-23 15:50:30 +00:00
BOOST_REQUIRE ( util : : jsonParseStrict ( input , parsedInput ) ) ;
2019-03-11 16:54:01 +00:00
2019-12-23 15:50:30 +00:00
solidity : : frontend : : StandardCompiler compiler ;
2019-03-11 16:54:01 +00:00
Json : : Value result = compiler . compile ( parsedInput ) ;
BOOST_CHECK ( containsAtMostWarnings ( result ) ) ;
Json : : Value contract = getContractResult ( result , " fileA " , " A " ) ;
BOOST_REQUIRE ( contract . isObject ( ) ) ;
BOOST_REQUIRE ( contract [ " evm " ] [ " bytecode " ] [ " object " ] . isString ( ) ) ;
BOOST_CHECK ( contract [ " evm " ] [ " bytecode " ] [ " object " ] . asString ( ) . length ( ) > 20 ) ;
2020-08-20 14:56:25 +00:00
// Now disable stack optimizations and UnusedFunctionParameterPruner (p)
2019-03-11 16:54:01 +00:00
// results in "stack too deep"
2020-08-20 14:56:25 +00:00
string optimiserSteps = OptimiserSettings : : DefaultYulOptimiserSteps ;
optimiserSteps . erase (
remove_if ( optimiserSteps . begin ( ) , optimiserSteps . end ( ) , [ ] ( char ch ) { return ch = = ' p ' ; } ) ,
optimiserSteps . end ( )
) ;
2019-03-11 16:54:01 +00:00
parsedInput [ " settings " ] [ " optimizer " ] [ " details " ] [ " yulDetails " ] [ " stackAllocation " ] = false ;
2020-08-20 14:56:25 +00:00
parsedInput [ " settings " ] [ " optimizer " ] [ " details " ] [ " yulDetails " ] [ " optimizerSteps " ] = optimiserSteps ;
2019-03-11 16:54:01 +00:00
result = compiler . compile ( parsedInput ) ;
BOOST_REQUIRE ( result [ " errors " ] . isArray ( ) ) ;
BOOST_CHECK ( result [ " errors " ] [ 0 ] [ " severity " ] = = " error " ) ;
2019-12-03 18:06:04 +00:00
BOOST_REQUIRE ( result [ " errors " ] [ 0 ] [ " message " ] . isString ( ) ) ;
BOOST_CHECK ( result [ " errors " ] [ 0 ] [ " message " ] . asString ( ) . find ( " Stack too deep when compiling inline assembly " ) ! = std : : string : : npos ) ;
2020-07-01 07:46:06 +00:00
BOOST_CHECK ( result [ " errors " ] [ 0 ] [ " type " ] = = " CompilerError " ) ;
2019-03-11 16:54:01 +00:00
}
2019-05-14 16:19:08 +00:00
BOOST_AUTO_TEST_CASE ( standard_output_selection_wildcard )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{
" A " :
{
" content " : " pragma solidity >=0.0; contract C { function f() public pure {} } "
}
} ,
" settings " :
{
" outputSelection " :
{
" * " : { " C " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value parsedInput ;
2019-12-23 15:50:30 +00:00
BOOST_REQUIRE ( util : : jsonParseStrict ( input , parsedInput ) ) ;
2019-05-14 16:19:08 +00:00
2019-12-23 15:50:30 +00:00
solidity : : frontend : : StandardCompiler compiler ;
2019-05-14 16:19:08 +00:00
Json : : Value result = compiler . compile ( parsedInput ) ;
BOOST_REQUIRE ( result [ " contracts " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " A " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " A " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " A " ] [ " C " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " A " ] [ " C " ] [ " evm " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " A " ] [ " C " ] [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " sources " ] [ " A " ] . isObject ( ) ) ;
}
BOOST_AUTO_TEST_CASE ( standard_output_selection_wildcard_colon_source )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{
" :A " :
{
" content " : " pragma solidity >=0.0; contract C { function f() public pure {} } "
}
} ,
" settings " :
{
" outputSelection " :
{
" * " : { " C " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value parsedInput ;
2019-12-23 15:50:30 +00:00
BOOST_REQUIRE ( util : : jsonParseStrict ( input , parsedInput ) ) ;
2019-05-14 16:19:08 +00:00
2019-12-23 15:50:30 +00:00
solidity : : frontend : : StandardCompiler compiler ;
2019-05-14 16:19:08 +00:00
Json : : Value result = compiler . compile ( parsedInput ) ;
BOOST_REQUIRE ( result [ " contracts " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " :A " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " :A " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " :A " ] [ " C " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " :A " ] [ " C " ] [ " evm " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " :A " ] [ " C " ] [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " sources " ] [ " :A " ] . isObject ( ) ) ;
}
BOOST_AUTO_TEST_CASE ( standard_output_selection_wildcard_empty_source )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{
" " :
{
" content " : " pragma solidity >=0.0; contract C { function f() public pure {} } "
}
} ,
" settings " :
{
" outputSelection " :
{
" * " : { " C " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value parsedInput ;
2019-12-23 15:50:30 +00:00
BOOST_REQUIRE ( util : : jsonParseStrict ( input , parsedInput ) ) ;
2019-05-14 16:19:08 +00:00
2019-12-23 15:50:30 +00:00
solidity : : frontend : : StandardCompiler compiler ;
2019-05-14 16:19:08 +00:00
Json : : Value result = compiler . compile ( parsedInput ) ;
BOOST_REQUIRE ( result [ " contracts " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " " ] [ " C " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " " ] [ " C " ] [ " evm " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " " ] [ " C " ] [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " sources " ] [ " " ] . isObject ( ) ) ;
}
BOOST_AUTO_TEST_CASE ( standard_output_selection_wildcard_multiple_sources )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{
" A " :
{
" content " : " pragma solidity >=0.0; contract C { function f() public pure {} } "
} ,
" B " :
{
" content " : " pragma solidity >=0.0; contract D { function f() public pure {} } "
}
} ,
" settings " :
{
" outputSelection " :
{
" * " : { " D " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value parsedInput ;
2019-12-23 15:50:30 +00:00
BOOST_REQUIRE ( util : : jsonParseStrict ( input , parsedInput ) ) ;
2019-05-14 16:19:08 +00:00
2019-12-23 15:50:30 +00:00
solidity : : frontend : : StandardCompiler compiler ;
2019-05-14 16:19:08 +00:00
Json : : Value result = compiler . compile ( parsedInput ) ;
BOOST_REQUIRE ( result [ " contracts " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " B " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " B " ] . size ( ) = = 1 ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " B " ] [ " D " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " B " ] [ " D " ] [ " evm " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " contracts " ] [ " B " ] [ " D " ] [ " evm " ] [ " bytecode " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] . size ( ) = = 2 ) ;
BOOST_REQUIRE ( result [ " sources " ] [ " A " ] . isObject ( ) ) ;
BOOST_REQUIRE ( result [ " sources " ] [ " B " ] . isObject ( ) ) ;
}
2020-07-08 20:08:50 +00:00
BOOST_AUTO_TEST_CASE ( stopAfter_invalid_value )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{ " " : { " content " : " pragma solidity >=0.0; contract C { function f() public pure {} } " } } ,
" settings " :
{
" stopAfter " : " rrr " ,
" outputSelection " :
{
" * " : { " C " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Invalid value for \" settings.stopAfter \" . Only valid value is \" parsing \" . " ) ) ;
}
BOOST_AUTO_TEST_CASE ( stopAfter_invalid_type )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{ " " : { " content " : " pragma solidity >=0.0; contract C { function f() public pure {} } " } } ,
" settings " :
{
" stopAfter " : 3 ,
" outputSelection " :
{
" * " : { " C " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " \" settings.stopAfter \" must be a string. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( stopAfter_bin_conflict )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " :
{ " " : { " content " : " pragma solidity >=0.0; contract C { function f() public pure {} } " } } ,
" settings " :
{
" stopAfter " : " parsing " ,
" outputSelection " :
{
" * " : { " C " : [ " evm.bytecode " ] }
}
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Requested output selection conflicts with \" settings.stopAfter \" . " ) ) ;
}
BOOST_AUTO_TEST_CASE ( stopAfter_ast_output )
{
char const * input = R " (
{
" language " : " Solidity " ,
" sources " : {
" a.sol " : {
" content " : " // SPDX-License-Identifier: GPL-3.0 \n import \" tes32.sol \" ; \n contract C is X { constructor() {} } "
}
} ,
" settings " : {
" stopAfter " : " parsing " ,
" outputSelection " : { " * " : { " " : [ " ast " ] } }
}
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( result [ " sources " ] . isObject ( ) ) ;
BOOST_CHECK ( result [ " sources " ] [ " a.sol " ] . isObject ( ) ) ;
BOOST_CHECK ( result [ " sources " ] [ " a.sol " ] [ " ast " ] . isObject ( ) ) ;
}
2017-04-19 14:54:14 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
} // end namespaces