MarkSupportedInputStream.java

1
/*-
2
 * #%L
3
 * io.earcam.utilitarian.io
4
 * %%
5
 * Copyright (C) 2017 earcam
6
 * %%
7
 * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8
 *
9
 * You <b>must</b> choose to accept, in full - any individual or combination of
10
 * the following licenses:
11
 * <ul>
12
 * 	<li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13
 * 	<li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14
 * 	<li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15
 * 	<li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16
 * </ul>
17
 * #L%
18
 */
19
package io.earcam.utilitarian.io;
20
21
import java.io.IOException;
22
import java.io.InputStream;
23
import java.util.Arrays;
24
25
import javax.annotation.concurrent.NotThreadSafe;
26
27
/**
28
 * <p>
29
 * Wraps an {@link InputStream} to ensure {@link InputStream#markSupported()} returns {@code true}.
30
 * </p>
31
 *
32
 *
33
 * <p>
34
 * <b>Note:</b> if calls to {@link #read()} exceed the {@code readLimit} parameter of {@link #mark(int)}
35
 * then the mark is removed and a call to {@link #reset()} will throw an {@link IOException}.
36
 * </p>
37
 *
38
 */
39
@NotThreadSafe
40
public final class MarkSupportedInputStream extends InputStream {
41
42
	private int[] buffer = new int[0];
43
	private int readPosition = 0;
44
	private int writePosition = 0;
45
	private int readLimit = 0;
46
	private final InputStream delegate;
47
48
49
	/**
50
	 * Create an InputStream with mark supported
51
	 *
52
	 * @param delegate the {@link InputStream} to wrap
53
	 */
54
	public MarkSupportedInputStream(InputStream delegate)
55
	{
56
		this.delegate = delegate;
57
	}
58
59
60
	/**
61
	 * For efficient use of memory, this convenience static method
62
	 * returns the {@code input} argument IFF it claims to to support marking,
63
	 * otherwise the stream is wrapped
64
	 *
65
	 * @param input the {@link InputStream} to check
66
	 * @return an {@link InputStream} that supports marking
67
	 */
68
	public static InputStream ensureMarkSupported(InputStream input)
69
	{
70 2 1. ensureMarkSupported : negated conditional → KILLED
2. ensureMarkSupported : mutated return of Object value for io/earcam/utilitarian/io/MarkSupportedInputStream::ensureMarkSupported to ( if (x != null) null else throw new RuntimeException ) → KILLED
		return input.markSupported() ? input : new MarkSupportedInputStream(input);
71
	}
72
73
74
	@Override
75
	public int read() throws IOException
76
	{
77 1 1. read : negated conditional → KILLED
		if(writePosition == readLimit) {
78
			readPosition = writePosition = readLimit = 0;
79 1 1. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
			return delegate.read();
80
		}
81 2 1. read : changed conditional boundary → KILLED
2. read : negated conditional → KILLED
		if(readPosition < writePosition) {
82 2 1. read : Replaced integer addition with subtraction → KILLED
2. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
			return buffer[readPosition++];
83
		}
84
		int read = delegate.read();
85
		buffer[writePosition] = read;
86 1 1. read : Replaced integer addition with subtraction → KILLED
		writePosition++;
87 1 1. read : Replaced integer addition with subtraction → KILLED
		readPosition++;
88 1 1. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
		return read;
89
	}
90
91
92
	@Override
93
	public final boolean markSupported()
94
	{
95 1 1. markSupported : replaced return of integer sized value with (x == 0 ? 1 : 0) → SURVIVED
		return true;
96
	}
97
98
99
	@Override
100
	public synchronized void mark(int readLimit)
101
	{
102 1 1. mark : Replaced integer addition with subtraction → KILLED
		this.readLimit = readLimit + 1;
103 4 1. mark : changed conditional boundary → SURVIVED
2. mark : changed conditional boundary → SURVIVED
3. mark : negated conditional → KILLED
4. mark : negated conditional → KILLED
		if(buffer.length < this.readLimit || readPosition > 0) {
104 1 1. mark : Replaced integer addition with subtraction → KILLED
			buffer = Arrays.copyOfRange(buffer, readPosition, readPosition + this.readLimit);
105 1 1. mark : Replaced integer subtraction with addition → KILLED
			writePosition -= readPosition;
106
		}
107
		readPosition = 0;
108
	}
109
110
111
	@Override
112
	public synchronized void reset() throws IOException
113
	{
114 1 1. reset : negated conditional → KILLED
		if(readLimit == 0) {
115
			throw new IOException("Not marked, or current position > marked position + readLimit");
116
		}
117
		readPosition = 0;
118
	}
119
}

Mutations

70

1.1
Location : ensureMarkSupported
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.ensureMarkSupportedReturnsOriginalWhenOriginalSupportsMarking()
negated conditional → KILLED

2.2
Location : ensureMarkSupported
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.ensureMarkSupportedReturnsOriginalWhenOriginalSupportsMarking()
mutated return of Object value for io/earcam/utilitarian/io/MarkSupportedInputStream::ensureMarkSupported to ( if (x != null) null else throw new RuntimeException ) → KILLED

77

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
negated conditional → KILLED

79

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

81

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
changed conditional boundary → KILLED

2.2
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
negated conditional → KILLED

82

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.increasingReadLimitMarksWithinReset()
Replaced integer addition with subtraction → KILLED

2.2
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markAndResetWithinLimit()
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

86

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
Replaced integer addition with subtraction → KILLED

87

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
Replaced integer addition with subtraction → KILLED

88

1.1
Location : read
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

95

1.1
Location : markSupported
Killed by : none
replaced return of integer sized value with (x == 0 ? 1 : 0) → SURVIVED

102

1.1
Location : mark
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markAndResetWithinLimit()
Replaced integer addition with subtraction → KILLED

103

1.1
Location : mark
Killed by : none
changed conditional boundary → SURVIVED

2.2
Location : mark
Killed by : none
changed conditional boundary → SURVIVED

3.3
Location : mark
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
negated conditional → KILLED

4.4
Location : mark
Killed by : io.earcam.utilitarian.io.ReplaceAllInputStreamTest.deleteMutlipleOccurrences()
negated conditional → KILLED

104

1.1
Location : mark
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markExceedsLimit()
Replaced integer addition with subtraction → KILLED

105

1.1
Location : mark
Killed by : io.earcam.utilitarian.io.ReplaceAllInputStreamTest.deleteMutlipleOccurrences()
Replaced integer subtraction with addition → KILLED

114

1.1
Location : reset
Killed by : io.earcam.utilitarian.io.MarkSupportedInputStreamTest.markAndResetWithinLimit()
negated conditional → KILLED

Active mutators

Tests examined


Report generated by PIT 1.4.3