InputStreamUtils.java

1
package com.renomad.minum.web;
2
3
import com.renomad.minum.security.ForbiddenUseException;
4
import com.renomad.minum.utils.UtilsException;
5
6
import java.io.ByteArrayOutputStream;
7
import java.io.IOException;
8
import java.io.InputStream;
9
import java.nio.charset.StandardCharsets;
10
import java.util.Objects;
11
12
/**
13
 * Handy helpful utilities for working with input streams.
14
 */
15
final class InputStreamUtils implements IInputStreamUtils {
16
17
    private final int maxReadLineSizeBytes;
18
19
    public InputStreamUtils(int maxReadLineSizeBytes) {
20
        this.maxReadLineSizeBytes = maxReadLineSizeBytes;
21
    }
22
23
    @Override
24
    public String readLine(InputStream inputStream) throws IOException  {
25
        final int NEWLINE_DECIMAL = 10;
26
        final int CARRIAGE_RETURN_DECIMAL = 13;
27
28 1 1. readLine : Replaced integer division with multiplication → SURVIVED
        final var result = new ByteArrayOutputStream(maxReadLineSizeBytes / 3);
29
        int bytesRead = 0;
30 1 1. readLine : Changed increment from 1 to -1 → KILLED
        for (int i = 0;; i++) {
31 2 1. readLine : changed conditional boundary → KILLED
2. readLine : negated conditional → KILLED
            if (i >= maxReadLineSizeBytes) {
32 1 1. readLine : removed call to java/io/InputStream::close → SURVIVED
                inputStream.close();
33
                throw new ForbiddenUseException("client sent more bytes than allowed for a single line.  max: " + maxReadLineSizeBytes);
34
            }
35
            int a = inputStream.read();
36 1 1. readLine : negated conditional → KILLED
            if (a == -1) {
37 2 1. readLine : negated conditional → KILLED
2. readLine : changed conditional boundary → KILLED
                if (bytesRead > 0) {
38 1 1. readLine : replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → SURVIVED
                    return result.toString(StandardCharsets.UTF_8);
39
                } else {
40
                    /*
41
                    it could be unclear whether we read a line that's an empty string, or we
42
                    reached the end of stream.  With this code, if we get an empty string,
43
                    that means the line we read is just an empty string, and if we get a null,
44
                    that means we didn't have any characters read into our ByteArrayOutputStream,
45
                    and tried reading at the end of stream.
46
                    */
47 1 1. readLine : replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → KILLED
                    return null;
48
                }
49
            }
50 1 1. readLine : negated conditional → KILLED
            if (a == CARRIAGE_RETURN_DECIMAL) continue;
51 1 1. readLine : negated conditional → KILLED
            if (a == NEWLINE_DECIMAL) break;
52 1 1. readLine : removed call to java/io/ByteArrayOutputStream::write → KILLED
            result.write(a);
53 1 1. readLine : Changed increment from 1 to -1 → KILLED
            bytesRead += 1;
54
        }
55 1 1. readLine : replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → KILLED
        return result.toString(StandardCharsets.UTF_8);
56
    }
57
58
    @Override
59
    public byte[] read(int lengthToRead, InputStream inputStream) {
60
        final int typicalBufferSize = 1024 * 8;
61
        byte[] buf = new byte[Math.min(lengthToRead, typicalBufferSize)]; // 8k buffer is my understanding of a decent size.  Fast, doesn't waste too much space.
62
        byte[] data;
63
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
64
        int read;
65
        int totalRead = 0;
66
        try {
67 2 1. read : changed conditional boundary → KILLED
2. read : negated conditional → KILLED
            while ((read = inputStream.read(buf)) >= 0) {
68 1 1. read : Replaced integer addition with subtraction → KILLED
                totalRead += read;
69 2 1. read : negated conditional → KILLED
2. read : changed conditional boundary → KILLED
                if (totalRead < lengthToRead) {
70
                    // if we haven't gotten everything we wanted, write this to the output and loop again
71 1 1. read : removed call to java/io/ByteArrayOutputStream::write → KILLED
                    baos.write(buf, 0, read);
72
                } else {
73 3 1. read : Replaced integer subtraction with addition → KILLED
2. read : Replaced integer subtraction with addition → KILLED
3. read : removed call to java/io/ByteArrayOutputStream::write → KILLED
                    baos.write(buf, 0, read - (totalRead - lengthToRead));
74
                    break;
75
                }
76
            }
77
        } catch (IOException ex) {
78
            throw new UtilsException(ex);
79
        }
80
        data = baos.toByteArray();
81
82 1 1. read : negated conditional → KILLED
        if (data.length != lengthToRead) {
83
            String message = String.format("length of bytes read (%d) must be what we expected (%d)", data.length, lengthToRead);
84
            throw new ForbiddenUseException(message);
85
        }
86 1 1. read : replaced return value with null for com/renomad/minum/web/InputStreamUtils::read → KILLED
        return data;
87
    }
88
89
    @Override
90
    public boolean equals(Object o) {
91 2 1. equals : negated conditional → KILLED
2. equals : replaced boolean return with false for com/renomad/minum/web/InputStreamUtils::equals → KILLED
        if (this == o) return true;
92 3 1. equals : negated conditional → KILLED
2. equals : negated conditional → KILLED
3. equals : replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → KILLED
        if (o == null || getClass() != o.getClass()) return false;
93
        InputStreamUtils that = (InputStreamUtils) o;
94 2 1. equals : negated conditional → KILLED
2. equals : replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → KILLED
        return maxReadLineSizeBytes == that.maxReadLineSizeBytes;
95
    }
96
97
    @Override
98
    public int hashCode() {
99 1 1. hashCode : replaced int return with 0 for com/renomad/minum/web/InputStreamUtils::hashCode → KILLED
        return Objects.hash(maxReadLineSizeBytes);
100
    }
101
}

