Range.java

1
package com.renomad.minum.web;
2
3
import java.util.List;
4
import java.util.Objects;
5
import java.util.regex.Matcher;
6
import java.util.regex.Pattern;
7
8
final class Range {
9
10
    private static final Pattern rangeHeaderPattern = Pattern.compile("^bytes=(?<first>[0-9]{0,13})-(?<second>[0-9]{0,13})$");
11
    private final Long rangeFirstPart;
12
    private final Long rangeSecondPart;
13
    private final Long length;
14
    private final Long offset;
15
    private final boolean hasRangeHeader;
16
17
    /**
18
     * Constructor for a range.
19
     * @param fullLength the actual length of the file, as determined by requesting
20
     *                   data from the operating system.
21
     */
22
    public Range(Headers requestHeaders, long fullLength) {
23
        List<String> rangeHeaders = requestHeaders.valueByKey("range");
24 1 1. <init> : negated conditional → KILLED
        if (rangeHeaders == null) {
25
            hasRangeHeader = false;
26
            rangeFirstPart = null;
27
            rangeSecondPart = null;
28
            length = fullLength;
29
            offset = 0L;
30
        } else {
31
            hasRangeHeader = true;
32 2 1. <init> : negated conditional → TIMED_OUT
2. <init> : changed conditional boundary → KILLED
            if (rangeHeaders.size() > 1) {
33
                throw new BadRequestException("Error: Request contained more than one Range header");
34
            }
35
            // the "Range:" header provides a desired range, and can request multiple ranges.
36
            // this server does not currently handle multiple ranges, so if that is requested we
37
            // will ignore the range header and return a 200 with the entire contents.
38
            String rangeHeader = rangeHeaders.getFirst();
39
            Matcher matcher = rangeHeaderPattern.matcher(rangeHeader);
40 1 1. <init> : negated conditional → KILLED
            if (matcher.matches()) {
41
                String firstPart = matcher.group("first");
42
                String secondPart = matcher.group("second");
43
44 1 1. <init> : negated conditional → TIMED_OUT
                if (!firstPart.isEmpty()) {
45
                    rangeFirstPart = Long.parseLong(firstPart);
46
                } else {
47
                    rangeFirstPart = null;
48
                }
49
50 1 1. <init> : negated conditional → TIMED_OUT
                if (!secondPart.isEmpty()) {
51
                    rangeSecondPart = Long.parseLong(secondPart);
52
                } else {
53
                    rangeSecondPart = null;
54
                }
55
56
                // options
57
                // 1: there's a first and second part
58
                // 2: only a second part
59
                // 3: only a first part
60
                // 4: (invalid) the first part is larger than the second part
61
                // 5: (invalid) either of the range values are invalid longs
62
                // 6: missing both first and second part - return whole file
63
64
                // option 1
65 2 1. <init> : negated conditional → TIMED_OUT
2. <init> : negated conditional → KILLED
                if (rangeFirstPart != null && rangeSecondPart != null) {
66 2 1. <init> : changed conditional boundary → SURVIVED
2. <init> : negated conditional → TIMED_OUT
                    if (rangeFirstPart > rangeSecondPart) {
67
                        throw new BadRequestException("Error: The value of the first part of the range was larger than the second.");
68
                    } else {
69 2 1. <init> : Replaced long subtraction with addition → TIMED_OUT
2. <init> : Replaced long addition with subtraction → TIMED_OUT
                        length = (rangeSecondPart - rangeFirstPart) + 1;
70 2 1. <init> : negated conditional → TIMED_OUT
2. <init> : changed conditional boundary → TIMED_OUT
                        if (length > fullLength) {
71
                            throw new BadRequestException("Invalid Range header: %s. file length: %d".formatted(rangeHeader, fullLength));
72
                        }
73
                        offset = rangeFirstPart;
74
                    }
75
                // option 3
76 1 1. <init> : negated conditional → TIMED_OUT
                } else if (rangeFirstPart != null) {
77
                    offset = rangeFirstPart;
78 1 1. <init> : Replaced long subtraction with addition → TIMED_OUT
                    length = fullLength - offset;
79 2 1. <init> : changed conditional boundary → TIMED_OUT
2. <init> : negated conditional → KILLED
                    if (length < 0) {
80
                        throw new BadRequestException("Invalid Range header: %s. file length: %d".formatted(rangeHeader, fullLength));
81
                    }
82
                // option 2
83 1 1. <init> : negated conditional → TIMED_OUT
                } else if (rangeSecondPart != null) {
84 1 1. <init> : Replaced long subtraction with addition → KILLED
                    offset = fullLength - rangeSecondPart;
85 2 1. <init> : negated conditional → TIMED_OUT
2. <init> : changed conditional boundary → TIMED_OUT
                    if (offset < 0) {
86
                        throw new BadRequestException("Invalid Range header: %s. file length: %d".formatted(rangeHeader, fullLength));
87
                    }
88
                    length = rangeSecondPart;
89
                // option 6
90
                } else {
91
                    length = fullLength;
92
                    offset = 0L;
93
                }
94
95
            } else {
96
                rangeFirstPart = null;
97
                rangeSecondPart = null;
98
                length = fullLength;
99
                offset = 0L;
100
            }
101
        }
102
    }
103
104
    public Long getRangeFirstPart() {
105 1 1. getRangeFirstPart : replaced Long return value with 0L for com/renomad/minum/web/Range::getRangeFirstPart → KILLED
        return rangeFirstPart;
106
    }
107
108
    public Long getRangeSecondPart() {
109 1 1. getRangeSecondPart : replaced Long return value with 0L for com/renomad/minum/web/Range::getRangeSecondPart → KILLED
        return rangeSecondPart;
110
    }
111
112
    public Long getLength() {
113 1 1. getLength : replaced Long return value with 0L for com/renomad/minum/web/Range::getLength → KILLED
        return length;
114
    }
115
116
    public Long getOffset() {
117 1 1. getOffset : replaced Long return value with 0L for com/renomad/minum/web/Range::getOffset → KILLED
        return offset;
118
    }
119
120
    public boolean hasRangeHeader() {
121 2 1. hasRangeHeader : replaced boolean return with false for com/renomad/minum/web/Range::hasRangeHeader → TIMED_OUT
2. hasRangeHeader : replaced boolean return with true for com/renomad/minum/web/Range::hasRangeHeader → KILLED
        return hasRangeHeader;
122
    }
123
124
    @Override
125
    public boolean equals(Object o) {
126 2 1. equals : negated conditional → TIMED_OUT
2. equals : replaced boolean return with false for com/renomad/minum/web/Range::equals → KILLED
        if (this == o) return true;
127 3 1. equals : replaced boolean return with true for com/renomad/minum/web/Range::equals → KILLED
2. equals : negated conditional → KILLED
3. equals : negated conditional → KILLED
        if (o == null || getClass() != o.getClass()) return false;
128
        Range range = (Range) o;
129 6 1. equals : negated conditional → TIMED_OUT
2. equals : negated conditional → TIMED_OUT
3. equals : replaced boolean return with true for com/renomad/minum/web/Range::equals → TIMED_OUT
4. equals : negated conditional → TIMED_OUT
5. equals : negated conditional → TIMED_OUT
6. equals : negated conditional → KILLED
        return hasRangeHeader == range.hasRangeHeader && Objects.equals(rangeFirstPart, range.rangeFirstPart) && Objects.equals(rangeSecondPart, range.rangeSecondPart) && Objects.equals(length, range.length) && Objects.equals(offset, range.offset);
130
    }
131
132
    @Override
133
    public int hashCode() {
134 1 1. hashCode : replaced int return with 0 for com/renomad/minum/web/Range::hashCode → TIMED_OUT
        return Objects.hash(rangeFirstPart, rangeSecondPart, length, offset, hasRangeHeader);
135
    }
136
137
    @Override
138
    public String toString() {
139 1 1. toString : replaced return value with "" for com/renomad/minum/web/Range::toString → KILLED
        return "Range{" +
140
                "rangeFirstPart=" + rangeFirstPart +
141
                ", rangeSecondPart=" + rangeSecondPart +
142
                ", length=" + length +
143
                ", offset=" + offset +
144
                ", hasRangeHeader=" + hasRangeHeader +
145
                '}';
146
    }
147
}

