/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockito.internal.stubbing.defaultanswers; import org.junit.Test; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; @SuppressWarnings("unused") public class ReturnsGenericDeepStubsTest { interface ListOfInteger extends List<Integer> {} interface AnotherListOfInteger extends ListOfInteger {} interface GenericsNest<K extends Comparable<K> & Cloneable> extends Map<K, Set<Number>> { Set<Number> remove(Object key); // override with fixed ParameterizedType List<? super Number> returningWildcard(); Map<String, K> returningNonMockableNestedGeneric(); K returningK(); <O extends K> List<O> paramTypeWithTypeParams(); <S extends Appendable, T extends S> T twoTypeParams(S s); <O extends K> O typeVarWithTypeParams(); Number returnsNormalType(); } @Test public void generic_deep_mock_frenzy__look_at_these_chained_calls() throws Exception { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); Set<? extends Map.Entry<? extends Cloneable, Set<Number>>> entries = mock.entrySet(); Iterator<? extends Map.Entry<? extends Cloneable,Set<Number>>> entriesIterator = mock.entrySet().iterator(); Map.Entry<? extends Cloneable, Set<Number>> nextEntry = mock.entrySet().iterator().next(); Cloneable cloneableKey = mock.entrySet().iterator().next().getKey(); Comparable<?> comparableKey = mock.entrySet().iterator().next().getKey(); Set<Number> value = mock.entrySet().iterator().next().getValue(); Iterator<Number> numbersIterator = mock.entrySet().iterator().next().getValue().iterator(); Number number = mock.entrySet().iterator().next().getValue().iterator().next(); } @Test 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 { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); Cloneable cloneable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method = mock.paramTypeWithTypeParams().get(0); Comparable<?> comparable_bound_that_is_declared_on_typevar_K_in_the_class_which_is_referenced_by_typevar_O_declared_on_the_method = mock.paramTypeWithTypeParams().get(0); } @Test public void can_create_mock_from_multiple_type_variable_bounds_when_method_return_type_is_referencing_a_typevar_on_class() throws Exception { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); Cloneable cloneable_bound_of_typevar_K = mock.returningK(); Comparable<?> comparable_bound_of_typevar_K = mock.returningK(); } @Test 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 { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); Cloneable cloneable_bound_of_typevar_K_referenced_by_typevar_O = (Cloneable) mock.typeVarWithTypeParams(); Comparable<?> comparable_bound_of_typevar_K_referenced_by_typevar_O = (Comparable<?>) mock.typeVarWithTypeParams(); } @Test public void can_create_mock_from_return_types_declared_with_a_bounded_wildcard() throws Exception { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); List<? super Integer> objects = mock.returningWildcard(); Number type_that_is_the_upper_bound_of_the_wildcard = (Number) mock.returningWildcard().get(45); type_that_is_the_upper_bound_of_the_wildcard.floatValue(); } @Test public void can_still_work_with_raw_type_in_the_return_type() throws Exception { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); Number the_raw_type_that_should_be_returned = mock.returnsNormalType(); the_raw_type_that_should_be_returned.floatValue(); } @Test public void will_return_default_value_on_non_mockable_nested_generic() throws Exception { GenericsNest<?> genericsNest = mock(GenericsNest.class, RETURNS_DEEP_STUBS); ListOfInteger listOfInteger = mock(ListOfInteger.class, RETURNS_DEEP_STUBS); AnotherListOfInteger anotherListOfInteger = mock(AnotherListOfInteger.class, RETURNS_DEEP_STUBS); assertThat(genericsNest.returningNonMockableNestedGeneric().keySet().iterator().next()).isNull(); assertThat(listOfInteger.get(25)).isEqualTo(0); assertThat(anotherListOfInteger.get(25)).isEqualTo(0); } @Test(expected = ClassCastException.class) public void as_expected_fail_with_a_CCE_on_callsite_when_erasure_takes_place_for_example___StringBuilder_is_subject_to_erasure() throws Exception { GenericsNest<?> mock = mock(GenericsNest.class, RETURNS_DEEP_STUBS); // following assignment needed to create a ClassCastException on the call site (i.e. : here) StringBuilder stringBuilder_assignment_that_should_throw_a_CCE = mock.twoTypeParams(new StringBuilder()).append(2).append(3); } }