Example #1
0
def test_compare_no_hash(tmp_path):
    """
    "omnidiff compare" fails cleanly when hashes are missing.
    """
    # TODO - this behaviour may well change in future, in which case we can
    # test the new behaviour instead.
    def set_up(path, fast=False):
        path.mkdir()
        (path / 'dupe1.txt').write_bytes(b'equal')
        (path / 'dupe2.txt').write_bytes(b'equal')
        (path / 'unequal.txt').write_bytes(str(path).encode('utf8'))
        info = DirInfo(path)
        info.populate(fast=fast)
        info.save()
        return path
    # Missing hash on the old side
    old_dir = set_up(tmp_path / 'old', fast=True)
    new_dir = set_up(tmp_path / 'new')
    with patch('sys.argv', ['omnidiff', 'compare', str(old_dir), str(new_dir)]):
        with pytest.raises(Exception, match='hash.*old'):
            main()
    # Missing hash on the new side
    old_dir = set_up(tmp_path / 'old2')
    new_dir = set_up(tmp_path / 'new2', fast=True)
    with patch('sys.argv', ['omnidiff', 'compare', str(old_dir), str(new_dir)]):
        with pytest.raises(Exception, match='hash.*new2'):
            main()
Example #2
0
def test_main(capsys):
    """
    Running with no arguments displays the help message.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    check_help_message(capsys)
Example #3
0
def test_compare_counts(tmp_path, capsys):
    """
    "omnidiff compare" counts files in various states.
    """
    # We could do some complicated mocks with DirInfo, but it's easier just to
    # create the files we want.
    def set_up(path, extra_files=()):
        path.mkdir()
        (path / 'equal1.txt').write_bytes(b'equal1')
        (path / 'equal2.txt').write_bytes(b'equal2')
        (path / 'unequal.txt').write_bytes(str(path).encode('utf8'))
        for extra in extra_files:
            (path / extra).write_bytes(b'extra')
        info = DirInfo(path)
        info.populate()
        info.save()
        return path
    old_dir = set_up(tmp_path / 'old', ['a', 'b'])
    new_dir = set_up(tmp_path / 'new', ['c'])
    with patch('sys.argv', ['omnidiff', 'compare', str(old_dir), str(new_dir)]):
        with pytest.raises(SystemExit, match='0'):
            main()
    out = capsys.readouterr()[0]
    results = {}
    for row in out.splitlines():
        key, _, value = row.partition(':')
        results[key] = int(value)
    assert results == {'old': 5, 'new': 4, 'identical': 2, 'changed': 1, 'vanished': 2, 'added': 1}
Example #4
0
def test_main_help(capsys):
    """
    Help message includes at least usage message and top-level options.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    check_help_message(capsys)
Example #5
0
def test_compare_lists(tmp_path, capsys):
    # Same setup as test_compare_counts. Could make it a fixture?
    def set_up(path, extra_files=()):
        path.mkdir()
        (path / 'equal1.txt').write_bytes(b'equal1')
        (path / 'equal2.txt').write_bytes(b'equal2')
        (path / 'unequal.txt').write_bytes(str(path).encode('utf8'))
        for extra in extra_files:
            (path / extra).write_bytes(b'extra')
        info = DirInfo(path)
        info.populate()
        info.save()
        return path
    old_dir = set_up(tmp_path / 'old', ['a', 'b'])
    new_dir = set_up(tmp_path / 'new', ['c'])
    with patch('sys.argv', ['omnidiff', 'compare', str(old_dir), str(new_dir), '--list-identical', '--list-changed', '--list-vanished', '--list-added']):
        with pytest.raises(SystemExit, match='0'):
            main()
    out = capsys.readouterr()[0]
    assert '\nidentical files:\n  equal1.txt\n  equal2.txt\n' in out
    assert '\nchanged files:\n  unequal.txt\n' in out
    assert '\nvanished files:\n  a\n  b\n' in out
    assert '\nadded files:\n  c\n' in out
    with patch('sys.argv', ['omnidiff', 'compare', str(old_dir), str(new_dir), '--list-all']):
        with pytest.raises(SystemExit, match='0'):
            main()
    out = capsys.readouterr()[0]
    assert '\nidentical files:\n  equal1.txt\n  equal2.txt\n' in out
    assert '\nchanged files:\n  unequal.txt\n' in out
    assert '\nvanished files:\n  a\n  b\n' in out
    assert '\nadded files:\n  c\n' in out