Mutations

24

1.1
Location : <init>
Killed by : com.renomad.minum.web.ResponseTests
negated conditional → KILLED

32

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : <init>
Killed by : com.renomad.minum.web.RangeTests
changed conditional boundary → KILLED

40

1.1
Location : <init>
Killed by : com.renomad.minum.web.RangeTests
negated conditional → KILLED

44

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

50

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

65

1.1
Location : <init>
Killed by : com.renomad.minum.web.RangeTests
negated conditional → KILLED

2.2
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

66

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : <init>
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

69

1.1
Location : <init>
Killed by : none
Replaced long subtraction with addition → TIMED_OUT

2.2
Location : <init>
Killed by : none
Replaced long addition with subtraction → TIMED_OUT

70

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : <init>
Killed by : none
changed conditional boundary → TIMED_OUT

76

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

78

1.1
Location : <init>
Killed by : none
Replaced long subtraction with addition → TIMED_OUT

79

1.1
Location : <init>
Killed by : none
changed conditional boundary → TIMED_OUT

2.2
Location : <init>
Killed by : com.renomad.minum.web.RangeTests
negated conditional → KILLED

83

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

84

1.1
Location : <init>
Killed by : com.renomad.minum.web.RangeTests
Replaced long subtraction with addition → KILLED

