import getpass
import lzma
import os
import re
import sys

import pytest

import py7zr
import py7zr.archiveinfo
import py7zr.callbacks
import py7zr.cli
import py7zr.properties

from . import check_output, decode_all, ltime2

if sys.version_info < (3, 6):
    import pathlib2 as pathlib
else:
    import pathlib

testdata_path = os.path.join(os.path.dirname(__file__), 'data')
os.umask(0o022)


@pytest.mark.basic
def test_basic_initinfo():
    archive = py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb'))
    assert archive is not None


@pytest.mark.cli
def test_cli_list_1(capsys):
    arc = os.path.join(testdata_path, 'test_1.7z')
    expected = """total 4 files and directories in solid archive
   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
"""
    expected += "{} D....            0            0  scripts\n".format(ltime2(2019, 3, 14, 0, 10, 8))
    expected += "{} ....A          111          441  scripts/py7zr\n".format(ltime2(2019, 3, 14, 0, 10, 8))
    expected += "{} ....A           58               setup.cfg\n".format(ltime2(2019, 3, 14, 0, 7, 13))
    expected += "{} ....A          559               setup.py\n".format(ltime2(2019, 3, 14, 0, 9, 1))
    expected += "------------------- ----- ------------ ------------  ------------------------\n"
    cli = py7zr.cli.Cli()
    cli.run(["l", arc])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.basic
def test_cli_list_2(capsys):
    arc = os.path.join(testdata_path, 'test_3.7z')
    expected = "total 28 files and directories in solid archive\n"
    expected += "   Date      Time    Attr         Size   Compressed  Name\n"
    expected += "------------------- ----- ------------ ------------  ------------------------\n"
    expected += "{} D....            0            0  5.9.7\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64\n".format(ltime2(2018, 10, 18, 14, 52, 43))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/include\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/include/QtX11Extras\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/lib\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/lib/cmake\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/lib/cmake/Qt5X11Extras\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/lib/pkgconfig\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/mkspecs\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} D....            0            0  5.9.7/gcc_64/mkspecs/modules\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} ....A           26         8472  5.9.7/gcc_64/include/QtX11Extras/QX11Info\n".format(ltime2(2018, 10, 16, 10, 26, 21))  # noqa: E501
    expected += "{} ....A          176               5.9.7/gcc_64/include/QtX11Extras/QtX11Extras\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A          201               5.9.7/gcc_64/include/QtX11Extras/QtX11ExtrasDepends\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A           32               5.9.7/gcc_64/include/QtX11Extras/QtX11ExtrasVersion\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A          722               5.9.7/gcc_64/lib/libQt5X11Extras.la\n".format(ltime2(2018, 10, 16, 10, 26, 27))  # noqa: E501
    expected += "{} ....A         2280               5.9.7/gcc_64/include/QtX11Extras/qtx11extrasglobal.h\n".format(ltime2(2018, 10, 16, 10, 26, 21))  # noqa: E501
    expected += "{} ....A          222               5.9.7/gcc_64/include/QtX11Extras/qtx11extrasversion.h\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A         2890               5.9.7/gcc_64/include/QtX11Extras/qx11info_x11.h\n".format(ltime2(2018, 10, 16, 10, 26, 21))  # noqa: E501
    expected += "{} ....A           24               5.9.7/gcc_64/lib/libQt5X11Extras.so\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} ....A           24               5.9.7/gcc_64/lib/libQt5X11Extras.so.5\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} ....A        14568               5.9.7/gcc_64/lib/libQt5X11Extras.so.5.9.7\n".format(ltime2(2018, 10, 16, 10, 26, 27))  # noqa: E501
    expected += "{} ....A           24               5.9.7/gcc_64/lib/libQt5X11Extras.so.5.9\n".format(ltime2(2018, 10, 18, 14, 52, 42))  # noqa: E501
    expected += "{} ....A         6704               5.9.7/gcc_64/lib/cmake/Qt5X11Extras/Qt5X11ExtrasConfig.cmake\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A          287               5.9.7/gcc_64/lib/cmake/Qt5X11Extras/Qt5X11ExtrasConfigVersion.cmake\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A          283               5.9.7/gcc_64/lib/pkgconfig/Qt5X11Extras.pc\n".format(ltime2(2018, 10, 16, 10, 26, 27))  # noqa: E501
    expected += "{} ....A          555               5.9.7/gcc_64/mkspecs/modules/qt_lib_x11extras.pri\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A          526               5.9.7/gcc_64/mkspecs/modules/qt_lib_x11extras_private.pri\n".format(ltime2(2018, 10, 16, 10, 26, 24))  # noqa: E501
    expected += "{} ....A         1064               5.9.7/gcc_64/lib/libQt5X11Extras.prl\n".format(ltime2(2018, 10, 18, 10, 28, 16))  # noqa: E501
    expected += "------------------- ----- ------------ ------------  ------------------------\n"
    cli = py7zr.cli.Cli()
    cli.run(["l", arc])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.api
