|
1 | 1 | #!/usr/bin/env bash
|
| 2 | +# ------------------------------------------------------------------------------ |
| 3 | +# vim:ts=4:et |
| 4 | +# This file is part of solidity. |
| 5 | +# |
| 6 | +# solidity is free software: you can redistribute it and/or modify |
| 7 | +# it under the terms of the GNU General Public License as published by |
| 8 | +# the Free Software Foundation, either version 3 of the License, or |
| 9 | +# (at your option) any later version. |
| 10 | +# |
| 11 | +# solidity is distributed in the hope that it will be useful, |
| 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | +# GNU General Public License for more details. |
| 15 | +# |
| 16 | +# You should have received a copy of the GNU General Public License |
| 17 | +# along with solidity. If not, see <http://www.gnu.org/licenses/> |
| 18 | +# |
| 19 | +# (c) solidity contributors. |
| 20 | +# ------------------------------------------------------------------------------ |
| 21 | +# Bash script to test the import/exports. |
| 22 | +# ast import/export tests: |
| 23 | +# - first exporting a .sol file to JSON, then loading it into the compiler |
| 24 | +# and exporting it again. The second JSON should be identical to the first. |
| 25 | + |
| 26 | +set -euo pipefail |
2 | 27 |
|
3 |
| -set -e |
4 |
| - |
5 |
| -# Bash script to test the ast-import option of the compiler by |
6 |
| -# first exporting a .sol file to JSON, then loading it into the compiler |
7 |
| -# and exporting it again. The second JSON should be identical to the first |
8 | 28 | READLINK=readlink
|
9 | 29 | if [[ "$OSTYPE" == "darwin"* ]]; then
|
10 | 30 | READLINK=greadlink
|
11 | 31 | fi
|
12 | 32 | REPO_ROOT=$(${READLINK} -f "$(dirname "$0")"/..)
|
13 | 33 | SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-${REPO_ROOT}/build}
|
14 |
| -SOLC=${SOLIDITY_BUILD_DIR}/solc/solc |
15 |
| -SPLITSOURCES=${REPO_ROOT}/scripts/splitSources.py |
| 34 | +SOLC="${SOLIDITY_BUILD_DIR}/solc/solc" |
| 35 | +SPLITSOURCES="${REPO_ROOT}/scripts/splitSources.py" |
| 36 | + |
| 37 | +# shellcheck source=scripts/common.sh |
| 38 | +source "${REPO_ROOT}/scripts/common.sh" |
| 39 | + |
| 40 | +function print_usage |
| 41 | +{ |
| 42 | + echo "Usage: ${0} ast [--exit-on-error|--help]." |
| 43 | +} |
| 44 | + |
| 45 | +function print_used_commands |
| 46 | +{ |
| 47 | + local test_directory="$1" |
| 48 | + local export_command="$2" |
| 49 | + local import_command="$3" |
| 50 | + printError "You can find the files used for this test here: ${test_directory}" |
| 51 | + printError "Used commands for test:" |
| 52 | + printError "# export" |
| 53 | + echo "$ ${export_command}" >&2 |
| 54 | + printError "# import" |
| 55 | + echo "$ ${import_command}" >&2 |
| 56 | +} |
| 57 | + |
| 58 | +function print_stderr_stdout |
| 59 | +{ |
| 60 | + local error_message="$1" |
| 61 | + local stderr_file="$2" |
| 62 | + local stdout_file="$3" |
| 63 | + printError "$error_message" |
| 64 | + printError "" |
| 65 | + printError "stderr:" |
| 66 | + cat "$stderr_file" >&2 |
| 67 | + printError "" |
| 68 | + printError "stdout:" |
| 69 | + cat "$stdout_file" >&2 |
| 70 | +} |
| 71 | + |
| 72 | +function check_import_test_type_unset |
| 73 | +{ |
| 74 | + [ -z "$IMPORT_TEST_TYPE" ] || fail "ERROR: Import test type can only be set once. Aborting." |
| 75 | +} |
| 76 | + |
| 77 | +IMPORT_TEST_TYPE= |
| 78 | +EXIT_ON_ERROR=0 |
| 79 | +for PARAM in "$@" |
| 80 | +do |
| 81 | + case "$PARAM" in |
| 82 | + ast) check_import_test_type_unset ; IMPORT_TEST_TYPE="ast" ;; |
| 83 | + --help) print_usage ; exit 0 ;; |
| 84 | + --exit-on-error) EXIT_ON_ERROR=1 ;; |
| 85 | + *) fail "Unknown option '$PARAM'. Aborting. $(print_usage)" ;; |
| 86 | + esac |
| 87 | +done |
16 | 88 |
|
17 | 89 | SYNTAXTESTS_DIR="${REPO_ROOT}/test/libsolidity/syntaxTests"
|
18 | 90 | ASTJSONTESTS_DIR="${REPO_ROOT}/test/libsolidity/ASTJSON"
|
19 |
| -NSOURCES="$(find "$SYNTAXTESTS_DIR" -type f | wc -l)" |
20 |
| - |
21 |
| -# DEV_DIR="${REPO_ROOT}/../tmp/contracts/" |
22 |
| -# NSOURCES="$(find $DEV_DIR -type f | wc -l)" #TODO use find command |
23 | 91 |
|
24 | 92 | FAILED=0
|
25 | 93 | UNCOMPILABLE=0
|
26 | 94 | TESTED=0
|
27 | 95 |
|
28 |
| -if [[ "$(find . -maxdepth 0 -type d -empty)" == "" ]]; then |
29 |
| - echo "Test directory not empty. Skipping!" |
30 |
| - exit 1 |
31 |
| -fi |
| 96 | +function test_ast_import_export_equivalence |
| 97 | +{ |
| 98 | + local sol_file="$1" |
| 99 | + local input_files=( "${@:2}" ) |
32 | 100 |
|
33 |
| -# function tests whether exporting and importing again leaves the JSON ast unchanged |
34 |
| -# Results are recorded by adding to FAILED or UNCOMPILABLE. |
35 |
| -# Also, in case of a mismatch a diff and the respective ASTs are printed |
36 |
| -# Expected parameters: |
37 |
| -# $1 name of the file to be exported and imported |
38 |
| -# $2 any files needed to do so that might be in parent directories |
39 |
| -function testImportExportEquivalence { |
40 |
| - local nth_input_file="$1" |
41 |
| - IFS=" " read -r -a all_input_files <<< "$2" |
| 101 | + local export_command=("$SOLC" --combined-json ast --pretty-json --json-indent 4 "${input_files[@]}") |
| 102 | + local import_command=("$SOLC" --import-ast --combined-json ast --pretty-json --json-indent 4 expected.json) |
42 | 103 |
|
43 |
| - if $SOLC "$nth_input_file" "${all_input_files[@]}" > /dev/null 2>&1 |
| 104 | + # export ast - save ast json as expected result (silently) |
| 105 | + if ! "${export_command[@]}" > expected.json 2> stderr_export.txt |
44 | 106 | then
|
45 |
| - ! [[ -e stderr.txt ]] || { echo "stderr.txt already exists. Refusing to overwrite."; exit 1; } |
| 107 | + print_stderr_stdout "ERROR: AST reimport failed (export) for input file ${sol_file}." ./stderr_export.txt ./expected.json |
| 108 | + print_used_commands "$(pwd)" "${export_command[*]} > expected.json" "${import_command[*]}" |
| 109 | + return 1 |
| 110 | + fi |
| 111 | + |
| 112 | + # (re)import ast - and export it again as obtained result (silently) |
| 113 | + if ! "${import_command[@]}" > obtained.json 2> stderr_import.txt |
| 114 | + then |
| 115 | + print_stderr_stdout "ERROR: AST reimport failed (import) for input file ${sol_file}." ./stderr_import.txt ./obtained.json |
| 116 | + print_used_commands "$(pwd)" "${export_command[*]} > expected.json" "${import_command[*]}" |
| 117 | + return 1 |
| 118 | + fi |
46 | 119 |
|
47 |
| - # save exported json as expected result (silently) |
48 |
| - $SOLC --combined-json ast --pretty-json "$nth_input_file" "${all_input_files[@]}" > expected.json 2> /dev/null |
49 |
| - # import it, and export it again as obtained result (silently) |
50 |
| - if ! $SOLC --import-ast --combined-json ast --pretty-json expected.json > obtained.json 2> stderr.txt |
| 120 | + # compare expected and obtained ASTs |
| 121 | + if ! diff_files expected.json obtained.json |
| 122 | + then |
| 123 | + printError "ERROR: AST reimport failed for ${sol_file}" |
| 124 | + if (( EXIT_ON_ERROR == 1 )) |
51 | 125 | then
|
52 |
| - # For investigating, use exit 1 here so the script stops at the |
53 |
| - # first failing test |
54 |
| - # exit 1 |
55 |
| - FAILED=$((FAILED + 1)) |
56 |
| - echo -e "ERROR: AST reimport failed for input file $nth_input_file" |
57 |
| - echo |
58 |
| - echo "Compiler stderr:" |
59 |
| - cat ./stderr.txt |
60 |
| - echo |
61 |
| - echo "Compiler stdout:" |
62 |
| - cat ./obtained.json |
| 126 | + print_used_commands "$(pwd)" "${export_command[*]}" "${import_command[*]}" |
63 | 127 | return 1
|
64 | 128 | fi
|
65 |
| - DIFF="$(diff expected.json obtained.json)" |
66 |
| - if [ "$DIFF" != "" ] |
67 |
| - then |
68 |
| - if [ "$DIFFVIEW" == "" ] |
69 |
| - then |
70 |
| - echo -e "ERROR: JSONS differ for $1: \n $DIFF \n" |
71 |
| - echo "Expected:" |
72 |
| - cat ./expected.json |
73 |
| - echo "Obtained:" |
74 |
| - cat ./obtained.json |
75 |
| - else |
76 |
| - # Use user supplied diff view binary |
77 |
| - $DIFFVIEW expected.json obtained.json |
78 |
| - fi |
79 |
| - FAILED=$((FAILED + 1)) |
80 |
| - return 2 |
81 |
| - fi |
82 |
| - TESTED=$((TESTED + 1)) |
83 |
| - rm expected.json obtained.json |
84 |
| - rm -f stderr.txt |
| 129 | + FAILED=$((FAILED + 1)) |
| 130 | + fi |
| 131 | + TESTED=$((TESTED + 1)) |
| 132 | +} |
| 133 | + |
| 134 | +# function tests whether exporting and importing again is equivalent. |
| 135 | +# Results are recorded by incrementing the FAILED or UNCOMPILABLE global variable. |
| 136 | +# Also, in case of a mismatch a diff is printed |
| 137 | +# Expected parameters: |
| 138 | +# $1 name of the file to be exported and imported |
| 139 | +# $2 any files needed to do so that might be in parent directories |
| 140 | +function test_import_export_equivalence { |
| 141 | + local sol_file="$1" |
| 142 | + local input_files=( "${@:2}" ) |
| 143 | + local output |
| 144 | + local solc_return_code |
| 145 | + local compile_test |
| 146 | + |
| 147 | + case "$IMPORT_TEST_TYPE" in |
| 148 | + ast) compile_test="--ast-compact-json" ;; |
| 149 | + *) assertFail "Unknown import test type '${IMPORT_TEST_TYPE}'. Aborting." ;; |
| 150 | + esac |
| 151 | + |
| 152 | + set +e |
| 153 | + output=$("$SOLC" "${compile_test}" "${input_files[@]}" 2>&1) |
| 154 | + solc_return_code=$? |
| 155 | + set -e |
| 156 | + |
| 157 | + # if input files where compilable with success |
| 158 | + if (( solc_return_code == 0 )) |
| 159 | + then |
| 160 | + case "$IMPORT_TEST_TYPE" in |
| 161 | + ast) test_ast_import_export_equivalence "${sol_file}" "${input_files[@]}" ;; |
| 162 | + *) assertFail "Unknown import test type '${IMPORT_TEST_TYPE}'. Aborting." ;; |
| 163 | + esac |
85 | 164 | else
|
86 |
| - # echo "contract $solfile could not be compiled " |
87 | 165 | UNCOMPILABLE=$((UNCOMPILABLE + 1))
|
| 166 | + |
| 167 | + # solc will return exit code 2, if it was terminated by an uncaught exception. |
| 168 | + # This should normally not happen, so we terminate the test execution here |
| 169 | + # and print some details about the corresponding solc invocation. |
| 170 | + if (( solc_return_code == 2 )) |
| 171 | + then |
| 172 | + fail "\n\nERROR: Uncaught Exception while executing '$SOLC ${compile_test} ${input_files[*]}':\n${output}\n" |
| 173 | + fi |
88 | 174 | fi
|
89 |
| - # return 0 |
90 | 175 | }
|
91 |
| -echo "Looking at $NSOURCES .sol files..." |
92 | 176 |
|
93 | 177 | WORKINGDIR=$PWD
|
94 | 178 |
|
95 |
| -# for solfile in $(find $DEV_DIR -name *.sol) |
| 179 | +command_available "$SOLC" --version |
| 180 | +command_available jq --version |
| 181 | + |
| 182 | +case "$IMPORT_TEST_TYPE" in |
| 183 | + ast) TEST_DIRS=("${SYNTAXTESTS_DIR}" "${ASTJSONTESTS_DIR}") ;; |
| 184 | + *) assertFail "Import test type not defined. $(print_usage)" ;; |
| 185 | +esac |
| 186 | + |
96 | 187 | # boost_filesystem_bug specifically tests a local fix for a boost::filesystem
|
97 | 188 | # bug. Since the test involves a malformed path, there is no point in running
|
98 |
| -# AST tests on it. See https://github.com/boostorg/filesystem/issues/176 |
99 |
| -# shellcheck disable=SC2044 |
100 |
| -for solfile in $(find "$SYNTAXTESTS_DIR" "$ASTJSONTESTS_DIR" -name "*.sol" -and -not -name "boost_filesystem_bug.sol") |
| 189 | +# tests on it. See https://github.com/boostorg/filesystem/issues/176 |
| 190 | +IMPORT_TEST_FILES=$(find "${TEST_DIRS[@]}" -name "*.sol" -and -not -name "boost_filesystem_bug.sol") |
| 191 | + |
| 192 | +NSOURCES="$(echo "${IMPORT_TEST_FILES}" | wc -l)" |
| 193 | +echo "Looking at ${NSOURCES} .sol files..." |
| 194 | + |
| 195 | +for solfile in $IMPORT_TEST_FILES |
101 | 196 | do
|
102 |
| - echo -n "." |
| 197 | + echo -n "·" |
103 | 198 | # create a temporary sub-directory
|
104 | 199 | FILETMP=$(mktemp -d)
|
105 | 200 | cd "$FILETMP"
|
|
108 | 203 | OUTPUT=$("$SPLITSOURCES" "$solfile")
|
109 | 204 | SPLITSOURCES_RC=$?
|
110 | 205 | set -e
|
111 |
| - if [ ${SPLITSOURCES_RC} == 0 ] |
| 206 | + |
| 207 | + if (( SPLITSOURCES_RC == 0 )) |
112 | 208 | then
|
113 |
| - # echo $OUTPUT |
114 |
| - NSOURCES=$((NSOURCES - 1)) |
115 |
| - for i in $OUTPUT; |
116 |
| - do |
117 |
| - testImportExportEquivalence "$i" "$OUTPUT" |
118 |
| - NSOURCES=$((NSOURCES + 1)) |
119 |
| - done |
120 |
| - elif [ ${SPLITSOURCES_RC} == 1 ] |
| 209 | + IFS=' ' read -ra OUTPUT_ARRAY <<< "$OUTPUT" |
| 210 | + test_import_export_equivalence "$solfile" "${OUTPUT_ARRAY[@]}" |
| 211 | + elif (( SPLITSOURCES_RC == 1 )) |
121 | 212 | then
|
122 |
| - testImportExportEquivalence "$solfile" |
123 |
| - elif [ ${SPLITSOURCES_RC} == 2 ] |
| 213 | + test_import_export_equivalence "$solfile" "$solfile" |
| 214 | + elif (( SPLITSOURCES_RC == 2 )) |
124 | 215 | then
|
125 | 216 | # The script will exit with return code 2, if an UnicodeDecodeError occurred.
|
126 | 217 | # This is the case if e.g. some tests are using invalid utf-8 sequences. We will ignore
|
127 | 218 | # these errors, but print the actual output of the script.
|
128 |
| - echo -e "\n${OUTPUT}\n" |
129 |
| - testImportExportEquivalence "$solfile" |
| 219 | + printError "\n\n${OUTPUT}\n\n" |
| 220 | + test_import_export_equivalence "$solfile" "$solfile" |
130 | 221 | else
|
131 | 222 | # All other return codes will be treated as critical errors. The script will exit.
|
132 |
| - echo -e "\nGot unexpected return code ${SPLITSOURCES_RC} from ${SPLITSOURCES}. Aborting." |
133 |
| - echo -e "\n${OUTPUT}\n" |
| 223 | + printError "\n\nGot unexpected return code ${SPLITSOURCES_RC} from '${SPLITSOURCES} ${solfile}'. Aborting." |
| 224 | + printError "\n\n${OUTPUT}\n\n" |
134 | 225 |
|
135 | 226 | cd "$WORKINGDIR"
|
136 | 227 | # Delete temporary files
|
|
144 | 235 | rm -rf "$FILETMP"
|
145 | 236 | done
|
146 | 237 |
|
147 |
| -echo "" |
| 238 | +echo |
148 | 239 |
|
149 |
| -if [ "$FAILED" = 0 ] |
| 240 | +if (( FAILED == 0 )) |
150 | 241 | then
|
151 |
| - echo "SUCCESS: $TESTED syntaxTests passed, $FAILED failed, $UNCOMPILABLE could not be compiled ($NSOURCES sources total)." |
| 242 | + echo "SUCCESS: ${TESTED} tests passed, ${FAILED} failed, ${UNCOMPILABLE} could not be compiled (${NSOURCES} sources total)." |
152 | 243 | else
|
153 |
| - echo "FAILURE: Out of $NSOURCES sources, $FAILED failed, ($UNCOMPILABLE could not be compiled)." |
154 |
| - exit 1 |
| 244 | + fail "FAILURE: Out of ${NSOURCES} sources, ${FAILED} failed, (${UNCOMPILABLE} could not be compiled)." |
155 | 245 | fi
|
0 commit comments