"""Unit tests: upgrade"""
import pytest


@pytest.mark.parametrize('condition', ['override', 'equal', 'existing_repo'])
def test_upgrade_errors(tmpdir, runner, yadm, condition):
    """Test upgrade() error conditions"""

    home = tmpdir.mkdir('home')
    yadm_dir = home.join('.config/yadm')
    yadm_data = home.join('.local/share/yadm')
    override = ''
    if condition == 'override':
        override = 'override'
    if condition == 'equal':
        yadm_data = yadm_dir
    if condition == 'existing_repo':
        yadm_dir.ensure_dir('repo.git')
        yadm_data.ensure_dir('repo.git')

    script = f"""
        YADM_TEST=1 source {yadm}
        YADM_DIR="{yadm_dir}"
        YADM_DATA="{yadm_data}"
        YADM_REPO="{yadm_data}/repo.git"
        YADM_LEGACY_ARCHIVE="files.gpg"
        YADM_OVERRIDE_REPO="{override}"
        upgrade
    """
    run = runner(command=['bash'], inp=script)
    assert run.failure
    assert 'Unable to upgrade' in run.err
    if condition in ['override', 'equal']:
        assert 'Paths have been overridden' in run.err
    elif condition == 'existing_repo':
        assert 'already exists' in run.err


@pytest.mark.parametrize(
    'condition', ['no-paths', 'untracked', 'tracked', 'submodules'])
def test_upgrade(tmpdir, runner, yadm, condition):
    """Test upgrade()

    When testing the condition of git-tracked data, "echo" will be used as a
    mock for git. echo will return true, simulating a positive result from "git
    ls-files". Also echo will report the parameters for "git mv".
    """
    legacy_paths = ('config', 'encrypt', 'bootstrap', 'hooks/pre_cmd')
    home = tmpdir.mkdir('home')
    yadm_dir = home.join('.config/yadm')
    yadm_data = home.join('.local/share/yadm')
    yadm_legacy = home.join('.yadm')

    if condition != 'no-paths':
        yadm_dir.join('repo.git/config').write('test-repo', ensure=True)
        yadm_dir.join('files.gpg').write('files.gpg', ensure=True)
        for path in legacy_paths:
            yadm_legacy.join(path).write(path, ensure=True)

    mock_git = ""
    if condition != 'no-paths':
        mock_git = f'''
            function git() {{
                echo "$@"
                if [[ "$*" = *"submodule status" ]]; then
                    { 'echo " 1234567 mymodule (1.0)"'
                        if condition == 'submodules' else ':' }
                fi
                if [[ "$*" = *ls-files* ]]; then
                    return { 1 if condition == 'untracked' else 0 }
                fi
                return 0
            }}
        '''

    script = f"""
        YADM_TEST=1 source {yadm}
        YADM_LEGACY_DIR="{yadm_legacy}"
        YADM_DIR="{yadm_dir}"
        YADM_DATA="{yadm_data}"
        YADM_REPO="{yadm_data}/repo.git"
        YADM_ARCHIVE="{yadm_data}/archive"
        GIT_PROGRAM="git"
        {mock_git}
        function cd {{ echo "$@";}}
        upgrade
    """
    run = runner(command=['bash'], inp=script)
    assert run.success
    assert run.err == ''
    if condition == 'no-paths':
        assert 'Upgrade is not necessary' in run.out
    else:
        for (lpath, npath) in [
                ('repo.git', 'repo.git'), ('files.gpg', 'archive')]:
            expected = (
                f'Moving {yadm_dir.join(lpath)} '
                f'to {yadm_data.join(npath)}')
            assert expected in run.out
        for path in legacy_paths:
            expected = (
                f'Moving {yadm_legacy.join(path)} '
                f'to {yadm_dir.join(path)}')
            assert expected in run.out
        if condition == 'untracked':
            assert 'test-repo' in yadm_data.join('repo.git/config').read()
            assert 'files.gpg' in yadm_data.join('archive').read()
            for path in legacy_paths:
                assert path in yadm_dir.join(path).read()
        elif condition in ['tracked', 'submodules']:
            expected = (
                f'mv {yadm_dir.join("files.gpg")} '
                f'{yadm_data.join("archive")}')
            assert expected in run.out
            assert 'files tracked by yadm have been renamed' in run.out
            if condition == 'submodules':
                assert 'submodule deinit -- mymodule' in run.out
                assert 'submodule update --init --recursive -- mymodule' \
                    in run.out
            else:
                assert 'submodule deinit' not in run.out
                assert 'submodule update --init --recursive' not in run.out
