def test_unravel_path_no_resolvers():
    import time
    from jupyter_sigplot.sigplot import _unravel_path

    tilde_full = os.path.expanduser('~')

    # Go all the way through the environment instead of a mock to be sure the
    # whole thing works end to end
    with EnvironmentVariable('TEST_UNRAVEL', str(time.time())) as envvar:
        env_key = envvar.key
        env_val = envvar.new_value

        cases = [
            # input                 # expected output
            ('',                    ''),
            ('.',                   '.'),

            ('~',                   tilde_full),

            ('$%s' % env_key,       env_val),
            ('/$%s' % env_key,      os.path.join('/', env_val)),

            ('~/$%s' % env_key,     os.path.join(tilde_full, env_val)),
        ]

        for (input, expected) in cases:
            actual = _unravel_path(input)
            assert(actual == expected)
def test_unravel_path():
    import time
    from jupyter_sigplot.sigplot import _unravel_path

    cwd_full = os.getcwd()
    tilde_full = os.path.expanduser('~')

    # Go all the way through the environment instead of a mock to be sure the
    # whole thing works end to end
    with EnvironmentVariable('TEST_UNRAVEL', str(time.time())) as envvar:
        env_key = envvar.key
        env_val = envvar.new_value

        cases = [
            # input                 # expected output
            ('', cwd_full),
            ('.', cwd_full),
            ('./nonesuch/..', cwd_full),
            ('~', tilde_full),

            # Leading / because bare words are unraveled relative to cwd
            ('/$%s' % env_key, os.path.join('/', env_val)),
            ('~/$%s' % env_key, os.path.join(tilde_full, env_val)),
            ('/', '/'),
            ('/../', '/'),
        ]

        platform_specific_cases = [
            ('/tmp', '/tmp'),
            ('/tmp/foo/..', '/tmp'),
        ]

        for (input, expected) in platform_specific_cases:
            # macOS-compatibility
            if sys.platform.startswith('darwin'):
                cases.append((input, "/private" + expected))
            else:
                cases.append((input, expected))

        for (input, expected) in cases:
            actual = _unravel_path(input)
            assert (actual == expected)
def test_unravel_path_resolvers(expandvars_mock, expanduser_mock):
    # This test isolates just the behavior of the `resolvers` argument to
    # _unravel_path. The set of test cases grows rather quickly if you cross
    # resolver equivalence classes with input equivalence classes, so we'll
    # just trust that testing each axis independently is sufficient.
    from jupyter_sigplot.sigplot import _unravel_path

    # Set up scaffolding to record the names of functions, in order, as they
    # are called.
    call_list = []

    def reset():
        call_list[:] = []

    # Note that all functions take a single argument
    def make_recorder(name):
        def f(a):
            call_list.append(name)
            return a
        return f

    def recordit(f):
        r = make_recorder(f.__name__)

        def wrapped(a):
            r(a)
            return f(a)
        wrapped.__name__ = f.__name__
        return wrapped

    expandvars_mock.side_effect = make_recorder('expandvars')
    expanduser_mock.side_effect = make_recorder('expanduser')

    @recordit
    def one(p): return p + '1'

    @recordit
    def two(p): return p + '2'

    @recordit
    def three(p): return p + '3'

    for resolvers, expected in [
            ([],                     ''),
            ([one],                  '1'),
            ([one, two],             '12'),
            ([two, one],             '21'),
            ([one, two, three],      '123'),
            ([three, two, one, one], '3211'),
    ]:
        reset()
        expected_names = ['expandvars', 'expanduser'] + \
                         [f.__name__ for f in resolvers]
        actual = _unravel_path('', resolvers)
        # Ensure that resolvers are called in the right sequence relative to
        # one another and relative to expandvars/expanduser
        assert(call_list == expected_names)
        # Ensure that resolvers are composed (output of rN is input of rN+1)
        assert(actual == expected)

    # Check that we get an error when resolvers arg is not as expected
    for resolvers in [
        3,
        # 0, Equivalent to resolvers=None, i.e., no resolvers
        'a string',
        [3, 0],
        ['a string'],
    ]:
        with pytest.raises(TypeError):
            _unravel_path('foo.tmp', resolvers)