/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.revapi.java;
import static java.util.stream.Collectors.toList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Test;
import org.revapi.API;
import org.revapi.AnalysisContext;
import org.revapi.Element;
import org.revapi.Report;
import org.revapi.java.compilation.InclusionFilter;
import org.revapi.java.filters.AnnotatedElementFilter;
import org.revapi.java.model.JavaElementForest;
import org.revapi.java.model.MethodElement;
import org.revapi.java.model.MethodParameterElement;
/**
* @author Lukas Krejci
* @since 0.5.1
*/
public class AnnotatedElementFilterTest extends AbstractJavaElementAnalyzerTest {
@Test
public void testExcludeByAnnotationPresence() throws Exception {
testWith("{\"revapi\":{\"java\":{\"filter\":{\"annotated\":{\"regex\": true, \"exclude\":" +
"[\"@annotationfilter.NonPublic.*\"]}}}}}", results -> {
Assert.assertEquals(73, results.size());
assertNotContains(results.stream().map(Element::getFullHumanReadableString).collect(toList()),
"class annotationfilter.NonPublicClass", "field annotationfilter.NonPublicClass.f",
"method void annotationfilter.NonPublicClass::m()",
"method void annotationfilter.PublicClass::implDetail()",
"class annotationfilter.PublicClass.NonPublicInnerClass");
});
}
@Test
public void testExcludeByAnnotationWithAttributeValues() throws Exception {
testWith("{\"revapi\":{\"java\":{\"filter\":{\"annotated\":{\"exclude\":" +
"[\"@annotationfilter.NonPublic(since = \\\"2.0\\\")\"]}}}}}", results -> {
Assert.assertEquals(112, results.size());
assertNotContains(results.stream().map(Element::getFullHumanReadableString).collect(toList()),
"method void annotationfilter.PublicClass::implDetail()");
});
}
@Test
public void testIncludeByAnnotationPresence() throws Exception {
testWith("{\"revapi\":{\"java\":{\"filter\":{\"annotated\":{\"include\":" +
"[\"@annotationfilter.Public\"]}}}}}", results -> {
Assert.assertEquals(59, results.size());
assertNotContains(results.stream().map(Element::getFullHumanReadableString).collect(toList()),
"class annotationfilter.NonPublic", "method java.lang.String annotationfilter.NonPublic::since()",
"class annotationfilter.NonPublicClass", "field annotationfilter.NonPublicClass.f",
"class annotationfilter.Public", "class annotationfilter.UndecisiveClass",
"field annotationfilter.UndecisiveClass.f",
"method void annotationfilter.UndecisiveClass::m()");
});
}
@Test
public void testIncludeByAnnotationWithAttributeValues() throws Exception {
testWith("{\"revapi\":{\"java\":{\"filter\":{\"annotated\":{\"include\":" +
"[\"@annotationfilter.NonPublic(since = \\\"2.0\\\")\"]}}}}}", results -> {
Assert.assertEquals(2, results.size());
Assert.assertEquals("method void annotationfilter.PublicClass::implDetail()",
results.get(0).getFullHumanReadableString());
});
}
@Test
public void testIncludeAndExclude() throws Exception {
testWith("{\"revapi\":{\"java\":{\"filter\":{\"annotated\":{\"regex\" : true, \"exclude\":" +
"[\"@annotationfilter.NonPublic.*\"]," +
"\"include\": [\"@annotationfilter.Public\"]}}}}}", results
-> {
Assert.assertEquals(39, results.size());
assertNotContains(results.stream().map(Element::getFullHumanReadableString).collect(toList()),
"class annotationfilter.NonPublic",
"method java.lang.String annotationfilter.NonPublic::since()",
"class annotationfilter.NonPublicClass", "field annotationfilter.NonPublicClass.f",
"class annotationfilter.Public",
"method void annotationfilter.PublicClass::implDetail()",
"class annotationfilter.PublicClass.NonPublicInnerClass",
"class annotationfilter.UndecisiveClass", "field annotationfilter.UndecisiveClass.f",
"method void annotationfilter.UndecisiveClass::m()");
});
}
@Test
public void testChangesReportedOnAnnotationElements() throws Exception {
ArrayList<Report> reports = new ArrayList<>();
CollectingReporter reporter = new CollectingReporter(reports);
runAnalysis(reporter,
"{\"revapi\": {\"java\": {\"filter\": {\"annotated\": {\"regex\": true," +
" \"include\":[\"@Attributes.Anno.*\"]}}}}}",
"v1/annotations/Attributes.java", "v2/annotations/Attributes.java");
Assert.assertEquals(2, reports.size());
Report parameterChange = reports.stream().filter(r -> r.getNewElement() instanceof MethodParameterElement)
.findFirst().orElse(null);
Report annotationChanges = reports.stream().filter(r -> r.getNewElement() instanceof MethodElement)
.findFirst().orElse(null);
Assert.assertEquals(1, parameterChange.getDifferences().size());
Assert.assertEquals("java.method.parameterTypeChanged", parameterChange.getDifferences().get(0).code);
Assert.assertEquals(3, annotationChanges.getDifferences().size());
Assert.assertEquals(new HashSet<>(Arrays.asList("java.annotation.attributeValueChanged",
"java.annotation.attributeAdded", "java.element.nowDeprecated")),
annotationChanges.getDifferences().stream().map(d -> d.code).collect(Collectors.toSet()));
}
private void testWith(String configJSON, Consumer<List<Element>> test) throws Exception {
ArchiveAndCompilationPath archive = createCompiledJar("test.jar", "annotationfilter/NonPublic.java",
"annotationfilter/NonPublicClass.java", "annotationfilter/Public.java",
"annotationfilter/PublicClass.java", "annotationfilter/UndecisiveClass.java");
try {
JavaArchiveAnalyzer analyzer = new JavaArchiveAnalyzer(
new API(Arrays.asList(new ShrinkwrapArchive(archive.archive)), null),
Executors.newSingleThreadExecutor(), null, false,
InclusionFilter.acceptAll());
JavaElementForest forest = analyzer.analyze();
AnnotatedElementFilter filter = new AnnotatedElementFilter();
AnalysisContext ctx = AnalysisContext.builder().withConfigurationFromJSON(configJSON).build();
filter.initialize(ctx);
List<Element> results = forest.search(Element.class, true, filter, null);
test.accept(results);
} finally {
deleteDir(archive.compilationPath);
}
}
private <T> void assertNotContains(List<T> list, T... elements) {
ArrayList<T> intersection = new ArrayList<>(list);
intersection.retainAll(Arrays.asList(elements));
if (!intersection.isEmpty()) {
Assert.fail("List " + list + " shouldn't have contained any of the " + Arrays.asList(elements));
}
}
}