1 /*
2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package test.java.io.InputStream;
24 
25 import org.testng.annotations.Test;
26 
27 /**
28  * @test
29  * @bug 4016710 6516099
30  * @summary check for correct implementation of InputStream.skip{NBytes}
31  */
32 
33 import java.io.EOFException;
34 import java.io.InputStream;
35 import java.io.IOException;
36 
37 public class Skip {
38     private static final int EOF = -1;
39 
dotest(InputStream in, int curpos, long total, long toskip, long expected)40     private static void dotest(InputStream in, int curpos, long total,
41                                long toskip, long expected) throws Exception {
42         try {
43             System.err.println("\n\nCurrently at pos = " + curpos +
44                                "\nTotal bytes in the Stream = " + total +
45                                "\nNumber of bytes to skip = " + toskip +
46                                "\nNumber of bytes that should be skipped = " +
47                                expected);
48 
49             long skipped = in.skip(toskip);
50 
51             System.err.println("actual number skipped: "+ skipped);
52 
53             if ((skipped < 0) || (skipped > expected)) {
54                 throw new RuntimeException("Unexpected byte count skipped");
55             }
56         } catch (IOException e) {
57             System.err.println("IOException is thrown: " + e);
58         } catch (Throwable e) {
59             throw new RuntimeException("Unexpected " + e + " is thrown!");
60         }
61     }
62 
dotestExact(MyInputStream in, long curpos, long total, long toskip, boolean expectIOE, boolean expectEOFE)63     private static void dotestExact(MyInputStream in, long curpos, long total,
64         long toskip, boolean expectIOE, boolean expectEOFE) {
65 
66         System.err.println("\n\nCurrently at pos = " + curpos +
67                            "\nTotal bytes in the Stream = " + total +
68                            "\nNumber of bytes to skip = " + toskip);
69 
70         try {
71             long pos = in.position();
72             assert pos == curpos : pos + " != " + curpos;
73             in.skipNBytes(toskip);
74             if (in.position() != pos + (toskip < 0 ? 0 : toskip)) {
75                 throw new RuntimeException((in.position() - pos) +
76                     " bytes skipped; expected " + toskip);
77             }
78         } catch (EOFException eofe) {
79             if (!expectEOFE) {
80                 throw new RuntimeException("Unexpected EOFException", eofe);
81             }
82             System.err.println("Caught expected EOFException");
83         } catch (IOException ioe) {
84             if (!expectIOE) {
85                 throw new RuntimeException("Unexpected IOException", ioe);
86             }
87             System.err.println("Caught expected IOException");
88         }
89     }
90 
91     @Test
testSkip()92     public void testSkip() throws Exception {
93         MyInputStream in = new MyInputStream(11);
94 
95         // test for negative skip
96         dotest(in,  0, 11, -23,  0);
97 
98         // check for skip beyond EOF starting from before EOF
99         dotest(in,  0, 11,  20, 11);
100 
101         // check for skip after EOF
102         dotest(in, EOF, 11,  20,  0);
103 
104         in = new MyInputStream(9000);
105 
106         // check for skip equal to the read chunk size in InputStream.java
107         dotest(in,  0, 9000, 2048, 2048);
108 
109         // check for skip larger than the read chunk size in InputStream.java
110         dotest(in, 2048, 9000, 5000, 5000);
111 
112         // check for skip beyond EOF starting from before EOF
113         dotest(in, 7048, 9000, 5000, 1952);
114 
115         in = new MyInputStream(5000);
116 
117         // check for multiple chunk reads
118         dotest(in, 0, 5000, 6000, 5000);
119 
120         /*
121          * check for skip larger than Integer.MAX_VALUE
122          * (Takes about 2 hrs on a sparc ultra-1)
123          * long total = (long)Integer.MAX_VALUE + (long)10;
124          * long toskip = total - (long)6;
125          * in = new MyInputStream(total);
126          * dotest(in, 0, total, toskip, toskip);
127          */
128 
129         // tests for skipping an exact number of bytes
130 
131         final long streamLength = Long.MAX_VALUE;
132         in = new MyInputStream(streamLength);
133 
134         // negative skip: OK
135         dotestExact(in, 0, streamLength, -1, false, false);
136 
137         // negative skip at EOF: OK
138         in.position(streamLength);
139         dotestExact(in, streamLength, streamLength, -1, false, false);
140         in.position(0);
141 
142         // zero skip: OK
143         dotestExact(in, 0, streamLength, 0, false, false);
144 
145         // zero skip at EOF: OK
146         in.position(streamLength);
147         dotestExact(in, streamLength, streamLength, 0, false, false);
148 
149         // skip(1) at EOF: EOFE
150         dotestExact(in, streamLength, streamLength, 1, false, true);
151         in.position(0);
152 
153         final long n = 31; // skip count
154         long pos = 0;
155 
156         // skip(n) returns negative value: IOE
157         in.setState(-1, 100);
158         dotestExact(in, pos, streamLength, n, true, false);
159 
160         // skip(n) returns n + 1: IOE
161         in.setState(n + 1, 100);
162         dotestExact(in, pos, streamLength, n, true, false);
163         pos += n + 1;
164 
165         // skip(n) returns n/2 but only n/4 subsequent reads succeed: EOFE
166         in.setState(n/2, n/2 + n/4);
167         dotestExact(in, pos, streamLength, n, false, true);
168         pos += n/2 + n/4;
169 
170         // skip(n) returns n/2 but n - n/2 subsequent reads succeed: OK
171         in.setState(n/2, n);
172         dotestExact(in, pos, streamLength, n, false, false);
173         pos += n;
174     }
175 }
176 
177 class MyInputStream extends InputStream {
178     private static final int EOF = -1;
179 
180     private final long endoffile;
181 
182     private long readctr = 0;
183 
184     private boolean isStateSet = false;
185     private long skipReturn;
186     private long readLimit;
187 
MyInputStream(long endoffile)188     public MyInputStream(long endoffile) {
189         this.endoffile = endoffile;
190     }
191 
192     /**
193      * Limits the behavior of skip() and read().
194      *
195      * @param skipReturn the value to be returned by skip()
196      * @param maxReads   the maximum number of reads past the current position
197      *                   before EOF is reached
198      */
setState(long skipReturn, long maxReads)199     public void setState(long skipReturn, long maxReads) {
200         this.skipReturn = skipReturn;
201         this.readLimit = readctr + maxReads;
202         isStateSet = true;
203     }
204 
read()205     public int read() {
206         if (readctr == endoffile ||
207             (isStateSet && readctr >= readLimit)) {
208             return EOF;
209         }
210         else {
211             readctr++;
212             return 0;
213         }
214     }
215 
available()216     public int available() { return 0; }
217 
position()218     public long position() { return readctr; }
219 
position(long pos)220     public void position(long pos) {
221         readctr = pos < 0 ? 0 : Math.min(pos, endoffile);
222     }
223 
224     public long skip(long n) throws IOException {
225         if (isStateSet) {
226             return skipReturn < 0 ? skipReturn : super.skip(skipReturn);
227         }
228 
229         // InputStream skip implementation.
230         return super.skip(n); // readctr is implicitly incremented
231     }
232 }
233