def test_basic_not_implemented_yet1(tmp_path):
    with pytest.raises(NotImplementedError):
        py7zr.SevenZipFile(tmp_path.joinpath('test_x.7z'), mode='x')


@pytest.mark.api
def test_basic_not_implemented_yet3(tmp_path):
    with tmp_path.joinpath('test_a.7z').open('w') as f:
        f.write('foo')
    with pytest.raises(NotImplementedError):
        py7zr.SevenZipFile(tmp_path.joinpath('test_a.7z'), mode='a')


@pytest.mark.api
def test_basic_wrong_option_value(tmp_path):
    with pytest.raises(ValueError):
        py7zr.SevenZipFile(tmp_path.joinpath('test_p.7z'), mode='p')


@pytest.mark.basic
def test_basic_extract_1(tmp_path):
    archive = py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb'))
    expected = [{'filename': 'setup.cfg', 'mode': 33188, 'mtime': 1552522033,
                 'digest': 'ff77878e070c4ba52732b0c847b5a055a7c454731939c3217db4a7fb4a1e7240'},
                {'filename': 'setup.py', 'mode': 33188, 'mtime': 1552522141,
                 'digest': 'b916eed2a4ee4e48c51a2b51d07d450de0be4dbb83d20e67f6fd166ff7921e49'},
                {'filename': 'scripts/py7zr', 'mode': 33261, 'mtime': 1552522208,
                'digest': 'b0385e71d6a07eb692f5fb9798e9d33aaf87be7dfff936fd2473eab2a593d4fd'}
                ]
    decode_all(archive, expected, tmp_path)


@pytest.mark.basic
def test_basic_extract_2(tmp_path):
    archive = py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_2.7z'), 'rb'))
    expected = [{'filename': 'qt.qt5.597.gcc_64/installscript.qs',
                 'digest': '39445276e79ea43c0fa8b393b35dc621fcb2045cb82238ddf2b838a4fbf8a587'}]
    decode_all(archive, expected, tmp_path)


@pytest.mark.basic
def test_basic_decode_3(tmp_path):
    """Test when passing path string instead of file-like object."""
    archive = py7zr.SevenZipFile(os.path.join(testdata_path, 'test_1.7z'))
    expected = [{'filename': 'setup.cfg', 'mode': 33188, 'mtime': 1552522033,
                 'digest': 'ff77878e070c4ba52732b0c847b5a055a7c454731939c3217db4a7fb4a1e7240'}]
    decode_all(archive, expected, tmp_path)


@pytest.mark.api
def test_py7zr_is_7zfile():
    assert py7zr.is_7zfile(os.path.join(testdata_path, 'test_1.7z'))


@pytest.mark.api
def test_py7zr_is_7zfile_fileish():
    assert py7zr.is_7zfile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb'))


