/* * SonarQube Java * Copyright (C) 2012-2016 SonarSource SA * mailto:contact AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.java.resolve; import org.junit.Before; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; public class TypeSubstitutionTest { TypeSubstitution substitution; TypeVariableJavaType k; TypeVariableJavaType v; JavaType c1; JavaType c2; JavaSymbol.PackageJavaSymbol packageJavaSymbol = new JavaSymbol.PackageJavaSymbol(null, null); @Before public void setUp() { k = new TypeVariableJavaType(new JavaSymbol.TypeVariableJavaSymbol("K", packageJavaSymbol)); v = new TypeVariableJavaType(new JavaSymbol.TypeVariableJavaSymbol("V", packageJavaSymbol)); c1 = new JavaType(JavaType.CLASS, null); c2 = new JavaType(JavaType.CLASS, null); substitution = new TypeSubstitution() .add(k, c1) .add(v, c2); } @Test public void should_be_empty() { TypeSubstitution substitution = new TypeSubstitution(); assertThat(substitution.size()).isEqualTo(0); assertThat(substitution.substitutionEntries()).isEmpty(); assertThat(substitution.substitutedTypes()).isEmpty(); assertThat(substitution.typeVariables()).isEmpty(); } @Test public void should_contain_exact_number_of_substitution() { assertThat(substitution.size()).isEqualTo(2); assertThat(substitution.substitutionEntries()).hasSize(2); assertThat(substitution.substitutedTypes()).hasSize(2); assertThat(substitution.typeVariables()).hasSize(2); } @Test public void should_contain_substitution() { assertThat(substitution.substitutedType(k)).isEqualTo(c1); assertThat(substitution.substitutedType(v)).isEqualTo(c2); } @Test public void should_be_ordered() { assertThat(substitution.typeVariables().get(0)).isEqualTo(k); assertThat(substitution.typeVariables().get(1)).isEqualTo(v); assertThat(substitution.substitutedTypes().get(0)).isEqualTo(c1); assertThat(substitution.substitutedTypes().get(1)).isEqualTo(c2); } @Test public void equivalent_type_substitutions_should_compute_same_hashCode() { TypeSubstitution newSubstitution = new TypeSubstitution() .add(k, c1) .add(v, c2); assertThat(substitution.hashCode()).isEqualTo(newSubstitution.hashCode()); } @Test public void order_should_be_Taken_into_account_for_hashCode() { // couples swapped TypeSubstitution newSubstitution = new TypeSubstitution() .add(v, c2) .add(k, c1); assertThat(substitution.hashCode()).isNotEqualTo(newSubstitution.hashCode()); // variables swapped newSubstitution = new TypeSubstitution() .add(v, c1) .add(k, c2); assertThat(substitution.hashCode()).isNotEqualTo(newSubstitution.hashCode()); // substitutions swapped newSubstitution = new TypeSubstitution() .add(k, c2) .add(v, c1); assertThat(substitution.hashCode()).isNotEqualTo(newSubstitution.hashCode()); } @Test public void equivalent_type_substitutions_should_be_equals() { TypeSubstitution newSubstitution = new TypeSubstitution() .add(k, c1) .add(v, c2); assertThat(substitution.equals(newSubstitution)).isTrue(); assertThat(substitution.equals(substitution)).isTrue(); } @Test public void different_substitution_are_not_equals() { assertThat(substitution.equals(new TypeSubstitution())).isFalse(); assertThat(substitution.equals(null)).isFalse(); assertThat(substitution.equals(new Object())).isFalse(); } @Test public void order_should_be_taken_into_account_for_equality_test() { // couples swapped TypeSubstitution newSubstitution = new TypeSubstitution() .add(v, c2) .add(k, c1); assertThat(substitution.equals(newSubstitution)).isFalse(); // variables swapped newSubstitution = new TypeSubstitution() .add(v, c1) .add(k, c2); assertThat(substitution.equals(newSubstitution)).isFalse(); // substitutions swapped newSubstitution = new TypeSubstitution() .add(k, c2) .add(v, c1); assertThat(substitution.equals(newSubstitution)).isFalse(); } @Test public void test_combine() throws Exception { TypeVariableJavaType a = newTypeVar("A"); TypeVariableJavaType b = newTypeVar("B"); TypeVariableJavaType x = newTypeVar("X"); TypeVariableJavaType y = newTypeVar("Y"); JavaType s = newType("S"); JavaType i = newType("I"); TypeSubstitution t0 = new TypeSubstitution().add(a, s).add(b, i); TypeSubstitution t1 = new TypeSubstitution().add(a, x).add(b, y); TypeSubstitution combined = t1.combine(t0); assertThat(combined.typeVariables()).hasSize(2).containsSequence(x, y); assertThat(combined.substitutedTypes()).hasSize(2).containsSequence(s, i); TypeSubstitution t3 = new TypeSubstitution().add(a, s).add(b, newParameterizedType("G", i)); TypeSubstitution t4 = new TypeSubstitution().add(a, x).add(b, newParameterizedType("G", y)); combined = t4.combine(t3); assertThat(combined.typeVariables()).hasSize(2).containsSequence(x, y); assertThat(combined.substitutedTypes()).hasSize(2).containsSequence(s, i); TypeSubstitution t5 = new TypeSubstitution().add(a, new WildCardType(x, WildCardType.BoundType.SUPER)).add(b, new WildCardType(y, WildCardType.BoundType.EXTENDS)); combined = t5.combine(t0); assertThat(combined.typeVariables()).hasSize(2).containsSequence(x, y); assertThat(combined.substitutedTypes()).hasSize(2).containsSequence(s, i); TypeSubstitution t6 = new TypeSubstitution().add(a, s).add(b, new ArrayJavaType(i, null)); TypeSubstitution t7 = new TypeSubstitution().add(a, x).add(b, new ArrayJavaType(y, null)); combined = t7.combine(t6); assertThat(combined.typeVariables()).hasSize(2).containsSequence(x, y); assertThat(combined.substitutedTypes()).hasSize(2).containsSequence(s, i); ParametrizedTypeJavaType listOfY = newParameterizedType("List", y); TypeSubstitution t8 = new TypeSubstitution().add(a, new WildCardType(x, WildCardType.BoundType.SUPER)).add(b, listOfY); TypeSubstitution t9 = new TypeSubstitution().add(a, y).add(b, listOfY); combined = t8.combine(t9); assertThat(combined.typeVariables()).hasSize(2).containsSequence(x, b); assertThat(combined.substitutedTypes()).hasSize(2).containsSequence(y, listOfY); } private JavaType newType(String name) { return new JavaType(JavaType.CLASS, new JavaSymbol.TypeJavaSymbol(0, name, packageJavaSymbol)); } private TypeVariableJavaType newTypeVar(String name) { return new TypeVariableJavaType(new JavaSymbol.TypeVariableJavaSymbol(name, packageJavaSymbol)); } private ParametrizedTypeJavaType newParameterizedType(String name, JavaType substitutedType) { JavaSymbol.TypeJavaSymbol symbol = new JavaSymbol.TypeJavaSymbol(0, name, packageJavaSymbol); symbol.addTypeParameter(k); TypeSubstitution newSubstitution = new TypeSubstitution().add(k, substitutedType); return new ParametrizedTypeJavaType(symbol, newSubstitution); } }