1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.stubbing.defaultanswers;
6 
7 import org.junit.Test;
8 
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13 
14 import static org.assertj.core.api.Assertions.assertThat;
15 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
16 import static org.mockito.Mockito.mock;
17 
18 @SuppressWarnings("unused")
19 public class ReturnsGenericDeepStubsTest {
20     interface ListOfInteger extends List<Integer> {}
21 
22     interface AnotherListOfInteger extends ListOfInteger {}
23 
24     interface GenericsNest<K extends Comparable<K> & Cloneable> extends Map<K, Set<Number>> {
remove(Object key)25         Set<Number> remove(Object key); // override with fixed ParameterizedType
returningWildcard()26         List<? super Number> returningWildcard();
returningNonMockableNestedGeneric()27         Map<String, K> returningNonMockableNestedGeneric();
returningK()28         K returningK();
paramTypeWithTypeParams()29         <O extends K> List<O> paramTypeWithTypeParams();
twoTypeParams(S s)30         <S extends Appendable, T extends S> T twoTypeParams(S s);
typeVarWithTypeParams()31         <O extends K> O typeVarWithTypeParams();
returnsNormalType()32         Number returnsNormalType();
33     }
34 
35     @Test
generic_deep_mock_frenzy__look_at_these_chained_calls()36     public void generic_deep_mock_frenzy__look_at_these_chained_calls() throws Exception {
37         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
38 
39         Set<? extends Map.Entry<? extends Cloneable, Set<Number>>> entries = mock.entrySet();
40         Iterator<? extends Map.Entry<? extends Cloneable,Set<Number>>> entriesIterator = mock.entrySet().iterator();
41         Map.Entry<? extends Cloneable, Set<Number>> nextEntry = mock.entrySet().iterator().next();
42 
43         Cloneable cloneableKey = mock.entrySet().iterator().next().getKey();
44         Comparable<?> comparableKey = mock.entrySet().iterator().next().getKey();
45 
46         Set<Number> value = mock.entrySet().iterator().next().getValue();
47         Iterator<Number> numbersIterator = mock.entrySet().iterator().next().getValue().iterator();
48         Number number = mock.entrySet().iterator().next().getValue().iterator().next();
49     }
50 
51     @Test
can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_parameterizedtype_that_is_referencing_a_typevar_on_class()52     public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_parameterizedtype_that_is_referencing_a_typevar_on_class() throws Exception {
53         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
54 
55         Cloneable cloneable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method =
56                 mock.paramTypeWithTypeParams().get(0);
57         Comparable<?> comparable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method =
58                 mock.paramTypeWithTypeParams().get(0);
59     }
60 
61     @Test
can_create_mock_from_multiple_type_variable_bounds_when_method_return_type_is_referencing_a_typevar_on_class()62     public void can_create_mock_from_multiple_type_variable_bounds_when_method_return_type_is_referencing_a_typevar_on_class() throws Exception {
63         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
64 
65         Cloneable cloneable_bound_of_typevar_K = mock.returningK();
66         Comparable<?> comparable_bound_of_typevar_K = mock.returningK();
67     }
68 
69     @Test
can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_typevar_that_is_referencing_a_typevar_on_class()70     public void can_create_mock_from_multiple_type_variable_bounds_when_return_type_of_parameterized_method_is_a_typevar_that_is_referencing_a_typevar_on_class() throws Exception {
71         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
72 
73         Cloneable cloneable_bound_of_typevar_K_referenced_by_typevar_O = (Cloneable) mock.typeVarWithTypeParams();
74         Comparable<?> comparable_bound_of_typevar_K_referenced_by_typevar_O = (Comparable<?>) mock.typeVarWithTypeParams();
75     }
76 
77     @Test
can_create_mock_from_return_types_declared_with_a_bounded_wildcard()78     public void can_create_mock_from_return_types_declared_with_a_bounded_wildcard() throws Exception {
79         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
80 
81         List<? super Integer> objects = mock.returningWildcard();
82         Number type_that_is_the_upper_bound_of_the_wildcard = (Number) mock.returningWildcard().get(45);
83         type_that_is_the_upper_bound_of_the_wildcard.floatValue();
84     }
85 
86     @Test
can_still_work_with_raw_type_in_the_return_type()87     public void can_still_work_with_raw_type_in_the_return_type() throws Exception {
88         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
89 
90         Number the_raw_type_that_should_be_returned = mock.returnsNormalType();
91         the_raw_type_that_should_be_returned.floatValue();
92     }
93 
94     @Test
will_return_default_value_on_non_mockable_nested_generic()95     public void will_return_default_value_on_non_mockable_nested_generic() throws Exception {
96         GenericsNest<?> genericsNest = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
97         ListOfInteger listOfInteger = mock(ListOfInteger.class, RETURNS_DEEP_STUBS);
98         AnotherListOfInteger anotherListOfInteger = mock(AnotherListOfInteger.class, RETURNS_DEEP_STUBS);
99 
100         assertThat(genericsNest.returningNonMockableNestedGeneric().keySet().iterator().next()).isNull();
101         assertThat(listOfInteger.get(25)).isEqualTo(0);
102         assertThat(anotherListOfInteger.get(25)).isEqualTo(0);
103     }
104 
105     @Test(expected = ClassCastException.class)
as_expected_fail_with_a_CCE_on_callsite_when_erasure_takes_place_for_example___StringBuilder_is_subject_to_erasure()106     public void as_expected_fail_with_a_CCE_on_callsite_when_erasure_takes_place_for_example___StringBuilder_is_subject_to_erasure() throws Exception {
107         GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
108 
109         // following assignment needed to create a ClassCastException on the call site (i.e. : here)
110         StringBuilder stringBuilder_assignment_that_should_throw_a_CCE =
111                 mock.twoTypeParams(new StringBuilder()).append(2).append(3);
112     }
113 }
114