@pytest.mark.api
def test_py7zr_is_7zfile_path():
    assert py7zr.is_7zfile(pathlib.Path(testdata_path).joinpath('test_1.7z'))


@pytest.mark.basic
def test_py7zr_is_not_7zfile(tmp_path):
    target = tmp_path.joinpath('test_not.7z')
    with target.open('wb') as f:
        f.write(b'12345dahodjg98adfjfak;')
    with target.open('rb') as f:
        assert not py7zr.is_7zfile(f)


@pytest.mark.cli
def test_cli_help(capsys):

    expected = 'usage: py7zr [-h] [--version] {l,x,c,t,i} ...\n\npy7zr\n\noptional arguments:\n  -h, --help'
    cli = py7zr.cli.Cli()
    with pytest.raises(SystemExit):
        cli.run(["-h"])
    out, err = capsys.readouterr()
    assert out.startswith(expected)


@pytest.mark.cli
def test_cli_no_subcommand(capsys):
    expected = py7zr.cli.Cli._get_version()
    expected += '\nusage: py7zr [-h] [--version] {l,x,c,t,i} ...\n\npy7zr\n\noptional arguments:\n  -h, --help'
    cli = py7zr.cli.Cli()
    cli.run([])
    out, err = capsys.readouterr()
    assert out.startswith(expected)


@pytest.mark.cli
def test_cli_list_verbose(capsys):
    arcfile = os.path.join(testdata_path, "test_1.7z")
    expected = '''Listing archive: {}
--
Path = {}
Type = 7z
Phisical Size = 657
Headers Size = 216
Method = LZMA2
Solid = +
Blocks = 1

total 4 files and directories in solid archive
   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
'''.format(arcfile, arcfile)
    expected += "{} D....            0            0  scripts\n".format(ltime2(2019, 3, 14, 0, 10, 8))
    expected += "{} ....A          111          441  scripts/py7zr\n".format(ltime2(2019, 3, 14, 0, 10, 8))
    expected += "{} ....A           58               setup.cfg\n".format(ltime2(2019, 3, 14, 0, 7, 13))
    expected += "{} ....A          559               setup.py\n".format(ltime2(2019, 3, 14, 0, 9, 1))
    expected += "------------------- ----- ------------ ------------  ------------------------\n"
    cli = py7zr.cli.Cli()
    cli.run(["l", "--verbose", arcfile])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.cli
def test_cli_test(capsys):
    arcfile = os.path.join(testdata_path, 'test_2.7z')
    expected = """Testing archive: {}
--
Path = {}
Type = 7z
Phisical Size = 1663
Headers Size = 203
Method = LZMA2
Solid = -
Blocks = 1

Everything is Ok
""".format(arcfile, arcfile)
    cli = py7zr.cli.Cli()
    cli.run(["t", arcfile])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.cli
def test_cli_info(capsys):
    expected = py7zr.cli.Cli._get_version()
    if lzma.is_check_supported(lzma.CHECK_CRC64):
        check0 = '\n0              CRC64'
    else:
        check0 = ''
    if lzma.is_check_supported(lzma.CHECK_SHA256):
        check1 = '\n0             SHA256'
    else:
        check1 = ''
    expected_checks = '''0              CRC32{}{}'''.format(check1, check0)
    expected += '''\n
Formats:
7z    37 7a bc af 27 1c

Codecs and hashes:
00              COPY
21             LZMA2
03             DELTA
030101          LZMA
03030103         BCJ
03030205         PPC
03030401        IA64
03030501         ARM
03030701        ARMT
03030805       SPARC
040108       DEFLATE
040202         BZip2
04f71101   ZStandard
06f10701       7zAES
{}
'''.format(expected_checks)
    cli = py7zr.cli.Cli()
    cli.run(["i"])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.cli
