Skip to content

Commit

Permalink
Open-source more of check_api/src/test/java/com/google/errorprone/util
Browse files Browse the repository at this point in the history
These tests still don't compile due to a cycle between test_helpers and check_api

PiperOrigin-RevId: 686487416
  • Loading branch information
cushon authored and Error Prone Team committed Oct 16, 2024
1 parent 4f630fc commit c897d8f
Show file tree
Hide file tree
Showing 7 changed files with 4,522 additions and 0 deletions.
9 changes: 9 additions & 0 deletions check_api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@
<version>${autoservice.version}</version>
</path>
</annotationProcessorPaths>
<testExcludes>
<!-- TODO(b/172597965): maven sees a cycle here since test_helpers depends on check_api -->
<testExclude>**/ASTHelpersFindSuperMethodsTest.java</testExclude>
<testExclude>**/ASTHelpersTest.java</testExclude>
<testExclude>**/CommentsTest.java</testExclude>
<testExclude>**/FindIdentifiersTest.java</testExclude>
<testExclude>**/MoreAnnotationsTest.java</testExclude>
<testExclude>**/ReachabilityTest.java</testExclude>
</testExcludes>
</configuration>
<executions>
<execution>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/*
* Copyright 2017 The Error Prone Authors.
*
* 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 com.google.errorprone.util;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Table;
import com.google.errorprone.VisitorState;
import com.google.errorprone.matchers.CompilerBasedAbstractTest;
import com.google.errorprone.scanner.Scanner;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Types;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
* Test cases for {@link ASTHelpers#findSuperMethod(MethodSymbol, Types)} and {@link
* ASTHelpers#findSuperMethod(MethodSymbol, Types)}.
*
* @author Łukasz Hanuszczak ([email protected])
*/
@RunWith(JUnit4.class)
public final class ASTHelpersFindSuperMethodsTest extends CompilerBasedAbstractTest {

private FindSuperMethodsTestScanner scanner;

@Before
public void prepareScanClassHierarchy() {
writeFile(
"Foo.java",
"""
abstract class Foo {
public abstract void foo();
}
""");
writeFile(
"Bar.java",
"""
class Bar extends Foo {
@Override
public void foo() {
System.out.println("bar");
}
}
""");
writeFile(
"Baz.java",
"""
class Baz extends Bar {
@Override
public void foo() {
System.out.println("baz");
}
}
""");
writeFile(
"Quux.java",
"""
class Quux extends Baz {
public void foo(String string) {
System.out.println("I am not an override! " + string);
}
public int bar(int x, int y) {
return x * y;
}
}
""");
writeFile(
"Norf.java",
"""
class Norf extends Quux {
@Override
public void foo() {
System.out.println("norf");
}
@Override
public int bar(int x, int y) {
return super.bar(x, y) + 42;
}
}
""");

scanner = new FindSuperMethodsTestScanner();
assertCompiles(scanner);
}

@Test
public void findSuperMethods_findsSingleMethod() {
MethodSymbol barOfNorf = scanner.getMethod("Norf", "bar");
MethodSymbol barOfQuux = scanner.getMethod("Quux", "bar");
assertThat(findSuperMethods(barOfNorf)).containsExactly(barOfQuux);
}

@Test
public void findSuperMethods_findsAllMethodsInTheHierarchy() {
MethodSymbol fooOfNorf = scanner.getMethod("Norf", "foo");
MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo");
MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo");
MethodSymbol fooOfQuux = scanner.getMethod("Foo", "foo");
assertThat(findSuperMethods(fooOfNorf))
.containsExactly(fooOfBaz, fooOfBar, fooOfQuux)
.inOrder();
}

@Test
public void findSuperMethod_findsNothingForAbstractMethod() {
MethodSymbol fooOfFoo = scanner.getMethod("Foo", "foo");
assertThat(findSuperMethod(fooOfFoo)).isEqualTo(Optional.empty());
}

@Test
public void findSuperMethod_findsNothingForNewNonAbstractMethod() {
MethodSymbol barOfQuux = scanner.getMethod("Quux", "bar");
assertThat(findSuperMethod(barOfQuux)).isEqualTo(Optional.empty());
}

@Test
public void findSuperMethod_findsAbstractSuperMethod() {
MethodSymbol fooOfFoo = scanner.getMethod("Foo", "foo");
MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo");
assertThat(findSuperMethod(fooOfBar)).isEqualTo(Optional.of(fooOfFoo));
}

@Test
public void findSuperMethod_findsNormalSuperMethodForDirectSuperclass() {
MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo");
MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo");
assertThat(findSuperMethod(fooOfBaz)).isEqualTo(Optional.of(fooOfBar));

MethodSymbol barOfQuux = scanner.getMethod("Quux", "bar");
MethodSymbol barOfNorf = scanner.getMethod("Norf", "bar");
assertThat(findSuperMethod(barOfNorf)).isEqualTo(Optional.of(barOfQuux));
}

@Test
public void findSuperMethod_findsNormalSuperMethodForNonDirectSuperclass() {
MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo");
MethodSymbol fooOfNorf = scanner.getMethod("Norf", "foo");
assertThat(findSuperMethod(fooOfNorf)).isEqualTo(Optional.of(fooOfBaz));
}

private ImmutableList<MethodSymbol> findSuperMethods(MethodSymbol method) {
return ImmutableList.copyOf(ASTHelpers.findSuperMethods(method, getTypes()));
}

private Optional<MethodSymbol> findSuperMethod(MethodSymbol method) {
return ASTHelpers.findSuperMethod(method, getTypes());
}

private Types getTypes() {
return scanner.getState().getTypes();
}

/**
* A quite hacky class used to assert things in {@link ASTHelpersFindSuperMethodsTest}.
*
* <p>This does two things: it builds a mapping from class names and method names to method
* symbols (for easy assertions) and keeps track of the last visited {@link VisitorState}.
*
* <p>We cannot do assertions in the {@link Scanner#scan(Tree, VisitorState)} like all the other
* test cases do because we need data from all processed classes (and {@link Scanner#scan(Tree,
* VisitorState)} is triggered for every single class). Therefore we need to make all assertions
* in the test method itself but {@link ASTHelpers#findSuperMethods(MethodSymbol, Types)} requires
* a {@link VisitorState} to be used. So we simply remember last state passed to the {@link
* Scanner#scan(Tree, VisitorState)}.
*/
private static class FindSuperMethodsTestScanner extends Scanner {

// A `class name -> method name -> method symbol` structure mapping of given files.
private final Table<String, String, MethodSymbol> methods;

// Last state passed to the `Scanner#scan` method.
private VisitorState state;

public FindSuperMethodsTestScanner() {
this.methods = HashBasedTable.create();
}

public MethodSymbol getMethod(String className, String methodName) {
return methods.get(className, methodName);
}

public VisitorState getState() {
return state;
}

@Override
public Void scan(Tree tree, VisitorState state) {
this.state = state;
return super.scan(tree, state);
}

@Override
public Void visitMethod(MethodTree methodTree, VisitorState state) {
String classContext = ASTHelpers.getSymbol(methodTree).owner.getSimpleName().toString();
String methodContext = methodTree.getName().toString();

MethodSymbol method = ASTHelpers.getSymbol(methodTree);
if (!methods.contains(classContext, methodContext)) {
methods.put(classContext, methodContext, method);
}

return super.visitMethod(methodTree, state);
}
}
}
Loading

0 comments on commit c897d8f

Please sign in to comment.