Back to Repositories

Testing SCM Command Correction Logic in thefuck

This test suite validates the source control management (SCM) correction functionality in thefuck, ensuring proper handling of Git and Mercurial command corrections when users accidentally use the wrong SCM commands.

Test Coverage Overview

The test suite provides comprehensive coverage of SCM command correction scenarios, focusing on Git and Mercurial (hg) commands. Key test cases include:

  • Detection of incorrect SCM usage in repositories
  • Command translation between Git and Mercurial
  • Error message pattern matching
  • Edge cases with invalid or missing repositories

Implementation Analysis

The testing approach utilizes pytest’s parametrize feature for data-driven testing, allowing multiple test scenarios with different inputs and expected outputs. The implementation leverages pytest fixtures and mocking to isolate SCM detection logic and ensure consistent test behavior.

Testing patterns include mock objects for SCM detection, command object handling, and parametrized test cases for various command combinations.

Technical Details

Testing tools and configuration:

  • pytest framework for test organization
  • pytest-mock for mocking SCM detection
  • Command class from thefuck.types for command representation
  • Parametrized test cases for multiple scenarios
  • Fixture-based mock injection

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Isolation of external dependencies through mocking
  • Comprehensive positive and negative test cases
  • Clear test organization with descriptive function names
  • Efficient test data management using parametrization
  • Proper fixture usage for test setup

nvbn/thefuck

tests/rules/test_scm_correction.py

            
import pytest
from thefuck.rules.scm_correction import match, get_new_command
from thefuck.types import Command


@pytest.fixture
def get_actual_scm_mock(mocker):
    return mocker.patch('thefuck.rules.scm_correction._get_actual_scm',
                        return_value=None)


@pytest.mark.parametrize('script, output, actual_scm', [
    ('git log', 'fatal: Not a git repository '
                '(or any of the parent directories): .git',
     'hg'),
    ('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
               "(.hg not found)!",
     'git')])
def test_match(get_actual_scm_mock, script, output, actual_scm):
    get_actual_scm_mock.return_value = actual_scm
    assert match(Command(script, output))


@pytest.mark.parametrize('script, output, actual_scm', [
    ('git log', '', 'hg'),
    ('git log', 'fatal: Not a git repository '
                '(or any of the parent directories): .git',
     None),
    ('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
               "(.hg not found)!",
     None),
    ('not-scm log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
                    "(.hg not found)!",
     'git')])
def test_not_match(get_actual_scm_mock, script, output, actual_scm):
    get_actual_scm_mock.return_value = actual_scm
    assert not match(Command(script, output))


@pytest.mark.parametrize('script, actual_scm, result', [
    ('git log', 'hg', 'hg log'),
    ('hg log', 'git', 'git log')])
def test_get_new_command(get_actual_scm_mock, script, actual_scm, result):
    get_actual_scm_mock.return_value = actual_scm
    new_command = get_new_command(Command(script, ''))
    assert new_command == result