def test_cli_extract(tmp_path):
    arcfile = os.path.join(testdata_path, "test_1.7z")
    cli = py7zr.cli.Cli()
    cli.run(["x", arcfile, str(tmp_path.resolve())])
    expected = [{'filename': 'setup.cfg', 'mode': 33188, 'mtime': 1552522033,
                 'digest': 'ff77878e070c4ba52732b0c847b5a055a7c454731939c3217db4a7fb4a1e7240'},
                {'filename': 'setup.py', 'mode': 33188, 'mtime': 1552522141,
                 'digest': 'b916eed2a4ee4e48c51a2b51d07d450de0be4dbb83d20e67f6fd166ff7921e49'},
                {'filename': 'scripts/py7zr', 'mode': 33261, 'mtime': 1552522208,
                 'digest': 'b0385e71d6a07eb692f5fb9798e9d33aaf87be7dfff936fd2473eab2a593d4fd'}
                ]
    check_output(expected, tmp_path)


@pytest.mark.cli
def test_cli_encrypted_extract(monkeypatch, tmp_path):

    def _getpasswd():
        return 'secret'

    monkeypatch.setattr(getpass, "getpass", _getpasswd)

    arcfile = os.path.join(testdata_path, "encrypted_1.7z")
    cli = py7zr.cli.Cli()
    cli.run(["x", "--password", arcfile, str(tmp_path.resolve())])
    expected = [{'filename': 'test1.txt', 'mode': 33188,
                 'digest': '0f16b2f4c3a74b9257cd6229c0b7b91855b3260327ef0a42ecf59c44d065c5b2'},
                {'filename': 'test/test2.txt', 'mode': 33188,
                 'digest': '1d0d28682fca74c5912ea7e3f6878ccfdb6e4e249b161994b7f2870e6649ef09'}
                ]
    check_output(expected, tmp_path)


@pytest.mark.basic
def test_digests():
    arcfile = os.path.join(testdata_path, "test_2.7z")
    archive = py7zr.SevenZipFile(arcfile)
    assert archive.test() is None
    assert archive.testzip() is None


@pytest.mark.basic
def test_digests_corrupted():
    arcfile = os.path.join(testdata_path, "crc_corrupted.7z")
    with py7zr.SevenZipFile(arcfile) as archive:
        assert archive.test() is None
        archive.reset()
        assert archive.testzip().endswith('src/scripts/py7zr')


@pytest.mark.cli
def test_non7z_ext(capsys, tmp_path):
    expected = "not a 7z file\n"
    arcfile = os.path.join(testdata_path, "test_1.txt")
    cli = py7zr.cli.Cli()
    cli.run(["x", arcfile, str(tmp_path.resolve())])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.cli
def test_non7z_test(capsys):
    expected = "not a 7z file\n"
    arcfile = os.path.join(testdata_path, "test_1.txt")
    cli = py7zr.cli.Cli()
    cli.run(["t", arcfile])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.cli
def test_non7z_list(capsys):
    expected = "not a 7z file\n"
    arcfile = os.path.join(testdata_path, "test_1.txt")
    cli = py7zr.cli.Cli()
    cli.run(["l", arcfile])
    out, err = capsys.readouterr()
    assert out == expected


@pytest.mark.cli
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_archive_creation(tmp_path, capsys):
    tmp_path.joinpath('src').mkdir()
    py7zr.unpack_7zarchive(os.path.join(testdata_path, 'test_1.7z'), path=tmp_path.joinpath('src'))
    os.chdir(str(tmp_path))
    target = "target.7z"
    source = 'src'
    cli = py7zr.cli.Cli()
    cli.run(['c', target, source])
    out, err = capsys.readouterr()


@pytest.mark.cli
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_archive_already_exist(tmp_path, capsys):
    expected = 'Archive file exists!\n'
    py7zr.unpack_7zarchive(os.path.join(testdata_path, 'test_1.7z'), path=tmp_path.joinpath('src'))
    target = tmp_path / "target.7z"
    with target.open('w') as f:
        f.write('Already exist!')
    source = str(tmp_path / 'src')
    cli = py7zr.cli.Cli()
    with pytest.raises(SystemExit):
        cli.run(['c', str(target), source])
    out, err = capsys.readouterr()
    assert err == expected


