File: InflaterClose.java

package info (click to toggle)
openjdk-25 25.0.1%2B8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 825,408 kB
  • sloc: java: 5,585,680; cpp: 1,333,948; xml: 1,321,242; ansic: 488,034; asm: 404,003; objc: 21,088; sh: 15,106; javascript: 13,265; python: 8,319; makefile: 2,518; perl: 357; awk: 351; pascal: 103; exp: 83; sed: 72; jsp: 24
file content (271 lines) | stat: -rw-r--r-- 12,808 bytes parent folder | download | duplicates (3)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*
 * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import org.junit.jupiter.api.Test;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.jupiter.api.Assertions.assertEquals;

/*
 * @test
 * @bug 8225763
 * @summary Test that the close() and end() methods on java.util.zip.Inflater
 * @run junit InflaterClose
 */
public class InflaterClose {

    private static final String originalStr = "foobarhelloworld!!!!";
    private static final byte[] originalBytes = originalStr.getBytes(US_ASCII);
    private static final byte[] compressedData = compress();

    /**
     * Closes the Inflater multiple times and then expects close() and end() to be called that
     * many times.
     */
    @Test
    public void testCloseMultipleTimes() throws Exception {
        final int numTimes = 3;
        final Inflater simpleInflater = new Inflater();
        final String inflatedData = closeMultipleTimesAfterInflating(numTimes, simpleInflater);
        assertValidInflatedData(inflatedData, simpleInflater.getClass());

        final OverrideClose overriddenClose = new OverrideClose();
        final String ocInflatedData = closeMultipleTimesAfterInflating(numTimes, overriddenClose);
        assertValidInflatedData(ocInflatedData, overriddenClose.getClass());
        // make sure close was called numTimes
        assertEquals(numTimes, overriddenClose.numTimesCloseCalled, "close() was expected to be" +
                " called " + numTimes + ", but was called " + overriddenClose.numTimesCloseCalled +
                " time(s) on " + overriddenClose.getClass().getName());

        final OverrideEnd overriddenEnd = new OverrideEnd();
        final String oeInflatedData = closeMultipleTimesAfterInflating(numTimes, overriddenEnd);
        assertValidInflatedData(oeInflatedData, overriddenEnd.getClass());
        // make sure end was called called numTimes
        assertEquals(numTimes, overriddenEnd.numTimesEndCalled, "end() was expected to be called " +
                numTimes + ", but was called " + overriddenEnd.numTimesEndCalled + " time(s) on " +
                overriddenEnd.getClass().getName());

        final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
        final String oceInflatedData = closeMultipleTimesAfterInflating(numTimes,
                overriddenCloseAndEnd);
        assertValidInflatedData(oceInflatedData, overriddenCloseAndEnd.getClass());
        // make sure end was called called numTimes
        assertEquals(numTimes, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected" +
                " to be called " + numTimes + ", but was called " +
                overriddenCloseAndEnd.numTimesEndCalled +
                " time(s) on " + overriddenCloseAndEnd.getClass().getName());
        assertEquals(numTimes, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected" +
                " to be called " + numTimes + ", but was called " +
                overriddenCloseAndEnd.numTimesCloseCalled + " time(s) on " +
                overriddenCloseAndEnd.getClass().getName());
    }

    /**
     * Closes the Inflater first and then calls end(). Verifies that close() was called
     * just once but end() was called twice (once internally through close() and once
     * explicitly)
     */
    @Test
    public void testCloseThenEnd() throws Exception {
        final Inflater simpleInflater = new Inflater();
        final String inflatedData = inflateCloseThenEnd(simpleInflater);
        assertValidInflatedData(inflatedData, simpleInflater.getClass());

        final OverrideClose overriddenClose = new OverrideClose();
        final String ocInflatedData = inflateCloseThenEnd(overriddenClose);
        assertValidInflatedData(ocInflatedData, overriddenClose.getClass());
        // make sure close was called once
        assertEquals(1, overriddenClose.numTimesCloseCalled, "close() was expected to be called" +
                " once, but was called " + overriddenClose.numTimesCloseCalled + " time(s) on "
                + overriddenClose.getClass().getName());

        final OverrideEnd overriddenEnd = new OverrideEnd();
        final String oeInflatedData = inflateCloseThenEnd(overriddenEnd);
        assertValidInflatedData(oeInflatedData, overriddenEnd.getClass());
        // make sure end was called twice (once through close() and then explicitly)
        assertEquals(2, overriddenEnd.numTimesEndCalled, "end() was expected to be called twice," +
                " but was called " + overriddenEnd.numTimesEndCalled + " time(s) on "
                + overriddenEnd.getClass().getName());

        final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
        final String oceInflatedData = inflateCloseThenEnd(overriddenCloseAndEnd);
        assertValidInflatedData(oceInflatedData, overriddenCloseAndEnd.getClass());
        // make sure end was called twice (once through close and once explicitly)
        // and close was called once
        assertEquals(2, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to be called" +
                " twice, but was called " + overriddenCloseAndEnd.numTimesEndCalled
                + " time(s) on " + overriddenCloseAndEnd.getClass().getName());
        assertEquals(1, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected to be" +
                " called once, but was called " + overriddenClose.numTimesCloseCalled
                + " time(s) on " + overriddenCloseAndEnd.getClass().getName());
    }

