import os
import pytest
import pickle
from fsspec.core import _expand_paths, OpenFile, caches, get_compression
from fsspec.implementations.tests.test_memory import m


@pytest.mark.parametrize('path, name_function, num, out', [
    [['apath'], None, 1, ['apath']],
    ['apath.*.csv', None, 1, ['apath.0.csv']],
    ['apath.*.csv', None, 2, ['apath.0.csv', 'apath.1.csv']],
    ['a*', lambda x: 'abc'[x], 2, ['aa', 'ab']]
])
def test_expand_paths(path, name_function, num, out):
    assert _expand_paths(path, name_function, num) == out


def test_expand_error():
    with pytest.raises(ValueError):
        _expand_paths("*.*", None, 1)


def test_openfile_api(m):
    m.open('somepath', 'wb').write(b'data')
    of = OpenFile(m, 'somepath')
    assert str(of) == "<OpenFile 'somepath'>"
    f = of.open()
    assert f.read() == b'data'
    f.close()
    with OpenFile(m, 'somepath', mode='rt') as f:
        f.read() == 'data'


# For test_cache_pickleable(). Functions are only picklable if they are defined
# at the top-level of a module
def _fetcher(start, end):
    return b'0' * (end - start)


@pytest.mark.parametrize('Cache_imp', caches.values())
def test_cache_empty_file(Cache_imp):
    blocksize = 5
    size = 0
    cache = Cache_imp(blocksize, _fetcher, size)
    assert cache._fetch(0, 0) == b''


@pytest.mark.parametrize('Cache_imp', caches.values())
def test_cache_pickleable(Cache_imp):
    blocksize = 5
    size = 100
    cache = Cache_imp(blocksize, _fetcher, size)
    cache._fetch(0, 5)  # fill in cache
    unpickled = pickle.loads(pickle.dumps(cache))
    assert isinstance(unpickled, Cache_imp)
    assert unpickled.blocksize == blocksize
    assert unpickled.size == size
    assert unpickled._fetch(0, 10) == b'0' * 10


def test_xz_lzma_compressions():
    pytest.importorskip("lzma")
    # Ensure that both 'xz' and 'lzma' compression names can be parsed
    assert get_compression('some_file.xz', 'infer') == 'xz'
    assert get_compression('some_file.xz', 'xz') == 'xz'
    assert get_compression('some_file.xz', 'lzma') == 'lzma'
