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/>.
*/
/**
* @ date 2017
* Unit tests for interface / StandardCompiler . h .
*/
# include <string>
# include <boost/test/unit_test.hpp>
# include <libsolidity/interface/StandardCompiler.h>
2017-04-19 17:39:37 +00:00
# include <libdevcore/JSON.h>
2019-02-05 22:04:35 +00:00
# include <test/Metadata.h>
2017-04-19 14:54:14 +00:00
using namespace std ;
using namespace dev : : eth ;
namespace dev
{
namespace solidity
{
namespace test
{
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 ] ;
}
2017-04-19 14:54:14 +00:00
Json : : Value compile ( string const & _input )
{
StandardCompiler compiler ;
string output = compiler . compile ( _input ) ;
Json : : Value ret ;
2018-02-07 01:05:20 +00:00
BOOST_REQUIRE ( 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
solidity : : StandardCompiler compiler ;
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 " (
{
" language " : " INVALID "
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " Only \" Solidity \" is supported as a language. " ) ) ;
}
BOOST_AUTO_TEST_CASE ( valid_language )
{
char const * input = R " (
{
" language " : " Solidity "
}
) " ;
Json : : Value result = compile ( input ) ;
BOOST_CHECK ( ! containsError ( result , " JSONError " , " Only \" Solidity \" is supported as a language. " ) ) ;
}
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 ) ) ;
}
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 ) ;
BOOST_CHECK ( containsError ( result , " JSONError " , " The \" enabled \" setting must be a boolean. " ) ) ;
}
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 ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
2017-05-02 14:20:27 +00:00
BOOST_CHECK ( contract [ " devdoc " ] . isObject ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " devdoc " ] ) , " { \" methods \" :{}} " ) ;
2017-05-02 14:20:27 +00:00
BOOST_CHECK ( contract [ " userdoc " ] . isObject ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " userdoc " ] ) , " { \" methods \" :{}} " ) ;
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 (
dev : : test : : bytecodeSansMetadata ( contract [ " evm " ] [ " bytecode " ] [ " object " ] . asString ( ) ) ,
2018-08-14 09:41:40 +00:00
" 6080604052348015600f57600080fd5b50603580601d6000396000f3fe6080604052600080fdfe "
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 "
" callvalue \n /* \" --CODEGEN-- \" :8:17 */ \n dup1 \n "
" /* \" --CODEGEN-- \" :5:7 */ \n iszero \n tag_1 \n jumpi \n "
2018-12-05 21:11:31 +00:00
" /* \" --CODEGEN-- \" :30:31 */ \n 0x00 \n /* \" --CODEGEN-- \" :27:28 */ \n "
2018-01-04 16:08:47 +00:00
" dup1 \n /* \" --CODEGEN-- \" :20:32 */ \n revert \n /* \" --CODEGEN-- \" :5:7 */ \n "
" tag_1: \n /* \" fileA \" :0:14 contract A { } */ \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 "
" /* \" fileA \" :0:14 contract A { } */ \n mstore(0x40, 0x80) \n 0x00 \n "
2018-01-04 16:08:47 +00:00
" dup1 \n revert \n \n auxdata: 0xa165627a7a72305820 "
) = = 0 ) ;
2017-04-19 17:39:37 +00:00
BOOST_CHECK ( contract [ " evm " ] [ " gasEstimates " ] . isObject ( ) ) ;
2017-06-14 17:36:05 +00:00
BOOST_CHECK_EQUAL (
dev : : jsonCompactPrint ( contract [ " evm " ] [ " gasEstimates " ] ) ,
2018-01-04 16:08:47 +00:00
" { \" creation \" :{ \" codeDepositCost \" : \" 10600 \" , \" executionCost \" : \" 66 \" , \" totalCost \" : \" 10666 \" }} "
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 (
dev : : jsonCompactPrint ( contract [ " evm " ] [ " legacyAssembly " ] [ " .code " ] ) ,
" [{ \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" value \" : \" 80 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" value \" : \" 40 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" MSTORE \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" CALLVALUE \" }, "
" { \" begin \" :8, \" end \" :17, \" name \" : \" DUP1 \" }, "
" { \" begin \" :5, \" end \" :7, \" name \" : \" ISZERO \" }, "
" { \" begin \" :5, \" end \" :7, \" name \" : \" PUSH [tag] \" , \" value \" : \" 1 \" }, "
" { \" begin \" :5, \" end \" :7, \" name \" : \" JUMPI \" }, "
" { \" begin \" :30, \" end \" :31, \" name \" : \" PUSH \" , \" value \" : \" 0 \" }, "
" { \" begin \" :27, \" end \" :28, \" name \" : \" DUP1 \" }, "
" { \" begin \" :20, \" end \" :32, \" name \" : \" REVERT \" }, "
" { \" begin \" :5, \" end \" :7, \" name \" : \" tag \" , \" value \" : \" 1 \" }, "
" { \" begin \" :5, \" end \" :7, \" name \" : \" JUMPDEST \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" POP \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH #[$] \" , \" value \" : \" 0000000000000000000000000000000000000000000000000000000000000000 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" DUP1 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH [$] \" , \" value \" : \" 0000000000000000000000000000000000000000000000000000000000000000 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" value \" : \" 0 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" CODECOPY \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" PUSH \" , \" value \" : \" 0 \" }, "
" { \" begin \" :0, \" end \" :14, \" name \" : \" RETURN \" }] "
) ;
2017-04-19 17:39:37 +00:00
BOOST_CHECK ( contract [ " metadata " ] . isString ( ) ) ;
2017-05-02 22:34:12 +00:00
BOOST_CHECK ( dev : : 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 (
dev : : jsonCompactPrint ( result [ " sources " ] [ " fileA " ] [ " legacyAST " ] ) ,
2017-03-20 18:06:17 +00:00
" { \" attributes \" :{ \" absolutePath \" : \" fileA \" , \" exportedSymbols \" :{ \" A \" :[1]}}, \" children \" : "
2017-05-17 16:22:39 +00:00
" [{ \" attributes \" :{ \" baseContracts \" :[null], \" contractDependencies \" :[null], \" contractKind \" : \" contract \" , "
2017-05-30 17:25:54 +00:00
" \" documentation \" :null, \" 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 (
dev : : jsonCompactPrint ( error ) ,
2018-05-02 18:49:36 +00:00
" { \" component \" : \" general \" , \" formattedMessage \" : \" fileA:1:23: ParserError: Expected identifier but got '}' \\ n "
" 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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
}
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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
}
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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
}
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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
}
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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [{ \" constant \" :false, \" inputs \" :[], \" name \" : \" f \" , \" outputs \" :[], \" payable \" :false, \" stateMutability \" : \" nonpayable \" , \" type \" : \" function \" }] " ) ;
}
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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [{ \" constant \" :false, \" inputs \" :[], \" name \" : \" f \" , \" outputs \" :[], \" payable \" :false, \" stateMutability \" : \" nonpayable \" , \" type \" : \" function \" }] " ) ;
}
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 ( ) ) ;
BOOST_CHECK_EQUAL ( dev : : jsonCompactPrint ( contract [ " abi " ] ) , " [] " ) ;
}
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 ) ;
2018-02-22 13:47:36 +00:00
// test default
result = compile ( inputForVersion ( " " ) ) ;
BOOST_CHECK ( result [ " contracts " ] [ " fileA " ] [ " A " ] [ " metadata " ] . asString ( ) . find ( " \" evmVersion \" : \" byzantium \" " ) ! = string : : npos ) ;
// test invalid
result = compile ( inputForVersion ( " \" evmVersion \" : \" invalid \" , " ) ) ;
BOOST_CHECK ( result [ " errors " ] [ 0 ] [ " message " ] . asString ( ) = = " Invalid EVM version requested. " ) ;
}
2017-04-19 14:54:14 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
}
}
} // end namespaces