mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			107 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python3
 | 
						|
#
 | 
						|
# This script reads C++ or RST source files and writes all
 | 
						|
# multi-line strings into individual files.
 | 
						|
# This can be used to extract the Solidity test cases
 | 
						|
# into files for e.g. fuzz testing as
 | 
						|
# scripts/isolate_tests.py test/libsolidity/*
 | 
						|
 | 
						|
import sys
 | 
						|
import re
 | 
						|
import os
 | 
						|
import hashlib
 | 
						|
from os.path import join, isfile, split
 | 
						|
 | 
						|
def extract_test_cases(path):
 | 
						|
    lines = open(path, encoding="utf8", errors='ignore', mode='r', newline='').read().splitlines()
 | 
						|
 | 
						|
    inside = False
 | 
						|
    delimiter = ''
 | 
						|
    tests = []
 | 
						|
 | 
						|
    for l in lines:
 | 
						|
        if inside:
 | 
						|
            if l.strip().endswith(')' + delimiter + '";'):
 | 
						|
                inside = False
 | 
						|
            else:
 | 
						|
                tests[-1] += l + '\n'
 | 
						|
        else:
 | 
						|
            m = re.search(r'R"([^(]*)\($', l.strip())
 | 
						|
            if m:
 | 
						|
                inside = True
 | 
						|
                delimiter = m.group(1)
 | 
						|
                tests += ['']
 | 
						|
 | 
						|
    return tests
 | 
						|
 | 
						|
# Contract sources are indented by 4 spaces.
 | 
						|
# Look for `pragma solidity`, `contract`, `library` or `interface`
 | 
						|
# and abort a line not indented properly.
 | 
						|
def extract_docs_cases(path):
 | 
						|
    inside = False
 | 
						|
    extractedLines = []
 | 
						|
    tests = []
 | 
						|
 | 
						|
    # Collect all snippets of indented blocks
 | 
						|
    for l in open(path, mode='r', errors='ignore', encoding='utf8', newline='').read().splitlines():
 | 
						|
        if l != '':
 | 
						|
            if not inside and l.startswith(' '):
 | 
						|
                # start new test
 | 
						|
                extractedLines += ['']
 | 
						|
            inside = l.startswith(' ')
 | 
						|
        if inside:
 | 
						|
            extractedLines[-1] += l + '\n'
 | 
						|
 | 
						|
    codeStart = "(// SPDX-License-Identifier:|pragma solidity|contract.*{|library.*{|interface.*{)"
 | 
						|
 | 
						|
    # Filter all tests that do not contain Solidity or are indented incorrectly.
 | 
						|
    for lines in extractedLines:
 | 
						|
        if re.search(r'^\s{0,3}' + codeStart, lines, re.MULTILINE):
 | 
						|
            print("Indentation error in " + path + ":")
 | 
						|
            print(lines)
 | 
						|
            exit(1)
 | 
						|
        if re.search(r'^\s{4}' + codeStart, lines, re.MULTILINE):
 | 
						|
            tests.append(lines)
 | 
						|
 | 
						|
    return tests
 | 
						|
 | 
						|
def write_cases(f, tests):
 | 
						|
    cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
 | 
						|
    for test in tests:
 | 
						|
        # When code examples are extracted they are indented by 8 spaces, which violates the style guide,
 | 
						|
        # so before checking remove 4 spaces from each line.
 | 
						|
        remainder = re.sub(r'^ {4}', '', test, 0, re.MULTILINE)
 | 
						|
        sol_filename = 'test_%s_%s.sol' % (hashlib.sha256(test.encode("utf-8")).hexdigest(), cleaned_filename)
 | 
						|
        open(sol_filename, mode='w', encoding='utf8', newline='').write(remainder)
 | 
						|
 | 
						|
def extract_and_write(f, path):
 | 
						|
    if docs:
 | 
						|
        cases = extract_docs_cases(path)
 | 
						|
    else:
 | 
						|
        if f.endswith('.sol'):
 | 
						|
            cases = [open(path, mode='r', encoding='utf8', newline='').read()]
 | 
						|
        else:
 | 
						|
            cases = extract_test_cases(path)
 | 
						|
    write_cases(f, cases)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    path = sys.argv[1]
 | 
						|
    docs = False
 | 
						|
    if len(sys.argv) > 2 and sys.argv[2] == 'docs':
 | 
						|
        docs = True
 | 
						|
 | 
						|
    if isfile(path):
 | 
						|
        extract_and_write(path, path)
 | 
						|
    else:
 | 
						|
        for root, subdirs, files in os.walk(path):
 | 
						|
            if '_build' in subdirs:
 | 
						|
                subdirs.remove('_build')
 | 
						|
            if 'compilationTests' in subdirs:
 | 
						|
                subdirs.remove('compilationTests')
 | 
						|
            for f in files:
 | 
						|
                _, tail = split(f)
 | 
						|
                if tail == "invalid_utf8_sequence.sol":
 | 
						|
                    continue  # ignore the test with broken utf-8 encoding
 | 
						|
                path = join(root, f)
 | 
						|
                extract_and_write(f, path)
 |