Back to Repositories

Testing Bash Shell Integration Workflows in TheFuck

This test suite validates the bash shell integration functionality of TheFuck command-line tool, focusing on command correction behaviors and user interaction modes. It verifies both Python 2 and Python 3 compatibility along with instant mode features.

Test Coverage Overview

The test suite provides comprehensive coverage of TheFuck’s bash shell integration, including command confirmation flows, arrow key navigation, and history management.

Key areas tested include:
  • Command confirmation workflows
  • Arrow-based command selection
  • History modification verification
  • Instant mode functionality
  • Cross-Python version compatibility

Implementation Analysis

The implementation utilizes pytest’s parametrized fixtures to test multiple Python environments and configuration modes. The testing approach employs spawned processes to simulate real shell interactions, with explicit timeout handling and state verification.

Notable patterns include:
  • Fixture parametrization for environment variants
  • Process spawning for shell simulation
  • State verification through history checks
  • Modular test function organization

Technical Details

Testing infrastructure includes:
  • Pytest framework with functional markers
  • Docker containers for Python 2 and 3 environments
  • Custom spawnu utility for process management
  • Bash environment configuration
  • Timeout handling mechanisms
  • History file manipulation

Best Practices Demonstrated

The test suite exemplifies several testing best practices for command-line tools. It maintains isolation between tests, handles environment setup systematically, and verifies both positive and negative scenarios.

Key practices include:
  • Isolated test environments
  • Comprehensive environment setup
  • Clear test case organization
  • Explicit state verification
  • Cross-version compatibility testing

nvbn/thefuck

tests/functional/test_bash.py

            
import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
    refuse_with_confirmation, history_changed, history_not_changed, \
    select_command_with_arrows, how_to_configure


python_3 = (u'thefuck/python3',
            u'',
            u'sh')

python_2 = (u'thefuck/python2',
            u'',
            u'sh')


init_bashrc = u'''echo '
export SHELL=/bin/bash
export PS1="$ "
echo > $HISTFILE
eval $(thefuck --alias {})
echo "instant mode ready: $THEFUCK_INSTANT_MODE"
' > ~/.bashrc'''


@pytest.fixture(params=[(python_3, False),
                        (python_3, True),
                        (python_2, False)])
def proc(request, spawnu, TIMEOUT):
    container, instant_mode = request.param
    proc = spawnu(*container)
    proc.sendline(init_bashrc.format(
        u'--enable-experimental-instant-mode' if instant_mode else ''))
    proc.sendline(u"bash")
    if instant_mode:
        assert proc.expect([TIMEOUT, u'instant mode ready: True'])
    return proc


@pytest.mark.functional
def test_with_confirmation(proc, TIMEOUT):
    with_confirmation(proc, TIMEOUT)
    history_changed(proc, TIMEOUT, u'echo test')


@pytest.mark.functional
def test_select_command_with_arrows(proc, TIMEOUT):
    select_command_with_arrows(proc, TIMEOUT)
    history_changed(proc, TIMEOUT, u'git help', u'git hook')


@pytest.mark.functional
def test_refuse_with_confirmation(proc, TIMEOUT):
    refuse_with_confirmation(proc, TIMEOUT)
    history_not_changed(proc, TIMEOUT)


@pytest.mark.functional
def test_without_confirmation(proc, TIMEOUT):
    without_confirmation(proc, TIMEOUT)
    history_changed(proc, TIMEOUT, u'echo test')


@pytest.mark.functional
def test_how_to_configure_alias(proc, TIMEOUT):
    proc.sendline('unset -f fuck')
    how_to_configure(proc, TIMEOUT)