File: test_zopfli.py

package info (click to toggle)
python-zopfli 0.2.3.post1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 192 kB
  • sloc: ansic: 372; python: 335; makefile: 8
file content (145 lines) | stat: -rw-r--r-- 4,097 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python

import gzip
import shutil
import subprocess
import sys
import zlib
from io import BytesIO
from pathlib import Path

import zopfli.gzip
import zopfli.zlib
import zopfli.png

import pytest


class BaseTests(object):
    data = (Path(__file__).parent.parent / "README.rst").read_bytes()

    def test_reversible(self):
        data = self.data
        assert self.decompress(self.compress(data)) == data

    def test_iterations_help(self):
        data = self.data
        assert len(self.compress(data, numiterations=1)) > len(
            self.compress(data, numiterations=1000)
        )


class TestZlib(BaseTests):
    compress = staticmethod(zopfli.zlib.compress)
    decompress = staticmethod(zlib.decompress)


class TestGzip(BaseTests):

    compress = staticmethod(zopfli.gzip.compress)

    def decompress(self, s):
        return gzip.GzipFile(fileobj=BytesIO(s)).read()


# The first eight bytes of a PNG file always contain the following (decimal) values:
#   137 80 78 71 13 10 26 10
# https://www.w3.org/TR/PNG-Structure.html
PNG_HEADER = b"\x89PNG\r\n\x1a\n"

DATA_DIR = Path(__file__).parent / "data"


class TestPngOptimize:
    @staticmethod
    def assert_valid_png_header(data):
        assert len(data) >= 8
        assert data[:8] == PNG_HEADER

    @pytest.fixture(params=list(DATA_DIR.glob("*.png")))
    def png_file(self, request):
        return request.param

    @pytest.fixture
    def png_data(self, png_file):
        png = png_file.read_bytes()
        self.assert_valid_png_header(png)
        return png

    @pytest.mark.parametrize(
        "kwargs",
        [
            {},  # default
            {"verbose": True},
            {"lossy_transparent": True},
            {"lossy_8bit": True},
            {"use_zopfli": False},
            {"filter_strategies": "01234mepb"},
            {"keepchunks": ["gAMA", "bKGD"]},
            {"num_iterations": 30},
            {"num_iterations_large": 10},
        ],
    )
    def test_optimize_with_arguments(self, png_data, kwargs):
        result_png = zopfli.png.optimize(png_data, **kwargs)

        self.assert_valid_png_header(result_png)
        assert len(result_png) < len(png_data)

    @pytest.mark.parametrize(
        "options",
        [
            [],  # default
            ["-v"],
            ["-m"],
            ["--lossy_transparent", "--lossy_8bit"],
            ["-q"],
            ["--always_zopflify"],
            ["--iterations", "20"],
            ["--filters", "0me"],
            ["--keepchunks", "sBIT,bKGD"],
        ],
    )
    def test_cli(self, png_file, tmp_path, options):
        output_file = tmp_path / png_file.name
        cmd = (
            [sys.executable, "-m", "zopfli.png"]
            + options
            + [str(png_file), str(output_file)]
        )
        p = subprocess.run(cmd, check=True, capture_output=True)
        if "-v" in options:
            assert "Result is smaller" in p.stdout.decode()
        assert output_file.exists()
        assert output_file.stat().st_size < png_file.stat().st_size

    @pytest.mark.parametrize(
        "overwrite, answer", [(True, ""), (False, "y"), (False, "N")]
    )
    def test_cli_overwrite(self, tmp_path, answer, overwrite):
        input_file = next(DATA_DIR.glob("*.png"))
        output_file = tmp_path / input_file.name
        shutil.copy(input_file, output_file)
        cmd = (
            [sys.executable, "-m", "zopfli.png", "-v"]
            + (["-y"] if overwrite else [])
            + [str(input_file), str(output_file)]
        )

        p = subprocess.run(cmd, input=answer.encode(), check=True, capture_output=True)

        stdout = p.stdout.decode()

        assert "Result is smaller" in stdout
        assert ("exists, overwrite? (y/N)" in stdout) ^ overwrite

        if overwrite or answer == "y":
            assert output_file.stat().st_size < input_file.stat().st_size
        elif not overwrite and answer == "N":
            assert output_file.stat().st_size == input_file.stat().st_size


if __name__ == "__main__":
    import sys

    pytest.main(sys.argv)