from typing import Any, Dict from unittest import mock from unittest.mock import MagicMock from toot import User, cli from tests.integration.conftest import Run # TODO: figure out how to test login EMPTY_CONFIG: Dict[Any, Any] = { "apps": {}, "users": {}, "active_user": None } SAMPLE_CONFIG = { "active_user": "frank@foo.social", "apps": { "foo.social": { "base_url": "http://foo.social", "client_id": "123", "client_secret": "123", "instance": "foo.social" }, "bar.social": { "base_url": "http://bar.social", "client_id": "123", "client_secret": "123", "instance": "bar.social" }, }, "users": { "frank@foo.social": { "access_token": "123", "instance": "foo.social", "username": "frank" }, "frank@bar.social": { "access_token": "123", "instance": "bar.social", "username": "frank" }, } } def test_env(run: Run): result = run(cli.auth.env) assert result.exit_code == 0 assert "toot" in result.stdout assert "Python" in result.stdout @mock.patch("toot.config.load_config") def test_auth_empty(load_config: MagicMock, run: Run): load_config.return_value = EMPTY_CONFIG result = run(cli.auth.auth) assert result.exit_code == 0 assert result.stdout.strip() == "You are not logged in to any accounts" @mock.patch("toot.config.load_config") def test_auth_full(load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.auth) assert result.exit_code == 0 assert result.stdout.strip().startswith("Authenticated accounts:") assert "frank@foo.social" in result.stdout assert "frank@bar.social" in result.stdout # Saving config is mocked so we don't mess up our local config # TODO: could this be implemented using an auto-use fixture so we have it always # mocked? @mock.patch("toot.config.load_app") @mock.patch("toot.config.save_app") @mock.patch("toot.config.save_user") def test_login_cli( save_user: MagicMock, save_app: MagicMock, load_app: MagicMock, user: User, run: Run, ): load_app.return_value = None result = run( cli.auth.login_cli, "--instance", "http://localhost:3000", "--email", f"{user.username}@example.com", "--password", "password", ) assert result.exit_code == 0 assert "✓ Successfully logged in." in result.stdout save_app.assert_called_once() (app,) = save_app.call_args.args assert app.instance == "localhost:3000" assert app.base_url == "http://localhost:3000" assert app.client_id assert app.client_secret save_user.assert_called_once() (new_user,) = save_user.call_args.args assert new_user.instance == "localhost:3000" assert new_user.username == user.username # access token will be different since this is a new login assert new_user.access_token and new_user.access_token != user.access_token assert save_user.call_args.kwargs == {"activate": True} @mock.patch("toot.config.load_app") @mock.patch("toot.config.save_app") @mock.patch("toot.config.save_user") def test_login_cli_wrong_password( save_user: MagicMock, save_app: MagicMock, load_app: MagicMock, user: User, run: Run, ): load_app.return_value = None result = run( cli.auth.login_cli, "--instance", "http://localhost:3000", "--email", f"{user.username}@example.com", "--password", "wrong password", ) assert result.exit_code == 1 assert result.stderr.strip() == "Error: Login failed" save_app.assert_called_once() (app,) = save_app.call_args.args assert app.instance == "localhost:3000" assert app.base_url == "http://localhost:3000" assert app.client_id assert app.client_secret save_user.assert_not_called() @mock.patch("toot.config.load_config") @mock.patch("toot.config.delete_user") def test_logout(delete_user: MagicMock, load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.logout, "frank@foo.social") assert result.exit_code == 0 assert result.stdout.strip() == "✓ Account frank@foo.social logged out" delete_user.assert_called_once_with(User("foo.social", "frank", "123")) @mock.patch("toot.config.load_config") def test_logout_not_logged_in(load_config: MagicMock, run: Run): load_config.return_value = EMPTY_CONFIG result = run(cli.auth.logout) assert result.exit_code == 1 assert result.stderr.strip() == "Error: You're not logged into any accounts" @mock.patch("toot.config.load_config") def test_logout_account_not_specified(load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.logout) assert result.exit_code == 1 assert result.stderr.startswith("Error: Specify account to log out") @mock.patch("toot.config.load_config") def test_logout_account_does_not_exist(load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.logout, "banana") assert result.exit_code == 1 assert result.stderr.startswith("Error: Account not found") @mock.patch("toot.config.load_config") @mock.patch("toot.config.activate_user") def test_activate(activate_user: MagicMock, load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.activate, "frank@foo.social") assert result.exit_code == 0 assert result.stdout.strip() == "✓ Account frank@foo.social activated" activate_user.assert_called_once_with(User("foo.social", "frank", "123")) @mock.patch("toot.config.load_config") def test_activate_not_logged_in(load_config: MagicMock, run: Run): load_config.return_value = EMPTY_CONFIG result = run(cli.auth.activate) assert result.exit_code == 1 assert result.stderr.strip() == "Error: You're not logged into any accounts" @mock.patch("toot.config.load_config") def test_activate_account_not_given(load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.activate) assert result.exit_code == 1 assert result.stderr.startswith("Error: Specify account to activate") @mock.patch("toot.config.load_config") def test_activate_invalid_Account(load_config: MagicMock, run: Run): load_config.return_value = SAMPLE_CONFIG result = run(cli.auth.activate, "banana") assert result.exit_code == 1 assert result.stderr.startswith("Error: Account not found")