2017-01-24 22:36:35 +00:00
#!/usr/bin/env bash
#------------------------------------------------------------------------------
# Bash script to run commandline Solidity tests.
#
# The documentation for solidity is hosted at:
#
# https://solidity.readthedocs.org
#
# ------------------------------------------------------------------------------
# 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/>
#
# (c) 2016 solidity contributors.
#------------------------------------------------------------------------------
set -e
2018-12-20 11:17:33 +00:00
## GLOBAL VARIABLES
2017-07-12 17:06:36 +00:00
REPO_ROOT = $( cd $( dirname " $0 " ) /.. && pwd )
2019-04-26 09:57:49 +00:00
source " ${ REPO_ROOT } /scripts/common.sh "
2017-01-24 22:36:35 +00:00
SOLC = " $REPO_ROOT /build/solc/solc "
2019-04-15 21:51:31 +00:00
INTERACTIVE = true
if ! tty -s || [ " $CI " ]
then
INTERACTIVE = ""
fi
2017-01-24 22:36:35 +00:00
2018-08-06 16:32:18 +00:00
FULLARGS = "--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc"
2017-07-19 19:12:49 +00:00
2019-04-26 09:57:49 +00:00
# extend stack size in case we run via ASAN
if [ [ -n " ${ CIRCLECI } " ] ] || [ [ -n " $CI " ] ] ; then
ulimit -s 16384
ulimit -a
2018-09-28 21:31:23 +00:00
fi
2017-10-05 18:46:38 +00:00
2019-04-26 09:57:49 +00:00
## FUNCTIONS
2017-10-05 18:46:38 +00:00
2017-07-12 17:06:36 +00:00
function compileFull( )
{
2018-08-09 12:58:28 +00:00
local expected_exit_code = 0
local expect_output = 0
if [ [ $1 = '-e' ] ]
then
expected_exit_code = 1
expect_output = 1
shift;
fi
if [ [ $1 = '-w' ] ]
then
expect_output = 1
shift;
fi
2017-07-19 19:27:05 +00:00
local files = " $* "
2018-08-09 12:58:28 +00:00
local output
local stderr_path = $( mktemp)
2017-07-19 19:27:05 +00:00
2017-01-24 22:36:35 +00:00
set +e
2018-08-09 12:58:28 +00:00
" $SOLC " $FULLARGS $files >/dev/null 2>" $stderr_path "
local exit_code = $?
local errors = $( grep -v -E 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|\^-------------------------------\^' < " $stderr_path " )
2017-07-12 17:06:36 +00:00
set -e
2018-08-09 12:58:28 +00:00
rm " $stderr_path "
2017-07-19 19:27:05 +00:00
2018-08-09 12:58:28 +00:00
if [ [ \
" $exit_code " -ne " $expected_exit_code " || \
( $expect_output -eq 0 && -n " $errors " ) || \
( $expect_output -ne 0 && -z " $errors " ) \
] ]
2017-07-12 17:06:36 +00:00
then
2018-08-09 12:58:28 +00:00
printError "Unexpected compilation result:"
printError " Expected failure: $expected_exit_code - Expected warning / error output: $expect_output "
printError " Was failure: $exit_code "
echo " $errors "
2017-10-05 18:46:38 +00:00
printError "While calling:"
echo " \" $SOLC \" $FULLARGS $files "
printError "Inside directory:"
pwd
2017-07-12 17:06:36 +00:00
false
fi
}
2019-04-07 16:24:14 +00:00
function ask_expectation_update( )
{
2019-04-15 21:51:31 +00:00
if [ $INTERACTIVE ]
then
local newExpectation = " ${ 1 } "
local expectationFile = " ${ 2 } "
while true;
do
read -p "(u)pdate expectation/(q)uit? "
case $REPLY in
u* ) echo " $newExpectation " > $expectationFile ; break; ;
q* ) exit 1; ;
esac
done
2019-06-12 17:03:45 +00:00
else
exit 1
2019-04-15 21:51:31 +00:00
fi
2019-04-07 16:24:14 +00:00
}
2018-08-06 16:52:49 +00:00
# General helper function for testing SOLC behaviour, based on file name, compile opts, exit code, stdout and stderr.
# An failure is expected.
2018-12-20 11:08:42 +00:00
function test_solc_behaviour( )
{
2018-08-06 16:52:49 +00:00
local filename = " ${ 1 } "
local solc_args = " ${ 2 } "
2018-12-11 14:47:19 +00:00
local solc_stdin = " ${ 3 } "
2019-04-16 13:17:33 +00:00
[ -z " $solc_stdin " ] && solc_stdin = "/dev/stdin"
2018-12-11 14:47:19 +00:00
local stdout_expected = " ${ 4 } "
local exit_code_expected = " ${ 5 } "
local stderr_expected = " ${ 6 } "
2019-04-07 16:24:14 +00:00
local stdout_expectation_file = " ${ 7 } " # the file to write to when user chooses to update stdout expectation
local stderr_expectation_file = " ${ 8 } " # the file to write to when user chooses to update stderr expectation
2018-08-06 16:52:49 +00:00
local stdout_path = ` mktemp`
local stderr_path = ` mktemp`
2019-04-07 16:24:14 +00:00
trap " rm -f $stdout_path $stderr_path " EXIT
2018-12-06 11:31:27 +00:00
if [ [ " $exit_code_expected " = "" ] ] ; then exit_code_expected = "0" ; fi
2018-08-06 16:52:49 +00:00
2019-04-16 13:17:33 +00:00
local solc_command = " $SOLC ${ filename } ${ solc_args } < $solc_stdin "
2018-08-06 16:52:49 +00:00
set +e
2019-04-16 13:17:33 +00:00
" $SOLC " " ${ filename } " ${ solc_args } <" $solc_stdin " >" $stdout_path " 2>" $stderr_path "
2018-08-06 16:52:49 +00:00
exitCode = $?
set -e
2018-12-20 11:08:42 +00:00
if [ [ " $solc_args " = = *"--standard-json" * ] ]
then
2018-12-13 12:31:12 +00:00
sed -i -e 's/{[^{]*Warning: This is a pre-release compiler version[^}]*},\{0,1\}//' " $stdout_path "
2018-12-19 11:22:19 +00:00
sed -i -e 's/"errors":\[\],\{0,1\}//' " $stdout_path "
2018-12-13 12:31:12 +00:00
else
sed -i -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' " $stderr_path "
sed -i -e 's/ Consider adding "pragma .*$//' " $stderr_path "
fi
2019-03-11 16:30:46 +00:00
# Remove path to cpp file
sed -i -e 's/^\(Exception while assembling:\).*/\1/' " $stderr_path "
2019-03-21 16:17:42 +00:00
# Remove exception class name.
sed -i -e 's/^\(Dynamic exception type:\).*/\1/' " $stderr_path "
2018-09-10 19:22:13 +00:00
2018-12-20 11:08:42 +00:00
if [ [ $exitCode -ne " $exit_code_expected " ] ]
then
2018-12-06 11:31:27 +00:00
printError " Incorrect exit code. Expected $exit_code_expected but got $exitCode . "
2018-08-06 16:52:49 +00:00
exit 1
fi
2018-12-20 11:08:42 +00:00
if [ [ " $( cat $stdout_path ) " != " ${ stdout_expected } " ] ]
then
2018-12-06 11:31:27 +00:00
printError "Incorrect output on stdout received. Expected:"
2019-04-15 21:51:31 +00:00
echo -e " ${ stdout_expected } "
2018-08-06 16:52:49 +00:00
printError "But got:"
2019-04-15 21:51:31 +00:00
echo -e " $( cat $stdout_path ) "
2018-12-20 11:52:14 +00:00
2019-04-07 16:24:14 +00:00
printError " When running $solc_command "
if [ -n " $stdout_expectation_file " ]
then
ask_expectation_update " $( cat $stdout_path ) " " $stdout_expectation_file "
else
exit 1
fi
2018-08-06 16:52:49 +00:00
fi
2018-12-20 11:08:42 +00:00
if [ [ " $( cat $stderr_path ) " != " ${ stderr_expected } " ] ]
then
2018-08-06 16:52:49 +00:00
printError "Incorrect output on stderr received. Expected:"
2019-04-15 21:51:31 +00:00
echo -e " ${ stderr_expected } "
2018-08-06 16:52:49 +00:00
printError "But got:"
2019-04-15 21:51:31 +00:00
echo -e " $( cat $stderr_path ) "
2018-12-20 11:52:14 +00:00
2019-04-07 16:24:14 +00:00
printError " When running $solc_command "
2018-08-06 16:52:49 +00:00
2019-04-07 16:24:14 +00:00
if [ -n " $stderr_expectation_file " ]
then
ask_expectation_update " $( cat $stderr_path ) " " $stderr_expectation_file "
else
exit 1
fi
fi
2018-08-06 16:52:49 +00:00
}
2018-12-20 11:17:33 +00:00
function test_solc_assembly_output( )
{
local input = " ${ 1 } "
local expected = " ${ 2 } "
local solc_args = " ${ 3 } "
local expected_object = "object \"object\" { code " ${ expected } " }"
output = $( echo " ${ input } " | " $SOLC " - ${ solc_args } 2>/dev/null)
empty = $( echo $output | sed -ne '/' " ${ expected_object } " '/p' )
if [ -z " $empty " ]
then
printError "Incorrect assembly output. Expected: "
echo -e ${ expected }
printError " with arguments ${ solc_args } , but got: "
echo " ${ output } "
exit 1
fi
}
## RUN
echo "Checking that the bug list is up to date..."
" $REPO_ROOT " /scripts/update_bugs_by_version.py
printTask "Testing unknown options..."
(
set +e
output = $( " $SOLC " --allow= test 2>& 1)
failed = $?
set -e
if [ " $output " = = "unrecognised option '--allow=test'" ] && [ $failed -ne 0 ]
then
echo "Passed"
else
printError " Incorrect response to unknown options: $STDERR "
exit 1
fi
)
2018-08-06 16:52:49 +00:00
printTask "Testing passing files that are not found..."
2019-04-07 16:24:14 +00:00
test_solc_behaviour "file_not_found.sol" "" "" "" 1 "\"file_not_found.sol\" is not found." "" ""
2018-08-06 16:52:49 +00:00
printTask "Testing passing files that are not files..."
2019-04-07 16:24:14 +00:00
test_solc_behaviour "." "" "" "" 1 "\".\" is not a valid file." "" ""
2018-08-06 16:52:49 +00:00
2018-08-09 18:37:49 +00:00
printTask "Testing passing empty remappings..."
2019-04-07 16:24:14 +00:00
test_solc_behaviour " ${ 0 } " "=/some/remapping/target" "" "" 1 "Invalid remapping: \"=/some/remapping/target\"." "" ""
test_solc_behaviour " ${ 0 } " "ctx:=/some/remapping/target" "" "" 1 "Invalid remapping: \"ctx:=/some/remapping/target\"." "" ""
2018-12-11 14:47:19 +00:00
2018-12-06 11:31:27 +00:00
printTask "Running general commandline tests..."
2018-09-10 19:22:13 +00:00
(
2018-12-20 11:32:53 +00:00
cd " $REPO_ROOT " /test/cmdlineTests/
2018-12-20 11:28:42 +00:00
for tdir in */
2018-12-20 11:08:42 +00:00
do
2018-12-20 11:32:53 +00:00
if [ -e " ${ tdir } /input.json " ]
then
inputFile = ""
stdin = " ${ tdir } /input.json "
2019-04-07 16:24:14 +00:00
stdout = " $( cat ${ tdir } /output.json 2>/dev/null || true ) "
2019-04-16 12:43:32 +00:00
stdoutExpectationFile = " ${ tdir } /output.json "
2018-12-20 11:32:53 +00:00
args = "--standard-json " $( cat ${ tdir } /args 2>/dev/null || true )
else
inputFile = " ${ tdir } input.sol "
stdin = ""
2019-04-07 16:24:14 +00:00
stdout = " $( cat ${ tdir } /output 2>/dev/null || true ) "
2019-04-16 12:43:32 +00:00
stdoutExpectationFile = " ${ tdir } /output "
2018-12-20 11:32:53 +00:00
args = $( cat ${ tdir } /args 2>/dev/null || true )
fi
2018-12-20 11:28:42 +00:00
exitCode = $( cat ${ tdir } /exit 2>/dev/null || true )
2019-04-07 16:24:14 +00:00
err = " $( cat ${ tdir } /err 2>/dev/null || true ) "
stderrExpectationFile = " ${ tdir } /err "
2018-12-20 11:28:42 +00:00
printTask " - ${ tdir } "
2019-04-07 16:24:14 +00:00
test_solc_behaviour " $inputFile " \
" $args " \
" $stdin " \
" $stdout " \
" $exitCode " \
" $err " \
" $stdoutExpectationFile " \
" $stderrExpectationFile "
2018-12-20 11:08:42 +00:00
done
2018-09-10 19:22:13 +00:00
)
2017-10-05 18:46:38 +00:00
printTask "Compiling various other contracts and libraries..."
2017-07-12 17:06:36 +00:00
(
2018-12-20 11:08:42 +00:00
cd " $REPO_ROOT " /test/compilationTests/
2018-12-20 11:12:53 +00:00
for dir in */
2018-12-20 11:08:42 +00:00
do
2018-12-20 11:12:53 +00:00
echo " - $dir "
cd " $dir "
compileFull -w *.sol */*.sol
cd ..
2018-12-20 11:08:42 +00:00
done
2017-07-12 17:06:36 +00:00
)
2017-10-05 18:46:38 +00:00
printTask "Compiling all examples from the documentation..."
2018-09-03 10:54:29 +00:00
SOLTMPDIR = $( mktemp -d)
2017-07-10 21:53:31 +00:00
(
set -e
2018-09-03 10:54:29 +00:00
cd " $SOLTMPDIR "
2017-07-10 21:53:31 +00:00
" $REPO_ROOT " /scripts/isolate_tests.py " $REPO_ROOT " /docs/ docs
for f in *.sol
do
2018-08-09 18:48:41 +00:00
# The contributors guide uses syntax tests, but we cannot
# really handle them here.
if grep -E 'DeclarationError:|// ----' " $f " >/dev/null
then
continue
fi
2017-07-12 17:06:36 +00:00
echo " $f "
2018-08-09 12:58:28 +00:00
opts = ''
2018-08-09 18:48:41 +00:00
# We expect errors if explicitly stated, or if imports
# are used (in the style guide)
if grep -E "This will not compile|import \"" " $f " >/dev/null
2018-08-09 12:58:28 +00:00
then
opts = "-e"
fi
if grep "This will report a warning" " $f " >/dev/null
then
opts = " $opts -w "
fi
2018-09-03 10:54:29 +00:00
compileFull $opts " $SOLTMPDIR / $f "
2017-07-10 21:53:31 +00:00
done
)
2018-09-03 10:54:29 +00:00
rm -rf " $SOLTMPDIR "
2017-07-10 21:53:31 +00:00
echo "Done."
2017-10-05 18:46:38 +00:00
printTask "Testing library checksum..."
2018-04-24 13:18:12 +00:00
echo '' | " $SOLC " - --link --libraries a:0x90f20564390eAe531E810af625A22f51385Cd222 >/dev/null
! echo '' | " $SOLC " - --link --libraries a:0x80f20564390eAe531E810af625A22f51385Cd222 & >/dev/null
2017-02-16 16:13:55 +00:00
2017-10-05 18:46:38 +00:00
printTask "Testing long library names..."
2018-04-24 13:18:12 +00:00
echo '' | " $SOLC " - --link --libraries aveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeerylonglibraryname:0x90f20564390eAe531E810af625A22f51385Cd222 >/dev/null
2017-03-14 10:58:43 +00:00
2018-10-04 12:55:02 +00:00
printTask "Testing linking itself..."
SOLTMPDIR = $( mktemp -d)
(
cd " $SOLTMPDIR "
set -e
echo 'library L { function f() public pure {} } contract C { function f() public pure { L.f(); } }' > x.sol
" $SOLC " --bin -o . x.sol 2>/dev/null
# Explanation and placeholder should be there
grep -q '//' C.bin && grep -q '__' C.bin
# But not in library file.
grep -q -v '[/_]' L.bin
# Now link
" $SOLC " --link --libraries x.sol:L:0x90f20564390eAe531E810af625A22f51385Cd222 C.bin
# Now the placeholder and explanation should be gone.
grep -q -v '[/_]' C.bin
)
rm -rf " $SOLTMPDIR "
2018-04-24 13:18:12 +00:00
printTask "Testing overwriting files..."
2018-09-03 10:54:29 +00:00
SOLTMPDIR = $( mktemp -d)
2017-03-10 18:10:47 +00:00
(
set -e
# First time it works
2018-09-03 10:54:29 +00:00
echo 'contract C {} ' | " $SOLC " - --bin -o " $SOLTMPDIR /non-existing-stuff-to-create " 2>/dev/null
2017-03-10 18:10:47 +00:00
# Second time it fails
2018-09-03 10:54:29 +00:00
! echo 'contract C {} ' | " $SOLC " - --bin -o " $SOLTMPDIR /non-existing-stuff-to-create " 2>/dev/null
2017-03-10 18:10:47 +00:00
# Unless we force
2018-09-03 10:54:29 +00:00
echo 'contract C {} ' | " $SOLC " - --overwrite --bin -o " $SOLTMPDIR /non-existing-stuff-to-create " 2>/dev/null
2017-03-10 18:10:47 +00:00
)
2018-09-03 10:54:29 +00:00
rm -rf " $SOLTMPDIR "
2017-03-10 18:10:47 +00:00
2018-11-21 17:10:56 +00:00
printTask "Testing assemble, yul, strict-assembly and optimize..."
(
echo '{}' | " $SOLC " - --assemble & >/dev/null
echo '{}' | " $SOLC " - --yul & >/dev/null
echo '{}' | " $SOLC " - --strict-assembly & >/dev/null
# Test options above in conjunction with --optimize.
# Using both, --assemble and --optimize should fail.
! echo '{}' | " $SOLC " - --assemble --optimize & >/dev/null
2019-02-06 13:39:43 +00:00
! echo '{}' | " $SOLC " - --yul --optimize & >/dev/null
2018-11-29 14:56:51 +00:00
# Test yul and strict assembly output
# Non-empty code results in non-empty binary representation with optimizations turned off,
# while it results in empty binary representation with optimizations turned on.
test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x:u256 := 0:u256 }" "--yul"
test_solc_assembly_output "{ let x := 0 }" "{ let x := 0 }" "--strict-assembly"
2019-04-04 15:48:29 +00:00
test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize"
2018-11-21 17:10:56 +00:00
)
2018-04-24 13:18:12 +00:00
printTask "Testing standard input..."
2018-09-03 10:54:29 +00:00
SOLTMPDIR = $( mktemp -d)
2018-04-24 13:18:12 +00:00
(
set +e
output = $( " $SOLC " --bin 2>& 1)
result = $?
set -e
# This should fail
2018-12-20 11:08:42 +00:00
if [ [ !( " $output " = ~ "No input files given" ) || ( $result = = 0) ] ]
then
2018-04-24 13:18:12 +00:00
printError " Incorrect response to empty input arg list: $STDERR "
exit 1
fi
set +e
output = $( echo 'contract C {} ' | " $SOLC " - --bin 2>/dev/null | grep -q "<stdin>:C" )
result = $?
set -e
# The contract should be compiled
2018-12-20 11:08:42 +00:00
if [ [ " $result " != 0 ] ]
then
2018-04-24 13:18:12 +00:00
exit 1
fi
2018-10-15 15:54:48 +00:00
# This should not fail
set +e
output = $( echo '' | " $SOLC " --ast - 2>/dev/null)
set -e
2018-12-20 11:08:42 +00:00
if [ [ $? != 0 ] ]
then
2018-10-15 15:54:48 +00:00
exit 1
fi
2018-04-24 13:18:12 +00:00
)
2017-10-05 18:46:38 +00:00
printTask "Testing soljson via the fuzzer..."
2018-09-03 10:54:29 +00:00
SOLTMPDIR = $( mktemp -d)
2017-02-16 16:13:55 +00:00
(
2017-03-10 18:10:47 +00:00
set -e
2018-09-03 10:54:29 +00:00
cd " $SOLTMPDIR "
2017-03-22 19:19:20 +00:00
" $REPO_ROOT " /scripts/isolate_tests.py " $REPO_ROOT " /test/
2017-07-10 21:53:31 +00:00
" $REPO_ROOT " /scripts/isolate_tests.py " $REPO_ROOT " /docs/ docs
2017-08-30 23:24:25 +00:00
2019-04-01 14:57:58 +00:00
echo *.sol | xargs -P 4 -n 50 " $REPO_ROOT " /build/test/tools/solfuzzer --quiet --input-files
echo *.sol | xargs -P 4 -n 50 " $REPO_ROOT " /build/test/tools/solfuzzer --without-optimizer --quiet --input-files
2017-02-16 16:13:55 +00:00
)
2018-09-03 10:54:29 +00:00
rm -rf " $SOLTMPDIR "
2018-12-20 11:17:33 +00:00
2018-02-26 19:41:18 +00:00
echo "Commandline tests successful."