Back to Repositories

Testing Grunt Task Correction Handler in thefuck

This test suite validates the grunt task not found functionality in thefuck command line tool, focusing on command correction and task name matching. It ensures proper handling of misspelled Grunt tasks and provides appropriate corrections.

Test Coverage Overview

The test coverage focuses on the grunt_task_not_found rule implementation, validating both matching and correction of invalid Grunt commands.

  • Tests command matching for misspelled Grunt tasks
  • Verifies command correction suggestions
  • Handles various command formats including task arguments
  • Covers both positive and negative test cases

Implementation Analysis

The testing approach utilizes pytest fixtures and parametrized tests to validate the rule’s functionality.

  • Uses pytest.fixture to mock Grunt help output
  • Implements parametrized test cases for different command scenarios
  • Validates both match() and get_new_command() functions
  • Simulates Grunt CLI behavior with BytesIO streams

Technical Details

Test implementation leverages several technical components:

  • pytest framework for test organization
  • Mock objects for command simulation
  • BytesIO for stdout simulation
  • Command type from thefuck.types
  • Parametrized test decorators for multiple test cases

Best Practices Demonstrated

The test suite demonstrates several testing best practices:

  • Isolation of test cases using fixtures
  • Comprehensive positive and negative test scenarios
  • Clear test case organization with parametrize
  • Effective mocking of system dependencies
  • Maintainable test structure with reusable components

nvbn/thefuck

tests/rules/test_grunt_task_not_found.py

            
# -*- encoding: utf-8 -*-

from io import BytesIO
import pytest
from thefuck.types import Command
from thefuck.rules.grunt_task_not_found import match, get_new_command

output = '''
Warning: Task "{}" not found. Use --force to continue.

Aborted due to warnings.


Execution Time (2016-08-13 21:01:40 UTC+3)
loading tasks  11ms  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 92%
Total 12ms

'''.format

grunt_help_stdout = b'''
Grunt: The JavaScript Task Runner (v0.4.5)

Usage
 grunt [options] [task [task ...]]

Options
    --help, -h  Display this help text.
        --base  Specify an alternate base path. By default, all file paths are
                relative to the Gruntfile. (grunt.file.setBase) *
    --no-color  Disable colored output.
   --gruntfile  Specify an alternate Gruntfile. By default, grunt looks in the
                current or parent directories for the nearest Gruntfile.js or
                Gruntfile.coffee file.
   --debug, -d  Enable debugging mode for tasks that support it.
       --stack  Print a stack trace when exiting with a warning or fatal error.
   --force, -f  A way to force your way past warnings. Want a suggestion? Don't
                use this option, fix your code.
       --tasks  Additional directory paths to scan for task and "extra" files.
                (grunt.loadTasks) *
         --npm  Npm-installed grunt plugins to scan for task and "extra" files.
                (grunt.loadNpmTasks) *
    --no-write  Disable writing files (dry run).
 --verbose, -v  Verbose mode. A lot more information output.
 --version, -V  Print the grunt version. Combine with --verbose for more info.
  --completion  Output shell auto-completion rules. See the grunt-cli
                documentation for more information.

Options marked with * have methods exposed via the grunt API and should instead
be specified inside the Gruntfile wherever possible.

Available tasks
  autoprefixer  Prefix CSS files. *
    concurrent  Run grunt tasks concurrently *
         clean  Clean files and folders. *
       compass  Compile Sass to CSS using Compass *
        concat  Concatenate files. *
       connect  Start a connect web server. *
          copy  Copy files. *
        cssmin  Minify CSS *
       htmlmin  Minify HTML *
      imagemin  Minify PNG, JPEG, GIF and SVG images *
        jshint  Validate files with JSHint. *
        uglify  Minify files with UglifyJS. *
         watch  Run predefined tasks whenever watched files change.
       filerev  File revisioning based on content hashing *
        cdnify  Replace scripts with refs to the Google CDN *
         karma  run karma. *
         newer  Run a task with only those source files that have been modified
                since the last successful run.
     any-newer  DEPRECATED TASK.  Use the "newer" task instead
 newer-postrun  Internal task.
   newer-clean  Remove cached timestamps.
    ngAnnotate  Add, remove and rebuild AngularJS dependency injection
                annotations *
    ngconstant  Dynamic angular constant generator task. *
        svgmin  Minify SVG *
        usemin  Replaces references to non-minified scripts / stylesheets *
 useminPrepare  Using HTML markup as the primary source of information *
       wiredep  Inject Bower components into your source code. *
         serve  Compile then start a connect web server
        server  DEPRECATED TASK. Use the "serve" task instead
          test  Alias for "clean:server", "ngconstant:test", "wiredep",
                "concurrent:test", "autoprefixer", "connect:test", "karma"
                tasks.
         build  Alias for "ngconstant:production", "clean:dist", "wiredep",
                "useminPrepare", "concurrent:dist", "autoprefixer", "concat",
                "ngAnnotate", "copy:dist", "cdnify", "cssmin", "uglify",
                "filerev", "usemin", "htmlmin" tasks.
       default  Alias for "newer:jshint", "test", "build" tasks.

Tasks run in the order specified. Arguments may be passed to tasks that accept
them by using colons, like "lint:files". Tasks marked with * are "multi tasks"
and will iterate over all sub-targets if no argument is specified.

The list of available tasks may change based on tasks directories or grunt
plugins specified in the Gruntfile or via command-line options.

For more information, see http://gruntjs.com/
'''


@pytest.fixture(autouse=True)
def grunt_help(mocker):
    patch = mocker.patch('thefuck.rules.grunt_task_not_found.Popen')
    patch.return_value.stdout = BytesIO(grunt_help_stdout)
    return patch


@pytest.mark.parametrize('command', [
    Command('grunt defualt', output('defualt')),
    Command('grunt buld:css', output('buld:css'))])
def test_match(command):
    assert match(command)


@pytest.mark.parametrize('command', [
    Command('npm nuild', output('nuild')),
    Command('grunt rm', '')])
def test_not_match(command):
    assert not match(command)


@pytest.mark.parametrize('command, result', [
    (Command('grunt defualt', output('defualt')), 'grunt default'),
    (Command('grunt cmpass:all', output('cmpass:all')), 'grunt compass:all'),
    (Command('grunt cmpass:all --color', output('cmpass:all')),
     'grunt compass:all --color')])
def test_get_new_command(command, result):
    assert get_new_command(command) == result