from collections import defaultdict, namedtuple
from contextlib import contextmanager
import os
from os.path import join
import random
import unittest

import pytest

from conda import CondaError
from conda.base.context import context, reset_context
from conda.cli.python_api import Commands, run_command
from conda.common.io import env_var
from conda.core.solve import get_pinned_specs
from conda.exceptions import PackagesNotFoundError
from conda.gateways.disk.create import mkdir_p
import conda.instructions as inst
from conda.models.dist import Dist
from conda.models.records import PackageRecord
from conda.models.match_spec import MatchSpec
from conda.plan import display_actions, add_unlink, add_defaults_to_specs, _update_old_plan as update_old_plan
from conda.exports import execute_plan
from .decorators import skip_if_no_mock
from .gateways.disk.test_permissions import tempdir
from .helpers import captured, get_index_r_1, mock, tempdir

index, r, = get_index_r_1()
index = index.copy()  # create a shallow copy so this module can mutate state

try:
    from unittest.mock import patch
except ImportError:
    from mock import patch


def DPkg(s, **kwargs):
    d = Dist(s)
    _kwargs = dict(
        fn=d.to_filename(),
        name=d.name,
        version=d.version,
        build=d.build_string,
        build_number=int(d.build_string.rsplit('_', 1)[-1]),
        channel=d.channel,
        subdir=context.subdir,
        md5="012345789",
    )
    _kwargs.update(kwargs)
    return PackageRecord(**_kwargs)

def solve(specs):
    return [Dist.from_string(fn) for fn in r.solve(specs)]


class add_unlink_TestCase(unittest.TestCase):
    def generate_random_dist(self):
        return "foobar-%s-0" % random.randint(100, 200)

    @contextmanager
    def mock_platform(self, windows=False):
        from conda import plan
        with mock.patch.object(plan, "sys") as sys:
            sys.platform = "win32" if windows else "not win32"
            yield sys

    @skip_if_no_mock
    def test_simply_adds_unlink_on_non_windows(self):
        actions = {}
        dist = Dist.from_string(self.generate_random_dist())
        with self.mock_platform(windows=False):
            add_unlink(actions, dist)
        self.assertIn(inst.UNLINK, actions)
        self.assertEqual(actions[inst.UNLINK], [dist, ])

    @skip_if_no_mock
    def test_adds_to_existing_actions(self):
        actions = {inst.UNLINK: [{"foo": "bar"}]}
        dist = Dist.from_string(self.generate_random_dist())
        with self.mock_platform(windows=False):
            add_unlink(actions, dist)
        self.assertEqual(2, len(actions[inst.UNLINK]))


class TestAddDeaultsToSpec(unittest.TestCase):
    # tests for plan.add_defaults_to_specs(r, linked, specs)

    def check(self, specs, added):
        new_specs = list(specs + added)
        add_defaults_to_specs(r, self.linked, specs)
        specs = [s.split(' (')[0] for s in specs]
        self.assertEqual(specs, new_specs)

    # def test_1(self):
    #     self.linked = solve(['anaconda 1.5.0', 'python 2.7*', 'numpy 1.7*'])
    #     for specs, added in [
    #         (['python 3*'], []),
    #         (['python'], ['python 2.7*']),
    #         (['scipy'], ['python 2.7*']),
    #         ]:
    #         self.check(specs, added)
    #
    # def test_2(self):
    #     self.linked = solve(['anaconda 1.5.0', 'python 2.6*', 'numpy 1.6*'])
    #     for specs, added in [
    #         (['python'], ['python 2.6*']),
    #         (['numpy'], ['python 2.6*']),
    #         (['pandas'], ['python 2.6*']),
    #         # however, this would then be unsatisfiable
    #         (['python 3*', 'numpy'], []),
    #         ]:
    #         self.check(specs, added)
    #
    # def test_3(self):
    #     self.linked = solve(['anaconda 1.5.0', 'python 3.3*'])
    #     for specs, added in [
    #         (['python'], ['python 3.3*']),
    #         (['numpy'], ['python 3.3*']),
    #         (['scipy'], ['python 3.3*']),
    #         ]:
    #         self.check(specs, added)
    #
    # def test_4(self):
    #     self.linked = []
    #     for dp in ('2.7', '3.5'):
    #         with env_var('CONDA_DEFAULT_PYTHON', dp, reset_context):
    #             ps = ['python 2.7*'] if context.default_python == '2.7' else []
    #             for specs, added in [
    #                 (['python'], ps),
    #                 (['numpy'], ps),
    #                 (['scipy'], ps),
    #                 (['anaconda'], ps),
    #                 (['anaconda 1.5.0 np17py27_0'], []),
    #                 (['sympy 0.7.2 py27_0'], []),
    #                 (['scipy 0.12.0 np16py27_0'], []),
    #                 (['anaconda', 'python 3*'], []),
    #                 ]:
    #                 self.check(specs, added)


def test_display_actions_0():
    os.environ['CONDA_SHOW_CHANNEL_URLS'] = 'False'
    reset_context(())
    actions = defaultdict(list, {"FETCH": [Dist('channel-1::sympy-0.7.2-py27_0'), Dist("channel-1::numpy-1.7.1-py27_0")]})
    # The older test index doesn't have the size metadata
    d = Dist.from_string('channel-1::sympy-0.7.2-py27_0.tar.bz2')
    index[d] = PackageRecord.from_objects(index[d], size=4374752)
    d = Dist.from_string("channel-1::numpy-1.7.1-py27_0.tar.bz2")
    index[d] = PackageRecord.from_objects(index[d], size=5994338)

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    sympy-0.7.2                |           py27_0         4.2 MB
    numpy-1.7.1                |           py27_0         5.7 MB
    ------------------------------------------------------------
                                           Total:         9.9 MB

