rfield@1422: /* katleman@1448: * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. rfield@1422: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. rfield@1422: * rfield@1422: * This code is free software; you can redistribute it and/or modify it rfield@1422: * under the terms of the GNU General Public License version 2 only, as rfield@1422: * published by the Free Software Foundation. Oracle designates this rfield@1422: * particular file as subject to the "Classpath" exception as provided rfield@1422: * by Oracle in the LICENSE file that accompanied this code. rfield@1422: * rfield@1422: * This code is distributed in the hope that it will be useful, but WITHOUT rfield@1422: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or rfield@1422: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License rfield@1422: * version 2 for more details (a copy is included in the LICENSE file that rfield@1422: * accompanied this code). rfield@1422: * rfield@1422: * You should have received a copy of the GNU General Public License version rfield@1422: * 2 along with this work; if not, write to the Free Software Foundation, rfield@1422: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. rfield@1422: * rfield@1422: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA rfield@1422: * or visit www.oracle.com if you need additional information or have any rfield@1422: * questions. rfield@1422: */ rfield@1422: rfield@1422: package org.openjdk.tests.vm; rfield@1422: rfield@1422: import java.util.*; rfield@1422: rfield@1422: import org.testng.ITestResult; rfield@1422: import org.testng.annotations.Test; rfield@1422: import org.testng.annotations.DataProvider; rfield@1422: import org.testng.annotations.AfterMethod; rfield@1422: import org.testng.annotations.AfterSuite; rfield@1422: rfield@1422: import org.openjdk.tests.separate.*; rfield@1422: import org.openjdk.tests.separate.Compiler; rfield@1422: rfield@1422: import org.openjdk.tests.shapegen.Hierarchy; rfield@1422: import org.openjdk.tests.shapegen.HierarchyGenerator; rfield@1422: import org.openjdk.tests.shapegen.ClassCase; rfield@1422: rfield@1422: import static org.testng.Assert.*; rfield@1422: import static org.openjdk.tests.separate.SourceModel.*; rfield@1422: import static org.openjdk.tests.separate.SourceModel.Class; rfield@1422: import static org.openjdk.tests.separate.SourceModel.Method; rfield@1422: import static org.openjdk.tests.separate.SourceModel.Type; rfield@1422: rfield@1422: public class FDSeparateCompilationTest extends TestHarness { rfield@1422: rfield@1422: private static String EMPTY = "\"\""; rfield@1422: rfield@1422: public FDSeparateCompilationTest() { rfield@1422: super(false, true); rfield@1422: } rfield@1422: rfield@1422: @DataProvider(name = "allShapes", parallel = true) rfield@1422: public Object[][] hierarchyGenerator() { rfield@1422: ArrayList allCases = new ArrayList<>(); rfield@1422: rfield@1422: HierarchyGenerator hg = new HierarchyGenerator(); rfield@1422: for (Object x : hg.getOK()) { rfield@1422: allCases.add(new Object[]{x}); rfield@1422: } rfield@1422: for (Object x : hg.getErr()) { rfield@1422: allCases.add(new Object[]{x}); rfield@1422: } rfield@1422: return allCases.toArray(new Object[0][]); rfield@1422: } rfield@1422: rfield@1422: // The expected value obtained when invoking the method from the specified rfield@1422: // class. If returns null, then an AbstractMethodError is expected. rfield@1422: private static String getExpectedResult(ClassCase cc) { rfield@1422: Set provs = cc.get_mprov(); rfield@1422: if (cc.get_mres() != null) { rfield@1422: return cc.get_mres().getName(); rfield@1422: } else if (provs != null && provs.size() == 1) { rfield@1422: ClassCase cand = provs.iterator().next(); rfield@1422: switch (cand.kind) { rfield@1422: case CCONCRETE: rfield@1422: case IDEFAULT: rfield@1422: return cand.getName(); rfield@1422: case CNONE: rfield@1422: case IVAC: rfield@1422: return getExpectedResult(cand); rfield@1422: } rfield@1422: } rfield@1422: return null; rfield@1422: } rfield@1422: rfield@1422: private static final ConcreteMethod canonicalMethod = new ConcreteMethod( rfield@1422: "String", "m", "returns " + EMPTY + ";", AccessFlag.PUBLIC); rfield@1422: rfield@1422: @Test(groups = "vm", dataProvider = "allShapes") rfield@1422: public void separateCompilationTest(Hierarchy hs) { rfield@1422: ClassCase cc = hs.root; rfield@1422: Type type = sourceTypeFrom(hs.root); rfield@1422: rfield@1422: Class specimen = null; rfield@1422: if (type instanceof Class) { rfield@1422: Class ctype = (Class)type; rfield@1422: if (ctype.isAbstract()) { rfield@1422: specimen = new Class("Test" + ctype.getName(), ctype); rfield@1422: } else { rfield@1422: specimen = ctype; rfield@1422: } rfield@1422: } else { rfield@1422: specimen = new Class("Test" + type.getName(), (Interface)type); rfield@1422: } rfield@1422: rfield@1422: String value = getExpectedResult(cc); rfield@1422: if (value != null) { rfield@1422: assertInvokeVirtualEquals(value, specimen, canonicalMethod, EMPTY); rfield@1422: } else { rfield@1422: assertThrows(AbstractMethodError.class, specimen, rfield@1422: canonicalMethod, EMPTY); rfield@1422: } rfield@1422: } rfield@1422: rfield@1422: @AfterMethod rfield@1422: public void printCaseError(ITestResult result) { rfield@1422: if (result.getStatus() == ITestResult.FAILURE) { rfield@1422: Hierarchy hs = (Hierarchy)result.getParameters()[0]; rfield@1422: System.out.println("Separate compilation case " + hs); rfield@1422: printCaseDetails(hs); rfield@1422: } rfield@1422: } rfield@1422: rfield@1422: @AfterSuite rfield@1422: public void cleanupCompilerCache() { rfield@1422: Compiler.purgeCache(); rfield@1422: } rfield@1422: rfield@1422: private void printCaseDetails(Hierarchy hs) { rfield@1422: String exp = getExpectedResult(hs.root); rfield@1422: for (String s : hs.getDescription()) { rfield@1422: System.out.println(" " + s); rfield@1422: } rfield@1422: if (exp != null) { rfield@1422: System.out.println(" Expected \"" + exp + "\""); rfield@1422: } else { rfield@1422: System.out.println(" Expected AbstractMethodError"); rfield@1422: } rfield@1422: } rfield@1422: rfield@1422: private Type sourceTypeFrom(ClassCase cc) { rfield@1422: Type type = null; rfield@1422: rfield@1422: if (cc.isInterface()) { rfield@1422: Interface iface = new Interface(cc.getName()); rfield@1422: for (ClassCase scc : cc.getInterfaces()) { rfield@1422: Interface supertype = (Interface)sourceTypeFrom(scc); rfield@1422: iface.addSuperType(supertype); rfield@1422: } rfield@1422: type = iface; rfield@1422: } else { rfield@1422: Class cls = new Class(cc.getName()); rfield@1422: if (cc.hasSuperclass()) { rfield@1422: Class superc = (Class)sourceTypeFrom(cc.getSuperclass()); rfield@1422: cls.setSuperClass(superc); rfield@1422: } rfield@1422: for (ClassCase scc : cc.getInterfaces()) { rfield@1422: Interface supertype = (Interface)sourceTypeFrom(scc); rfield@1422: cls.addSuperType(supertype); rfield@1422: } rfield@1422: if (cc.isAbstract()) { rfield@1422: cls.getAccessFlags().add(AccessFlag.ABSTRACT); rfield@1422: } rfield@1422: type = cls; rfield@1422: } rfield@1422: Method method = methodFrom(cc); rfield@1422: if (method != null) { rfield@1422: type.addMethod(method); rfield@1422: } rfield@1422: return type; rfield@1422: } rfield@1422: rfield@1422: private Method methodFrom(ClassCase cc) { rfield@1422: switch (cc.kind) { rfield@1422: case IVAC: rfield@1422: case CNONE: return null; rfield@1422: case IPRESENT: rfield@1422: case CABSTRACT: rfield@1422: return new AbstractMethod("String", "m", AccessFlag.PUBLIC); rfield@1422: case IDEFAULT: rfield@1422: return new DefaultMethod( rfield@1422: "String", "m", "return \"" + cc.getName() + "\";"); rfield@1422: case CCONCRETE: rfield@1422: return new ConcreteMethod( rfield@1422: "String", "m", "return \"" + cc.getName() + "\";", rfield@1422: AccessFlag.PUBLIC); rfield@1422: default: rfield@1422: fail("Unknown method type in class"); rfield@1422: return null; rfield@1422: } rfield@1422: } rfield@1422: }