85

1.1
Location : <init>
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : <init>
Killed by : none
changed conditional boundary → TIMED_OUT

105

1.1
Location : getRangeFirstPart
Killed by : com.renomad.minum.web.RangeTests
replaced Long return value with 0L for com/renomad/minum/web/Range::getRangeFirstPart → KILLED

109

1.1
Location : getRangeSecondPart
Killed by : com.renomad.minum.web.RangeTests
replaced Long return value with 0L for com/renomad/minum/web/Range::getRangeSecondPart → KILLED

113

1.1
Location : getLength
Killed by : com.renomad.minum.web.RangeTests
replaced Long return value with 0L for com/renomad/minum/web/Range::getLength → KILLED

117

1.1
Location : getOffset
Killed by : com.renomad.minum.web.RangeTests
replaced Long return value with 0L for com/renomad/minum/web/Range::getOffset → KILLED

121

1.1
Location : hasRangeHeader
Killed by : com.renomad.minum.web.ResponseTests
replaced boolean return with true for com/renomad/minum/web/Range::hasRangeHeader → KILLED

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

126

1.1
Location : equals
Killed by : com.renomad.minum.web.RangeTests
replaced boolean return with false for com/renomad/minum/web/Range::equals → KILLED

2.2
Location : equals
Killed by : none
negated conditional → TIMED_OUT

127

1.1
Location : equals
Killed by : com.renomad.minum.web.RangeTests
replaced boolean return with true for com/renomad/minum/web/Range::equals → KILLED

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

3.3
Location : equals
Killed by : com.renomad.minum.web.RangeTests
negated conditional → KILLED

129

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

2.2
Location : equals
Killed by : none
negated conditional → TIMED_OUT

3.3
Location : equals
Killed by : none
negated conditional → TIMED_OUT

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

5.5
Location : equals
Killed by : none
negated conditional → TIMED_OUT

6.6
Location : equals
Killed by : none
negated conditional → TIMED_OUT

134

1.1
Location : hashCode
Killed by : none
replaced int return with 0 for com/renomad/minum/web/Range::hashCode → TIMED_OUT

139

1.1
Location : toString
Killed by : com.renomad.minum.web.RangeTests
replaced return value with "" for com/renomad/minum/web/Range::toString → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0