/* * Copyright 2017-present Facebook, Inc. * * 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.facebook.buck.jvm.java.abi; import static org.junit.Assert.fail; import com.facebook.buck.jvm.java.testutil.compiler.TestCompiler; import com.facebook.buck.testutil.integration.TestDataHelper; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import javax.lang.model.element.Element; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import org.junit.Before; import org.junit.Rule; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; public class DescriptorAndSignatureFactoryTestBase { @Rule public TestCompiler testCompiler = new TestCompiler(); protected Elements elements; List<String> errors = new ArrayList<>(); @Before public void setUp() throws IOException { Path sourceFile = TestDataHelper.getTestDataScenario(this, "descriptor_and_signature_factories") .resolve("Foo.java"); testCompiler.addSourceFile(sourceFile); elements = testCompiler.getElements(); testCompiler.compile(); } protected List<String> getTestErrors( Function<FieldNode, String> fieldNodeExpectedValueGetter, Function<MethodNode, String> methodNodeExpectedValueGetter, Function<ClassNode, String> classNodeExpectedValueGetter, Function<Element, String> elementActualValueGetter) throws IOException { TypeElement fooElement = elements.getTypeElement("com.facebook.foo.Foo"); findErrors( fooElement, fieldNodeExpectedValueGetter, methodNodeExpectedValueGetter, classNodeExpectedValueGetter, elementActualValueGetter); return errors; } private void findErrors( TypeElement typeElement, Function<FieldNode, String> fieldNodeExpectedValueGetter, Function<MethodNode, String> methodNodeExpectedValueGetter, Function<ClassNode, String> classNodeExpectedValueGetter, Function<Element, String> elementActualValueGetter) throws IOException { ClassNode typeNode = getClassNode(elements.getBinaryName(typeElement).toString()); for (Element enclosedElement : typeElement.getEnclosedElements()) { Name elementName = enclosedElement.getSimpleName(); String actual = elementActualValueGetter.apply(enclosedElement); switch (enclosedElement.getKind()) { case FIELD: checkValue( "Field", elementName, fieldNodeExpectedValueGetter.apply(getFieldNode(typeNode, elementName)), actual); break; case CONSTRUCTOR: case METHOD: checkValue( "Method", elementName, methodNodeExpectedValueGetter.apply(getMethodNode(typeNode, elementName)), actual); break; case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: ClassNode innerTypeNode = getClassNode(elements.getBinaryName((TypeElement) enclosedElement).toString()); checkValue( "Class", elementName, classNodeExpectedValueGetter.apply(innerTypeNode), actual); findErrors( (TypeElement) enclosedElement, fieldNodeExpectedValueGetter, methodNodeExpectedValueGetter, classNodeExpectedValueGetter, elementActualValueGetter); break; // $CASES-OMITTED$ default: fail( String.format( "Didn't implement testing for element kind %s", enclosedElement.getKind())); continue; } } } private void checkValue(String type, Name elementName, String expected, String actual) { if (expected != actual && (expected == null || !expected.equals(actual))) { errors.add( String.format( "%s %s:\n\tExpected: %s\n\tActual: %s", type, elementName, expected, actual)); } } private FieldNode getFieldNode(ClassNode classNode, Name name) { return classNode .fields .stream() .filter(field -> name.contentEquals(field.name)) .findFirst() .orElse(null); } private MethodNode getMethodNode(ClassNode classNode, Name name) { return classNode .methods .stream() .filter(field -> name.contentEquals(field.name)) .findFirst() .orElse(null); } private ClassNode getClassNode(String classBinaryName) throws IOException { ClassNode classNode = new ClassNode(Opcodes.ASM5); testCompiler.getClasses().acceptClassVisitor(classBinaryName, 0, classNode); return classNode; } }