Mutations

28

1.1
Location : readLine
Killed by : none
Replaced integer division with multiplication → SURVIVED
Covering tests

30

1.1
Location : readLine
Killed by : com.renomad.minum.web.WebTests
Changed increment from 1 to -1 → KILLED

31

1.1
Location : readLine
Killed by : com.renomad.minum.web.WebTests
changed conditional boundary → KILLED

2.2
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

32

1.1
Location : readLine
Killed by : none
removed call to java/io/InputStream::close → SURVIVED
Covering tests

36

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

37

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

2.2
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition(com.renomad.minum.web.RequestTests)
changed conditional boundary → KILLED

38

1.1
Location : readLine
Killed by : none
replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → SURVIVED
Covering tests

47

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition(com.renomad.minum.web.RequestTests)
replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → KILLED

50

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition2(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

51

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.test_Request_getMultipartIterable_EdgeCase_No_Valid_Boundary_3(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

52

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.test_Request_getMultipartIterable_EdgeCase_No_Valid_Boundary_3(com.renomad.minum.web.RequestTests)
removed call to java/io/ByteArrayOutputStream::write → KILLED

53

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.testEndOfStreamWhileReadingStreamingMultipartPartition2(com.renomad.minum.web.RequestTests)
Changed increment from 1 to -1 → KILLED

55

1.1
Location : readLine
Killed by : com.renomad.minum.web.RequestTests.test_Request_getMultipartIterable_EdgeCase_No_Valid_Boundary_3(com.renomad.minum.web.RequestTests)
replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → KILLED

67

1.1
Location : read
Killed by : com.renomad.minum.web.WebTests
changed conditional boundary → KILLED

2.2
Location : read
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ComplaintAfterGetBody(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

68

1.1
Location : read
Killed by : com.renomad.minum.web.WebTests
Replaced integer addition with subtraction → KILLED

69

1.1
Location : read
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testReadingLarge(com.renomad.minum.web.InputStreamUtilsTests)
negated conditional → KILLED

2.2
Location : read
Killed by : com.renomad.minum.web.WebTests
changed conditional boundary → KILLED

71

1.1
Location : read
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testReadingLarge(com.renomad.minum.web.InputStreamUtilsTests)
removed call to java/io/ByteArrayOutputStream::write → KILLED

73

1.1
Location : read
Killed by : com.renomad.minum.web.WebTests
Replaced integer subtraction with addition → KILLED

2.2
Location : read
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ComplaintAfterGetBody(com.renomad.minum.web.RequestTests)
Replaced integer subtraction with addition → KILLED

3.3
Location : read
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ComplaintAfterGetBody(com.renomad.minum.web.RequestTests)
removed call to java/io/ByteArrayOutputStream::write → KILLED

82

1.1
Location : read
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ComplaintAfterGetBody(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

86

1.1
Location : read
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ComplaintAfterGetBody(com.renomad.minum.web.RequestTests)
replaced return value with null for com/renomad/minum/web/InputStreamUtils::read → KILLED

91

1.1
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
negated conditional → KILLED

2.2
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
replaced boolean return with false for com/renomad/minum/web/InputStreamUtils::equals → KILLED

92

1.1
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
negated conditional → KILLED

2.2
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
negated conditional → KILLED

3.3
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → KILLED

94

1.1
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
negated conditional → KILLED

2.2
Location : equals
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → KILLED

99

1.1
Location : hashCode
Killed by : com.renomad.minum.web.InputStreamUtilsTests.testEquals(com.renomad.minum.web.InputStreamUtilsTests)
replaced int return with 0 for com/renomad/minum/web/InputStreamUtils::hashCode → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0