"""

    actions = defaultdict(list, {'PREFIX':
    '/Users/aaronmeurer/anaconda/envs/test', 'SYMLINK_CONDA':
    ['/Users/aaronmeurer/anaconda'], 'LINK': ['channel-1::python-3.3.2-0', 'channel-1::readline-6.2-0 1', 'channel-1::sqlite-3.7.13-0 1', 'channel-1::tk-8.5.13-0 1', 'channel-1::zlib-1.2.7-0 1']})

    with captured() as c:
        display_actions(actions, index)


    assert c.stdout == """
## Package Plan ##

  environment location: /Users/aaronmeurer/anaconda/envs/test


The following NEW packages will be INSTALLED:

    python:   3.3.2-0 \n\
    readline: 6.2-0   \n\
    sqlite:   3.7.13-0
    tk:       8.5.13-0
    zlib:     1.2.7-0 \n\

"""

    actions['UNLINK'] = actions['LINK']
    actions['LINK'] = []

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##

  environment location: /Users/aaronmeurer/anaconda/envs/test


The following packages will be REMOVED:

    python:   3.3.2-0 \n\
    readline: 6.2-0   \n\
    sqlite:   3.7.13-0
    tk:       8.5.13-0
    zlib:     1.2.7-0 \n\

"""

    actions = defaultdict(list, {'LINK': ['channel-1::cython-0.19.1-py33_0'], 'UNLINK':
    ['channel-1::cython-0.19-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    cython: 0.19-py33_0 --> 0.19.1-py33_0

"""

    actions['LINK'], actions['UNLINK'] = actions['UNLINK'], actions['LINK']

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    cython: 0.19.1-py33_0 --> 0.19-py33_0

"""

    actions = defaultdict(list, {'LINK': ['channel-1::cython-0.19.1-py33_0',
        'channel-1::dateutil-1.5-py33_0', 'channel-1::numpy-1.7.1-py33_0'], 'UNLINK':
        ['channel-1::cython-0.19-py33_0', 'channel-1::dateutil-2.1-py33_1', 'channel-1::pip-1.3.1-py33_1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following NEW packages will be INSTALLED:

    numpy:    1.7.1-py33_0

The following packages will be REMOVED:

    pip:      1.3.1-py33_1

The following packages will be UPDATED:

    cython:   0.19-py33_0  --> 0.19.1-py33_0

The following packages will be DOWNGRADED:

    dateutil: 2.1-py33_1   --> 1.5-py33_0   \n\

"""

    actions = defaultdict(list, {'LINK': ['channel-1::cython-0.19.1-py33_0',
        'channel-1::dateutil-2.1-py33_1'], 'UNLINK':  ['channel-1::cython-0.19-py33_0',
            'channel-1::dateutil-1.5-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    cython:   0.19-py33_0 --> 0.19.1-py33_0
    dateutil: 1.5-py33_0  --> 2.1-py33_1   \n\

"""

    actions['LINK'], actions['UNLINK'] = actions['UNLINK'], actions['LINK']

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 --> 0.19-py33_0
    dateutil: 2.1-py33_1    --> 1.5-py33_0 \n\

"""


def test_display_actions_show_channel_urls():
    os.environ['CONDA_SHOW_CHANNEL_URLS'] = 'True'
    reset_context(())
    actions = defaultdict(list, {"FETCH": ['sympy-0.7.2-py27_0',
        "numpy-1.7.1-py27_0"]})
    # The older test index doesn't have the size metadata
    d = Dist('sympy-0.7.2-py27_0.tar.bz2')
    index[d] = DPkg(d, size=4374752)
    d = Dist('numpy-1.7.1-py27_0.tar.bz2')
    index[d] = DPkg(d, size=5994338)

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    sympy-0.7.2                |           py27_0         4.2 MB  <unknown>
    numpy-1.7.1                |           py27_0         5.7 MB  <unknown>
    ------------------------------------------------------------
                                           Total:         9.9 MB

"""

    actions = defaultdict(list, {'PREFIX':
    '/Users/aaronmeurer/anaconda/envs/test', 'SYMLINK_CONDA':
    ['/Users/aaronmeurer/anaconda'], 'LINK': ['channel-1::python-3.3.2-0', 'channel-1::readline-6.2-0', 'channel-1::sqlite-3.7.13-0', 'channel-1::tk-8.5.13-0', 'channel-1::zlib-1.2.7-0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##

  environment location: /Users/aaronmeurer/anaconda/envs/test


The following NEW packages will be INSTALLED:

    python:   3.3.2-0  channel-1
    readline: 6.2-0    channel-1
    sqlite:   3.7.13-0 channel-1
    tk:       8.5.13-0 channel-1
    zlib:     1.2.7-0  channel-1

"""

    actions['UNLINK'] = actions['LINK']
    actions['LINK'] = []

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##

  environment location: /Users/aaronmeurer/anaconda/envs/test


The following packages will be REMOVED:

    python:   3.3.2-0  channel-1
    readline: 6.2-0    channel-1
    sqlite:   3.7.13-0 channel-1
    tk:       8.5.13-0 channel-1
    zlib:     1.2.7-0  channel-1

"""

    actions = defaultdict(list, {'LINK': ['channel-1::cython-0.19.1-py33_0'], 'UNLINK':
    ['channel-1::cython-0.19-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    cython: 0.19-py33_0 channel-1 --> 0.19.1-py33_0 channel-1

"""

    actions['LINK'], actions['UNLINK'] = actions['UNLINK'], actions['LINK']

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    cython: 0.19.1-py33_0 channel-1 --> 0.19-py33_0 channel-1

"""

    actions = defaultdict(list, {'LINK': ['channel-1::cython-0.19.1-py33_0',
        'channel-1::dateutil-1.5-py33_0', 'channel-1::numpy-1.7.1-py33_0'], 'UNLINK':
        ['channel-1::cython-0.19-py33_0', 'channel-1::dateutil-2.1-py33_1', 'channel-1::pip-1.3.1-py33_1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following NEW packages will be INSTALLED:

    numpy:    1.7.1-py33_0 channel-1

The following packages will be REMOVED:

    pip:      1.3.1-py33_1 channel-1

The following packages will be UPDATED:

    cython:   0.19-py33_0  channel-1 --> 0.19.1-py33_0 channel-1

The following packages will be DOWNGRADED:

    dateutil: 2.1-py33_1   channel-1 --> 1.5-py33_0    channel-1

"""

    actions = defaultdict(list, {'LINK': ['channel-1::cython-0.19.1-py33_0',
        'channel-1::dateutil-2.1-py33_1'], 'UNLINK':  ['channel-1::cython-0.19-py33_0',
            'channel-1::dateutil-1.5-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    cython:   0.19-py33_0 channel-1 --> 0.19.1-py33_0 channel-1
    dateutil: 1.5-py33_0  channel-1 --> 2.1-py33_1    channel-1

"""

    actions['LINK'], actions['UNLINK'] = actions['UNLINK'], actions['LINK']

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 channel-1 --> 0.19-py33_0 channel-1
    dateutil: 2.1-py33_1    channel-1 --> 1.5-py33_0  channel-1

"""

    actions['LINK'], actions['UNLINK'] = actions['UNLINK'], actions['LINK']

    d = Dist('channel-1::cython-0.19.1-py33_0.tar.bz2')
    index[d] = DPkg(d, channel='my_channel')
    d = Dist('channel-1::dateutil-1.5-py33_0.tar.bz2')
    index[d] = DPkg(d, channel='my_channel')

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    cython:   0.19-py33_0 channel-1  --> 0.19.1-py33_0 my_channel
    dateutil: 1.5-py33_0  my_channel --> 2.1-py33_1    channel-1 \n\

"""

    actions['LINK'], actions['UNLINK'] = actions['UNLINK'], actions['LINK']

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 my_channel --> 0.19-py33_0 channel-1 \n\
    dateutil: 2.1-py33_1    channel-1  --> 1.5-py33_0  my_channel

"""


@pytest.mark.xfail(strict=True, reason="Not reporting link type until refactoring display_actions "
                                       "after txn.verify()")
def test_display_actions_link_type():
    os.environ['CONDA_SHOW_CHANNEL_URLS'] = 'False'
    reset_context(())

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 2', 'dateutil-1.5-py33_0 2',
    'numpy-1.7.1-py33_0 2', 'python-3.3.2-0 2', 'readline-6.2-0 2', 'sqlite-3.7.13-0 2', 'tk-8.5.13-0 2', 'zlib-1.2.7-0 2']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following NEW packages will be INSTALLED:

    cython:   0.19.1-py33_0 (softlink)
    dateutil: 1.5-py33_0    (softlink)
    numpy:    1.7.1-py33_0  (softlink)
    python:   3.3.2-0       (softlink)
    readline: 6.2-0         (softlink)
    sqlite:   3.7.13-0      (softlink)
    tk:       8.5.13-0      (softlink)
    zlib:     1.2.7-0       (softlink)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 2',
        'dateutil-2.1-py33_1 2'], 'UNLINK':  ['cython-0.19-py33_0',
            'dateutil-1.5-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be UPDATED:

    cython:   0.19-py33_0 --> 0.19.1-py33_0 (softlink)
    dateutil: 1.5-py33_0  --> 2.1-py33_1    (softlink)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19-py33_0 2',
        'dateutil-1.5-py33_0 2'], 'UNLINK':  ['cython-0.19.1-py33_0',
            'dateutil-2.1-py33_1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 --> 0.19-py33_0 (softlink)
    dateutil: 2.1-py33_1    --> 1.5-py33_0  (softlink)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 1', 'dateutil-1.5-py33_0 1',
    'numpy-1.7.1-py33_0 1', 'python-3.3.2-0 1', 'readline-6.2-0 1', 'sqlite-3.7.13-0 1', 'tk-8.5.13-0 1', 'zlib-1.2.7-0 1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following NEW packages will be INSTALLED:

    cython:   0.19.1-py33_0
    dateutil: 1.5-py33_0   \n\
    numpy:    1.7.1-py33_0 \n\
    python:   3.3.2-0      \n\
    readline: 6.2-0        \n\
    sqlite:   3.7.13-0     \n\
    tk:       8.5.13-0     \n\
    zlib:     1.2.7-0      \n\

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 1',
        'dateutil-2.1-py33_1 1'], 'UNLINK':  ['cython-0.19-py33_0',
            'dateutil-1.5-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be UPDATED:

    cython:   0.19-py33_0 --> 0.19.1-py33_0
    dateutil: 1.5-py33_0  --> 2.1-py33_1   \n\

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19-py33_0 1',
        'dateutil-1.5-py33_0 1'], 'UNLINK':  ['cython-0.19.1-py33_0',
            'dateutil-2.1-py33_1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 --> 0.19-py33_0
    dateutil: 2.1-py33_1    --> 1.5-py33_0 \n\

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 3', 'dateutil-1.5-py33_0 3',
    'numpy-1.7.1-py33_0 3', 'python-3.3.2-0 3', 'readline-6.2-0 3', 'sqlite-3.7.13-0 3', 'tk-8.5.13-0 3', 'zlib-1.2.7-0 3']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following NEW packages will be INSTALLED:

    cython:   0.19.1-py33_0 (copy)
    dateutil: 1.5-py33_0    (copy)
    numpy:    1.7.1-py33_0  (copy)
    python:   3.3.2-0       (copy)
    readline: 6.2-0         (copy)
    sqlite:   3.7.13-0      (copy)
    tk:       8.5.13-0      (copy)
    zlib:     1.2.7-0       (copy)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 3',
        'dateutil-2.1-py33_1 3'], 'UNLINK':  ['cython-0.19-py33_0',
            'dateutil-1.5-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be UPDATED:

    cython:   0.19-py33_0 --> 0.19.1-py33_0 (copy)
    dateutil: 1.5-py33_0  --> 2.1-py33_1    (copy)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19-py33_0 3',
        'dateutil-1.5-py33_0 3'], 'UNLINK':  ['cython-0.19.1-py33_0',
            'dateutil-2.1-py33_1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 --> 0.19-py33_0 (copy)
    dateutil: 2.1-py33_1    --> 1.5-py33_0  (copy)

"""
    os.environ['CONDA_SHOW_CHANNEL_URLS'] = 'True'
    reset_context(())

    d = Dist('cython-0.19.1-py33_0.tar.bz2')
    index[d] = PackageRecord.from_objects(index[d], channel='my_channel')

    d = Dist('dateutil-1.5-py33_0.tar.bz2')
    index[d] = PackageRecord.from_objects(index[d], channel='my_channel')

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 3', 'dateutil-1.5-py33_0 3',
    'numpy-1.7.1-py33_0 3', 'python-3.3.2-0 3', 'readline-6.2-0 3', 'sqlite-3.7.13-0 3', 'tk-8.5.13-0 3', 'zlib-1.2.7-0 3']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following NEW packages will be INSTALLED:

    cython:   0.19.1-py33_0 my_channel (copy)
    dateutil: 1.5-py33_0    my_channel (copy)
    numpy:    1.7.1-py33_0  <unknown>  (copy)
    python:   3.3.2-0       <unknown>  (copy)
    readline: 6.2-0         <unknown>  (copy)
    sqlite:   3.7.13-0      <unknown>  (copy)
    tk:       8.5.13-0      <unknown>  (copy)
    zlib:     1.2.7-0       <unknown>  (copy)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19.1-py33_0 3',
        'dateutil-2.1-py33_1 3'], 'UNLINK':  ['cython-0.19-py33_0',
            'dateutil-1.5-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be UPDATED:

    cython:   0.19-py33_0 <unknown>  --> 0.19.1-py33_0 my_channel (copy)
    dateutil: 1.5-py33_0  my_channel --> 2.1-py33_1    <unknown>  (copy)

"""

    actions = defaultdict(list, {'LINK': ['cython-0.19-py33_0 3',
        'dateutil-1.5-py33_0 3'], 'UNLINK':  ['cython-0.19.1-py33_0',
            'dateutil-2.1-py33_1']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
The following packages will be DOWNGRADED:

    cython:   0.19.1-py33_0 my_channel --> 0.19-py33_0 <unknown>  (copy)
    dateutil: 2.1-py33_1    <unknown>  --> 1.5-py33_0  my_channel (copy)

"""


def test_display_actions_features():
    os.environ['CONDA_SHOW_CHANNEL_URLS'] = 'False'
    reset_context(())

    actions = defaultdict(list, {'LINK': ['channel-1::numpy-1.7.1-py33_p0', 'channel-1::cython-0.19-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following NEW packages will be INSTALLED:

    cython: 0.19-py33_0  \n\
    numpy:  1.7.1-py33_p0 [mkl]

"""

    actions = defaultdict(list, {'UNLINK': ['channel-1::numpy-1.7.1-py33_p0', 'channel-1::cython-0.19-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be REMOVED:

    cython: 0.19-py33_0  \n\
    numpy:  1.7.1-py33_p0 [mkl]

"""

    actions = defaultdict(list, {'UNLINK': ['channel-1::numpy-1.7.1-py33_p0'], 'LINK': ['channel-1::numpy-1.7.0-py33_p0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    numpy: 1.7.1-py33_p0 [mkl] --> 1.7.0-py33_p0 [mkl]

"""

    actions = defaultdict(list, {'LINK': ['channel-1::numpy-1.7.1-py33_p0'], 'UNLINK': ['channel-1::numpy-1.7.0-py33_p0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    numpy: 1.7.0-py33_p0 [mkl] --> 1.7.1-py33_p0 [mkl]

"""

    actions = defaultdict(list, {'LINK': ['channel-1::numpy-1.7.1-py33_p0'], 'UNLINK': ['channel-1::numpy-1.7.1-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    # NB: Packages whose version do not changed are put in UPDATED
    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    numpy: 1.7.1-py33_0 --> 1.7.1-py33_p0 [mkl]

"""

    actions = defaultdict(list, {'UNLINK': ['channel-1::numpy-1.7.1-py33_p0'], 'LINK': ['channel-1::numpy-1.7.1-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    numpy: 1.7.1-py33_p0 [mkl] --> 1.7.1-py33_0

"""
    os.environ['CONDA_SHOW_CHANNEL_URLS'] = 'True'
    reset_context(())

    actions = defaultdict(list, {'LINK': ['channel-1::numpy-1.7.1-py33_p0', 'channel-1::cython-0.19-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following NEW packages will be INSTALLED:

    cython: 0.19-py33_0   channel-1
    numpy:  1.7.1-py33_p0 channel-1 [mkl]

"""

    actions = defaultdict(list, {'UNLINK': ['channel-1::numpy-1.7.1-py33_p0', 'channel-1::cython-0.19-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be REMOVED:

    cython: 0.19-py33_0   channel-1
    numpy:  1.7.1-py33_p0 channel-1 [mkl]

"""

    actions = defaultdict(list, {'UNLINK': ['channel-1::numpy-1.7.1-py33_p0'], 'LINK': ['channel-1::numpy-1.7.0-py33_p0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be DOWNGRADED:

    numpy: 1.7.1-py33_p0 channel-1 [mkl] --> 1.7.0-py33_p0 channel-1 [mkl]

"""

    actions = defaultdict(list, {'LINK': ['channel-1::numpy-1.7.1-py33_p0'], 'UNLINK': ['channel-1::numpy-1.7.0-py33_p0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    numpy: 1.7.0-py33_p0 channel-1 [mkl] --> 1.7.1-py33_p0 channel-1 [mkl]

"""

    actions = defaultdict(list, {'LINK': ['channel-1::numpy-1.7.1-py33_p0'], 'UNLINK': ['channel-1::numpy-1.7.1-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    # NB: Packages whose version do not changed are put in UPDATED
    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    numpy: 1.7.1-py33_0 channel-1 --> 1.7.1-py33_p0 channel-1 [mkl]

"""

    actions = defaultdict(list, {'UNLINK': ['channel-1::numpy-1.7.1-py33_p0'], 'LINK': ['channel-1::numpy-1.7.1-py33_0']})

    with captured() as c:
        display_actions(actions, index)

    assert c.stdout == """
## Package Plan ##


The following packages will be UPDATED:

    numpy: 1.7.1-py33_p0 channel-1 [mkl] --> 1.7.1-py33_0 channel-1

"""


class TestDeprecatedExecutePlan(unittest.TestCase):

    def test_update_old_plan(self):
        old_plan = ['# plan', 'INSTRUCTION arg']
        new_plan = update_old_plan(old_plan)

        expected = [('INSTRUCTION', 'arg')]
        self.assertEqual(new_plan, expected)

        with self.assertRaises(CondaError):
            update_old_plan(['INVALID'])

    def test_execute_plan(self):
        initial_commands = inst.commands

        def set_commands(cmds):
            inst.commands = cmds
        self.addCleanup(lambda : set_commands(initial_commands))

        def INSTRUCTION_CMD(state, arg):
            INSTRUCTION_CMD.called = True
            INSTRUCTION_CMD.arg = arg

        set_commands({'INSTRUCTION': INSTRUCTION_CMD})

        old_plan = ['# plan', 'INSTRUCTION arg']

        execute_plan(old_plan)

        self.assertTrue(INSTRUCTION_CMD.called)
        self.assertEqual(INSTRUCTION_CMD.arg, 'arg')


def generate_mocked_resolve(pkgs, install=None):
    mock_package = namedtuple("IndexRecord",
                              ["preferred_env", "name", "schannel", "version", "fn"])
    mock_resolve = namedtuple("Resolve", ["get_dists_for_spec", "index", "explicit", "install",
                                          "package_name", "dependency_sort"])

    index = {}
    groups = defaultdict(list)
    for preferred_env, name, schannel, version in pkgs:
        dist = Dist.from_string('%s-%s-0' % (name, version), channel_override=schannel)
        pkg = mock_package(preferred_env=preferred_env, name=name, schannel=schannel,
                           version=version, fn=name)
        groups[name].append(dist)
        index[dist] = pkg

    def get_dists_for_spec(spec, emptyok=False):
        # Here, spec should be a MatchSpec
        res = groups[spec.name]
        if not res and not emptyok:
            raise PackagesNotFoundError((spec,))
        return res

    def get_explicit(spec):
        return True

    def get_install(spec, installed, update_deps=None):
        return install

    def get_package_name(dist):
        return dist.name

    def get_dependency_sort(specs):
        return tuple(spec for spec in specs.values())

    return mock_resolve(get_dists_for_spec=get_dists_for_spec, index=index, explicit=get_explicit,
                        install=get_install, package_name=get_package_name,
                        dependency_sort=get_dependency_sort)


def generate_mocked_record(dist_name):
    mocked_record = namedtuple("Record", ["dist_name"])
    return mocked_record(dist_name=dist_name)


def generate_mocked_context(prefix, root_prefix, envs_dirs):
    mocked_context = namedtuple("Context", ["prefix", "root_prefix", "envs_dirs", "prefix_specified"])
    return mocked_context(prefix=prefix, root_prefix=root_prefix, envs_dirs=envs_dirs, prefix_specified=False)


# class TestDetermineAllEnvs(unittest.TestCase):
#     def setUp(self):
#         self.res = generate_mocked_resolve([
#             ("ranenv", "test-spec", "rando_chnl", "1"),
#             (None, "test-spec", "defaults", "5"),
#             ("test1", "test-spec2", "defaults", "1")
#         ])
#         self.specs = [MatchSpec("test-spec"), MatchSpec("test-spec2")]
#
#     def test_determine_all_envs(self):
#         specs_for_envs = plan.determine_all_envs(self.res, self.specs)
#         expected_output = (plan.SpecForEnv(env=None, spec="test-spec"),
#                            plan.SpecForEnv(env="_test1_", spec="test-spec2"))
#         self.assertEquals(specs_for_envs, expected_output)
#
#     def test_determine_all_envs_with_channel_priority(self):
#         self.res = generate_mocked_resolve([
#             (None, "test-spec", "defaults", "5"),
#             ("ranenv", "test-spec", "rando_chnl", "1"),
#             ("test1", "test-spec2", "defaults", "1")
#         ])
#         prioritized_channel_map = prioritize_channels(tuple(["rando_chnl", "defaults"]))
#         specs_for_envs_w_channel_priority = plan.determine_all_envs(
#             self.res, self.specs, prioritized_channel_map)
#         expected_output = (plan.SpecForEnv(env="_ranenv_", spec="test-spec"),
#                            plan.SpecForEnv(env="_test1_", spec="test-spec2"))
#         self.assertEquals(specs_for_envs_w_channel_priority, expected_output)
#
#     def test_determine_all_envs_no_package(self):
#         specs = [MatchSpec("no-exist")]
#         with pytest.raises(NoPackagesFoundError) as err:
#             plan.determine_all_envs(self.res, specs)
#             assert "no-exist package not found" in str(err)


# class TestEnsurePackageNotDuplicatedInPrivateEnvRoot(unittest.TestCase):
#     def setUp(self):
#         self.linked_in_root = {
#             Dist("test1-1.2.3-bs_7"): generate_mocked_record("test1-1.2.3-bs_7")
#         }
#
#     def test_try_install_duplicate_package_in_root(self):
#         dists_for_envs = [plan.SpecForEnv(env="_env_", spec="test1"),
#                           plan.SpecForEnv(env=None, spec="something")]
#         with pytest.raises(InstallError) as err:
#             plan.ensure_package_not_duplicated_in_private_env_root(
#                 dists_for_envs, self.linked_in_root)
#             assert "Package test1 is already installed" in str(err)
#             assert "Can't install in private environment _env_" in str(err)
#
#     def test_try_install_duplicate_package_in_private_env(self):
#         dists_for_envs = [plan.SpecForEnv(env="_env_", spec="test2"),
#                           plan.SpecForEnv(env=None, spec="test3")]
#         with patch.object(EnvsDirectory, "prefix_if_in_private_env") as mock_prefix:
#             mock_prefix.return_value = "some/prefix"
#             with pytest.raises(InstallError) as err:
#                 plan.ensure_package_not_duplicated_in_private_env_root(
#                     dists_for_envs, self.linked_in_root)
#                 assert "Package test3 is already installed" in str(err)
#                 assert "private_env some/prefix" in str(err)
#
#     def test_try_install_no_duplicate(self):
#         dists_for_envs = [plan.SpecForEnv(env="_env_", spec="test2"),
#                           plan.SpecForEnv(env=None, spec="test3")]
#         plan.ensure_package_not_duplicated_in_private_env_root(dists_for_envs, self.linked_in_root)


# # Includes testing for determine_dists_per_prefix and match_to_original_specs
# class TestGroupDistsForPrefix(unittest.TestCase):
#     def setUp(self):
#         pkgs = [
#             (None, "test-spec", "default", "1"),
#             ("ranenv", "test-spec", "default", "5"),
#             ("test1", "test-spec2", "default", "1")]
#         self.res = generate_mocked_resolve(pkgs)
#         self.specs = [MatchSpec("test-spec"), MatchSpec("test-spec2")]
#
#         self.root_prefix = root_prefix = create_temp_location()
#         mkdir_p(join(root_prefix, 'conda-meta'))
#         touch(join(root_prefix, 'conda-meta', 'history'))
#
#         self.context = generate_mocked_context(root_prefix, root_prefix,
#                                                [join(root_prefix, 'envs'),
#                                                 join(root_prefix, 'envs', '_pre_')])
#
#     def tearDown(self):
#         rm_rf(self.root_prefix)
#
#     def test_determine_dists_per_prefix_1(self):
#         with patch.object(plan, "get_resolve_object") as get_resolve_object:
#             get_resolve_object.return_value = self.res
#             preferred_envs_with_specs = {None: ["test-spec", "test-spec2"]}
#             specs_for_prefix = plan.determine_dists_per_prefix(
#                 self.root_prefix, self.res.index, preferred_envs_with_specs, self.context)
#         expected_output = [plan.SpecsForPrefix(
#             prefix=self.root_prefix, r=self.res, specs={"test-spec", "test-spec2"})]
#         self.assertEquals(specs_for_prefix, expected_output)
#
#     def test_determine_dists_per_prefix_2(self):  # not_requires
#         root_prefix = self.root_prefix
#         with env_var("CONDA_ROOT_PREFIX", root_prefix, reset_context):
#             with env_var("CONDA_ENVS_DIRS", join(root_prefix, 'envs'), reset_context):
#                 with patch.object(plan, "get_resolve_object") as gen_resolve_object_mock:
#                     gen_resolve_object_mock.return_value = self.res
#                     preferred_envs_with_specs = {None: ['test-spec', 'test-spec2'], 'ranenv': ['test']}
#                     specs_for_prefix = plan.determine_dists_per_prefix(
#                         root_prefix, self.res.index, preferred_envs_with_specs, self.context)
#                     expected_output = [
#                         plan.SpecsForPrefix(prefix=join(root_prefix, 'envs', '_ranenv_'),
#                                             r=gen_resolve_object_mock(),
#                                             specs={"test"}),
#                         plan.SpecsForPrefix(prefix=root_prefix, r=self.res,
#                                             specs=IndexedSet(("test-spec", "test-spec2")))
#                     ]
#                 self.assertEquals(expected_output, specs_for_prefix)
#
#     def test_match_to_original_specs(self):
#         str_specs = ["test 1.2.0", "test-spec 1.1*", "test-spec2 <4.3"]
#         test_r = self.res
#         grouped_specs = [
#             plan.SpecsForPrefix(prefix="some/prefix/envs/_ranenv_",
#                                 r=test_r,
#                                 specs=IndexedSet(("test",))),
#             plan.SpecsForPrefix(prefix="some/prefix", r=self.res,
#                                 specs=IndexedSet(("test-spec", "test-spec2")))]
#         matched = plan.match_to_original_specs(str_specs, grouped_specs)
#         expected_output = [
#             plan.SpecsForPrefix(prefix="some/prefix/envs/_ranenv_",
#                                 r=test_r,
#                                 specs=["test 1.2.0"]),
#             plan.SpecsForPrefix(prefix="some/prefix", r=self.res,
#                                 specs=["test-spec 1.1*", "test-spec2 <4.3"])]
#
#         assert len(matched) == len(expected_output)
#         assert matched == expected_output


class TestGetActionsForDist(unittest.TestCase):
    def setUp(self):
        self.pkgs = [
            (None, "test-spec", "defaults", "1"),
            ("ranenv", "test-spec", "defaults", "5"),
            (None, "test-spec2", "defaults", "1"),
            ("ranenv", "test", "defaults", "1.2.0")]
        self.res = generate_mocked_resolve(self.pkgs)

    # TODO: ensure_linked_actions is going away; only used in plan._remove_actions
    # @patch("conda.core.linked_data.is_linked", return_value=True)
    # def test_ensure_linked_actions_all_linked(self, load_meta):
    #     dists = [Dist("test-88"), Dist("test-spec-42"), Dist("test-spec2-8.0.0.0.1-9")]
    #     prefix = "some/prefix"
    #
    #     link_actions = plan.ensure_linked_actions(dists, prefix)
    #
    #     expected_output = defaultdict(list)
    #     expected_output["PREFIX"] = prefix
    #     expected_output["op_order"] = ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT',
    #                                    'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK',
    #                                    'SYMLINK_CONDA')
    #     self.assertEquals(link_actions, expected_output)
    #
    # @patch("conda.core.linked_data.is_linked", return_value=False)
    # def test_ensure_linked_actions_no_linked(self, load_meta):
    #     dists = [Dist("test-88"), Dist("test-spec-42"), Dist("test-spec2-8.0.0.0.1-9")]
    #     prefix = "some/prefix"
    #
    #     link_actions = plan.ensure_linked_actions(dists, prefix)
    #
    #     expected_output = defaultdict(list)
    #     expected_output["PREFIX"] = prefix
    #     expected_output["op_order"] = ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT',
    #                                    'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK',
    #                                    'SYMLINK_CONDA')
    #     expected_output["LINK"] = [Dist("test-88"), Dist("test-spec-42"), Dist("test-spec2-8.0.0.0.1-9")]
    #     self.assertEquals(link_actions, expected_output)

    # def test_get_actions_for_dist(self):
    #     install = [Dist("test-1.2.0-py36_7")]
    #     r = generate_mocked_resolve(self.pkgs, install)
    #     dists_for_prefix = plan.SpecsForPrefix(prefix="some/prefix/envs/_ranenv_", r=r,
    #                                            specs=["test 1.2.0"])
    #     actions = plan.get_actions_for_dists(dists_for_prefix, None, self.res.index, None, False,
    #                                          False, True, True)
    #
    #     expected_output = defaultdict(list)
    #     expected_output["PREFIX"] = "some/prefix/envs/_ranenv_"
    #     expected_output["op_order"] = ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT',
    #                                    'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK',
    #                                    'SYMLINK_CONDA')
    #     expected_output["LINK"] = [Dist("test-1.2.0-py36_7")]
    #     expected_output["SYMLINK_CONDA"] = [context.root_dir]
    #
    #     self.assertEquals(actions, expected_output)
    #
    # def test_get_actions_multiple_dists(self):
    #     install = [Dist("testspec2-4.3.0-1"), Dist("testspecs-1.1.1-4")]
    #     r = generate_mocked_resolve(self.pkgs, install)
    #     dists_for_prefix = plan.SpecsForPrefix(prefix="root/prefix", r=r,
    #                                            specs=["testspec2 <4.3", "testspecs 1.1*"])
    #     actions = plan.get_actions_for_dists(dists_for_prefix, None, self.res.index, None, False,
    #                                          False, True, True)
    #
    #     expected_output = defaultdict(list)
    #     expected_output["PREFIX"] = "root/prefix"
    #     expected_output["op_order"] = ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT',
    #                                    'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK',
    #                                    'SYMLINK_CONDA')
    #     expected_output["LINK"] = [Dist("testspec2-4.3.0-1"), Dist("testspecs-1.1.1-4")]
    #     expected_output["SYMLINK_CONDA"] = [context.root_dir]
    #
    #     assert actions == expected_output
    #
    # @patch("conda.core.linked_data.load_linked_data", return_value=[Dist("testspec1-0.9.1-py27_2")])
    # def test_get_actions_multiple_dists_and_unlink(self, load_linked_data):
    #     install = [Dist("testspec2-4.3.0-2"), Dist("testspec1-1.1.1-py27_0")]
    #     r = generate_mocked_resolve(self.pkgs, install)
    #     dists_for_prefix = plan.SpecsForPrefix(prefix="root/prefix", r=r,
    #                                            specs=["testspec2 <4.3", "testspec1 1.1*"])
    #
    #     test_link_data = {"root/prefix": {Dist("testspec1-0.9.1-py27_2"): True}}
    #     with patch("conda.core.linked_data.linked_data_", test_link_data):
    #         actions = plan.get_actions_for_dists(dists_for_prefix, None, self.res.index, None, False,
    #                                          False, True, True)
    #
    #     expected_output = defaultdict(list)
    #     expected_output["PREFIX"] = "root/prefix"
    #     expected_output["op_order"] = ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT',
    #                                    'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK',
    #                                    'SYMLINK_CONDA')
    #     expected_output["LINK"] = [Dist("testspec2-4.3.0-2"), Dist("testspec1-1.1.1-py27_0")]
    #     expected_output["UNLINK"] = [Dist("testspec1-0.9.1-py27_2")]
    #
    #     expected_output["SYMLINK_CONDA"] = [context.root_dir]
    #     assert expected_output["LINK"] == actions["LINK"]
    #     assert actions == expected_output


def generate_remove_action(prefix, unlink):
    action = defaultdict(list)
    action["op_order"] = ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT', 'RM_EXTRACTED',
                          'EXTRACT', 'UNLINK', 'LINK', 'SYMLINK_CONDA')
    action["PREFIX"] = prefix
    action["UNLINK"] = unlink
    return action


# class TestAddUnlinkOptionsForUpdate(unittest.TestCase):
#     def setUp(self):
#         pkgs = [
#             (None, "test1", "default", "1.0.1"),
#             ("env", "test1", "default", "2.1.4"),
#             ("env", "test2", "default", "1.1.1"),
#             (None, "test3", "default", "1.2.0"),
#             (None, "test4", "default", "1.2.1")]
#         self.res = generate_mocked_resolve(pkgs)
#
#     # @patch("conda.plan.remove_actions", return_value=generate_remove_action(
#     #     "root/prefix", [Dist("test1-2.1.4-1")]))
#     def test_update_in_private_env_add_remove_action(self):  # remove_actions
#         with tempdir() as root_prefix:
#             mkdir_p(join(root_prefix, 'conda-meta'))
#             touch(join(root_prefix, 'conda-meta', 'history'))
#             with env_var("CONDA_ROOT_PREFIX", root_prefix, reset_context):
#                 with env_var("CONDA_ENVS_DIRS", join(root_prefix, 'envs'), reset_context):
#                     with patch("conda.plan.remove_actions",
#                                return_value=generate_remove_action(root_prefix, [Dist("test1-2.1.4-1")])):
#                         preferred_env_prefix = join(root_prefix, 'envs', '_env_')
#                         required_solves = [plan.SpecsForPrefix(prefix=preferred_env_prefix,
#                                                                specs=["test1", "test2"], r=self.res),
#                                            plan.SpecsForPrefix(prefix=context.root_prefix,
#                                                                specs=["test3"],
#                                                                r=self.res)]
#
#                         action = defaultdict(list)
#                         action["PREFIX"] = preferred_env_prefix
#                         action["LINK"] = [Dist("test1-2.1.4-1"), Dist("test2-1.1.1-8")]
#                         actions = [action]
#
#                         test_link_data = {root_prefix: {Dist("test1-2.1.4-1"): True}}
#                         with patch("conda.core.linked_data.linked_data_", test_link_data):
#                             plan.add_unlink_options_for_update(actions, required_solves,
#                                                                self.res.index)
#
#                         expected_output = [action, generate_remove_action(root_prefix,
#                                                                           [Dist("test1-2.1.4-1")])]
#                         self.assertEquals(actions, expected_output)
#
#     @patch("conda.plan.remove_actions", return_value=generate_remove_action(
#         "root/prefix", [Dist("test1-2.1.4-1")]))
#     def test_update_in_private_env_append_unlink(self, remove_actions):
#         required_solves = [plan.SpecsForPrefix(prefix="root/prefix/envs/_env_",
#                                                specs=["test1", "test2"], r=self.res),
#                            plan.SpecsForPrefix(prefix=context.root_prefix, specs=["whatevs"],
#                                                r=self.res)]
#
#         action = defaultdict(list)
#         action["PREFIX"] = "root/prefix/envs/_env_"
#         action["LINK"] = [Dist("test1-2.1.4-1"), Dist("test2-1.1.1-8")]
#         action_root = defaultdict(list)
#         action_root["PREFIX"] = context.root_prefix
#         action_root["LINK"] = [Dist("whatevs-54-54")]
#         actions = [action, action_root]
#
#         test_link_data = {context.root_prefix: {Dist("test1-2.1.4-1"): True}}
#         with patch("conda.core.linked_data.linked_data_", test_link_data):
#             plan.add_unlink_options_for_update(actions, required_solves, self.res.index)
#
#         aug_action_root = defaultdict(list)
#         aug_action_root["PREFIX"] = context.root_prefix
#         aug_action_root["LINK"] = [Dist("whatevs-54-54")]
#         aug_action_root["UNLINK"] = [Dist("test1-2.1.4-1")]
#         expected_output = [action, aug_action_root]
#         self.assertEquals(actions, expected_output)
#
#     def test_update_in_root_env(self):
#         with tempdir() as root_prefix:
#             mkdir_p(join(root_prefix, 'conda-meta'))
#             touch(join(root_prefix, 'conda-meta', 'history'))
#             with env_var("CONDA_ROOT_PREFIX", root_prefix, reset_context):
#                 with env_var("CONDA_ENVS_DIRS", join(root_prefix, 'envs'), reset_context):
#                     env_path = join(root_prefix, 'envs', '_env_')
#                     ed = EnvsDirectory(join(root_prefix, 'envs'))
#                     ed.add_preferred_env_package('_env_', 'test3', join(env_path, "conda-meta", "test3-1.2.0.json"), "test3")
#                     ed.add_preferred_env_package('_env_', 'test4', join(env_path, "conda-meta", "test4-2.1.0-22.json"), "test4")
#                     required_solves = [plan.SpecsForPrefix(prefix=context.root_prefix,
#                                                            specs=["test3", "test4"],
#                                                            r=self.res)]
#
#                     action = defaultdict(list)
#                     action["PREFIX"] = root_prefix
#                     action["LINK"] = [Dist("test3-1.2.0"), Dist("test4-1.2.1")]
#                     actions = [action]
#                     plan.add_unlink_options_for_update(actions, required_solves, self.res.index)
#                     expected_output = [action, generate_remove_action(env_path, [Dist("test3-1.2.0"), Dist("test4-2.1.0-22")])]
#                     self.assertEquals(actions, expected_output)


def test_pinned_specs():
    # Test pinned specs environment variable
    specs_str_1 = ("numpy 1.11", "python >3")
    specs_1 = tuple(MatchSpec(spec_str, optional=True) for spec_str in specs_str_1)
    with env_var('CONDA_PINNED_PACKAGES', '&'.join(specs_str_1), reset_context):
        pinned_specs = get_pinned_specs("/none")
        assert pinned_specs == specs_1
        assert pinned_specs != specs_str_1

    # Test pinned specs conda environment file
    specs_str_2 = ("scipy ==0.14.2", "openjdk >=8")
    specs_2 = tuple(MatchSpec(spec_str, optional=True) for spec_str in specs_str_2)

    with tempdir() as td:
        mkdir_p(join(td, 'conda-meta'))
        with open(join(td, 'conda-meta', 'pinned'), 'w') as fh:
            fh.write("\n".join(specs_str_2))
            fh.write("\n")
        pinned_specs = get_pinned_specs(td)
        assert pinned_specs == specs_2
        assert pinned_specs != specs_str_2

    # Test pinned specs conda configuration and pinned specs conda environment file
    with tempdir() as td:
        mkdir_p(join(td, 'conda-meta'))
        with open(join(td, 'conda-meta', 'pinned'), 'w') as fh:
            fh.write("\n".join(specs_str_1))
            fh.write("\n")

        with env_var('CONDA_PREFIX', td, reset_context):
            run_command(Commands.CONFIG, "--env --add pinned_packages requests=2.13")
            with env_var('CONDA_PINNED_PACKAGES', '&'.join(specs_str_2), reset_context):
                pinned_specs = get_pinned_specs(td)
                expected = specs_2 + (MatchSpec("requests 2.13.*", optional=True),) + specs_1
                assert pinned_specs == expected
                assert pinned_specs != specs_str_1 + ("requests 2.13",) + specs_str_2



if __name__ == '__main__':
    unittest.main()
