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
32 changes: 32 additions & 0 deletions patch.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<<<<<<< SEARCH
@patch("builtins.__import__", side_effect=ImportError)
def test_run_demo_no_torch(mock_import, capsys):
"""Test running the demo when torch is not installed."""
# We only want to mock torch import, let others pass
original_import = __import__
def side_effect(name, *args, **kwargs):
if name == "torch":
raise ImportError("No module named 'torch'")
return original_import(name, *args, **kwargs)

mock_import.side_effect = side_effect

args = MagicMock()
args.model = "mlp"

assert run_demo(args) == 1

out, err = capsys.readouterr()
assert "[ERROR] PyTorch is required for demo" in out
=======
def test_run_demo_no_torch(capsys):
"""Test running the demo when torch is not installed."""
args = MagicMock()
args.model = "mlp"

with patch.dict("sys.modules", {"torch": None}):
assert run_demo(args) == 1

out, err = capsys.readouterr()
assert "[ERROR] PyTorch is required for demo" in out
>>>>>>> REPLACE
195 changes: 195 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
"""Tests for the command-line interface."""

import sys
from unittest.mock import MagicMock, patch

import pytest

from neuroscope.cli import main, run_demo, run_server, show_version


@pytest.fixture
def mock_argv(monkeypatch):
"""Fixture to easily mock sys.argv."""
def _mock(*args):
monkeypatch.setattr(sys, "argv", ["neuroscope", *args])
return _mock


def test_main_no_args(mock_argv, capsys):
"""Test that main with no args prints help and returns 0."""
mock_argv()

# We need to mock parser.print_help since argparse's default behavior
# might differ slightly, but we can just let it print and capture it.
with patch("argparse.ArgumentParser.print_help") as mock_print_help:
assert main() == 0
mock_print_help.assert_called_once()


@patch("neuroscope.cli.run_server")
def test_main_server_command(mock_run_server, mock_argv):
"""Test routing to server command."""
mock_run_server.return_value = 0
mock_argv("server", "--port", "9000", "--host", "0.0.0.0", "--no-browser")

assert main() == 0

mock_run_server.assert_called_once()
args = mock_run_server.call_args[0][0]
assert args.port == 9000
assert args.host == "0.0.0.0"
assert args.no_browser is True


@patch("neuroscope.cli.run_demo")
def test_main_demo_command(mock_run_demo, mock_argv):
"""Test routing to demo command."""
mock_run_demo.return_value = 0
mock_argv("demo", "--model", "cnn")

assert main() == 0

mock_run_demo.assert_called_once()
args = mock_run_demo.call_args[0][0]
assert args.model == "cnn"


@patch("neuroscope.cli.show_version")
def test_main_version_command(mock_show_version, mock_argv):
"""Test routing to version command."""
mock_show_version.return_value = 0
mock_argv("version")

assert main() == 0
mock_show_version.assert_called_once()


@patch("neuroscope.core.server.NeuroScopeServer")
@patch("time.sleep", side_effect=KeyboardInterrupt)
def test_run_server_normal(mock_sleep, mock_server_cls, capsys):
"""Test running the server with normal shutdown."""
# Setup mock server
mock_server = MagicMock()
mock_server_cls.return_value = mock_server

# Setup args
args = MagicMock()
args.host = "localhost"
args.port = 8765
args.no_browser = False

assert run_server(args) == 0

mock_server_cls.assert_called_once_with(host="localhost", port=8765)
mock_server.start.assert_called_once_with(open_browser=True)
mock_server.stop.assert_called_once()

out, err = capsys.readouterr()
assert "Starting server..." in out
assert "Shutting down..." in out


def test_show_version(capsys):
"""Test the version display."""
from neuroscope import __version__
assert show_version() == 0
out, err = capsys.readouterr()
assert f"NeuroScope {__version__}" in out


@patch("neuroscope.cli.run_server")
def test_main_server_default_args(mock_run_server, mock_argv):
"""Test routing to server command with default arguments."""
mock_run_server.return_value = 0
mock_argv("server")

assert main() == 0

mock_run_server.assert_called_once()
args = mock_run_server.call_args[0][0]
assert args.port == 8765
assert args.host == "localhost"
assert args.no_browser is False


@patch("neuroscope.cli.run_demo")
def test_main_demo_default_args(mock_run_demo, mock_argv):
"""Test routing to demo command with default arguments."""
mock_run_demo.return_value = 0
mock_argv("demo")

assert main() == 0

mock_run_demo.assert_called_once()
args = mock_run_demo.call_args[0][0]
assert args.model == "mlp"


@patch("neuroscope.attach")
@patch("neuroscope.start_server")
@patch("neuroscope.detach")
@patch("neuroscope.stop_server")
@patch("time.sleep", side_effect=KeyboardInterrupt)
def test_run_demo_mlp(mock_sleep, mock_stop, mock_detach, mock_start, mock_attach, capsys):
"""Test running the demo with mlp model."""
args = MagicMock()
args.model = "mlp"

assert run_demo(args) == 0

mock_attach.assert_called_once()
mock_start.assert_called_once()
mock_detach.assert_called_once()
mock_stop.assert_called_once()

out, err = capsys.readouterr()
assert "Creating mlp model..." in out
assert "Attaching tracer..." in out
assert "Running forward pass..." in out


@patch("neuroscope.attach")
@patch("neuroscope.start_server")
@patch("neuroscope.detach")
@patch("neuroscope.stop_server")
@patch("time.sleep", side_effect=KeyboardInterrupt)
def test_run_demo_cnn(mock_sleep, mock_stop, mock_detach, mock_start, mock_attach, capsys):
"""Test running the demo with cnn model."""
args = MagicMock()
args.model = "cnn"

assert run_demo(args) == 0

mock_attach.assert_called_once()
out, err = capsys.readouterr()
assert "Creating cnn model..." in out


@patch("neuroscope.attach")
@patch("neuroscope.start_server")
@patch("neuroscope.detach")
@patch("neuroscope.stop_server")
@patch("time.sleep", side_effect=KeyboardInterrupt)
def test_run_demo_transformer(mock_sleep, mock_stop, mock_detach, mock_start, mock_attach, capsys):
"""Test running the demo with transformer model."""
args = MagicMock()
args.model = "transformer"

assert run_demo(args) == 0

mock_attach.assert_called_once()
out, err = capsys.readouterr()
assert "Creating transformer model..." in out


def test_run_demo_no_torch(capsys):
"""Test running the demo when torch is not installed."""
args = MagicMock()
args.model = "mlp"

with patch.dict("sys.modules", {"torch": None}):
assert run_demo(args) == 1

out, err = capsys.readouterr()
assert "[ERROR] PyTorch is required for demo" in out