Path: blob/master/test/langtools/jdk/jshell/ClassMembersTest.java
40931 views
/*1* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 813982926* @summary Test access to members of user defined class.27* @build KullaTesting TestingInputStream ExpectedDiagnostic28* @run testng/timeout=600 ClassMembersTest29*/3031import java.lang.annotation.RetentionPolicy;32import java.util.ArrayList;33import java.util.List;3435import javax.tools.Diagnostic;3637import jdk.jshell.SourceCodeAnalysis;38import org.testng.annotations.DataProvider;39import org.testng.annotations.Test;40import jdk.jshell.TypeDeclSnippet;41import static jdk.jshell.Snippet.Status.OVERWRITTEN;42import static jdk.jshell.Snippet.Status.VALID;4344public class ClassMembersTest extends KullaTesting {4546@Test(dataProvider = "memberTestCase")47public void memberTest(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) {48MemberTestCase testCase = new MemberTestCase(accessModifier, codeChunk, isStaticMember, isStaticReference);49assertEval(testCase.generateSource());50String expectedMessage = testCase.expectedMessage;51if (testCase.codeChunk != CodeChunk.CONSTRUCTOR || testCase.isAccessible()) {52assertEval("A a = new A();");53}54if (expectedMessage == null) {55assertEval(testCase.useCodeChunk());56} else {57assertDeclareFail(testCase.useCodeChunk(), expectedMessage);58}59}6061private List<String> parseCode(String input) {62List<String> list = new ArrayList<>();63SourceCodeAnalysis codeAnalysis = getAnalysis();64String source = input;65while (!source.trim().isEmpty()) {66SourceCodeAnalysis.CompletionInfo info = codeAnalysis.analyzeCompletion(source);67list.add(info.source());68source = info.remaining();69}70return list;71}7273@Test(dataProvider = "memberTestCase")74public void extendsMemberTest(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) {75MemberTestCase testCase = new ExtendsMemberTestCase(accessModifier, codeChunk, isStaticMember, isStaticReference);76String input = testCase.generateSource();77List<String> ss = parseCode(input);78assertEval(ss.get(0));79if (testCase.codeChunk != CodeChunk.CONSTRUCTOR || testCase.isAccessible()) {80assertEval(ss.get(1));81assertEval("B b = new B();");82}83String expectedMessage = testCase.expectedMessage;84if (expectedMessage == null) {85assertEval(testCase.useCodeChunk());86} else {87assertDeclareFail(testCase.useCodeChunk(), expectedMessage);88}89}9091@Test92public void interfaceTest() {93String interfaceSource =94"interface A {\n" +95" default int defaultMethod() { return 1; }\n" +96" static int staticMethod() { return 2; }\n" +97" int method();\n" +98" class Inner1 {}\n" +99" static class Inner2 {}\n" +100"}";101assertEval(interfaceSource);102assertEval("A.staticMethod();", "2");103String classSource =104"class B implements A {\n" +105" public int method() { return 3; }\n" +106"}";107assertEval(classSource);108assertEval("B b = new B();");109assertEval("b.defaultMethod();", "1");110assertDeclareFail("B.staticMethod();",111new ExpectedDiagnostic("compiler.err.cant.resolve.location.args", 0, 14, 1, -1, -1, Diagnostic.Kind.ERROR));112assertEval("b.method();", "3");113assertEval("new A.Inner1();");114assertEval("new A.Inner2();");115assertEval("new B.Inner1();");116assertEval("new B.Inner2();");117}118119@Test120public void enumTest() {121String enumSource =122"enum E {A(\"s\");\n" +123" private final String s;\n" +124" private E(String s) { this.s = s; }\n" +125" public String method() { return s; }\n" +126" private String privateMethod() { return s; }\n" +127" public static String staticMethod() { return staticPrivateMethod(); }\n" +128" private static String staticPrivateMethod() { return \"a\"; }\n" +129"}";130assertEval(enumSource);131assertEval("E a = E.A;", "A");132assertDeclareFail("a.s;",133new ExpectedDiagnostic("compiler.err.report.access", 0, 3, 1, -1, -1, Diagnostic.Kind.ERROR));134assertDeclareFail("new E(\"q\");",135new ExpectedDiagnostic("compiler.err.enum.cant.be.instantiated", 0, 10, 0, -1, -1, Diagnostic.Kind.ERROR));136assertEval("a.method();", "\"s\"");137assertDeclareFail("a.privateMethod();",138new ExpectedDiagnostic("compiler.err.report.access", 0, 15, 1, -1, -1, Diagnostic.Kind.ERROR));139assertEval("E.staticMethod();", "\"a\"");140assertDeclareFail("a.staticPrivateMethod();",141new ExpectedDiagnostic("compiler.err.report.access", 0, 21, 1, -1, -1, Diagnostic.Kind.ERROR));142assertDeclareFail("E.method();",143new ExpectedDiagnostic("compiler.err.non-static.cant.be.ref", 0, 8, 1, -1, -1, Diagnostic.Kind.ERROR));144}145146@Test(dataProvider = "retentionPolicyTestCase")147public void annotationTest(RetentionPolicy policy) {148assertEval("import java.lang.annotation.*;");149String annotationSource =150"@Retention(RetentionPolicy." + policy.toString() + ")\n" +151"@interface A {}";152assertEval(annotationSource);153String classSource =154"@A class C {\n" +155" @A C() {}\n" +156" @A void f() {}\n" +157" @A int f;\n" +158" @A class Inner {}\n" +159"}";160assertEval(classSource);161String isRuntimeVisible = policy == RetentionPolicy.RUNTIME ? "true" : "false";162assertEval("C.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible);163assertEval("C.class.getDeclaredConstructor().getAnnotationsByType(A.class).length > 0;", isRuntimeVisible);164assertEval("C.class.getDeclaredMethod(\"f\").getAnnotationsByType(A.class).length > 0;", isRuntimeVisible);165assertEval("C.class.getDeclaredField(\"f\").getAnnotationsByType(A.class).length > 0;", isRuntimeVisible);166assertEval("C.Inner.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible);167}168169@DataProvider(name = "retentionPolicyTestCase")170public Object[][] retentionPolicyTestCaseGenerator() {171List<Object[]> list = new ArrayList<>();172for (RetentionPolicy policy : RetentionPolicy.values()) {173list.add(new Object[]{policy});174}175return list.toArray(new Object[list.size()][]);176}177178@DataProvider(name = "memberTestCase")179public Object[][] memberTestCaseGenerator() {180List<Object[]> list = new ArrayList<>();181for (AccessModifier accessModifier : AccessModifier.values()) {182for (Static isStaticMember : Static.values()) {183for (Static isStaticReference : Static.values()) {184for (CodeChunk codeChunk : CodeChunk.values()) {185if (codeChunk == CodeChunk.CONSTRUCTOR && isStaticMember == Static.STATIC) {186continue;187}188list.add(new Object[]{ accessModifier, codeChunk, isStaticMember, isStaticReference });189}190}191}192}193return list.toArray(new Object[list.size()][]);194}195196public static class ExtendsMemberTestCase extends MemberTestCase {197198public ExtendsMemberTestCase(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) {199super(accessModifier, codeChunk, isStaticMember, isStaticReference);200}201202@Override203public String getSourceTemplate() {204return super.getSourceTemplate() + "\n"205+ "class B extends A {}";206}207208@Override209public String errorMessage() {210if (!isAccessible()) {211if (codeChunk == CodeChunk.METHOD) {212return "compiler.err.cant.resolve.location.args";213}214if (codeChunk == CodeChunk.CONSTRUCTOR) {215return "compiler.err.cant.resolve.location";216}217}218return super.errorMessage();219}220221@Override222public String useCodeChunk() {223return useCodeChunk("B");224}225}226227public static class MemberTestCase {228public final AccessModifier accessModifier;229public final CodeChunk codeChunk;230public final Static isStaticMember;231public final Static isStaticReference;232public final String expectedMessage;233234public MemberTestCase(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember,235Static isStaticReference) {236this.accessModifier = accessModifier;237this.codeChunk = codeChunk;238this.isStaticMember = isStaticMember;239this.isStaticReference = isStaticReference;240this.expectedMessage = errorMessage();241}242243public String getSourceTemplate() {244return "class A {\n" +245" #MEMBER#\n" +246"}";247}248249public boolean isAccessible() {250return accessModifier != AccessModifier.PRIVATE;251}252253public String errorMessage() {254if (!isAccessible()) {255return "compiler.err.report.access";256}257if (codeChunk == CodeChunk.INNER_INTERFACE) {258return "compiler.err.abstract.cant.be.instantiated";259}260if (isStaticMember == Static.STATIC) {261if (isStaticReference == Static.NO && codeChunk == CodeChunk.INNER_CLASS) {262return "compiler.err.qualified.new.of.static.class";263}264return null;265}266if (isStaticReference == Static.STATIC) {267if (codeChunk == CodeChunk.CONSTRUCTOR) {268return null;269}270if (codeChunk == CodeChunk.INNER_CLASS) {271return "compiler.err.encl.class.required";272}273return "compiler.err.non-static.cant.be.ref";274}275return null;276}277278public String generateSource() {279return getSourceTemplate().replace("#MEMBER#", codeChunk.generateSource(accessModifier, isStaticMember));280}281282protected String useCodeChunk(String className) {283String name = className.toLowerCase();284switch (codeChunk) {285case CONSTRUCTOR:286return String.format("new %s();", className);287case METHOD:288if (isStaticReference == Static.STATIC) {289return String.format("%s.method();", className);290} else {291return String.format("%s.method();", name);292}293case FIELD:294if (isStaticReference == Static.STATIC) {295return String.format("%s.field;", className);296} else {297return String.format("%s.field;", name);298}299case INNER_CLASS:300if (isStaticReference == Static.STATIC) {301return String.format("new %s.Inner();", className);302} else {303return String.format("%s.new Inner();", name);304}305case INNER_INTERFACE:306return String.format("new %s.Inner();", className);307default:308throw new AssertionError("Unknown code chunk: " + this);309}310}311312public String useCodeChunk() {313return useCodeChunk("A");314}315}316317public enum AccessModifier {318PUBLIC("public"),319PROTECTED("protected"),320PACKAGE_PRIVATE(""),321PRIVATE("private");322323private final String modifier;324325AccessModifier(String modifier) {326this.modifier = modifier;327}328329public String getModifier() {330return modifier;331}332}333334public enum Static {335STATIC("static"), NO("");336337private final String modifier;338339Static(String modifier) {340this.modifier = modifier;341}342343public String getModifier() {344return modifier;345}346}347348public enum CodeChunk {349CONSTRUCTOR("#MODIFIER# A() {}"),350METHOD("#MODIFIER# int method() { return 10; }"),351FIELD("#MODIFIER# int field = 10;"),352INNER_CLASS("#MODIFIER# class Inner {}"),353INNER_INTERFACE("#MODIFIER# interface Inner {}");354355private final String code;356357CodeChunk(String code) {358this.code = code;359}360361public String generateSource(AccessModifier accessModifier, Static isStatic) {362return code.replace("#MODIFIER#", accessModifier.getModifier() + " " + isStatic.getModifier());363}364}365}366367368