1 | package edu.ucsb.cs156.courses.models; | |
2 | ||
3 | import java.util.ArrayList; | |
4 | import java.util.List; | |
5 | import java.util.Objects; | |
6 | ||
7 | /** | |
8 | * Represents a UCSB quarter. Allows easy conversion between QYY alphanumeric | |
9 | * format (F19, W20, S20, M20) and YYYYQ numerical format (20194, 20201, 20202, | |
10 | * 20203) as well as incrementing and decrementing. | |
11 | * | |
12 | */ | |
13 | ||
14 | public class Quarter { | |
15 | ||
16 | private int yyyyq; // YYYYQ where Q = 1, 2, 3 or 4 | |
17 | ||
18 | public Quarter(int yyyyq) { | |
19 |
1
1. <init> : removed call to edu/ucsb/cs156/courses/models/Quarter::setValue → KILLED |
setValue(yyyyq); |
20 | } | |
21 | ||
22 | public int getValue() { | |
23 |
1
1. getValue : replaced int return with 0 for edu/ucsb/cs156/courses/models/Quarter::getValue → KILLED |
return this.yyyyq; |
24 | } | |
25 | ||
26 | public void setValue(int yyyyq) { | |
27 |
1
1. setValue : negated conditional → KILLED |
if (invalidQtr(yyyyq)) |
28 | throw new IllegalArgumentException("Quarter constructor requires a integer ending in 1,2,3 or 4"); | |
29 | this.yyyyq = yyyyq; | |
30 | } | |
31 | ||
32 | /** | |
33 | * Construct a Quarter object from a string s, either in QYY or YYYYQ format. If | |
34 | * s is of length three, QYY format is expected, if 5 then YYYYQ format is | |
35 | * expected. Otherwise an IllegalArgumentException is thrown. | |
36 | * | |
37 | * @param s Quarter either in QYY or YYYYQ format | |
38 | */ | |
39 | ||
40 | public Quarter(String s) { | |
41 | ||
42 | switch (s | |
43 | .length()) { | |
44 | case 3: | |
45 | this.yyyyq = qyyToyyyyQ(s); | |
46 | return; | |
47 | case 5: | |
48 | this.yyyyq = yyyyqToInt(s); | |
49 | return; | |
50 | default: | |
51 | throw new IllegalArgumentException("Quarter shoudl be in QYY or YYYYQ format"); | |
52 | } | |
53 | } | |
54 | ||
55 | public String getYY() { | |
56 |
1
1. getYY : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getYY → KILLED |
return getYY(this.yyyyq); |
57 | } | |
58 | ||
59 | public String getYYYY() { | |
60 |
1
1. getYYYY : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getYYYY → KILLED |
return getYYYY(this.yyyyq); |
61 | } | |
62 | ||
63 | public String getYYYYQ() { | |
64 |
1
1. getYYYYQ : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getYYYYQ → KILLED |
return String.format("%d",this.yyyyq); |
65 | } | |
66 | ||
67 | public String toString() { | |
68 |
1
1. toString : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::toString → KILLED |
return yyyyqToQyy(this.yyyyq); |
69 | } | |
70 | ||
71 | public String getQ() { | |
72 |
1
1. getQ : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getQ → KILLED |
return getQ(this.yyyyq); |
73 | } | |
74 | ||
75 | private static boolean invalidQtr(int value) { | |
76 |
1
1. invalidQtr : Replaced integer modulus with multiplication → KILLED |
int index = value % 10; |
77 |
5
1. invalidQtr : changed conditional boundary → KILLED 2. invalidQtr : changed conditional boundary → KILLED 3. invalidQtr : negated conditional → KILLED 4. invalidQtr : negated conditional → KILLED 5. invalidQtr : replaced boolean return with true for edu/ucsb/cs156/courses/models/Quarter::invalidQtr → KILLED |
return (index < 1) || (index > 4); |
78 | } | |
79 | ||
80 | /** | |
81 | * Advance to the next quarter, and return the value of that quarter as an int. | |
82 | * | |
83 | * @return the new getValue() for the quarter, i.e. quarter as in in yyyyq | |
84 | * format | |
85 | */ | |
86 | public int increment() { | |
87 |
1
1. increment : Replaced integer modulus with multiplication → KILLED |
int q = this.yyyyq % 10; |
88 |
1
1. increment : Replaced integer division with multiplication → KILLED |
int yyyy = this.yyyyq / 10; |
89 | ||
90 |
6
1. increment : Replaced integer addition with subtraction → KILLED 2. increment : Replaced integer multiplication with division → KILLED 3. increment : Replaced integer addition with subtraction → KILLED 4. increment : Replaced integer addition with subtraction → KILLED 5. increment : negated conditional → KILLED 6. increment : removed call to edu/ucsb/cs156/courses/models/Quarter::setValue → KILLED |
setValue((q == 4) ? (((yyyy + 1) * 10) + 1) : (this.yyyyq + 1)); |
91 |
1
1. increment : replaced int return with 0 for edu/ucsb/cs156/courses/models/Quarter::increment → KILLED |
return this.yyyyq; |
92 | } | |
93 | ||
94 | /** | |
95 | * Subtract one from current quarter, and return the value of that quarter as an | |
96 | * int. | |
97 | * | |
98 | * @return the new getValue() for the quarter, i.e. quarter as in in yyyyq | |
99 | * format | |
100 | */ | |
101 | public int decrement() { | |
102 |
1
1. decrement : Replaced integer modulus with multiplication → KILLED |
int q = this.yyyyq % 10; |
103 |
1
1. decrement : Replaced integer division with multiplication → KILLED |
int yyyy = this.yyyyq / 10; |
104 | ||
105 |
6
1. decrement : Replaced integer subtraction with addition → KILLED 2. decrement : Replaced integer multiplication with division → KILLED 3. decrement : Replaced integer addition with subtraction → KILLED 4. decrement : Replaced integer subtraction with addition → KILLED 5. decrement : negated conditional → KILLED 6. decrement : removed call to edu/ucsb/cs156/courses/models/Quarter::setValue → KILLED |
setValue((q == 1) ? (((yyyy - 1) * 10) + 4) : (this.yyyyq - 1)); |
106 |
1
1. decrement : replaced int return with 0 for edu/ucsb/cs156/courses/models/Quarter::decrement → KILLED |
return this.yyyyq; |
107 | } | |
108 | ||
109 | /** | |
110 | * Convert yyyyq as string to int, throwing exception if format is incorrect | |
111 | * | |
112 | * @param yyyyq String in yyyyq format (e.g. 20194 for F19 (Fall 2019)) | |
113 | * @throws IllegalArgumentException | |
114 | * @return int representation of quarter | |
115 | */ | |
116 | public static int yyyyqToInt(String yyyyq) { | |
117 | String errorMsg = "Argument should be a string representation of a five digit integer yyyyq ending in 1,2,3 or 4"; | |
118 | int result = 0; | |
119 | try { | |
120 | result = Integer | |
121 | .parseInt(yyyyq); | |
122 | } catch (Exception e) { | |
123 | throw new IllegalArgumentException(errorMsg); | |
124 | } | |
125 |
1
1. yyyyqToInt : negated conditional → KILLED |
if (invalidQtr(result)) { |
126 | throw new IllegalArgumentException(errorMsg); | |
127 | } | |
128 |
1
1. yyyyqToInt : replaced int return with 0 for edu/ucsb/cs156/courses/models/Quarter::yyyyqToInt → KILLED |
return result; |
129 | } | |
130 | ||
131 | /** | |
132 | * Convert yyyyq int format to Yqq String format throwing exception if format is | |
133 | * incorrect | |
134 | * | |
135 | * @param yyyyq int (e.g. 20194 for Fall 2019 | |
136 | * @throws IllegalArgumentException | |
137 | * @return Qyy representation (e.g. F19) | |
138 | */ | |
139 | public static String yyyyqToQyy(int yyyyq) { | |
140 |
1
1. yyyyqToQyy : negated conditional → KILLED |
if (invalidQtr(yyyyq)) { |
141 | throw new IllegalArgumentException( | |
142 | "Argument should be a five digit integer in qqqqy format ending in 1,2,3 or 4"); | |
143 | } | |
144 |
1
1. yyyyqToQyy : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::yyyyqToQyy → KILLED |
return String |
145 | .format("%s%s", getQ(yyyyq), getYY(yyyyq)); | |
146 | } | |
147 | ||
148 | /** | |
149 | * Take yyyyq int format and return single character for quarter, either "W", | |
150 | * "S", "M", or "F" for last digit 1, 2, 3, 4, respectively. Throw illegal | |
151 | * argument exception if not in yyyyq format. | |
152 | * | |
153 | * @param yyyyq int (e.g. 20194 for Fall 2019) | |
154 | * @throws IllegalArgumentException | |
155 | * @return single char string for quarter (e.g. "F") | |
156 | */ | |
157 | public static String getQ(int yyyyq) { | |
158 |
1
1. getQ : negated conditional → KILLED |
if (invalidQtr(yyyyq)) { |
159 | throw new IllegalArgumentException( | |
160 | "Argument should be a five digit integer in qqqqy format ending in 1,2,3 or 4"); | |
161 | } | |
162 | String[] quarters = new String[] { "W", "S", "M", "F" }; | |
163 |
1
1. getQ : Replaced integer modulus with multiplication → KILLED |
int index = yyyyq % 10; |
164 |
2
1. getQ : Replaced integer subtraction with addition → KILLED 2. getQ : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getQ → KILLED |
return quarters[index - 1]; |
165 | } | |
166 | ||
167 | /** | |
168 | * Take yyyyq int format and return two digit year as a String Throw illegal | |
169 | * argument exception if not in yyyyq format. | |
170 | * | |
171 | * @param yyyyq int (e.g. 20194 for Fall 2019) | |
172 | * @throws IllegalArgumentException | |
173 | * @return two char string for year (e.g. "19") | |
174 | */ | |
175 | public static String getYY(int yyyyq) { | |
176 |
1
1. getYY : negated conditional → KILLED |
if (invalidQtr(yyyyq)) { |
177 | throw new IllegalArgumentException( | |
178 | "Argument should be a five digit integer in qqqqy format ending in 1,2,3 or 4"); | |
179 | } | |
180 |
3
1. getYY : Replaced integer division with multiplication → KILLED 2. getYY : Replaced integer modulus with multiplication → KILLED 3. getYY : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getYY → KILLED |
return String |
181 | .format("%02d", (yyyyq / 10) % 100); | |
182 | } | |
183 | ||
184 | /** | |
185 | * Take yyyyq int format and return four digit year as a String Throw illegal | |
186 | * argument exception if not in yyyyq format. | |
187 | * | |
188 | * @param yyyyq int (e.g. 20194 for Fall 2019) | |
189 | * @throws IllegalArgumentException | |
190 | * @return four char string for year (e.g. "2019") | |
191 | */ | |
192 | public static String getYYYY(int yyyyq) { | |
193 |
1
1. getYYYY : negated conditional → KILLED |
if (invalidQtr(yyyyq)) { |
194 | throw new IllegalArgumentException( | |
195 | "Argument should be a five digit integer in qqqqy format ending in 1,2,3 or 4"); | |
196 | } | |
197 |
2
1. getYYYY : Replaced integer division with multiplication → KILLED 2. getYYYY : replaced return value with "" for edu/ucsb/cs156/courses/models/Quarter::getYYYY → KILLED |
return String |
198 | .format("%04d", (yyyyq / 10)); | |
199 | } | |
200 | ||
201 | public static int qyyToyyyyQ(String qyy) { | |
202 | if (qyy | |
203 |
1
1. qyyToyyyyQ : negated conditional → KILLED |
.length() != 3) |
204 | throw new IllegalArgumentException("Argument should be in QYY format"); | |
205 | ||
206 | char q = qyy | |
207 | .charAt(0); | |
208 | String yy = qyy | |
209 | .substring(1, 3); | |
210 | String legalQuarters = "WSMF"; | |
211 | int qInt = legalQuarters | |
212 |
1
1. qyyToyyyyQ : Replaced integer addition with subtraction → KILLED |
.indexOf(q) + 1; |
213 |
1
1. qyyToyyyyQ : negated conditional → KILLED |
if (invalidQtr(qInt)) { |
214 | throw new IllegalArgumentException("First char should be one of " + legalQuarters); | |
215 | } | |
216 | int yyInt = Integer | |
217 | .parseInt(yy); | |
218 |
2
1. qyyToyyyyQ : changed conditional boundary → KILLED 2. qyyToyyyyQ : negated conditional → KILLED |
int century = (yyInt > 50) ? 1900 : 2000; |
219 |
4
1. qyyToyyyyQ : Replaced integer addition with subtraction → KILLED 2. qyyToyyyyQ : Replaced integer multiplication with division → KILLED 3. qyyToyyyyQ : Replaced integer addition with subtraction → KILLED 4. qyyToyyyyQ : replaced int return with 0 for edu/ucsb/cs156/courses/models/Quarter::qyyToyyyyQ → KILLED |
return (century + yyInt) * 10 + qInt; |
220 | } | |
221 | ||
222 | ||
223 | @Override | |
224 | public boolean equals(Object o) { | |
225 |
1
1. equals : negated conditional → KILLED |
if (o == this) |
226 |
1
1. equals : replaced boolean return with false for edu/ucsb/cs156/courses/models/Quarter::equals → KILLED |
return true; |
227 |
1
1. equals : negated conditional → KILLED |
if (!(o instanceof Quarter)) { |
228 |
1
1. equals : replaced boolean return with true for edu/ucsb/cs156/courses/models/Quarter::equals → KILLED |
return false; |
229 | } | |
230 | Quarter quarter = (Quarter) o; | |
231 |
2
1. equals : negated conditional → KILLED 2. equals : replaced boolean return with true for edu/ucsb/cs156/courses/models/Quarter::equals → KILLED |
return yyyyq == quarter.yyyyq; |
232 | } | |
233 | ||
234 | @Override | |
235 | public int hashCode() { | |
236 |
1
1. hashCode : replaced int return with 0 for edu/ucsb/cs156/courses/models/Quarter::hashCode → KILLED |
return Objects.hashCode(yyyyq); |
237 | } | |
238 | ||
239 | ||
240 | ||
241 | /** | |
242 | * return a list of Quarters starting with the start parameter and ending with the end parameter, inclusive. | |
243 | * | |
244 | * The result will automatically go in chronological or reverse chronological order, depending | |
245 | * on the order of the parameters. | |
246 | * @param start | |
247 | * @param end | |
248 | * @return list of quarters in specified order | |
249 | */ | |
250 | ||
251 | public static List<Quarter> quarterList(String start, String end) { | |
252 | List<Quarter> result = new ArrayList<Quarter>(); | |
253 | ||
254 | int startInt = Quarter.yyyyqToInt(start); | |
255 | int endInt = Quarter.yyyyqToInt(end); | |
256 | ||
257 |
2
1. quarterList : changed conditional boundary → KILLED 2. quarterList : negated conditional → KILLED |
if (startInt < endInt) { |
258 |
2
1. quarterList : changed conditional boundary → KILLED 2. quarterList : negated conditional → KILLED |
for (Quarter iter = new Quarter(startInt); iter.getValue() <= endInt; iter.increment()) { |
259 | Quarter q = new Quarter(iter.getValue()); | |
260 | result.add(q); | |
261 | } | |
262 | } | |
263 |
2
1. quarterList : changed conditional boundary → KILLED 2. quarterList : negated conditional → KILLED |
if (startInt >= endInt) { |
264 |
2
1. quarterList : changed conditional boundary → KILLED 2. quarterList : negated conditional → KILLED |
for (Quarter iter = new Quarter(startInt); iter.getValue() >= endInt; iter.decrement()) { |
265 | Quarter q = new Quarter(iter.getValue()); | |
266 | result.add(q); | |
267 | } | |
268 | } | |
269 |
1
1. quarterList : replaced return value with Collections.emptyList for edu/ucsb/cs156/courses/models/Quarter::quarterList → KILLED |
return result; |
270 | } | |
271 | } | |
Mutations | ||
19 |
1.1 |
|
23 |
1.1 |
|
27 |
1.1 |
|
56 |
1.1 |
|
60 |
1.1 |
|
64 |
1.1 |
|
68 |
1.1 |
|
72 |
1.1 |
|
76 |
1.1 |
|
77 |
1.1 2.2 3.3 4.4 5.5 |
|
87 |
1.1 |
|
88 |
1.1 |
|
90 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
91 |
1.1 |
|
102 |
1.1 |
|
103 |
1.1 |
|
105 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
106 |
1.1 |
|
125 |
1.1 |
|
128 |
1.1 |
|
140 |
1.1 |
|
144 |
1.1 |
|
158 |
1.1 |
|
163 |
1.1 |
|
164 |
1.1 2.2 |
|
176 |
1.1 |
|
180 |
1.1 2.2 3.3 |
|
193 |
1.1 |
|
197 |
1.1 2.2 |
|
203 |
1.1 |
|
212 |
1.1 |
|
213 |
1.1 |
|
218 |
1.1 2.2 |
|
219 |
1.1 2.2 3.3 4.4 |
|
225 |
1.1 |
|
226 |
1.1 |
|
227 |
1.1 |
|
228 |
1.1 |
|
231 |
1.1 2.2 |
|
236 |
1.1 |
|
257 |
1.1 2.2 |
|
258 |
1.1 2.2 |
|
263 |
1.1 2.2 |
|
264 |
1.1 2.2 |
|
269 |
1.1 |