Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions slither/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
logging.basicConfig()
logger = logging.getLogger("Slither")

DEFAULT_EXCLUDE_TEST_PATHS = r"(?i)(^|/)(tests?|mocks?)(/|$)|(^|/)(test|mock)[^/]*\.sol$"


###################################################################################
###################################################################################
Expand Down Expand Up @@ -315,6 +317,16 @@ def parse_filter_paths(args: argparse.Namespace, filter_path: bool) -> list[str]
return []


def apply_exclude_test_filter(args: argparse.Namespace) -> None:
if not args.exclude_test:
return

if args.include_paths:
raise ValueError("Error: --exclude-test cannot be used with --include-paths")

args.filter_paths.append(DEFAULT_EXCLUDE_TEST_PATHS)


def parse_args(
detector_classes: list[type[AbstractDetector]],
printer_classes: list[type[AbstractPrinter]],
Expand Down Expand Up @@ -442,6 +454,13 @@ def parse_args(
default=defaults_flag_in_config["exclude_high"],
)

group_detector.add_argument(
"--exclude-test",
help="Exclude detector results matching test or mock file paths",
action="store_true",
default=defaults_flag_in_config["exclude_test"],
)

group_detector.add_argument(
"--exclude-location",
help="Exclude file location (filename and lines) from detector messages",
Expand Down Expand Up @@ -718,6 +737,7 @@ def parse_args(

args.filter_paths = parse_filter_paths(args, True)
args.include_paths = parse_filter_paths(args, False)
apply_exclude_test_filter(args)

# Verify our json-type output is valid
args.json_types = set(args.json_types.split(",")) # type:ignore
Expand Down
1 change: 1 addition & 0 deletions slither/utils/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class FailOnLevel(enum.Enum):
"exclude_low": False,
"exclude_medium": False,
"exclude_high": False,
"exclude_test": False,
"exclude_location": False,
"fail_on": FailOnLevel.PEDANTIC,
"json": None,
Expand Down
56 changes: 56 additions & 0 deletions tests/unit/utils/test_command_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from argparse import Namespace
import re

import pytest

from slither.__main__ import DEFAULT_EXCLUDE_TEST_PATHS, apply_exclude_test_filter


def test_apply_exclude_test_filter_adds_default_pattern():
args = Namespace(exclude_test=True, filter_paths=[], include_paths=[])

apply_exclude_test_filter(args)

assert args.filter_paths == [DEFAULT_EXCLUDE_TEST_PATHS]


def test_apply_exclude_test_filter_preserves_existing_filters():
args = Namespace(exclude_test=True, filter_paths=["vendor"], include_paths=[])

apply_exclude_test_filter(args)

assert args.filter_paths == ["vendor", DEFAULT_EXCLUDE_TEST_PATHS]


def test_apply_exclude_test_filter_rejects_include_paths():
args = Namespace(exclude_test=True, filter_paths=[], include_paths=["contracts"])

with pytest.raises(ValueError, match="--exclude-test cannot be used with --include-paths"):
apply_exclude_test_filter(args)


def test_apply_exclude_test_filter_noops_when_disabled():
args = Namespace(exclude_test=False, filter_paths=["vendor"], include_paths=[])

apply_exclude_test_filter(args)

assert args.filter_paths == ["vendor"]


@pytest.mark.parametrize(
"path",
[
"/repo/test/Token.sol",
"/repo/tests/Token.sol",
"/repo/mock/Token.sol",
"/repo/mocks/Token.sol",
"/repo/contracts/TestToken.sol",
"/repo/contracts/MockToken.sol",
],
)
def test_exclude_test_default_pattern_matches_test_and_mock_paths(path):
assert re.search(DEFAULT_EXCLUDE_TEST_PATHS, path)


def test_exclude_test_default_pattern_keeps_regular_contract_paths():
assert not re.search(DEFAULT_EXCLUDE_TEST_PATHS, "/repo/contracts/Token.sol")