From 95bdbedf91df701a9ec80d5b73f1a6ccd04ce7b1 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Sat, 27 Jul 2019 23:15:11 +0800 Subject: [PATCH] update tests --- .travis.yml | 6 +- solcx/main.py | 4 +- solcx/wrapper.py | 4 +- .../core/compilation/test_compile_empty.py | 23 ----- .../test_compile_from_source_code.py | 21 ---- .../core/compilation/test_compile_standard.py | 97 ------------------- .../test_compiler_from_source_file.py | 32 ------ .../compilation/test_compiler_remappings.py | 30 ------ tests/conftest.py | 58 ++++++++--- tests/test_compile.py | 38 +++++++- tests/test_compile_standard.py | 67 +++++++++++++ tests/test_library_linking.py | 88 +++++++++++------ tests/test_solc_version.py | 21 +++- 13 files changed, 224 insertions(+), 265 deletions(-) delete mode 100644 tests-old/core/compilation/test_compile_empty.py delete mode 100644 tests-old/core/compilation/test_compile_from_source_code.py delete mode 100644 tests-old/core/compilation/test_compile_standard.py delete mode 100644 tests-old/core/compilation/test_compiler_from_source_file.py delete mode 100644 tests-old/core/compilation/test_compiler_remappings.py create mode 100644 tests/test_compile_standard.py diff --git a/.travis.yml b/.travis.yml index fe8752e..94c41ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,8 @@ matrix: - sudo apt-get update - sudo apt-get install -y solc - pip install -r requirements-dev.txt + script: python -m pytest tests --cov=solcx + after_success: python -m coveralls - name: "Python 3.7.3 on Windows" os: windows # Windows 10.0.17134 N/A Build 17134 language: shell # 'language: python' is an error on Travis CI Windows @@ -32,8 +34,8 @@ matrix: - python -m pip install --upgrade pip - pip3 install -r requirements-dev.txt env: PATH=/c/Python37:/c/Python37/Scripts:$PATH + script: python -m pytest tests --cov=solcx + after_success: python -m coveralls -script: python -m pytest tests --cov=solcx -after_success: python -m coveralls notifications: email: false diff --git a/solcx/main.py b/solcx/main.py index e790eca..2461a8b 100644 --- a/solcx/main.py +++ b/solcx/main.py @@ -182,13 +182,13 @@ def compile_standard(input_data, allow_empty=False, **kwargs): return compiler_output -def link_code(unlinked_data, libraries): +def link_code(unlinked_bytecode, libraries): libraries_arg = ','.join(( ':'.join((lib_name, lib_address)) for lib_name, lib_address in libraries.items() )) stdoutdata, stderrdata, _, _ = solc_wrapper( - stdin=unlinked_data, + stdin=unlinked_bytecode, link=True, libraries=libraries_arg, ) diff --git a/solcx/wrapper.py b/solcx/wrapper.py index 13abdae..55e430a 100644 --- a/solcx/wrapper.py +++ b/solcx/wrapper.py @@ -153,8 +153,8 @@ def solc_wrapper(solc_binary=None, command.extend(('--evm-version', evm_version)) if ( - standard_json is None and - source_files is None and + not standard_json and + not source_files and "v0.5" in command[0] ): command.append('-') diff --git a/tests-old/core/compilation/test_compile_empty.py b/tests-old/core/compilation/test_compile_empty.py deleted file mode 100644 index 554d176..0000000 --- a/tests-old/core/compilation/test_compile_empty.py +++ /dev/null @@ -1,23 +0,0 @@ -import os - -import pytest - -from solc import ( - compile_files, - compile_standard, -) - -from solc.exceptions import ContractsNotFound - - -def test_compile_empty_folder(): - """Execute compile on a folder without contracts.""" - - with pytest.raises(ContractsNotFound): - compile_files([]) - - -@pytest.mark.requires_standard_json -def test_compile_standard_empty_sources(): - with pytest.raises(ContractsNotFound): - compile_standard({'language': 'Solidity', 'sources': {}}) diff --git a/tests-old/core/compilation/test_compile_from_source_code.py b/tests-old/core/compilation/test_compile_from_source_code.py deleted file mode 100644 index 0a50321..0000000 --- a/tests-old/core/compilation/test_compile_from_source_code.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - -from solc import compile_source - -pytestmark = pytest.mark.usefixtures('supported_solc_version') - - -def test_source_code_compilation(FOO_SOURCE, is_new_key_format): - output = compile_source(FOO_SOURCE, optimize=True) - assert output - - if is_new_key_format: - contact_key = ':Foo' - else: - contact_key = 'Foo' - - assert contact_key in output - - foo_contract_data = output[contact_key] - assert 'bin' in foo_contract_data - assert 'bin-runtime' in foo_contract_data diff --git a/tests-old/core/compilation/test_compile_standard.py b/tests-old/core/compilation/test_compile_standard.py deleted file mode 100644 index 7cf3e4e..0000000 --- a/tests-old/core/compilation/test_compile_standard.py +++ /dev/null @@ -1,97 +0,0 @@ -import os - -import pytest - -from solc import ( - compile_standard, -) -from solc.exceptions import SolcError - -pytestmark = pytest.mark.requires_standard_json - - -def contract_in_output_map(contract_name, contract_map): - try: - return int(contract_map - ['contracts/{}.sol'.format(contract_name)] - [contract_name] - ['evm']['bytecode']['object'], 16) is not None - except: - return False - - -def test_compile_standard(FOO_SOURCE): - result = compile_standard({ - 'language': 'Solidity', - 'sources': { - 'contracts/Foo.sol': { - 'content': FOO_SOURCE, - }, - }, - 'outputSelection': { - "*": {"*": ["evm.bytecode.object"]}, - }, - }) - - assert isinstance(result, dict) - assert 'contracts' in result - assert contract_in_output_map('Foo', result['contracts']) - - -def test_compile_standard_invalid_source(INVALID_SOURCE): - with pytest.raises(SolcError): - compile_standard({ - 'language': 'Solidity', - 'sources': { - 'contracts/Foo.sol': { - 'content': INVALID_SOURCE, - }, - }, - 'outputSelection': { - "*": {"*": ["evm.bytecode.object"]}, - }, - }) - - -def test_compile_standard_with_dependency(BAR_SOURCE, BAZ_SOURCE): - result = compile_standard({ - 'language': 'Solidity', - 'sources': { - 'contracts/Bar.sol': { - 'content': BAR_SOURCE, - }, - 'contracts/Baz.sol': { - 'content': BAZ_SOURCE, - }, - }, - 'outputSelection': { - "*": {"*": ["evm.bytecode.object"]}, - }, - }) - - assert isinstance(result, dict) - assert 'contracts' in result - assert contract_in_output_map('Bar', result['contracts']) - assert contract_in_output_map('Baz', result['contracts']) - - -def test_compile_standard_with_file_paths(FOO_SOURCE, is_new_key_format, contracts_dir): - source_file_path = os.path.join(contracts_dir, 'Foo.sol') - with open(source_file_path, 'w') as source_file: - source_file.write(FOO_SOURCE) - - result = compile_standard({ - 'language': 'Solidity', - 'sources': { - 'contracts/Foo.sol': { - 'urls': [source_file_path], - }, - }, - 'outputSelection': { - "*": {"*": ["evm.bytecode.object"]}, - }, - }, allow_paths=contracts_dir) - - assert isinstance(result, dict) - assert 'contracts' in result - assert contract_in_output_map('Foo', result['contracts']) diff --git a/tests-old/core/compilation/test_compiler_from_source_file.py b/tests-old/core/compilation/test_compiler_from_source_file.py deleted file mode 100644 index ad09c42..0000000 --- a/tests-old/core/compilation/test_compiler_from_source_file.py +++ /dev/null @@ -1,32 +0,0 @@ -import pytest - -import os - -from semantic_version import Spec -from solc import ( - get_solc_version, - compile_files, -) - -pytestmark = pytest.mark.usefixtures('supported_solc_version') - - -def test_source_files_compilation(FOO_SOURCE, is_new_key_format, contracts_dir): - source_file_path = os.path.join(contracts_dir, 'Foo.sol') - with open(source_file_path, 'w') as source_file: - source_file.write(FOO_SOURCE) - - output = compile_files([source_file_path], optimize=True) - - assert output - - if is_new_key_format: - contract_key = '{0}:Foo'.format(os.path.abspath(source_file_path)) - else: - contract_key = 'Foo' - - assert contract_key in output - - foo_contract_data = output[contract_key] - assert 'bin' in foo_contract_data - assert 'bin-runtime' in foo_contract_data diff --git a/tests-old/core/compilation/test_compiler_remappings.py b/tests-old/core/compilation/test_compiler_remappings.py deleted file mode 100644 index a0c1c66..0000000 --- a/tests-old/core/compilation/test_compiler_remappings.py +++ /dev/null @@ -1,30 +0,0 @@ -import os - -from semantic_version import Spec -from solc import ( - get_solc_version, - compile_files, -) - - -def test_import_remapping(contracts_dir, is_new_key_format, BAR_SOURCE, BAZ_SOURCE): - solc_version = get_solc_version() - - source_file_path = os.path.join(contracts_dir, 'Bar.sol') - with open(source_file_path, 'w') as source_file: - source_file.write(BAR_SOURCE) - - source_file_path = os.path.join(contracts_dir, 'Baz.sol') - with open(source_file_path, 'w') as source_file: - source_file.write(BAZ_SOURCE) - - output = compile_files([source_file_path], import_remappings=["contracts={}".format(contracts_dir)]) - - assert output - - if is_new_key_format: - contact_key = '{0}:Baz'.format(os.path.abspath(source_file_path)) - else: - contact_key = 'Baz' - - assert contact_key in output diff --git a/tests/conftest.py b/tests/conftest.py index 81e95ea..2b5bfad 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +#!/usr/bin/python3 + from base64 import b64encode import os import pytest @@ -5,15 +7,6 @@ import solcx -TEST_CONTRACT = '''pragma solidity >=0.4.11 <0.6.0; - -contract Foo { - function return13() public returns (uint) { - return 13; - } -} -''' - if sys.platform == "darwin": VERSIONS = solcx.get_installed_solc_versions() else: @@ -49,13 +42,48 @@ def all_versions(request): @pytest.fixture() -def contract_path(tmp_path): - source = tmp_path.joinpath('test.sol') +def foo_source(): + yield """pragma solidity >=0.4.11; + +contract Foo { + function return13() public returns (uint) { + return 13; + } +} +""" + + +@pytest.fixture() +def bar_source(): + yield """ +pragma solidity >=0.4.11; + +import "contracts/Foo.sol"; + +contract Bar is Foo { + function getFunky() public returns (bytes4) { + return 0x420Faded; + } +}""" + + +@pytest.fixture() +def invalid_source(): + yield """pragma solidity >=0.4.11; +contract Foo {""" + + +@pytest.fixture() +def foo_path(tmp_path, foo_source): + source = tmp_path.joinpath('Foo.sol') with source.open('w') as fp: - fp.write(TEST_CONTRACT) - return str(source) + fp.write(foo_source) + return source.as_posix() @pytest.fixture() -def contract_source(): - yield TEST_CONTRACT +def bar_path(tmp_path, bar_source): + source = tmp_path.joinpath('Bar.sol') + with source.open('w') as fp: + fp.write(bar_source) + return source.as_posix() diff --git a/tests/test_compile.py b/tests/test_compile.py index 2e8e926..6affcb6 100644 --- a/tests/test_compile.py +++ b/tests/test_compile.py @@ -1,6 +1,10 @@ +#!/usr/bin/python3 + +from pathlib import Path import pytest import solcx +from solcx.exceptions import ContractsNotFound @pytest.fixture(autouse=True) @@ -8,9 +12,35 @@ def setup(all_versions): pass -def test_compile_files(contract_path): - solcx.compile_files([contract_path]) +def test_compile_source(foo_source): + output = solcx.compile_source(foo_source, optimize=True) + _compile_assertions(output, ":Foo") + + +def test_compile_source_empty(): + with pytest.raises(ContractsNotFound): + solcx.compile_source(" ") + + +def test_compile_files(foo_path): + output = solcx.compile_files([foo_path]) + _compile_assertions(output, f"{foo_path}:Foo") + + +def test_import_remapping(foo_path, bar_path): + path = Path(bar_path).parent.as_posix() + output = solcx.compile_files([bar_path], import_remappings=[f"contracts={path}"]) + assert output + assert f'{bar_path}:Bar' in output + + +def test_compile_files_empty(): + with pytest.raises(ContractsNotFound): + solcx.compile_files([]) -def test_compile_source(contract_source): - solcx.compile_source(contract_source) +def _compile_assertions(output, key): + assert output + assert key in output + assert 'bin' in output[key] + assert 'bin-runtime' in output[key] diff --git a/tests/test_compile_standard.py b/tests/test_compile_standard.py new file mode 100644 index 0000000..7bd17b4 --- /dev/null +++ b/tests/test_compile_standard.py @@ -0,0 +1,67 @@ +#!/usr/bin/python3 + +from pathlib import Path +import pytest + +import solcx +from solcx.exceptions import SolcError, ContractsNotFound + + +@pytest.fixture(autouse=True) +def setup(all_versions): + pass + + +@pytest.fixture +def input_json(): + json = { + 'language': 'Solidity', + 'sources': {}, + 'settings': { + 'outputSelection': {"*": {"*": ["evm.bytecode.object"]}} + } + } + yield json + + +def test_compile_standard(input_json, foo_source): + input_json['sources'] = {'contracts/Foo.sol': {'content': foo_source}} + result = solcx.compile_standard(input_json) + + _compile_assertions(result, "Foo") + + +def test_compile_standard_invalid_source(input_json, invalid_source): + input_json['sources'] = {'contracts/Foo.sol': {'content': invalid_source}} + with pytest.raises(SolcError): + solcx.compile_standard(input_json) + + +def test_compile_standard_with_dependency(input_json, foo_source, bar_source): + input_json['sources'] = { + 'contracts/Foo.sol': {'content': foo_source}, + 'contracts/Bar.sol': {'content': bar_source}, + } + result = solcx.compile_standard(input_json) + + _compile_assertions(result, "Foo", "Bar") + + +def test_compile_standard_with_file_paths(input_json, foo_path): + input_json['sources'] = {'contracts/Foo.sol': {'urls': [foo_path]}} + result = solcx.compile_standard(input_json, allow_paths=Path(foo_path).parent.as_posix()) + + _compile_assertions(result, "Foo") + + +def test_compile_standard_empty(): + with pytest.raises(ContractsNotFound): + solcx.compile_standard({'language': 'Solidity', 'sources': {}}) + + +def _compile_assertions(output_json, *contract_names): + assert isinstance(output_json, dict) + assert 'contracts' in output_json + contracts = output_json['contracts'] + for key in contract_names: + assert int(contracts[f'contracts/{key}.sol'][key]['evm']['bytecode']['object'], 16) diff --git a/tests/test_library_linking.py b/tests/test_library_linking.py index b7af86d..2dd9087 100644 --- a/tests/test_library_linking.py +++ b/tests/test_library_linking.py @@ -1,32 +1,56 @@ -from solcx import link_code - -CODE = "6060604052610199806100126000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806344fd4fa01461004f57806358de5f041461005e578063e7f09e051461006d5761004d565b005b61005c600480505061007c565b005b61006b60048050506100db565b005b61007a600480505061013a565b005b73__TestB_________________________________630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73__TestC_________________________________630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73__TestA_________________________________630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b56" # noqa: E501 - -TEST_A_ADDRESS = "0xd3cda913deb6f67967b99d67acdfa1712c293601" -TEST_B_ADDRESS = "0x304a554a310c7e546dfe434669c62820b7d83490" -TEST_C_ADDRESS = "0xbb9bc244d798123fde783fcc1c72d3bb8c189413" - -LINKED_CODE = "6060604052610199806100126000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806344fd4fa01461004f57806358de5f041461005e578063e7f09e051461006d5761004d565b005b61005c600480505061007c565b005b61006b60048050506100db565b005b61007a600480505061013a565b005b73304a554a310c7e546dfe434669c62820b7d83490630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73bb9bc244d798123fde783fcc1c72d3bb8c189413630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73d3cda913deb6f67967b99d67acdfa1712c293601630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b56" # noqa: E501 - - -def test_partial_code_linking(all_versions): - output = link_code(CODE, {'TestA': TEST_A_ADDRESS}) - assert '__TestA__' not in output - assert '__TestB__' in output - assert '__TestC__' in output - assert TEST_A_ADDRESS[2:] in output - - -def test_full_code_linking(all_versions): - output = link_code(CODE, { - 'TestA': TEST_A_ADDRESS, - 'TestB': TEST_B_ADDRESS, - 'TestC': TEST_C_ADDRESS, - }) - assert '__TestA__' not in output - assert '__TestB__' not in output - assert '__TestC__' not in output - assert TEST_A_ADDRESS[2:] in output - assert TEST_B_ADDRESS[2:] in output - assert TEST_C_ADDRESS[2:] in output - assert output == LINKED_CODE +#!/usr/bin/python3 + +import pytest + +import solcx + +source = """pragma solidity >=0.4.11; +library UnlinkedLib { + function linkMethod(uint _value, uint _multiplier) public returns (uint) { + return _value * _multiplier; + } +} + +library OtherUnlinkedLib { + function otherLinkMethod(uint _value, uint _multiplier) public returns (uint) { + return _value * _multiplier; + } +} + +contract LinkTester { + function testLibraryLinks(uint amount, uint multiple) external returns (uint) { + uint a = UnlinkedLib.linkMethod(amount, multiple); + return OtherUnlinkedLib.otherLinkMethod(a, multiple); + } +}""" + +addr1 = "0x1234567890123456789012345678901234567890" +addr2 = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + + +@pytest.fixture +def bytecode(): + yield solcx.compile_source(source)[':LinkTester']['bin'] + + +def test_partial_link(all_versions, bytecode): + assert '_' in bytecode + assert addr1[2:] not in bytecode + output = solcx.link_code(bytecode, {':UnlinkedLib': addr1}) + assert output != bytecode + assert '_' in output + assert addr1[2:] in output + + +def test_full_link(all_versions, bytecode): + assert '_' in bytecode + assert addr1[2:] not in bytecode + assert addr2[2:] not in bytecode + output = solcx.link_code( + bytecode, + {':UnlinkedLib': addr1, ':OtherUnlinkedLib': addr2} + ) + assert output != bytecode + assert '_' not in output + assert addr1[2:] in output + assert addr2[2:] in output diff --git a/tests/test_solc_version.py b/tests/test_solc_version.py index 5ebfcbe..de77cab 100644 --- a/tests/test_solc_version.py +++ b/tests/test_solc_version.py @@ -1,13 +1,24 @@ +#!/usr/bin/python3 + import solcx -import semantic_version +from semantic_version import Version + + +def test_solc_supports_standard_json_interface(monkeypatch): + monkeypatch.setattr('solcx.main.get_solc_version', lambda: Version("0.5.0")) + assert solcx.main.solc_supports_standard_json_interface() + monkeypatch.setattr('solcx.main.get_solc_version', lambda: Version("0.4.11")) + assert solcx.main.solc_supports_standard_json_interface() + monkeypatch.setattr('solcx.main.get_solc_version', lambda: Version("0.4.10")) + assert not solcx.main.solc_supports_standard_json_interface() def test_get_solc_version(all_versions): - version = solcx.get_solc_version() - assert isinstance(version, semantic_version.Version) + v = solcx.get_solc_version() + assert isinstance(v, Version) def test_get_solc_version_string(all_versions): - version = solcx.get_solc_version_string() - assert isinstance(version, str) + v = solcx.get_solc_version_string() + assert isinstance(v, str)