    /**
     * Calls end() on the Inflater first and then calls close(). Verifies that close() was called
     * just once and end() twice.
     */
    @Test
    public void testEndThenClose() throws Exception {
        final Inflater simpleInflater = new Inflater();
        final String inflatedData = inflateThenEndThenClose(simpleInflater);
        assertValidInflatedData(inflatedData, simpleInflater.getClass());

        final OverrideClose overriddenClose = new OverrideClose();
        final String ocInflatedData = inflateThenEndThenClose(overriddenClose);
        assertValidInflatedData(ocInflatedData, overriddenClose.getClass());
        // make sure close was called once
        assertEquals(1, overriddenClose.numTimesCloseCalled, "close() was expected to be" +
                " called once, but was called " + overriddenClose.numTimesCloseCalled +
                " time(s) on " + overriddenClose.getClass().getName());

        final OverrideEnd overriddenEnd = new OverrideEnd();
        final String oeInflatedData = inflateThenEndThenClose(overriddenEnd);
        assertValidInflatedData(oeInflatedData, overriddenEnd.getClass());
        // make sure end was called twice (once through the explicit end call and
        // once through close())
        assertEquals(2, overriddenEnd.numTimesEndCalled, "end() was expected to be called twice," +
                " but was called " + overriddenEnd.numTimesEndCalled + " time(s) on "
                + overriddenEnd.getClass().getName());

        final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
        final String oceInflatedData = inflateThenEndThenClose(overriddenCloseAndEnd);
        assertValidInflatedData(oceInflatedData, overriddenCloseAndEnd.getClass());
        // make sure end was called twice (once through the explicit end call and
        // once through close())
        assertEquals(2, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to be called" +
                " twice, but was called " + overriddenCloseAndEnd.numTimesEndCalled +
                " time(s) on " + overriddenCloseAndEnd.getClass().getName());
        assertEquals(1, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected to be" +
                " called once, but was called " + overriddenClose.numTimesCloseCalled +
                " time(s) on " + overriddenCloseAndEnd.getClass().getName());
    }


    private String closeMultipleTimesAfterInflating(final int numTimes, final Inflater inflater)
            throws DataFormatException {
        // inflate() then call close() multiple times
        final byte[] inflatedData = inflate(inflater, compressedData);
        // call close()
        for (int i = 0; i < numTimes; i++) {
            inflater.close();
        }
        return new String(inflatedData, StandardCharsets.UTF_8);
    }

    private String inflateCloseThenEnd(final Inflater inflater) throws Exception {
        final byte[] inflatedData;
        // inflate then close() and then end()
        try (final Inflater inflt = inflater) {
            inflatedData = inflate(inflt, compressedData);
        }
        // end() the already closed inflater
        inflater.end();
        return new String(inflatedData, StandardCharsets.UTF_8);
    }

    private String inflateThenEndThenClose(final Inflater inflater) throws Exception {
        final byte[] inflatedData;
        // inflate then end() and then close()
        try (final Inflater inflt = inflater) {
            inflatedData = inflate(inflt, compressedData);
            // end() it first before it's (auto)closed by the try-with-resources
            inflt.end();
        }
        return new String(inflatedData, StandardCharsets.UTF_8);
    }

    private static byte[] inflate(final Inflater inflater, final byte[] compressedData)
            throws DataFormatException {
        final ByteArrayOutputStream inflatedData = new ByteArrayOutputStream();
        inflater.setInput(compressedData);
        while (!inflater.finished()) {
            byte[] tmpBuffer = new byte[100];
            final int numDecompressed = inflater.inflate(tmpBuffer);
            inflatedData.write(tmpBuffer, 0, numDecompressed);
        }
        return inflatedData.toByteArray();
    }

    private static byte[] compress() {
        final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
        try (final Deflater deflater = new Deflater()) {
            deflater.setInput(originalBytes);
            deflater.finish();
            while (!deflater.finished()) {
                final byte[] tmpBuffer = new byte[100];
                final int numCompressed = deflater.deflate(tmpBuffer);
                compressedBaos.write(tmpBuffer, 0, numCompressed);
            }
        }
        return compressedBaos.toByteArray();
    }

    private static void assertValidInflatedData(final String inflatedData,
                                                final Class<?> inflaterType) {
        assertEquals(originalStr, inflatedData, "Unexpected inflated data " + inflatedData
                + " generated by " + inflaterType.getName() + ", expected " + originalStr);
    }

    private static final class OverrideEnd extends Inflater {
        private int numTimesEndCalled = 0;

        @Override
        public void end() {
            this.numTimesEndCalled++;
            super.end();
        }
    }

    private static final class OverrideClose extends Inflater {
        private int numTimesCloseCalled = 0;

        @Override
        public void close() {
            this.numTimesCloseCalled++;
            super.close();
        }
    }

    private static final class OverrideCloseAndEnd extends Inflater {
        private int numTimesEndCalled = 0;
        private int numTimesCloseCalled = 0;

        @Override
        public void end() {
            this.numTimesEndCalled++;
            super.end();
        }

        @Override
        public void close() {
            this.numTimesCloseCalled++;
            super.close();
        }
    }
}