@pytest.mark.cli
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_archive_without_extension(tmp_path, capsys):
    py7zr.unpack_7zarchive(os.path.join(testdata_path, 'test_1.7z'), path=tmp_path.joinpath('src'))
    target = str(tmp_path / "target")
    source = str(tmp_path / 'src')
    cli = py7zr.cli.Cli()
    cli.run(['c', target, source])
    expected_target = tmp_path / "target.7z"
    assert expected_target.exists()


@pytest.mark.cli
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher")
def test_volume_creation(tmp_path, capsys):
    tmp_path.joinpath('src').mkdir()
    py7zr.unpack_7zarchive(os.path.join(testdata_path, 'lzma2bcj.7z'), path=tmp_path.joinpath('src'))
    target = str(tmp_path / "target.7z")
    source = str(tmp_path / 'src')
    cli = py7zr.cli.Cli()
    cli.run(['c', target, source, '-v', '2m'])
    out, err = capsys.readouterr()


@pytest.mark.cli
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher")
def test_volume_creation_wrong_volume_unit(tmp_path, capsys):
    expected = 'Error: Specified volume size is invalid.\n'
    target = str(tmp_path / "target.7z")
    source = tmp_path / 'src'
    source.mkdir()
    cli = py7zr.cli.Cli()
    with pytest.raises(SystemExit):
        cli.run(['c', target, str(source), '-v', '2P'])
    out, err = capsys.readouterr()
    assert err == expected


@pytest.mark.unit
def test_py7zr_write_mode(tmp_path):
    target = tmp_path.joinpath('target.7z')
    archive = py7zr.SevenZipFile(target, 'w')
    archive.write(os.path.join(testdata_path, "test1.txt"), "test1.txt")
    assert archive.files is not None
    assert len(archive.files) == 1
    for f in archive.files:
        assert f.filename in ('test1.txt')
        assert not f.emptystream


@pytest.mark.api
def test_py7zr_writeall_single(tmp_path):
    target = tmp_path.joinpath('target.7z')
    archive = py7zr.SevenZipFile(target, 'w')
    archive.writeall(os.path.join(testdata_path, "test1.txt"), "test1.txt")
    assert archive.files is not None
    assert len(archive.files) == 1
    for f in archive.files:
        assert f.filename in ('test1.txt')
        assert not f.emptystream


@pytest.mark.api
def test_py7zr_writeall_dir(tmp_path):
    target = tmp_path.joinpath('target.7z')
    archive = py7zr.SevenZipFile(target, 'w')
    archive.writeall(os.path.join(testdata_path, "src"), "src")
    assert archive.files is not None
    assert len(archive.files) == 2
    for f in archive.files:
        assert f.filename in ('src', 'src/bra.txt')
    archive._fpclose()


@pytest.mark.api
def test_py7zr_extract_specified_file(tmp_path):
    archive = py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb'))
    expected = [{'filename': 'scripts/py7zr', 'mode': 33261, 'mtime': 1552522208,
                'digest': 'b0385e71d6a07eb692f5fb9798e9d33aaf87be7dfff936fd2473eab2a593d4fd'}
                ]
    archive.extract(path=tmp_path, targets=['scripts', 'scripts/py7zr'])
    archive.close()
    assert tmp_path.joinpath('scripts').is_dir()
    assert tmp_path.joinpath('scripts/py7zr').exists()
    assert not tmp_path.joinpath('setup.cfg').exists()
    assert not tmp_path.joinpath('setup.py').exists()
    check_output(expected, tmp_path)


