"Fossies" - the Fresh Open Source Software Archive

Member "codespell-2.0.0/codespell_lib/tests/test_basic.py" (23 Nov 2020, 17847 Bytes) of package /linux/misc/codespell-2.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_basic.py": 1.17.1_vs_2.0.0.

    1 # -*- coding: utf-8 -*-
    2 
    3 from __future__ import print_function
    4 
    5 import contextlib
    6 import inspect
    7 import os
    8 import os.path as op
    9 from shutil import copyfile
   10 import subprocess
   11 import sys
   12 
   13 import pytest
   14 
   15 import codespell_lib as cs_
   16 from codespell_lib._codespell import EX_USAGE, EX_OK, EX_DATAERR
   17 
   18 
   19 def test_constants():
   20     """Test our EX constants."""
   21     assert EX_OK == 0
   22     assert EX_USAGE == 64
   23     assert EX_DATAERR == 65
   24 
   25 
   26 class MainWrapper(object):
   27     """Compatibility wrapper for when we used to return the count."""
   28 
   29     def main(self, *args, count=True, std=False, **kwargs):
   30         if count:
   31             args = ('--count',) + args
   32         code = cs_.main(*args, **kwargs)
   33         capsys = inspect.currentframe().f_back.f_locals['capsys']
   34         stdout, stderr = capsys.readouterr()
   35         assert code in (EX_OK, EX_USAGE, EX_DATAERR)
   36         if code == EX_DATAERR:  # have some misspellings
   37             code = int(stderr.split('\n')[-2])
   38         elif code == EX_OK and count:
   39             code = int(stderr.split('\n')[-2])
   40             assert code == 0
   41         if std:
   42             return (code, stdout, stderr)
   43         else:
   44             return code
   45 
   46 
   47 cs = MainWrapper()
   48 
   49 
   50 def run_codespell(args=(), cwd=None):
   51     """Run codespell."""
   52     args = ('--count',) + args
   53     proc = subprocess.Popen(
   54         ['codespell'] + list(args), cwd=cwd,
   55         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
   56     stderr = proc.communicate()[1].decode('utf-8')
   57     count = int(stderr.split('\n')[-2])
   58     return count
   59 
   60 
   61 def test_command(tmpdir):
   62     """Test running the codespell executable."""
   63     # With no arguments does "."
   64     d = str(tmpdir)
   65     assert run_codespell(cwd=d) == 0
   66     with open(op.join(d, 'bad.txt'), 'w') as f:
   67         f.write('abandonned\nAbandonned\nABANDONNED\nAbAnDoNnEd')
   68     assert run_codespell(cwd=d) == 4
   69 
   70 
   71 def test_basic(tmpdir, capsys):
   72     """Test some basic functionality."""
   73     assert cs.main('_does_not_exist_') == 0
   74     fname = op.join(str(tmpdir), 'tmp')
   75     with open(fname, 'w') as f:
   76         pass
   77     code, _, stderr = cs.main('-D', 'foo', f.name, std=True)
   78     assert code == EX_USAGE, 'missing dictionary'
   79     assert 'cannot find dictionary' in stderr
   80     assert cs.main(fname) == 0, 'empty file'
   81     with open(fname, 'a') as f:
   82         f.write('this is a test file\n')
   83     assert cs.main(fname) == 0, 'good'
   84     with open(fname, 'a') as f:
   85         f.write('abandonned\n')
   86     assert cs.main(fname) == 1, 'bad'
   87     with open(fname, 'a') as f:
   88         f.write('abandonned\n')
   89     assert cs.main(fname) == 2, 'worse'
   90     with open(fname, 'a') as f:
   91         f.write('tim\ngonna\n')
   92     assert cs.main(fname) == 2, 'with a name'
   93     assert cs.main('--builtin', 'clear,rare,names,informal', fname) == 4
   94     code, _, stderr = cs.main(fname, '--builtin', 'foo', std=True)
   95     assert code == EX_USAGE  # bad type
   96     assert 'Unknown builtin dictionary' in stderr
   97     d = str(tmpdir)
   98     code, _, stderr = cs.main(fname, '-D', op.join(d, 'foo'), std=True)
   99     assert code == EX_USAGE  # bad dict
  100     assert 'cannot find dictionary' in stderr
  101     os.remove(fname)
  102 
  103     with open(op.join(d, 'bad.txt'), 'w') as f:
  104         f.write('abandonned\nAbandonned\nABANDONNED\nAbAnDoNnEd')
  105     assert cs.main(d) == 4
  106     code, _, stderr = cs.main('-w', d, std=True)
  107     assert code == 0
  108     assert 'FIXED:' in stderr
  109     with open(op.join(d, 'bad.txt')) as f:
  110         new_content = f.read()
  111     assert cs.main(d) == 0
  112     assert new_content == 'abandoned\nAbandoned\nABANDONED\nabandoned'
  113 
  114     with open(op.join(d, 'bad.txt'), 'w') as f:
  115         f.write('abandonned abandonned\n')
  116     assert cs.main(d) == 2
  117     code, stdout, stderr = cs.main(
  118         '-q', '16', '-w', d, count=False, std=True)
  119     assert code == 0
  120     assert stdout == stderr == ''
  121     assert cs.main(d) == 0
  122 
  123     # empty directory
  124     os.mkdir(op.join(d, 'test'))
  125     assert cs.main(d) == 0
  126 
  127 
  128 def test_interactivity(tmpdir, capsys):
  129     """Test interaction"""
  130     # Windows can't read a currently-opened file, so here we use
  131     # NamedTemporaryFile just to get a good name
  132     with open(op.join(str(tmpdir), 'tmp'), 'w') as f:
  133         pass
  134     try:
  135         assert cs.main(f.name) == 0, 'empty file'
  136         with open(f.name, 'w') as f:
  137             f.write('abandonned\n')
  138         assert cs.main('-i', '-1', f.name) == 1, 'bad'
  139         with FakeStdin('y\n'):
  140             assert cs.main('-i', '3', f.name) == 1
  141         with FakeStdin('n\n'):
  142             code, stdout, _ = cs.main('-w', '-i', '3', f.name, std=True)
  143             assert code == 0
  144         assert '==>' in stdout
  145         with FakeStdin('x\ny\n'):
  146             assert cs.main('-w', '-i', '3', f.name) == 0
  147         assert cs.main(f.name) == 0
  148     finally:
  149         os.remove(f.name)
  150 
  151     # New example
  152     with open(op.join(str(tmpdir), 'tmp2'), 'w') as f:
  153         pass
  154     try:
  155         with open(f.name, 'w') as f:
  156             f.write('abandonned\n')
  157         assert cs.main(f.name) == 1
  158         with FakeStdin(' '):  # blank input -> Y
  159             assert cs.main('-w', '-i', '3', f.name) == 0
  160         assert cs.main(f.name) == 0
  161     finally:
  162         os.remove(f.name)
  163 
  164     # multiple options
  165     with open(op.join(str(tmpdir), 'tmp3'), 'w') as f:
  166         pass
  167     try:
  168         with open(f.name, 'w') as f:
  169             f.write('ackward\n')
  170 
  171         assert cs.main(f.name) == 1
  172         with FakeStdin(' \n'):  # blank input -> nothing
  173             assert cs.main('-w', '-i', '3', f.name) == 0
  174         assert cs.main(f.name) == 1
  175         with FakeStdin('0\n'):  # blank input -> nothing
  176             assert cs.main('-w', '-i', '3', f.name) == 0
  177         assert cs.main(f.name) == 0
  178         with open(f.name, 'r') as f_read:
  179             assert f_read.read() == 'awkward\n'
  180         with open(f.name, 'w') as f:
  181             f.write('ackward\n')
  182         assert cs.main(f.name) == 1
  183         with FakeStdin('x\n1\n'):  # blank input -> nothing
  184             code, stdout, _ = cs.main('-w', '-i', '3', f.name, std=True)
  185             assert code == 0
  186         assert 'a valid option' in stdout
  187         assert cs.main(f.name) == 0
  188         with open(f.name, 'r') as f:
  189             assert f.read() == 'backward\n'
  190     finally:
  191         os.remove(f.name)
  192 
  193 
  194 def test_summary(tmpdir, capsys):
  195     """Test summary functionality."""
  196     with open(op.join(str(tmpdir), 'tmp'), 'w') as f:
  197         pass
  198     code, stdout, stderr = cs.main(f.name, std=True, count=False)
  199     assert code == 0
  200     assert stdout == stderr == '', 'no output'
  201     code, stdout, stderr = cs.main(f.name, '--summary', std=True)
  202     assert code == 0
  203     assert stderr == '0\n'
  204     assert 'SUMMARY' in stdout
  205     assert len(stdout.split('\n')) == 5
  206     with open(f.name, 'w') as f:
  207         f.write('abandonned\nabandonned')
  208     assert code == 0
  209     code, stdout, stderr = cs.main(f.name, '--summary', std=True)
  210     assert stderr == '2\n'
  211     assert 'SUMMARY' in stdout
  212     assert len(stdout.split('\n')) == 7
  213     assert 'abandonned' in stdout.split()[-2]
  214 
  215 
  216 def test_ignore_dictionary(tmpdir, capsys):
  217     """Test ignore dictionary functionality."""
  218     d = str(tmpdir)
  219     with open(op.join(d, 'bad.txt'), 'w') as f:
  220         f.write('1 abandonned 1\n2 abandonned 2\nabondon\n')
  221     bad_name = f.name
  222     assert cs.main(bad_name) == 3
  223     with open(op.join(d, 'ignore.txt'), 'w') as f:
  224         f.write('abandonned\n')
  225     assert cs.main('-I', f.name, bad_name) == 1
  226 
  227 
  228 def test_ignore_word_list(tmpdir, capsys):
  229     """Test ignore word list functionality."""
  230     d = str(tmpdir)
  231     with open(op.join(d, 'bad.txt'), 'w') as f:
  232         f.write('abandonned\nabondon\nabilty\n')
  233     assert cs.main(d) == 3
  234     assert cs.main('-Labandonned,someword', '-Labilty', d) == 1
  235 
  236 
  237 def test_custom_regex(tmpdir, capsys):
  238     """Test custom word regex."""
  239     d = str(tmpdir)
  240     with open(op.join(d, 'bad.txt'), 'w') as f:
  241         f.write('abandonned_abondon\n')
  242     assert cs.main(d) == 0
  243     assert cs.main('-r', "[a-z]+", d) == 2
  244     code, stdout, _ = cs.main('-r', '[a-z]+', '--write-changes', d, std=True)
  245     assert code == EX_USAGE
  246     assert 'ERROR:' in stdout
  247 
  248 
  249 def test_exclude_file(tmpdir, capsys):
  250     """Test exclude file functionality."""
  251     d = str(tmpdir)
  252     with open(op.join(d, 'bad.txt'), 'wb') as f:
  253         f.write('1 abandonned 1\n2 abandonned 2\n'.encode('utf-8'))
  254     bad_name = f.name
  255     assert cs.main(bad_name) == 2
  256     with open(op.join(d, 'tmp.txt'), 'wb') as f:
  257         f.write('1 abandonned 1\n'.encode('utf-8'))
  258     assert cs.main(bad_name) == 2
  259     assert cs.main('-x', f.name, bad_name) == 1
  260 
  261 
  262 def test_encoding(tmpdir, capsys):
  263     """Test encoding handling."""
  264     # Some simple Unicode things
  265     with open(op.join(str(tmpdir), 'tmp'), 'w') as f:
  266         pass
  267     # with CaptureStdout() as sio:
  268     assert cs.main(f.name) == 0
  269     with open(f.name, 'wb') as f:
  270         f.write(u'naïve\n'.encode('utf-8'))
  271     assert cs.main(f.name) == 0
  272     assert cs.main('-e', f.name) == 0
  273     with open(f.name, 'ab') as f:
  274         f.write(u'naieve\n'.encode('utf-8'))
  275     assert cs.main(f.name) == 1
  276     # Binary file warning
  277     with open(f.name, 'wb') as f:
  278         f.write(b'\x00\x00naiive\x00\x00')
  279     code, stdout, stderr = cs.main(f.name, std=True, count=False)
  280     assert code == 0
  281     assert stdout == stderr == ''
  282     code, stdout, stderr = cs.main('-q', '0', f.name, std=True, count=False)
  283     assert code == 0
  284     assert stdout == ''
  285     assert 'WARNING: Binary file' in stderr
  286 
  287 
  288 def test_ignore(tmpdir, capsys):
  289     """Test ignoring of files and directories."""
  290     d = str(tmpdir)
  291     with open(op.join(d, 'good.txt'), 'w') as f:
  292         f.write('this file is okay')
  293     assert cs.main(d) == 0
  294     with open(op.join(d, 'bad.txt'), 'w') as f:
  295         f.write('abandonned')
  296     assert cs.main(d) == 1
  297     assert cs.main('--skip=bad*', d) == 0
  298     assert cs.main('--skip=bad.txt', d) == 0
  299     subdir = op.join(d, 'ignoredir')
  300     os.mkdir(subdir)
  301     with open(op.join(subdir, 'bad.txt'), 'w') as f:
  302         f.write('abandonned')
  303     assert cs.main(d) == 2
  304     assert cs.main('--skip=bad*', d) == 0
  305     assert cs.main('--skip=*ignoredir*', d) == 1
  306     assert cs.main('--skip=ignoredir', d) == 1
  307     assert cs.main('--skip=*ignoredir/bad*', d) == 1
  308 
  309 
  310 def test_check_filename(tmpdir, capsys):
  311     """Test filename check."""
  312     d = str(tmpdir)
  313     # Empty file
  314     with open(op.join(d, 'abandonned.txt'), 'w') as f:
  315         f.write('')
  316     assert cs.main('-f', d) == 1
  317     # Normal file with contents
  318     with open(op.join(d, 'abandonned.txt'), 'w') as f:
  319         f.write('.')
  320     assert cs.main('-f', d) == 1
  321     # Normal file with binary contents
  322     with open(op.join(d, 'abandonned.txt'), 'wb') as f:
  323         f.write(b'\x00\x00naiive\x00\x00')
  324     assert cs.main('-f', d) == 1
  325 
  326 
  327 @pytest.mark.skipif((not hasattr(os, "mkfifo") or not callable(os.mkfifo)),
  328                     reason='requires os.mkfifo')
  329 def test_check_filename_irregular_file(tmpdir, capsys):
  330     """Test irregular file filename check."""
  331     # Irregular file (!isfile())
  332     d = str(tmpdir)
  333     os.mkfifo(op.join(d, 'abandonned'))
  334     assert cs.main('-f', d) == 1
  335     d = str(tmpdir)
  336 
  337 
  338 def test_check_hidden(tmpdir, capsys):
  339     """Test ignoring of hidden files."""
  340     d = str(tmpdir)
  341     # visible file
  342     with open(op.join(d, 'test.txt'), 'w') as f:
  343         f.write('abandonned\n')
  344     assert cs.main(op.join(d, 'test.txt')) == 1
  345     assert cs.main(d) == 1
  346     # hidden file
  347     os.rename(op.join(d, 'test.txt'), op.join(d, '.test.txt'))
  348     assert cs.main(op.join(d, '.test.txt')) == 0
  349     assert cs.main(d) == 0
  350     assert cs.main('--check-hidden', op.join(d, '.test.txt')) == 1
  351     assert cs.main('--check-hidden', d) == 1
  352     # hidden file with typo in name
  353     os.rename(op.join(d, '.test.txt'), op.join(d, '.abandonned.txt'))
  354     assert cs.main(op.join(d, '.abandonned.txt')) == 0
  355     assert cs.main(d) == 0
  356     assert cs.main('--check-hidden', op.join(d, '.abandonned.txt')) == 1
  357     assert cs.main('--check-hidden', d) == 1
  358     assert cs.main('--check-hidden', '--check-filenames',
  359                    op.join(d, '.abandonned.txt')) == 2
  360     assert cs.main('--check-hidden', '--check-filenames', d) == 2
  361     # hidden directory
  362     assert cs.main(d) == 0
  363     assert cs.main('--check-hidden', d) == 1
  364     assert cs.main('--check-hidden', '--check-filenames', d) == 2
  365     os.mkdir(op.join(d, '.abandonned'))
  366     copyfile(op.join(d, '.abandonned.txt'),
  367              op.join(d, '.abandonned', 'abandonned.txt'))
  368     assert cs.main(d) == 0
  369     assert cs.main('--check-hidden', d) == 2
  370     assert cs.main('--check-hidden', '--check-filenames', d) == 5
  371 
  372 
  373 def test_case_handling(tmpdir, capsys):
  374     """Test that capitalized entries get detected properly."""
  375     # Some simple Unicode things
  376     with open(op.join(str(tmpdir), 'tmp'), 'w') as f:
  377         pass
  378     # with CaptureStdout() as sio:
  379     assert cs.main(f.name) == 0
  380     with open(f.name, 'wb') as f:
  381         f.write('this has an ACII error'.encode('utf-8'))
  382     code, stdout, _ = cs.main(f.name, std=True)
  383     assert code == 1
  384     assert 'ASCII' in stdout
  385     code, _, stderr = cs.main('-w', f.name, std=True)
  386     assert code == 0
  387     assert 'FIXED' in stderr
  388     with open(f.name, 'rb') as f:
  389         assert f.read().decode('utf-8') == 'this has an ASCII error'
  390 
  391 
  392 def test_context(tmpdir, capsys):
  393     """Test context options."""
  394     d = str(tmpdir)
  395     with open(op.join(d, 'context.txt'), 'w') as f:
  396         f.write('line 1\nline 2\nline 3 abandonned\nline 4\nline 5')
  397 
  398     # symmetric context, fully within file
  399     code, stdout, _ = cs.main('-C', '1', d, std=True)
  400     assert code == 1
  401     lines = stdout.split('\n')
  402     assert len(lines) == 5
  403     assert lines[0] == ': line 2'
  404     assert lines[1] == '> line 3 abandonned'
  405     assert lines[2] == ': line 4'
  406 
  407     # requested context is bigger than the file
  408     code, stdout, _ = cs.main('-C', '10', d, std=True)
  409     assert code == 1
  410     lines = stdout.split('\n')
  411     assert len(lines) == 7
  412     assert lines[0] == ': line 1'
  413     assert lines[1] == ': line 2'
  414     assert lines[2] == '> line 3 abandonned'
  415     assert lines[3] == ': line 4'
  416     assert lines[4] == ': line 5'
  417 
  418     # only before context
  419     code, stdout, _ = cs.main('-B', '2', d, std=True)
  420     assert code == 1
  421     lines = stdout.split('\n')
  422     assert len(lines) == 5
  423     assert lines[0] == ': line 1'
  424     assert lines[1] == ': line 2'
  425     assert lines[2] == '> line 3 abandonned'
  426 
  427     # only after context
  428     code, stdout, _ = cs.main('-A', '1', d, std=True)
  429     assert code == 1
  430     lines = stdout.split('\n')
  431     assert len(lines) == 4
  432     assert lines[0] == '> line 3 abandonned'
  433     assert lines[1] == ': line 4'
  434 
  435     # asymmetric context
  436     code, stdout, _ = cs.main('-B', '2', '-A', '1', d, std=True)
  437     assert code == 1
  438     lines = stdout.split('\n')
  439     assert len(lines) == 6
  440     assert lines[0] == ': line 1'
  441     assert lines[1] == ': line 2'
  442     assert lines[2] == '> line 3 abandonned'
  443     assert lines[3] == ': line 4'
  444 
  445     # both '-C' and '-A' on the command line
  446     code, stdout, _ = cs.main('-C', '2', '-A', '1', d, std=True)
  447     assert code == EX_USAGE
  448     lines = stdout.split('\n')
  449     assert 'ERROR' in lines[0]
  450 
  451     # both '-C' and '-B' on the command line
  452     code, stdout, stderr = cs.main('-C', '2', '-B', '1', d, std=True)
  453     assert code == EX_USAGE
  454     lines = stdout.split('\n')
  455     assert 'ERROR' in lines[0]
  456 
  457 
  458 def test_ignore_regex_flag(tmpdir, capsys):
  459     """Test ignore regex flag functionality."""
  460     d = str(tmpdir)
  461 
  462     # Invalid regex.
  463     code, stdout, _ = cs.main('--ignore-regex=(', std=True)
  464     assert code == EX_USAGE
  465     assert 'usage:' in stdout
  466 
  467     with open(op.join(d, 'flag.txt'), 'w') as f:
  468         f.write('# Please see http://example.com/abandonned for info\n')
  469     # Test file has 1 invalid entry, and it's not ignored by default.
  470     assert cs.main(f.name) == 1
  471     # An empty regex is the default value, and nothing is ignored.
  472     assert cs.main(f.name, '--ignore-regex=') == 1
  473     assert cs.main(f.name, '--ignore-regex=""') == 1
  474     # Non-matching regex results in nothing being ignored.
  475     assert cs.main(f.name, '--ignore-regex=^$') == 1
  476     # A word can be ignored.
  477     assert cs.main(f.name, '--ignore-regex=abandonned') == 0
  478     # Ignoring part of the word can result in odd behavior.
  479     assert cs.main(f.name, '--ignore-regex=nn') == 0
  480 
  481     with open(op.join(d, 'flag.txt'), 'w') as f:
  482         f.write('abandonned donn\n')
  483     # Test file has 2 invalid entries.
  484     assert cs.main(f.name) == 2
  485     # Ignoring donn breaks them both.
  486     assert cs.main(f.name, '--ignore-regex=donn') == 0
  487     # Adding word breaks causes only one to be ignored.
  488     assert cs.main(f.name, r'--ignore-regex=\Wdonn\W') == 1
  489 
  490 
  491 def test_config(tmpdir, capsys):
  492     """
  493     Tests loading options from a config file.
  494     """
  495     d = str(tmpdir)
  496 
  497     # Create sample files.
  498     with open(op.join(d, 'bad.txt'), 'w') as f:
  499         f.write('abandonned donn\n')
  500     with open(op.join(d, 'good.txt'), 'w') as f:
  501         f.write("good")
  502 
  503     # Create a config file.
  504     conffile = op.join(d, 'config.cfg')
  505     with open(conffile, 'w') as f:
  506         f.write(
  507             '[codespell]\n'
  508             'skip = bad.txt\n'
  509             'count = \n'
  510         )
  511 
  512     # Should fail when checking both.
  513     code, stdout, _ = cs.main(d, count=True, std=True)
  514     # Code in this case is not exit code, but count of misspellings.
  515     assert code == 2
  516     assert 'bad.txt' in stdout
  517 
  518     # Should pass when skipping bad.txt
  519     code, stdout, _ = cs.main('--config', conffile, d, count=True, std=True)
  520     assert code == 0
  521     assert 'bad.txt' not in stdout
  522 
  523 
  524 @contextlib.contextmanager
  525 def FakeStdin(text):
  526     if sys.version[0] == '2':
  527         from StringIO import StringIO
  528     else:
  529         from io import StringIO
  530     oldin = sys.stdin
  531     try:
  532         in_ = StringIO(text)
  533         sys.stdin = in_
  534         yield
  535     finally:
  536         sys.stdin = oldin