InputStreamUtils.java

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

Mutations

26

1.1
Location : readLine
Killed by : none
Replaced integer division with multiplication → TIMED_OUT

28

1.1
Location : readLine
Killed by : none
Changed increment from 1 to -1 → TIMED_OUT

29

1.1
Location : readLine
Killed by : none
changed conditional boundary → TIMED_OUT

2.2
Location : readLine
Killed by : com.renomad.minum.web.BoundaryBugTest
negated conditional → KILLED

30

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

34

1.1
Location : readLine
Killed by : com.renomad.minum.web.BoundaryBugTest
negated conditional → KILLED

35

1.1
Location : readLine
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : readLine
Killed by : none
changed conditional boundary → TIMED_OUT

36

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

45

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

48

1.1
Location : readLine
Killed by : com.renomad.minum.web.BoundaryBugTest
negated conditional → KILLED

49

1.1
Location : readLine
Killed by : com.renomad.minum.web.BoundaryBugTest
negated conditional → KILLED

50

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

51

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

53

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

65

1.1
Location : read
Killed by : none
changed conditional boundary → TIMED_OUT

2.2
Location : read
Killed by : com.renomad.minum.web.InputStreamUtilsTests
negated conditional → KILLED

66

1.1
Location : read
Killed by : none
Replaced integer addition with subtraction → TIMED_OUT

67

1.1
Location : read
Killed by : none
changed conditional boundary → TIMED_OUT

2.2
Location : read
Killed by : com.renomad.minum.web.InputStreamUtilsTests
negated conditional → KILLED

69

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

71

1.1
Location : read
Killed by : com.renomad.minum.FunctionalTests.test_PathFunction_Response(com.renomad.minum.FunctionalTests)
Replaced integer subtraction with addition → KILLED

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

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

77

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

81

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

86

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

2.2
Location : equals
Killed by : none
replaced boolean return with false for com/renomad/minum/web/InputStreamUtils::equals → TIMED_OUT

87

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

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

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

89

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

2.2
Location : equals
Killed by : none
replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → TIMED_OUT

94

1.1
Location : hashCode
Killed by : 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