Skip to content

Commit

Permalink
feat: implement tests for install command
Browse files Browse the repository at this point in the history
- add tests for install command
- add tests for impacted commands
    - run
    - test
    - deploy
    - compile
- using helper utility to handle moccasin toml scenarios
- add auto-install lib/github and lib/pypi folders when install (fix issue Cyfrin#209)
- fix issues with tests using COMPLEX_PROJECT path and not temporary one
- update test constants

WARNING: just test-z and live test KO since anvil-zksync is not installed (reported Cyfrin#216)
  • Loading branch information
s3bc40 committed Feb 25, 2025
1 parent 9c7eb0f commit 0fdc12b
Show file tree
Hide file tree
Showing 11 changed files with 882 additions and 38 deletions.
9 changes: 9 additions & 0 deletions moccasin/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,16 @@ def mox_install(
github_requirements.append(requirement)
else:
pip_requirements.append(requirement)

# Get dependencies install path and create it if it doesn't exist
# @dev allows to avoid vyper compiler error when missing one dir
install_path: Path = config.get_base_dependencies_install_path()
install_path.joinpath(PYPI).mkdir(exist_ok=True, parents=True)
install_path.joinpath(GITHUB).mkdir(exist_ok=True, parents=True)

# @dev in case of fresh install, dependencies might be ordered differently
# since we install pip packages first and github packages later
# @dev see _dependency_utils._write_new_dependencies
if len(pip_requirements) > 0:
_pip_installs(
pip_requirements, install_path.joinpath(PYPI), quiet, override_logger
Expand Down
139 changes: 131 additions & 8 deletions tests/cli/test_cli_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,52 @@
import subprocess
from pathlib import Path

import pytest
import tomli_w
from packaging.requirements import Requirement

from moccasin.config import Config
from tests.constants import (
LIB_GH_PATH,
LIB_PIP_PATH,
MOCCASIN_LIB_NAME,
MOCCASIN_TOML,
PIP_PACKAGE_NAME,
VERSION,
)
from tests.utils.helpers import (
get_temp_versions_toml_gh,
rewrite_temp_moccasin_toml_dependencies,
)

EXPECTED_HELP_TEXT = "Vyper compiler"


def test_compile_help(mox_path):
result = subprocess.run(
[mox_path, "compile", "-h"], check=True, capture_output=True, text=True
)
assert (
EXPECTED_HELP_TEXT in result.stdout
), "Help output does not contain expected text"
assert EXPECTED_HELP_TEXT in result.stdout, (
"Help output does not contain expected text"
)
assert result.returncode == 0


def test_build_help(mox_path):
result = subprocess.run(
[mox_path, "build", "-h"], check=True, capture_output=True, text=True
)
assert (
EXPECTED_HELP_TEXT in result.stdout
), "Help output does not contain expected text"
assert EXPECTED_HELP_TEXT in result.stdout, (
"Help output does not contain expected text"
)
assert result.returncode == 0


def test_compile_alias_build_project(
complex_temp_path, complex_cleanup_out_folder, mox_path
complex_temp_path,
complex_cleanup_out_folder,
complex_cleanup_dependencies_folder,
mox_path,
):
current_dir = Path.cwd()
try:
Expand All @@ -36,7 +57,22 @@ def test_compile_alias_build_project(
)
finally:
os.chdir(current_dir)
# Count the number of contracts in the contracts/ directory
# @dev avoid interfaces folder
contract_dir = complex_temp_path.joinpath("contracts")
contract_count = sum(
[
len(files)
for root, _, files in os.walk(contract_dir)
if "interfaces" not in root
]
)

assert complex_temp_path.joinpath().exists()

assert "Running compile command" in result.stderr
assert f"Compiling {contract_count} contracts to build/..." in result.stderr
assert "Done compiling project!" in result.stderr
assert result.returncode == 0


Expand All @@ -45,12 +81,99 @@ def test_compile_one(complex_temp_path, complex_cleanup_out_folder, mox_path):
try:
os.chdir(current_dir.joinpath(complex_temp_path))
result = subprocess.run(
[mox_path, "build", "BuyMeACoffee.vy"],
[mox_path, "build", "BuyMeACoffee.vy", "--no-install"],
check=True,
capture_output=True,
text=True,
)
finally:
os.chdir(current_dir)

assert not complex_temp_path.joinpath(LIB_GH_PATH).exists()
assert not complex_temp_path.joinpath(LIB_PIP_PATH).exists()
assert "Done compiling BuyMeACoffee" in result.stderr
assert result.returncode == 0


# @dev test adapted to the ordering of dependencies
@pytest.mark.parametrize(
"cli_args, rewrite_dependencies, expected_lib_path, expected_pip_deps, expected_gh_deps, expected_gh_versions",
[
# --no-install should skip package installation
(["BuyMeACoffee.vy", "--no-install"], [], False, ["snekmate==0.1.0"], [], None),
# Default behavior - installs dependencies
(
["BuyMeACoffee.vy"],
[
"PatrickAlphaC/test_repo",
f"{PIP_PACKAGE_NAME}>={VERSION}",
f"{MOCCASIN_LIB_NAME}==0.3.6",
],
True,
[f"{PIP_PACKAGE_NAME}>={VERSION}", f"{MOCCASIN_LIB_NAME}==0.3.6"],
["PatrickAlphaC/test_repo"],
{"patrickalphac/test_repo": "0.1.1"},
),
# Change compiled file
(["MyTokenPyPI.vy"], [], True, ["snekmate==0.1.0"], [], None),
],
)
def test_compile_with_flags(
complex_temp_path,
complex_cleanup_out_folder,
complex_cleanup_dependencies_folder,
mox_path,
cli_args,
rewrite_dependencies,
expected_lib_path,
expected_pip_deps,
expected_gh_deps,
expected_gh_versions,
):
current_dir = Path.cwd()
old_moccasin_toml = rewrite_temp_moccasin_toml_dependencies(
complex_temp_path, rewrite_dependencies
)

try:
os.chdir(current_dir.joinpath(complex_temp_path))
base_args = [mox_path, "build"]
result = subprocess.run(
base_args + cli_args, check=True, capture_output=True, text=True
)
finally:
os.chdir(current_dir)

assert complex_temp_path.joinpath(MOCCASIN_TOML).exists()

gh_dir_path = complex_temp_path.joinpath(LIB_GH_PATH)
pip_dir_path = complex_temp_path.joinpath(LIB_PIP_PATH)
assert gh_dir_path.exists() == expected_lib_path
assert pip_dir_path.exists() == expected_lib_path

for dep in expected_pip_deps:
pip_requirement = Requirement(dep)
assert pip_dir_path.joinpath(pip_requirement.name).exists() == expected_lib_path
if expected_gh_deps:
for dep in expected_gh_deps:
assert (
gh_dir_path.joinpath(dep.lower().split("@")[0]).exists()
== expected_lib_path
)

# Verify config state if versions are expected
project_root: Path = Config.find_project_root(complex_temp_path)
config = Config(project_root)
assert config.dependencies == expected_pip_deps + expected_gh_deps

# Verify gh versions file contents
if expected_gh_versions:
github_versions = get_temp_versions_toml_gh(complex_temp_path)
assert github_versions == expected_gh_versions

assert f"Done compiling {cli_args[0].replace('.vy', '')}" in result.stderr
assert result.returncode == 0

# Reset toml to the original for next test
with open(complex_temp_path.joinpath(MOCCASIN_TOML), "wb") as f:
tomli_w.dump(old_moccasin_toml, f)
103 changes: 102 additions & 1 deletion tests/cli/test_cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
import subprocess
from pathlib import Path

import pytest
import tomli_w
from packaging.requirements import Requirement

from moccasin.config import Config
from tests.constants import (
LIB_GH_PATH,
LIB_PIP_PATH,
MOCCASIN_LIB_NAME,
MOCCASIN_TOML,
PIP_PACKAGE_NAME,
VERSION,
)
from tests.utils.helpers import (
get_temp_versions_toml_gh,
rewrite_temp_moccasin_toml_dependencies,
)


# --------------------------------------------------------------
# WITHOUT ANVIL
Expand All @@ -11,7 +29,7 @@ def test_deploy_price_feed_pyevm(mox_path, complex_temp_path, complex_project_co
try:
os.chdir(complex_temp_path)
result = subprocess.run(
[mox_path, "deploy", "price_feed"],
[mox_path, "deploy", "price_feed", "--no-install"],
check=True,
capture_output=True,
text=True,
Expand All @@ -21,6 +39,89 @@ def test_deploy_price_feed_pyevm(mox_path, complex_temp_path, complex_project_co
assert "Deployed contract price_feed on pyevm to" in result.stderr


# @dev test adapted to the ordering of dependencies
@pytest.mark.parametrize(
"cli_args, rewrite_dependencies, expected_lib_path, expected_pip_deps, expected_gh_deps, expected_gh_versions",
[
# --no-install should skip package installation
(["price_feed", "--no-install"], [], False, ["snekmate==0.1.0"], [], None),
# Default behavior - installs dependencies
(
["price_feed"],
[
"PatrickAlphaC/test_repo",
f"{PIP_PACKAGE_NAME}>={VERSION}",
f"{MOCCASIN_LIB_NAME}==0.3.6",
],
True,
[f"{PIP_PACKAGE_NAME}>={VERSION}", f"{MOCCASIN_LIB_NAME}==0.3.6"],
["PatrickAlphaC/test_repo"],
{"patrickalphac/test_repo": "0.1.1"},
),
# Change compiled file
(["price_feed"], [], True, ["snekmate==0.1.0"], [], None),
],
)
def test_deploy_price_feed_pyevm_with_flags(
complex_temp_path,
complex_cleanup_out_folder,
complex_cleanup_dependencies_folder,
mox_path,
cli_args,
rewrite_dependencies,
expected_lib_path,
expected_pip_deps,
expected_gh_deps,
expected_gh_versions,
):
current_dir = Path.cwd()
old_moccasin_toml = rewrite_temp_moccasin_toml_dependencies(
complex_temp_path, rewrite_dependencies
)

try:
os.chdir(current_dir.joinpath(complex_temp_path))
base_args = [mox_path, "deploy"]
result = subprocess.run(
base_args + cli_args, check=True, capture_output=True, text=True
)
finally:
os.chdir(current_dir)

assert complex_temp_path.joinpath(MOCCASIN_TOML).exists()

gh_dir_path = complex_temp_path.joinpath(LIB_GH_PATH)
pip_dir_path = complex_temp_path.joinpath(LIB_PIP_PATH)
assert gh_dir_path.exists() == expected_lib_path
assert pip_dir_path.exists() == expected_lib_path

for dep in expected_pip_deps:
pip_requirement = Requirement(dep)
assert pip_dir_path.joinpath(pip_requirement.name).exists() == expected_lib_path
if expected_gh_deps:
for dep in expected_gh_deps:
assert (
gh_dir_path.joinpath(dep.lower().split("@")[0]).exists()
== expected_lib_path
)

# Verify config state if versions are expected
project_root: Path = Config.find_project_root(complex_temp_path)
config = Config(project_root)
assert config.dependencies == expected_pip_deps + expected_gh_deps

# Verify gh versions file contents
if expected_gh_versions:
github_versions = get_temp_versions_toml_gh(complex_temp_path)
assert github_versions == expected_gh_versions

assert "Deployed contract price_feed on pyevm to" in result.stderr

# Reset toml to the original for next test
with open(complex_temp_path.joinpath(MOCCASIN_TOML), "wb") as f:
tomli_w.dump(old_moccasin_toml, f)


# --------------------------------------------------------------
# WITH ANVIL
# --------------------------------------------------------------
Expand Down
Loading

0 comments on commit 0fdc12b

Please sign in to comment.