Skip to content

Commit

Permalink
fix: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Sep 11, 2024
1 parent 8859c16 commit f6d2dc8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 27 deletions.
34 changes: 21 additions & 13 deletions src/ape/pytest/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,27 +253,35 @@ def pytest_unconfigure(self):
def _insert_isolation_fixtures(item):
# Abstracted for testing purposes.
fixture_map = item.session._fixturemanager._arg2fixturedefs
scopes = {
definition.scope
scope_map = {
name: definition.scope
for name, definitions in fixture_map.items()
if name in item.fixturenames
for definition in definitions
}
scopes = [scope_map[n] for n in item.fixturenames if n in scope_map]

# NOTE: The order of this loop is very important!
# The order of the fixurenames determines the order they run.
for scope in ("session", "package", "module", "class"):
# iterate through scope levels and insert the isolation fixture
# prior to the first fixture with that scope
if scope not in scopes:
try:
index = scopes.index(scope)
except ValueError:
# Intermediate scope isolations aren't filled in
continue

# For non-function scoped isolation, the fixtures
# must go after the last fixture with that scope
# to ensure contracts deployed in fixtures persist.
name = f"_{scope}_isolation"

# Don't let isolation fixtures get added more than once!
if name not in item.fixturenames:
item.fixturenames.append(name)
item.fixturenames.insert(index, f"_{scope}_isolation")

# This line is needed to fix the calculation on subsequent checks
scopes.insert(index, scope)

# Function-isolation must go last.

# insert function isolation by default
if "_function_isolation" not in item.fixturenames:
item.fixturenames.append("_function_isolation")
try:
item.fixturenames.insert(scopes.index("function"), "_function_isolation")
except ValueError:
# No fixtures with function scope, so append function isolation.
item.fixturenames.insert(0, "_function_isolation")
17 changes: 8 additions & 9 deletions tests/functional/test_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,23 @@ def _create_fixture_entry(name: str, scope: str):
"fixture_at_module": [_create_fixture_entry("fixture_at_module", "module")],
"fixture_at_class": [_create_fixture_entry("fixture_at_class", "class")],
"other_random_fixture": [_create_fixture_entry("other_random_fixture", "function")],
# Show case where fixture is already present.
"_class_isolation": [_create_fixture_entry("_class_isolation", "class")],
"_function_isolation": [_create_fixture_entry("_function_isolation", "function")],
}

mock_item.session._fixturemanager._arg2fixturedefs = fixtures
mock_item.fixturenames = [*list(fixtures.keys()), "otheriteminnames"]
_insert_isolation_fixtures(mock_item)
actual_fixturenames = sorted(mock_item.fixturenames)
actual_fixturenames = mock_item.fixturenames

# NOTE: The order of this list is VERY IMPORTANT!
expected_fixturenames = [
"_class_isolation",
"_function_isolation",
"_module_isolation",
"_session_isolation",
"fixture_at_class",
"fixture_at_function",
"fixture_at_module",
"_session_isolation",
"fixture_at_session",
"_module_isolation",
"fixture_at_module",
"_class_isolation",
"fixture_at_class",
"other_random_fixture",
"otheriteminnames",
]
Expand Down
11 changes: 11 additions & 0 deletions tests/integration/cli/projects/test/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import pytest


@pytest.fixture(scope="session")
def session_one(chain):
chain.mine(4)


@pytest.fixture(scope="session")
def session_two(chain):
chain.mine(2)
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import pytest

INITIAL_BALANCE = 1_000_1 * 10**18

@pytest.fixture(scope="module", autouse=True)
def module_one(chain):
chain.mine(3)


@pytest.fixture(scope="session")
Expand All @@ -27,12 +30,39 @@ def start_block_number(chain):
return chain.blocks.height


@pytest.fixture(scope="function")
def function_one(chain):
chain.mine(1)


def test_isolation_first(alice, bob, chain, start_block_number):
assert chain.provider.get_block("latest").number == start_block_number
assert bob.balance == INITIAL_BALANCE
alice.transfer(bob, "1 ether")


def test_isolation_second(bob, chain, start_block_number):
assert chain.provider.get_block("latest").number == start_block_number
assert bob.balance == INITIAL_BALANCE
#
# def test_isolation_second(bob, chain, start_block_number):
# assert chain.provider.get_block("latest").number == start_block_number
# assert bob.balance == INITIAL_BALANCE


def test_isolation_with_session_module_and_function(chain, session_one, session_two, function_one):
"""
The sessions should be used, so that is 6.
Function is 1 and the module 3.
Also, setup does a transfer - that bumps up another 1.
Expected is 11.
"""
# NOTE: Module is on autouse=True
assert chain.blocks.height == 11


def test_isolation_module_ran_after(chain):
"""
This test runs after the test above.
We should be back at the beginning of the state after
the session and module function but before the function.
Expected = sessions + module = 4 + 2 + 3 + 1 (from setup) = 10
"""
assert chain.blocks.height == 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def test_session(chain, session_one, session_two):
"""
`session_one` mines 4 and `session_two` mines 2,
so we expected 6.
"""
assert chain.blocks.height == 6


def test_session2(chain):
"""
Session isolation doesn't revert other session fixtures,
so we are still at 6.
"""
assert chain.blocks.height == 6
2 changes: 1 addition & 1 deletion tests/integration/cli/test_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def test_show_internal(setup_pytester, integ_project, pytester, eth_tester_provi


@skip_projects_except("test", "with-contracts")
def test_test_isolation_disabled(setup_pytester, integ_project, pytester, eth_tester_provider):
def test_isolation_disabled(setup_pytester, integ_project, pytester, eth_tester_provider):
# check the disable isolation option actually disables built-in isolation
_ = eth_tester_provider # Ensure using EthTester for this test.
setup_pytester(integ_project)
Expand Down

0 comments on commit f6d2dc8

Please sign in to comment.