@pytest.mark.api
def test_py7zr_extract_and_getnames(tmp_path):
    archive = py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb'))
    allfiles = archive.getnames()
    filter_pattern = re.compile(r'scripts.*')
    targets = []
    for f in allfiles:
        if filter_pattern.match(f):
            targets.append(f)
    archive.extract(path=tmp_path, targets=targets)
    archive.close()
    assert tmp_path.joinpath('scripts').is_dir()
    assert tmp_path.joinpath('scripts/py7zr').exists()
    assert not tmp_path.joinpath('setup.cfg').exists()
    assert not tmp_path.joinpath('setup.py').exists()


@pytest.mark.api
def test_py7zr_extract_and_reset_iteration(tmp_path):
    archive = py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb'))
    iterations = archive.getnames()
    for target in iterations:
        archive.extract(path=tmp_path, targets=[target])
        archive.reset()
    archive.close()
    assert tmp_path.joinpath('scripts').is_dir()
    assert tmp_path.joinpath('scripts/py7zr').exists()
    assert tmp_path.joinpath('setup.cfg').exists()
    assert tmp_path.joinpath('setup.py').exists()


@pytest.mark.api
def test_context_manager_1(tmp_path):
    with py7zr.SevenZipFile(os.path.join(testdata_path, 'test_1.7z'), 'r') as z:
        z.extractall(path=tmp_path)
    assert tmp_path.joinpath('scripts').is_dir()
    assert tmp_path.joinpath('scripts/py7zr').exists()
    assert tmp_path.joinpath('setup.cfg').exists()
    assert tmp_path.joinpath('setup.py').exists()


@pytest.mark.api
def test_context_manager_2(tmp_path):
    target = tmp_path.joinpath('target.7z')
    with py7zr.SevenZipFile(target, 'w') as z:
        z.writeall(os.path.join(testdata_path, "src"), "src")


@pytest.mark.api
def test_extract_callback(tmp_path):

    class ECB(py7zr.callbacks.ExtractCallback):

        def __init__(self, ofd):
            self.ofd = ofd

        def report_start_preparation(self):
            self.ofd.write('preparation.\n')

        def report_start(self, processing_file_path, processing_bytes):
            self.ofd.write('start \"{}\" (compressed in {} bytes)\n'.format(processing_file_path, processing_bytes))

        def report_end(self, processing_file_path, wrote_bytes):
            self.ofd.write('end \"{}\" extracted to {} bytes\n'.format(processing_file_path, wrote_bytes))

        def report_postprocess(self):
            self.ofd.write('post processing.\n')

        def report_warning(self, message):
            self.ofd.write('warning: {:s}\n'.format(message))

    cb = ECB(sys.stdout)
    with py7zr.SevenZipFile(open(os.path.join(testdata_path, 'test_1.7z'), 'rb')) as archive:
        archive.extractall(path=tmp_path, callback=cb)


@pytest.mark.api
def test_py7zr_list_values():
    with py7zr.SevenZipFile(os.path.join(testdata_path, 'test_1.7z'), 'r') as z:
        file_list = z.list()
    assert file_list[0].filename == 'scripts'
    assert file_list[1].filename == 'scripts/py7zr'
    assert file_list[2].filename == 'setup.cfg'
    assert file_list[3].filename == 'setup.py'
    assert file_list[0].uncompressed == 0
    assert file_list[1].uncompressed == 111
    assert file_list[2].uncompressed == 58
    assert file_list[3].uncompressed == 559
    assert file_list[0].is_directory is True
    assert file_list[1].archivable is True
    assert file_list[2].archivable is True
    assert file_list[3].archivable is True
    assert file_list[0].compressed == 0
    assert file_list[1].compressed == 441
    assert file_list[2].compressed is None
    assert file_list[3].compressed is None
    assert file_list[0].crc32 is None
    assert file_list[1].crc32 == 0xb36aaedb
    assert file_list[2].crc32 == 0xdcbf8d07
    assert file_list[3].crc32 == 0x80fc72be