Example #6
0
def test_info_no_populate(mock_DirInfo):
    """
    info command doesn't populate if you tell it not to.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.cached.assert_called_once_with(os.path.abspath('.'))
    mock_DirInfo.cached.return_value.populate.assert_not_called()
Example #7
0
def test_dupes_missing_param(capsys):
    """
    info command takes one compulsory argument, the dirname.
    """
    with pytest.raises(SystemExit, match='2'):
        main()
    output = capsys.readouterr()
    assert "Missing argument 'DIRNAME'" in output.err
Example #8
0
def test_main_version(capsys):
    """
    --version option shows the version of the package.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    output = capsys.readouterr()
    assert output.out == f'omnidiff, version {omnidiff.__version__}\n'
Example #9
0
def test_compare(mock_DirInfo):
    """
    Comparing to directories loads stored data for both.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    assert mock_DirInfo.load.call_count == 2
    mock_DirInfo.load.assert_any_call('a')
    mock_DirInfo.load.assert_any_call('b')
Example #10
0
def test_dupes(mock_DirInfo):
    """
    dupes command reports on dupe groups, populating only if necessary.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.cached.assert_called_once_with(os.path.abspath('.'))
    mock_DirInfo.cached.return_value.populate.assert_not_called()
    mock_DirInfo.cached.return_value.dupe_groups.assert_called()
Example #11
0
def test_info_threads(mock_DirInfo):
    """
    Command-line supports populate() options: threads
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.return_value.populate.assert_called_once_with(
        **info_options(threads=99)
    )
Example #12
0
def test_info_no_empty(mock_DirInfo):
    """
    Command-line supports populate() options: no_empty
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.return_value.populate.assert_called_once_with(
        **info_options(no_empty=True)
    )
Example #13
0
def test_dupes_no_resume(mock_DirInfo):
    """
    Command-line supports populate() options: resume
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.return_value.populate.assert_called_once_with(
        **dupes_options(resume=False)
    )
    mock_DirInfo.return_value.dupe_groups.assert_called()
Example #14
0
def test_info_resume(mock_DirInfo):
    """
    Command-line supports populate() options: resume
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.return_value.populate.assert_not_called()
    mock_DirInfo.cached.return_value.populate.assert_called_once_with(
        **info_options(resume=True)
    )
Example #15
0
def test_dupes_populate(mock_DirInfo):
    """
    dupes command populates if you tell it to.
    """
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.cached.assert_called_once_with(os.path.abspath('.'))
    mock_DirInfo.cached.return_value.populate.assert_called_once_with(
        **dupes_options()
    )
    mock_DirInfo.cached.return_value.dupe_groups.assert_called()
Example #16
0
def test_dupes_no_cache(mock_DirInfo):
    """
    dupes command does populate if necessary.
    """
    mock_DirInfo.cached.return_value.file_count = 0
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.cached.assert_called_once_with(os.path.abspath('.'))
    mock_DirInfo.cached.return_value.populate.assert_called_once_with(
        **dupes_options()
    )
    mock_DirInfo.cached.return_value.dupe_groups.assert_called()
Example #17
0
def test_info(mock_DirInfo, capsys):
    """
    info command populates and saves the specified directory.
    """
    absname = os.path.abspath('.')
    mock_DirInfo.return_value.save.return_value = 'FILENAME'
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.assert_called_once_with(absname)
    mock_DirInfo.return_value.populate.assert_called_once_with(
        **info_options()
    )
    mock_DirInfo.return_value.save.assert_called_once()
    assert capsys.readouterr().out.startswith('Written FILENAME\n')
Example #18
0
def test_dupes_output(mock_DirInfo, capsys):
    """
    dupes command lists the members of the dupe groups.
    """
    mock_DirInfo.cached.return_value.dupe_groups.return_value = [
        frozenset({
            FileInfo.add_hash(FileStats('.', 'a', 123), b'111'),
            FileInfo.add_hash(FileStats('.', 'b', 123), b'111'),
        })
    ]
    with pytest.raises(SystemExit, match='0'):
        main()
    mock_DirInfo.cached.return_value.dupe_groups.assert_called()
    expected = '2 duplicates with size 123, hash 313131\n  a\n  b\n'
    assert capsys.readouterr().out == expected