Skip to content

Commit b9a7749

Browse files
committed
GP-146 Upgrade HeterogeneousMaxHolder exercise
1 parent 1444c25 commit b9a7749

File tree

2 files changed

+94
-69
lines changed

2 files changed

+94
-69
lines changed

1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
* key/value map, where the key is a type and the value is the maximum among all values of this type that were put.
88
* <p>
99
* It's based on the {@link Map} and provides an API that allows to put a value by type, and get a max value by type.
10+
* <p>
11+
* <p>
12+
* <strong>TODO: to get the most out of your learning, <a href="https://www.bobocode.com/learn">visit our website</a></strong>
13+
* <p>
14+
*
15+
* @author Taras Boychuk
1016
*/
1117
public class HeterogeneousMaxHolder {
1218

@@ -17,7 +23,7 @@ public class HeterogeneousMaxHolder {
1723
* If the current max value is less than a provided one, or if it's null, then a provided value gets stored and the old
1824
* max is returned. Otherwise, nothing new is added, and the provided value is returned.
1925
* <p>
20-
* So technically, this method always stored the greater value and returns the smaller one.
26+
* So technically, this method always stores the greater value and returns the smaller one.
2127
*
2228
* @param key a provided value type
2329
* @param value a value to put
@@ -27,9 +33,9 @@ public class HeterogeneousMaxHolder {
2733
// todo: implement a method according to javadoc
2834

2935
/**
30-
* An overloaded method put implements the same logic using a custom comparator. A given comparator is wrapped with
31-
* a null-safe comparator, considering null smaller than any non-null object.
32-
*
36+
* An overloaded method put implements the same logic using a custom comparator. A given comparator is wrapped with
37+
* a null-safe comparator, considering null smaller than any non-null object.
38+
* <p>
3339
* All arguments must not be null.
3440
*
3541
* @param key a provided value type

1-0-java-basics/1-3-2-heterogeneous-max-holder/src/test/java/com/bobocode/basics/HeterogeneousMaxHolderTest.java

+84-65
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
import org.junit.jupiter.api.Order;
99
import org.junit.jupiter.api.Test;
1010
import org.junit.jupiter.api.TestMethodOrder;
11+
import org.mockito.Mockito;
1112

1213
import java.lang.reflect.Method;
13-
import java.lang.reflect.Type;
14+
import java.lang.reflect.ParameterizedType;
1415
import java.math.BigDecimal;
1516
import java.util.Arrays;
1617
import java.util.Comparator;
@@ -23,6 +24,7 @@
2324
@TestMethodOrder(OrderAnnotation.class)
2425
class HeterogeneousMaxHolderTest {
2526
private HeterogeneousMaxHolder heterogeneousMaxHolder = new HeterogeneousMaxHolder();
27+
private HeterogeneousMaxHolder heterogeneousMaxHolderMock = Mockito.spy(HeterogeneousMaxHolder.class);
2628

2729
@Test
2830
@Order(1)
@@ -71,58 +73,53 @@ void putDeclaresOneTypeParam() {
7173
var putMethod = getPutMethod();
7274

7375
var methodTypeParameters = putMethod.getTypeParameters();
74-
7576
assertThat(methodTypeParameters).hasSize(1);
77+
78+
var typeParam = putMethod.getTypeParameters()[0];
79+
assertThat(typeParam.getName()).isEqualTo("T");
7680
}
7781

7882
@Test
7983
@Order(6)
80-
@DisplayName("put method type parameter is called 'T'")
81-
void putTypeParamIsCalledT() {
84+
@DisplayName("put method accepts type-safe key")
85+
void putMethodAcceptsTypeSafeKeyParameter() {
8286
var putMethod = getPutMethod();
8387

84-
var typeParam = putMethod.getTypeParameters()[0];
88+
var typeParam = (ParameterizedType) putMethod.getGenericParameterTypes()[0];
89+
var typeArgument = typeParam.getActualTypeArguments()[0];
8590

86-
assertThat(typeParam.getName()).isEqualTo("T");
91+
assertThat(typeParam.getRawType()).isEqualTo(Class.class);
92+
assertThat(typeArgument.getTypeName()).isEqualTo("T");
8793
}
8894

8995
@Test
9096
@Order(7)
91-
@DisplayName("type parameter 'T' is declared as Comparable")
92-
void typeParamIsComparable() {
97+
@DisplayName("put method accepts comparable value")
98+
void putMethodAcceptsComparableValueParameter() {
9399
var putMethod = getPutMethod();
94100

95101
var typeParam = putMethod.getTypeParameters()[0];
96-
var bound = typeParam.getBounds()[0];
102+
var boundType = (ParameterizedType) typeParam.getBounds()[0];
97103

98-
assertThat(bound.getTypeName()).isEqualTo(Comparable.class.getTypeName() + "<? super T>");
104+
assertThat(boundType.getRawType()).isEqualTo(Comparable.class);
99105
}
100106

101107
@Test
102108
@Order(8)
103-
@SneakyThrows
104-
@DisplayName("put method accepts type (class) and value (object) parameters")
105-
void putHasKeyValueParameters() {
106-
HeterogeneousMaxHolder.class.getMethod("put", Class.class, Comparable.class);
107-
}
109+
@DisplayName("put method supports value that has comparable super class")
110+
void putMethodAcceptsValueParameterWithComparableSuperClass() {
111+
var putMethod = getPutMethod();
108112

109-
@Test
110-
@Order(9)
111-
@SneakyThrows
112-
@DisplayName("put method params specify type arguments")
113-
void putParametersSpecifyTypeArguments() {
114-
var putMethod = HeterogeneousMaxHolder.class.getMethod("put", Class.class, Comparable.class);
115-
var genericParamTypeNames = Arrays.stream(putMethod.getGenericParameterTypes())
116-
.map(Type::getTypeName)
117-
.toList();
113+
var typeParam = putMethod.getTypeParameters()[0];
114+
var boundType = (ParameterizedType) typeParam.getBounds()[0];
115+
var typeArgument = boundType.getActualTypeArguments()[0].getTypeName();
118116

119-
assertThat(genericParamTypeNames)
120-
.contains(Class.class.getTypeName() + "<T>")
121-
.contains("T");
117+
assertThat(boundType.getRawType()).isEqualTo(Comparable.class);
118+
assertThat(typeArgument).isEqualTo("? super T");
122119
}
123120

124121
@Test
125-
@Order(10)
122+
@Order(9)
126123
@SneakyThrows
127124
@DisplayName("put stores provided value when current max is null")
128125
void putStoresValueWhenCurrentMaxIsNull() {
@@ -133,7 +130,7 @@ void putStoresValueWhenCurrentMaxIsNull() {
133130
}
134131

135132
@Test
136-
@Order(11)
133+
@Order(10)
137134
@SneakyThrows
138135
@DisplayName("put returns null when current max is null")
139136
void putReturnsNullWhenCurrentMaxIsNull() {
@@ -143,7 +140,7 @@ void putReturnsNullWhenCurrentMaxIsNull() {
143140
}
144141

145142
@Test
146-
@Order(12)
143+
@Order(11)
147144
@SneakyThrows
148145
@DisplayName("put stores provided value when current max is smaller than it")
149146
void putStoresValueWhenCurrentMaxIsSmaller() {
@@ -156,7 +153,7 @@ void putStoresValueWhenCurrentMaxIsSmaller() {
156153
}
157154

158155
@Test
159-
@Order(13)
156+
@Order(12)
160157
@SneakyThrows
161158
@DisplayName("put returns old max value when the provided value is greater than it")
162159
void putReturnsOldMaxValue() {
@@ -168,7 +165,7 @@ void putReturnsOldMaxValue() {
168165
}
169166

170167
@Test
171-
@Order(14)
168+
@Order(13)
172169
@SneakyThrows
173170
@DisplayName("put ignores provided value when the current max is greater than it")
174171
void putIgnoresNewValueWhenCurrentMaxIsGreater() {
@@ -181,7 +178,7 @@ void putIgnoresNewValueWhenCurrentMaxIsGreater() {
181178
}
182179

183180
@Test
184-
@Order(15)
181+
@Order(14)
185182
@SneakyThrows
186183
@DisplayName("put returns provided value when the current max is greater than it")
187184
void putReturnsProvidedValueWhenCurrentMaxIsGreater() {
@@ -193,45 +190,67 @@ void putReturnsProvidedValueWhenCurrentMaxIsGreater() {
193190
}
194191

195192
@Test
196-
@Order(16)
193+
@Order(15)
197194
@SneakyThrows
198-
@DisplayName("put method is overloaded with additional Comparator param")
195+
@DisplayName("put method is overloaded with additional Comparator parameter")
199196
void putIsOverloadedWithAdditionalComparatorParam() {
200-
var overloadedPutMethod = getOverloadedPutMethod();
201-
var params = overloadedPutMethod.getParameters();
197+
HeterogeneousMaxHolder.class.getMethod("put", Class.class, Object.class, Comparator.class);
198+
}
199+
200+
@Test
201+
@Order(16)
202+
@DisplayName("Overloaded put method declares one type parameter T")
203+
void overloadedPutDeclaresOneTypeParam() {
204+
var putMethod = getOverloadedPutMethod();
202205

203-
assertThat(params[2].getType()).isEqualTo(Comparator.class);
206+
var methodTypeParameters = putMethod.getTypeParameters();
207+
assertThat(methodTypeParameters).hasSize(1);
204208

209+
var typeParam = putMethod.getTypeParameters()[0];
210+
assertThat(typeParam.getName()).isEqualTo("T");
205211
}
206212

207213
@Test
208214
@Order(17)
209-
@DisplayName("Overloaded put has simple type param 'T'")
210-
void overloadedPutHasSimpleTypeParameterT() {
211-
var overloadedPutMethod = getOverloadedPutMethod();
215+
@DisplayName("Overloaded put method accepts type-safe key")
216+
void overloadedPutMethodAcceptsTypeSafeKeyParameter() {
217+
var putMethod = getOverloadedPutMethod();
218+
219+
var typeParam = (ParameterizedType) putMethod.getGenericParameterTypes()[0];
220+
var typeArgument = typeParam.getActualTypeArguments()[0];
212221

213-
assertThat(overloadedPutMethod.getTypeParameters()).hasSize(1);
214-
assertThat(overloadedPutMethod.getTypeParameters()[0].getTypeName()).isEqualTo("T");
222+
assertThat(typeParam.getRawType()).isEqualTo(Class.class);
223+
assertThat(typeArgument.getTypeName()).isEqualTo("T");
215224
}
216225

217226
@Test
218227
@Order(18)
228+
@DisplayName("Overloaded put method accepts value of arbitrary type T")
229+
void overloadedPutMethodAcceptsAnyValue() {
230+
var putMethod = getOverloadedPutMethod();
231+
232+
var genericValueTypeParam = putMethod.getGenericParameterTypes()[1];
233+
var actualValueTypeParm = putMethod.getParameterTypes()[1];
234+
235+
assertThat(genericValueTypeParam.getTypeName()).isEqualTo("T");
236+
assertThat(actualValueTypeParm).isEqualTo(Object.class);
237+
}
238+
239+
@Test
240+
@Order(19)
219241
@SneakyThrows
220-
@DisplayName("Overloaded put method params specify type arguments")
221-
void overloadedPutParametersSpecifyTypeArguments() {
242+
@DisplayName("Overloaded put method supports comparator of a super type")
243+
void overloadedPutAcceptsComparatorOfSuperTypes() {
222244
var putMethod = HeterogeneousMaxHolder.class.getMethod("put", Class.class, Object.class, Comparator.class);
223-
var genericParamTypeNames = Arrays.stream(putMethod.getGenericParameterTypes())
224-
.map(Type::getTypeName)
225-
.toList();
226245

227-
assertThat(genericParamTypeNames)
228-
.contains(Class.class.getTypeName() + "<T>")
229-
.contains("T")
230-
.contains(Comparator.class.getTypeName() + "<? super T>");
246+
var comparatorParam = (ParameterizedType) putMethod.getGenericParameterTypes()[2];
247+
var comparatorTypeArgument = comparatorParam.getActualTypeArguments()[0];
248+
249+
assertThat(comparatorTypeArgument.getTypeName()).isEqualTo("? super T");
231250
}
232251

233252
@Test
234-
@Order(19)
253+
@Order(20)
235254
@SneakyThrows
236255
@DisplayName("Overloaded put stores provided value when current max is null")
237256
void overloadedPutStoresValueWhenCurrentMaxIsNull() {
@@ -243,7 +262,7 @@ void overloadedPutStoresValueWhenCurrentMaxIsNull() {
243262
}
244263

245264
@Test
246-
@Order(20)
265+
@Order(21)
247266
@SneakyThrows
248267
@DisplayName("Overloaded put returns null when current max is null")
249268
void overloadedPutReturnsNullWhenCurrentMaxIsNull() {
@@ -253,7 +272,7 @@ void overloadedPutReturnsNullWhenCurrentMaxIsNull() {
253272
}
254273

255274
@Test
256-
@Order(21)
275+
@Order(22)
257276
@SneakyThrows
258277
@DisplayName("Overloaded put stores provided value when current max is smaller than it")
259278
void overloadedPutStoresValueWhenCurrentMaxIsSmaller() {
@@ -269,7 +288,7 @@ void overloadedPutStoresValueWhenCurrentMaxIsSmaller() {
269288
}
270289

271290
@Test
272-
@Order(22)
291+
@Order(23)
273292
@SneakyThrows
274293
@DisplayName("Overloaded put returns old max value when the provided value is greater than it")
275294
void overloadedPutReturnsOldMaxValue() {
@@ -284,7 +303,7 @@ void overloadedPutReturnsOldMaxValue() {
284303
}
285304

286305
@Test
287-
@Order(23)
306+
@Order(24)
288307
@SneakyThrows
289308
@DisplayName("Overloaded put ignores provided value when the current max is greater than it")
290309
void overloadedPutIgnoresNewValueWhenCurrentMaxIsGreater() {
@@ -300,7 +319,7 @@ void overloadedPutIgnoresNewValueWhenCurrentMaxIsGreater() {
300319
}
301320

302321
@Test
303-
@Order(24)
322+
@Order(25)
304323
@SneakyThrows
305324
@DisplayName("Overloaded put returns provided value when the current max is greater")
306325
void overloadedPutReturnsProvidedValueWhenCurrentMaxIsGreater() {
@@ -315,7 +334,7 @@ void overloadedPutReturnsProvidedValueWhenCurrentMaxIsGreater() {
315334
}
316335

317336
@Test
318-
@Order(25)
337+
@Order(26)
319338
@DisplayName("getMax method exists")
320339
void getMaxExists() {
321340
var getMaxMethodExists = Arrays.stream(HeterogeneousMaxHolder.class.getDeclaredMethods())
@@ -325,7 +344,7 @@ void getMaxExists() {
325344
}
326345

327346
@Test
328-
@Order(26)
347+
@Order(27)
329348
@DisplayName("getMax declares one simple type param 'T'")
330349
void getMaxDeclaresOneTypeParam() {
331350
var getMaxMethod = getGetMaxMethod();
@@ -337,7 +356,7 @@ void getMaxDeclaresOneTypeParam() {
337356
}
338357

339358
@Test
340-
@Order(27)
359+
@Order(28)
341360
@DisplayName("getMax has one parameter")
342361
void getMaxHasOneParameter() {
343362
var getMaxMethod = getGetMaxMethod();
@@ -349,7 +368,7 @@ void getMaxHasOneParameter() {
349368
}
350369

351370
@Test
352-
@Order(28)
371+
@Order(29)
353372
@DisplayName("getMax param specifies type arguments")
354373
void getMaxParamSpecifyTypeArguments() {
355374
var getMaxMethod = getGetMaxMethod();
@@ -360,7 +379,7 @@ void getMaxParamSpecifyTypeArguments() {
360379
}
361380

362381
@Test
363-
@Order(29)
382+
@Order(30)
364383
@DisplayName("getMax returns value when it exists")
365384
void getMaxReturnsValueWhenItExists() {
366385
givenMaxHolderWithData(String.class, "I am maximum");
@@ -371,7 +390,7 @@ void getMaxReturnsValueWhenItExists() {
371390
}
372391

373392
@Test
374-
@Order(30)
393+
@Order(31)
375394
@DisplayName("getMax returns value when it exists")
376395
void getMaxReturnsNullWhenNoValueByGivenTypeExists() {
377396
var returnedValue = callGetMax(String.class);
@@ -380,7 +399,7 @@ void getMaxReturnsNullWhenNoValueByGivenTypeExists() {
380399
}
381400

382401
@Test
383-
@Order(31)
402+
@Order(32)
384403
@DisplayName("HeterogeneousMaxHolder keeps track of value one per each type")
385404
void maxHolderKeepsTrackOfMultipleValuesPerType() {
386405
callPut(String.class, "A");

0 commit comments

Comments
 (0)