mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
isolate_tests: Extract code blocks from documentation using code block header
This commit is contained in:
parent
f62b80530b
commit
5291ca2dd4
@ -324,7 +324,7 @@ from the documentation or the other tests:
|
|||||||
# extract from tests:
|
# extract from tests:
|
||||||
path/to/solidity/scripts/isolate_tests.py path/to/solidity/test/libsolidity/SolidityEndToEndTest.cpp
|
path/to/solidity/scripts/isolate_tests.py path/to/solidity/test/libsolidity/SolidityEndToEndTest.cpp
|
||||||
# extract from documentation:
|
# extract from documentation:
|
||||||
path/to/solidity/scripts/isolate_tests.py path/to/solidity/docs docs
|
path/to/solidity/scripts/isolate_tests.py path/to/solidity/docs
|
||||||
|
|
||||||
The AFL documentation states that the corpus (the initial input files) should not be
|
The AFL documentation states that the corpus (the initial input files) should not be
|
||||||
too large. The files themselves should not be larger than 1 kB and there should be
|
too large. The files themselves should not be larger than 1 kB and there should be
|
||||||
|
@ -136,7 +136,7 @@ SOLTMPDIR=$(mktemp -d)
|
|||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
cd "$SOLTMPDIR"
|
cd "$SOLTMPDIR"
|
||||||
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs
|
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/
|
||||||
|
|
||||||
getAllAvailableVersions
|
getAllAvailableVersions
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ import sys
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import hashlib
|
import hashlib
|
||||||
from os.path import join, isfile, split
|
from os.path import join, isfile, split, basename
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
def extract_test_cases(path):
|
def extract_test_cases(path):
|
||||||
with open(path, encoding="utf8", errors='ignore', mode='r', newline='') as file:
|
with open(path, encoding="utf8", errors='ignore', mode='r', newline='') as file:
|
||||||
@ -35,54 +36,50 @@ def extract_test_cases(path):
|
|||||||
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
# Contract sources are indented by 4 spaces.
|
# Extract code examples based on a start marker
|
||||||
# Look for `pragma solidity`, `contract`, `library` or `interface`
|
# up until we reach EOF or a line that is not empty and doesn't start with 4
|
||||||
# and abort a line not indented properly.
|
# spaces.
|
||||||
def extract_docs_cases(path):
|
def extract_docs_cases(path):
|
||||||
|
beginMarkers = ['.. code-block:: solidity', '::']
|
||||||
|
immediatelyAfterMarker = False
|
||||||
insideBlock = False
|
insideBlock = False
|
||||||
insideBlockParameters = False
|
|
||||||
pastBlockParameters = False
|
|
||||||
extractedLines = []
|
|
||||||
tests = []
|
tests = []
|
||||||
|
|
||||||
# Collect all snippets of indented blocks
|
# Collect all snippets of indented blocks
|
||||||
|
|
||||||
with open(path, mode='r', errors='ignore', encoding='utf8', newline='') as f:
|
with open(path, mode='r', errors='ignore', encoding='utf8', newline='') as f:
|
||||||
lines = f.read().splitlines()
|
lines = f.read().splitlines()
|
||||||
for l in lines:
|
|
||||||
if l != '':
|
|
||||||
if not insideBlock and l.startswith(' '):
|
|
||||||
# start new test
|
|
||||||
extractedLines += ['']
|
|
||||||
insideBlockParameters = False
|
|
||||||
pastBlockParameters = False
|
|
||||||
insideBlock = l.startswith(' ')
|
|
||||||
if insideBlock:
|
|
||||||
if not pastBlockParameters:
|
|
||||||
# NOTE: For simplicity this allows blank lines between block parameters even
|
|
||||||
# though Sphinx does not. This does not matter since the first non-empty line in
|
|
||||||
# a Solidity file cannot start with a colon anyway.
|
|
||||||
if not l.strip().startswith(':') and (l != '' or not insideBlockParameters):
|
|
||||||
insideBlockParameters = False
|
|
||||||
pastBlockParameters = True
|
|
||||||
else:
|
|
||||||
insideBlockParameters = True
|
|
||||||
|
|
||||||
if not insideBlockParameters:
|
for line in lines:
|
||||||
extractedLines[-1] += l + '\n'
|
if insideBlock:
|
||||||
|
if immediatelyAfterMarker:
|
||||||
|
# Skip Sphinx instructions and empty lines between them
|
||||||
|
if line == '' or line.lstrip().startswith(":"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if line == '' or line.startswith(" "):
|
||||||
|
tests[-1] += line + "\n"
|
||||||
|
immediatelyAfterMarker = False
|
||||||
|
else:
|
||||||
|
insideBlock = False
|
||||||
|
elif any(map(line.lower().startswith, beginMarkers)):
|
||||||
|
insideBlock = True
|
||||||
|
immediatelyAfterMarker = True
|
||||||
|
tests += ['']
|
||||||
|
|
||||||
codeStart = "(// SPDX-License-Identifier:|pragma solidity|contract.*{|library.*{|interface.*{)"
|
codeStart = "(// SPDX-License-Identifier:|pragma solidity|contract.*{|library.*{|interface.*{)"
|
||||||
|
|
||||||
# Filter all tests that do not contain Solidity or are indented incorrectly.
|
for test in tests:
|
||||||
for lines in extractedLines:
|
if re.search(r'^\s{0,3}' + codeStart, test, re.MULTILINE):
|
||||||
if re.search(r'^\s{0,3}' + codeStart, lines, re.MULTILINE):
|
|
||||||
print("Indentation error in " + path + ":")
|
print("Indentation error in " + path + ":")
|
||||||
print(lines)
|
print(test)
|
||||||
exit(1)
|
exit(1)
|
||||||
if re.search(r'^\s{4}' + codeStart, lines, re.MULTILINE):
|
|
||||||
tests.append(lines)
|
|
||||||
|
|
||||||
return tests
|
# Filter out tests that are not supposed to be compilable.
|
||||||
|
return [
|
||||||
|
test.lstrip("\n")
|
||||||
|
for test in tests
|
||||||
|
if re.search(r'^\s{4}' + codeStart, test, re.MULTILINE) is not None
|
||||||
|
]
|
||||||
|
|
||||||
def write_cases(f, tests):
|
def write_cases(f, tests):
|
||||||
cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
|
cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
|
||||||
@ -94,30 +91,30 @@ def write_cases(f, tests):
|
|||||||
with open(sol_filename, mode='w', encoding='utf8', newline='') as fi:
|
with open(sol_filename, mode='w', encoding='utf8', newline='') as fi:
|
||||||
fi.write(remainder)
|
fi.write(remainder)
|
||||||
|
|
||||||
def extract_and_write(f, path):
|
def extract_and_write(path):
|
||||||
if docs:
|
if path.lower().endswith('.rst'):
|
||||||
cases = extract_docs_cases(path)
|
cases = extract_docs_cases(path)
|
||||||
|
elif path.endswith('.sol'):
|
||||||
|
with open(path, mode='r', encoding='utf8', newline='') as f:
|
||||||
|
cases = [f.read()]
|
||||||
else:
|
else:
|
||||||
if f.endswith('.sol'):
|
cases = extract_test_cases(path)
|
||||||
with open(path, mode='r', encoding='utf8', newline='') as _f:
|
|
||||||
cases = [_f.read()]
|
write_cases(basename(path), cases)
|
||||||
else:
|
|
||||||
cases = extract_test_cases(path)
|
|
||||||
write_cases(f, cases)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) == 1:
|
script_description = (
|
||||||
print("Usage: " + sys.argv[0] + " path-to-file-or-folder-to-extract-code-from [docs]")
|
"Reads Solidity, C++ or RST source files and extracts compilable solidity and yul code blocks from them. "
|
||||||
exit(1)
|
"Can be used to generate test cases to validade code examples. "
|
||||||
|
)
|
||||||
|
|
||||||
path = sys.argv[1]
|
parser = ArgumentParser(description=script_description)
|
||||||
docs = False
|
parser.add_argument(dest='path', help='Path to file or directory to look for code in.')
|
||||||
if len(sys.argv) > 2 and sys.argv[2] == 'docs':
|
options = parser.parse_args()
|
||||||
docs = True
|
path = options.path
|
||||||
|
|
||||||
if isfile(path):
|
if isfile(path):
|
||||||
_, tail = split(path)
|
extract_and_write(path)
|
||||||
extract_and_write(tail, path)
|
|
||||||
else:
|
else:
|
||||||
for root, subdirs, files in os.walk(path):
|
for root, subdirs, files in os.walk(path):
|
||||||
if '_build' in subdirs:
|
if '_build' in subdirs:
|
||||||
@ -125,8 +122,7 @@ if __name__ == '__main__':
|
|||||||
if 'compilationTests' in subdirs:
|
if 'compilationTests' in subdirs:
|
||||||
subdirs.remove('compilationTests')
|
subdirs.remove('compilationTests')
|
||||||
for f in files:
|
for f in files:
|
||||||
_, tail = split(f)
|
if basename(f) == "invalid_utf8_sequence.sol":
|
||||||
if tail == "invalid_utf8_sequence.sol":
|
|
||||||
continue # ignore the test with broken utf-8 encoding
|
continue # ignore the test with broken utf-8 encoding
|
||||||
path = join(root, f)
|
path = join(root, f)
|
||||||
extract_and_write(f, path)
|
extract_and_write(path)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
|
#
|
||||||
|
# Not actively tested or maintained. Exists in case we want to rebuild an
|
||||||
|
# ancient release.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
@ -361,7 +361,7 @@ SOLTMPDIR=$(mktemp -d)
|
|||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
cd "$SOLTMPDIR"
|
cd "$SOLTMPDIR"
|
||||||
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs
|
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/
|
||||||
developmentVersion=$("$REPO_ROOT/scripts/get_version.sh")
|
developmentVersion=$("$REPO_ROOT/scripts/get_version.sh")
|
||||||
|
|
||||||
for f in *.sol
|
for f in *.sol
|
||||||
@ -510,7 +510,7 @@ SOLTMPDIR=$(mktemp -d)
|
|||||||
set -e
|
set -e
|
||||||
cd "$SOLTMPDIR"
|
cd "$SOLTMPDIR"
|
||||||
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/test/
|
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/test/
|
||||||
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs
|
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/
|
||||||
|
|
||||||
echo ./*.sol | xargs -P 4 -n 50 "${SOLIDITY_BUILD_DIR}/test/tools/solfuzzer" --quiet --input-files
|
echo ./*.sol | xargs -P 4 -n 50 "${SOLIDITY_BUILD_DIR}/test/tools/solfuzzer" --quiet --input-files
|
||||||
echo ./*.sol | xargs -P 4 -n 50 "${SOLIDITY_BUILD_DIR}/test/tools/solfuzzer" --without-optimizer --quiet --input-files
|
echo ./*.sol | xargs -P 4 -n 50 "${SOLIDITY_BUILD_DIR}/test/tools/solfuzzer" --without-optimizer --quiet --input-files
|
||||||
|
@ -22,7 +22,7 @@ SOLTMPDIR=$(mktemp -d)
|
|||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
cd "$SOLTMPDIR"
|
cd "$SOLTMPDIR"
|
||||||
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs
|
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/
|
||||||
|
|
||||||
if npm -v >/dev/null 2>&1; then
|
if npm -v >/dev/null 2>&1; then
|
||||||
if npm list -g | grep solhint >/dev/null 2>&1; then
|
if npm list -g | grep solhint >/dev/null 2>&1; then
|
||||||
|
Loading…
Reference in New Issue
Block a user