/*******************************************************************************
 * Copyright (c) 2018, 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import junit.framework.Test;

import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
import org.eclipse.jdt.core.tests.util.Util;
import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;

@SuppressWarnings({ "rawtypes" })
public class JEP181NestTest extends AbstractComparableTest {

	String versionString = null;

public JEP181NestTest(String name) {
	super(name);
}
// No need for a tearDown()
@Override
protected void setUp() throws Exception {
	super.setUp();
	this.versionString = AbstractCompilerTest.getVersionString(this.complianceLevel);
}

/*
 * Toggle compiler in mode -11
 */
// Static initializer to specify tests subset using TESTS_* static variables
// All specified tests which do not belong to the class are skipped...
static {
//	TESTS_NAMES = new String[] { "testBug572190" };
//	TESTS_NUMBERS = new int[] { 50, 51, 52, 53 };
//	TESTS_RANGE = new int[] { 34, 38 };
}
private static final String[] source_classic = JEP181NestTest.getTestSeriesClassic();

public static Test suite() {
	return buildMinimalComplianceTestSuite(testClass(), F_11);
}
private static String[] getTestSeriesClassic() {
	return new String[] {
			"pack1/X.java",
			"package pack1;\n" +
					"public class X {\n" +
					"	public class Y {\n" +
					"		class Z {}\n" +
					"	}\n" +
					"	public static class A {\n" +
					"		public static class B {}\n" +
					"		public class C {}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		System.out.println(\"SUCCESS\");\n" +
					"	}\n" +
					"	public void foo() {\n" +
					"		System.out.println(\"foo\");\n" +
					"	}\n" +
					"}\n",
	};
}
private void verifyClassFile(String expectedOutput, String classFileName, int mode, boolean positive) throws IOException, ClassFormatException {
	String result = getClassFileContents(classFileName, mode);
	verifyOutput(result, expectedOutput, positive);
}
private String getClassFileContents( String classFileName, int mode) throws IOException,
ClassFormatException {
	File f = new File(OUTPUT_DIR + File.separator + classFileName);
	byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
	ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
	String result = disassembler.disassemble(classFileBytes, "\n", mode);
	return result;
}
private void verifyOutputPositive(String result, String expectedOutput) {
	verifyOutput(result, expectedOutput, true);
}
private void verifyOutputNegative(String result, String expectedOutput) {
	verifyOutput(result, expectedOutput, false);
}
private void verifyOutput(String result, String expectedOutput, boolean positive) {
	int index = result.indexOf(expectedOutput);
	if (positive) {
		if (index == -1 || expectedOutput.length() == 0) {
			System.out.println(Util.displayString(result, 3));
			System.out.println("...");
		}
		if (index == -1) {
			assertEquals("Wrong contents", expectedOutput, result);
		}
	} else {
		if (index != -1) {
			assertEquals("Unexpected contents", "", result);
		}
	}
}
private void verifyClassFile(String expectedOutput, String classFileName, int mode) throws IOException,
	ClassFormatException {
	verifyClassFile(expectedOutput, classFileName, mode, true);
}
private void verifyNegativeClassFile(String unExpectedOutput, String classFileName, int mode) throws IOException,
ClassFormatException {
	verifyClassFile(unExpectedOutput, classFileName, mode, false);
}
public void testBug535851_001() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);

	this.runConformTest(
			JEP181NestTest.source_classic,
			"SUCCESS",
			options
	);

	String expectedPartialOutput =
			"Nest Members:\n" +
			"   #37 pack1/X$A,\n" +
			"   #44 pack1/X$A$B,\n" +
			"   #46 pack1/X$A$C,\n" +
			"   #40 pack1/X$Y,\n" +
			"   #48 pack1/X$Y$Z\n";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
}
public void testBug535851_002() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);

	this.runConformTest(
		JEP181NestTest.source_classic,
		"SUCCESS",
		options
	);

	String expectedPartialOutput =
		"Nest Host: #17 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$A.class", ClassFileBytesDisassembler.SYSTEM);
}
public void testBug535851_003() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);

	this.runConformTest(
		JEP181NestTest.source_classic,
		"SUCCESS",
		options
	);

	String unExpectedPartialOutput =
		"NestMembers:";
	verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X$A.class", ClassFileBytesDisassembler.SYSTEM);
}
public void testBug535851_004() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);

	this.runConformTest(
			JEP181NestTest.source_classic,
			"SUCCESS",
			options
	);

	String expectedPartialOutput =
		"Nest Host: #24 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$Y$Z.class", ClassFileBytesDisassembler.SYSTEM);
}
// vanilla anonymous declaration
public void testBug535851_005() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	String[] files = new String[] {
			"pack1/X.java",
			"package pack1;\n" +
			"public class X {\n" +
			"	public static void main(String[] args) {\n" +
			"		System.out.println(\"SUCCESS\");\n" +
			"	}\n" +
			"	public void foo() {\n" +
			"		Y y = new Y() {\n" +
			"		    void bar() {}\n" +
			"		};\n" +
			"       System.out.println(y.toString());\n" +
			"	}\n" +
			"}\n" +
			"abstract class Y {\n" +
			"	abstract void bar();\n" +
			"}\n",
	};
	this.runConformTest(
			files,
			"SUCCESS",
			options
	);

	String expectedPartialOutput =
		"Nest Members:\n" +
		"   #33 pack1/X$1\n";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);

	expectedPartialOutput = "Nest Host: #23 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$1.class", ClassFileBytesDisassembler.SYSTEM);
	verifyNegativeClassFile(expectedPartialOutput, "pack1/Y.class", ClassFileBytesDisassembler.SYSTEM);
}
// anonymous declaration inside another anonymous declaration
public void testBug535851_006() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	String[] files = new String[] {
			"pack1/X.java",
			"package pack1;\n" +
			"public class X {\n" +
			"	public static void main(String[] args) {\n" +
			"		System.out.println(\"SUCCESS\");\n" +
			"	}\n" +
			"	public void foo() {\n" +
			"		Y y = new Y() {\n" +
			"		    void bar() {\n" +
			"		        Y y1 = new Y() {\n" +
			"		           void bar() {}\n" +
			"		        };\n" +
			"               System.out.println(y1.toString());\n" +
			"	        }\n" +
			"		};\n" +
			"       System.out.println(y.toString());\n" +
			"	}\n" +
			"}\n" +
			"abstract class Y {\n" +
			"	abstract void bar();\n" +
			"}\n",
	};
	this.runConformTest(
			files,
			"SUCCESS",
			options
	);

	String expectedPartialOutput =
			"Nest Members:\n" +
			"   #33 pack1/X$1,\n" +
			"   #48 pack1/X$1$1\n";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);

	expectedPartialOutput = "Nest Host: #48 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$1.class", ClassFileBytesDisassembler.SYSTEM);
	expectedPartialOutput = "Nest Host: #28 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$1$1.class", ClassFileBytesDisassembler.SYSTEM);
	verifyNegativeClassFile(expectedPartialOutput, "pack1/Y.class", ClassFileBytesDisassembler.SYSTEM);
}

// lambda with anonymous inside anonymous
public void testBug535851_007() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	String[] files = new String[] {
			"pack1/X.java",
			"package pack1;\n" +
			"\n" +
			"public class X {\n" +
			"	public static void main(String[] args) {\n" +
			"		System.out.println(\"SUCCESS\");\n" +
			"	}\n" +
			"	public void foo() {\n" +
			"		I i = ()->{\n" +
			"			Y y = new Y() {	\n" +
			"				@Override\n" +
			"				void bar() {\n" +
			"					Y y1 = new Y() {\n" +
			"						@Override\n" +
			"						void bar() {}\n" +
			"					};\n" +
			"					System.out.println(y1);\n" +
			"				}\n" +
			"			};\n" +
			"			System.out.println(y.toString());\n" +
			"		};\n" +
			"		i.apply();\n" +
			"	}\n" +
			"}\n" +
			"interface I {\n" +
			"	void apply();\n" +
			"}\n" +
			"abstract class Y {\n" +
			"	abstract void bar();\n" +
			"}\n",
	};
	this.runConformTest(
			files,
			"SUCCESS",
			options
	);

	String expectedPartialOutput =
			"Nest Members:\n" +
			"   #44 pack1/X$1,\n" +
			"   #77 pack1/X$1$1\n";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);

	expectedPartialOutput = "Nest Host: #42 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$1.class", ClassFileBytesDisassembler.SYSTEM);
	expectedPartialOutput = "Nest Host: #28 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$1$1.class", ClassFileBytesDisassembler.SYSTEM);
	verifyNegativeClassFile(expectedPartialOutput, "pack1/Y.class", ClassFileBytesDisassembler.SYSTEM);
}
// type declaration in method
public void testBug535851_008() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	String[] files = new String[] {
			"pack1/X.java",
			"package pack1;\n" +
			"\n" +
			"public class X {\n"+
			"   public void foo() {\n"+
			"       class Y {\n"+
			"           // nothing\n"+
			"       }\n"+
			"       Y y = new Y();\n"+
			"       System.out.println(\"SUCCESS\");\n"+
			"   }\n"+
			"   public static void main(String[] args) {\n"+
			"       new X().foo();\n"+
			"   }\n"+
			"}\n",
	};
	this.runConformTest(
			files,
			"SUCCESS",
			options
	);

	String expectedPartialOutput =
			"Nest Members:\n" +
			"   #15 pack1/X$1Y\n";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);

	expectedPartialOutput = "Nest Host: #22 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$1Y.class", ClassFileBytesDisassembler.SYSTEM);
}
// testing the inner private instance field access from enclosing type
public void testBug535918_001a() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_int = 100;\n" +
					"		public int pub_int = 200;\n" +
					"		\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = foo();\n" +
					"		System.out.println(\"SUCCESS:\" + sum);\n" +
					"	}\n" +
					"	public static int foo() {\n" +
					"		Y y = new Y();\n" +
					"		int i = y.priv_int;\n" +
					"		int j = y.pub_int;\n" +
					"		return i + j;\n" +
					"	}\n" +
					"	public void bar() {\n" +
					"		System.out.println(\"bar\");\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:300",
			options
	);

	String expectedPartialOutput =
		"getfield pack1.X$Y.priv_in";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String unExpectedPartialOutput =
			"access$";
		verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
}
//testing the inner private static field access from enclosing type
public void testBug535918_001b() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private static int priv_int = 100;\n" +
					"		public int pub_int = 200;\n" +
					"		\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = foo();\n" +
					"		System.out.println(\"SUCCESS:\" + sum);\n" +
					"	}\n" +
					"	public static int foo() {\n" +
					"		Y y = new Y();\n" +
					"		int i = y.priv_int;\n" +
					"		int j = y.pub_int;\n" +
					"		return i + j;\n" +
					"	}\n" +
					"	public void bar() {\n" +
					"		System.out.println(\"bar\");\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:300",
			options
	);

	String expectedPartialOutput = "getstatic pack1.X$Y.priv_int";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	expectedPartialOutput = "Nest Members:\n" +
			"   #50 pack1/X$Y\n";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	expectedPartialOutput = "Nest Host: #25 pack1/X\n";
	verifyClassFile(expectedPartialOutput, "pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String unExpectedPartialOutput = "invokestatic pack1.X$Y.access$";
	verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	unExpectedPartialOutput = "access$";
	verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
}
//testing the nested private field access from enclosing type
public void testBug535918_001c() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_int = 100;\n" +
					"		public int pub_int = 200;\n" +
					"		\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = foo();\n" +
					"		System.out.println(\"SUCCESS:\" + sum);\n" +
					"	}\n" +
					"	public static int foo() {\n" +
					"		Y y = new Y();\n" +
					"		int i = y.priv_int;\n" +
					"		int j = y.pub_int;\n" +
					"		return i + j;\n" +
					"	}\n" +
					"	public void bar() {\n" +
					"		System.out.println(\"bar\");\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:300",
			options
	);

	String unExpectedPartialOutput =
			"access$";
		verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
}
//testing the nested private method access from same type (implicit nesting/nest host)
public void testBug535918_002() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	private int priv_non_static_method() {\n" +
					"		return 100;\n" +
					"	}\n" +
					"	public int pub_non_static_method() {\n" +
					"		return priv_non_static_method();\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		X x = new X();\n" +
					"		int result =x.pub_non_static_method();\n" +
					"		System.out.println(result);\n" +
					"	}\n" +
					"}\n",
			},
			"100",
			options
	);

	String expectedPartialOutput =
		"invokevirtual pack1.X.priv_non_static_method()";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
}

// sibling access: private static field
public void testBug535918_003a() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private static int priv_int = 100;\n" +
					"	}\n" +
					"	public static class Z {\n" +
					"		public static int foo() {\n" +
					"			int i = Y.priv_int;\n" +
					"			return i;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = Z.foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #55 pack1/X$Y,\n" +
			"   #17 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #22 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #26 pack1/X");
	verifyOutputPositive(XZFile, "getstatic pack1.X$Y.priv_int");

	verifyOutputNegative(XYFile, "access$");
	verifyOutputNegative(XZFile, "invokestatic pack1.X$Y.access$0");
}
//sibling access: private instance field
public void testBug535918_003b() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_int = 100;\n" +
					"	}\n" +
					"	public static class Z {\n" +
					"		public static int foo() {\n" +
					"			Y y = new Y();\n" +
					"			int i = y.priv_int;\n" +
					"			return i;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = Z.foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #55 pack1/X$Y,\n" +
			"   #17 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #21 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #29 pack1/X");
	verifyOutputPositive(XZFile, "getfield pack1.X$Y.priv_int");

	verifyOutputNegative(XYFile, "access$");
	verifyOutputNegative(XZFile, "invokestatic pack1.X$Y.access$0");
}
//sibling access: private instance field via Allocation Expression Field reference
// note: internally this follows a different code path
public void testBug535918_003c() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_int = 100;\n" +
					"	}\n" +
					"	public static class Z {\n" +
					"		public static int foo() {\n" +
					"			int i = new Y().priv_int;\n" +
					"			return i;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = Z.foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #55 pack1/X$Y,\n" +
			"   #17 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #21 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #27 pack1/X");
	verifyOutputPositive(XZFile, "getfield pack1.X$Y.priv_int");

	verifyOutputNegative(XYFile, "access$");
	verifyOutputNegative(XZFile, "invokestatic pack1.X$Y.access$0");
}
//sibling and super: private static field access of a super-type is accessed from a sub-type with
//both super-type and sub-type being nestmates.
public void testBug535918_003d() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private static int priv_int = 100;\n" +
					"	}\n" +
					"	public static class Z extends Y {\n" +
					"		public static int foo() {\n" +
					"			int i = Y.priv_int;\n" +
					"			return i;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = Z.foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #55 pack1/X$Y,\n" +
			"   #17 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #22 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #24 pack1/X");
	verifyOutputPositive(XZFile, "getstatic pack1.X$Y.priv_int");

	verifyOutputNegative(XYFile, "access$");
	verifyOutputNegative(XZFile, "invokestatic pack1.X$Y.access$0");
}
//sibling and super: private instance field of a super-type is accessed from a sub-type with
//both super-type and sub-type being nestmates.
public void testBug535918_003e() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y{\n" +
					"		private int priv_int = 100;\n" +
					"	}\n" +
					"	public static class Z extends Y {\n" +
					"		public static int foo() {\n" +
					"			Y y = new Y();\n" +
					"			int i = y.priv_int;\n" +
					"			return i;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = Z.foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #55 pack1/X$Y,\n" +
			"   #17 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #21 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #26 pack1/X");
	verifyOutputPositive(XZFile, "getfield pack1.X$Y.priv_int");

	verifyOutputNegative(XYFile, "access$");
	verifyOutputNegative(XZFile, "invokestatic pack1.X$Y.access$0");
}
//sibling and super with super keyword: private instance field of a super-type is accessed from a sub-type
// user keyword super with both super-type and sub-type being nestmates.
public void testBug535918_003f() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y{\n" +
					"		private int priv_int = 100;\n" +
					"	}\n" +
					"	public static class Z extends Y {\n" +
					"		public int foo() {\n" +
					"			int i = super.priv_int;\n" +
					"			return i;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = new Z().foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #56 pack1/X$Y,\n" +
			"   #16 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #21 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #24 pack1/X");
	verifyOutputPositive(XZFile, "getfield pack1.X$Y.priv_int");

	verifyOutputNegative(XYFile, "access$");
	verifyOutputNegative(XZFile, "invokestatic pack1.X$Y.access$0");
}
//vanilla field access of enclosing type: private static field of enclosing type accessed in inner type
public void testBug535918_004a() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	private static int priv_int = 100;\n" +
					"	public static class Y {\n" +
					"		public static int foo() {\n" +
					"			return priv_int;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = Y.foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #22 pack1/X$Y\n";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #17 pack1/X");
	verifyOutputPositive(XYFile, "getstatic pack1.X.priv_int");

	verifyOutputNegative(XFile, "access$");
	verifyOutputNegative(XFile, "invokestatic pack1.X.access$0()");

}
//vanilla field access of enclosing type: private instance field of enclosing type accessed in inner type
public void testBug535918_004b() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	private int priv_int = 100;\n" +
					"	public class Y {\n" +
					"		public int foo() {\n" +
					"			return priv_int;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = new X().new Y().foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:100",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #20 pack1/X$Y\n";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #22 pack1/X");
	verifyOutputPositive(XYFile, "getfield pack1.X.priv_int");

	verifyOutputNegative(XFile, "access$");
	verifyOutputNegative(XYFile, "invokestatic pack1.X.access$0()");

}
//nestmate inner constructor call from outer - no synthetic and appropriate call site params
public void testBug535918_005a() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	class Y {\n" +
					"		class Z {\n" +
					"			private Z() {\n" +
					"			}\n" +
					"		}\n" +
					"		Z d;\n" +
					"		private Y() {\n" +
					"			this.d = new Z();\n" +
					"		}\n" +
					"	}\n" +
					"	@Override\n" +
					"	public String toString() {\n" +
					"		return \"SUCCESS\";\n" +
					"	}\n" +
					"  public static void main(String[] argv) {\n" +
					"    System.out.println(new X());\n" +
					"  }\n" +
					"}\n",
			},
			"SUCCESS",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XYZFile = getClassFileContents("pack1/X$Y$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #38 pack1/X$Y,\n" +
			"   #42 pack1/X$Y$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #31 pack1/X");
	verifyOutputPositive(XYZFile, "Nest Host: #24 pack1/X");
	verifyOutputPositive(XYFile, "invokespecial pack1.X$Y$Z(pack1.X$Y)"); //only one param

	verifyOutputNegative(XYZFile, "synthetic X$Y$Z");
	verifyOutputNegative(XYFile, "invokespecial pack1.X$Y$Z(pack1.X$Y, pack1.X$Y$Z)");
}
//nestmate sibling constructor call - no synthetic and appropriate call site params
public void testBug535918_005b() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	class Z {\n" +
					"		private Z() {\n" +
					"		}\n" +
					"	}\n" +
					"	class Y {\n" +
					"		Z d;\n" +
					"		private Y() {\n" +
					"			this.d = new Z();\n" +
					"		}\n" +
					"	}\n" +
					"	@Override\n" +
					"	public String toString() {\n" +
					"		return \"SUCCESS\";\n" +
					"	}\n" +
					"  public static void main(String[] argv) {\n" +
					"    System.out.println(new X());\n" +
					"  }\n" +
					"}\n",
			},
			"SUCCESS",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #38 pack1/X$Y,\n" +
			"   #41 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #30 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #22 pack1/X");
	verifyOutputPositive(XYFile, "invokespecial pack1.X$Z(pack1.X)"); //only one param

	verifyOutputNegative(XZFile, "synthetic X$Z");
	verifyOutputNegative(XYFile, "invokespecial pack1.X$Z(pack1.X$Y, pack1.X$Z)");
}
//nestmate outer constructor call from inner - no synthetic and appropriate call site params
public void testBug535918_005c() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	class Y {\n" +
					"		private Y() {\n" +
					"		}\n" +
					"		class Z {\n" +
					"			Y y;\n" +
					"			private Z() {\n" +
					"				this.y = new Y();\n" +
					"			}\n" +
					"		}\n" +
					"	}\n" +
					"	@Override\n" +
					"	public String toString() {\n" +
					"		return \"SUCCESS\";\n" +
					"	}\n" +
					"  public static void main(String[] argv) {\n" +
					"    System.out.println(new X());\n" +
					"  }\n" +
					"}\n",
			},
			"SUCCESS",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XYZFile = getClassFileContents("pack1/X$Y$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #38 pack1/X$Y,\n" +
			"   #42 pack1/X$Y$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #24 pack1/X");
	verifyOutputPositive(XYZFile, "Nest Host: #34 pack1/X");
	verifyOutputPositive(XYZFile, "invokespecial pack1.X$Y(pack1.X)"); //only one param

	verifyOutputNegative(XYFile, "synthetic X$Y");
	verifyOutputNegative(XYZFile, "invokespecial pack1.X$Y(pack1.X, pack1.X$Y)");
}
//nestmate super call to private constructor from sibling nestmate which is a subtype - no synthetic and appropriate call site params
public void testBug535918_005d() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	  private class Y {\n" +
					"	    private Y() {\n" +
					"	      super();\n" +
					"	    }\n" +
					"	  }\n" +
					"	  private class Z extends Y {\n" +
					"	    private Z() {\n" +
					"	      super();\n" +
					"	    }\n" +
					"	  }\n" +
					"  public static void main(String[] argv) {\n" +
					"		  System.out.println(\"SUCCESS\");\n" +
					"	  }\n" +
					"}\n",
			},
			"SUCCESS",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #35 pack1/X$Y,\n" +
			"   #38 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #22 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #21 pack1/X");
	verifyOutputPositive(XZFile, "invokespecial pack1.X$Y(pack1.X)"); //only one param

	verifyOutputNegative(XYFile, "synthetic X$Y");
	verifyOutputNegative(XZFile, "invokespecial pack1.X$Y(pack1.X, pack1.X$Y)");
}
// nestmate super call to private constructor from sibling nestmate which is a subtype
// super is a parameterized type
public void testBug535918_005e() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"  private static class Y<T> implements AutoCloseable {\n" +
					"    private Y() {\n" +
					"      super();\n" +
					"    }\n" +
					"    public void close() {\n" +
					"    }\n" +
					"  }\n" +
					"  @SuppressWarnings(\"unused\")\n" +
					"private static class Z extends Y<Object> {\n" +
					"    private Z() {\n" +
					"      super();\n" +
					"    }\n" +
					"  }\n" +
					"  public static void main(String[] args) {\n" +
					"	  System.out.println(\"SUCCESS\");\n" +
					"  }\n" +
					"}\n",
			},
			"SUCCESS",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XZFile = getClassFileContents("pack1/X$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #35 pack1/X$Y,\n" +
			"   #38 pack1/X$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #24 pack1/X");
	verifyOutputPositive(XZFile, "Nest Host: #19 pack1/X");
	verifyOutputPositive(XZFile, "invokespecial pack1.X$Y()"); //only one param

	verifyOutputNegative(XYFile, "synthetic pack1.X$Y(pack1.X.Y arg0)");
	verifyOutputNegative(XZFile, "2  invokespecial pack1.X$Y(pack1.X$Y)");
}
//nestmate constructor reference
public void testBug535918_005f() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"X.java",
					"interface I {\n" +
					"  X makeX(int x);\n" +
					"}\n" +
					"public class X {\n" +
					"  void foo() {\n" +
					"    class Y {\n" +
					"    	void f() {\n" +
					"    		I i = X::new;\n" +
					"    		i.makeX(123456);\n" +
					"    	}\n" +
					"    }\n" +
					"    new Y().f();\n" +
					"  }\n" +
					"  private X(int x) {\n" +
					"    super();\n" +
					"    System.out.println(\"SUCCESS\");\n" +
					"  }\n" +
					"  X() {\n" +
					"    super();\n" +
					"  }\n" +
					"  public static void main(String[] args) {\n" +
					"    new X().foo();\n" +
					"  }\n" +
					"}\n",
			},
			"SUCCESS",
			options
	);

	String XFile = getClassFileContents("X.class", ClassFileBytesDisassembler.SYSTEM);
	String X1YFile = getClassFileContents("X$1Y.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #8 X$1Y\n";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(X1YFile, "Nest Host: #33 X");

	verifyOutputNegative(X1YFile, "synthetic X$Y(pack1.X.Y arg0)");
}
//testing the nested private method access from enclosing type
public void testBug535918_005g() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_instance_method() {\n" +
					"			return 100;\n" +
					"		}\n" +
					"		public int pub_instance_method() {\n" +
					"			int pri = priv_instance_method();\n" +
					"			return 200 + pri;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"	public static int foo() {\n" +
					"		Y y = new Y();\n" +
					"		int i = y.priv_instance_method();\n" +
					"		int j = y.pub_instance_method();\n" +
					"		return i + j;\n" +
					"	}\n" +
					"	public void bar() {\n" +
					"		System.out.println(\"bar\");\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:400",
			options
	);

	String expectedPartialOutput =
		"invokevirtual pack1.X$Y.priv_instance_method()";
	verifyClassFile(expectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
}
//negative testing the nested private method access from enclosing type is not via invokespecial
public void testBug535918_005h() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_instance_method() {\n" +
					"			return 100;\n" +
					"		}\n" +
					"		public int pub_instance_method() {\n" +
					"			int pri = priv_instance_method();\n" +
					"			return 200 + pri;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"	public static int foo() {\n" +
					"		Y y = new Y();\n" +
					"		int i = y.priv_instance_method();\n" +
					"		int j = y.pub_instance_method();\n" +
					"		return i + j;\n" +
					"	}\n" +
					"	public void bar() {\n" +
					"		System.out.println(\"bar\");\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:400",
			options
	);

	String unExpectedPartialOutput =
		"invokespecial pack1.X$Y.priv_instance_method()";
	verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
}
//negative testing the synthetic method - access - not present in nested class
public void testBug535918_005i() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"public class X {\n" +
					"	public static class Y {\n" +
					"		private int priv_instance_method() {\n" +
					"			return 100;\n" +
					"		}\n" +
					"		public int pub_instance_method() {\n" +
					"			int pri = priv_instance_method();\n" +
					"			return 200 + pri;\n" +
					"		}\n" +
					"	}\n" +
					"	public static void main(String[] args) {\n" +
					"		int sum = foo();\n" +
					"		System.out.println(\"SUCCESS:\"+sum);\n" +
					"	}\n" +
					"	public static int foo() {\n" +
					"		Y y = new Y();\n" +
					"		int i = y.priv_instance_method();\n" +
					"		int j = y.pub_instance_method();\n" +
					"		return i + j;\n" +
					"	}\n" +
					"	public void bar() {\n" +
					"		System.out.println(\"bar\");\n" +
					"	}\n" +
					"}\n",
			},
			"SUCCESS:400",
			options
	);

	String unExpectedPartialOutput =
			"access$";
		verifyNegativeClassFile(unExpectedPartialOutput, "pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
}
//private interface method invoked from a method inside the same interface should be invokeinterface
public void testBug535918_005j() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"interface I {\n" +
					"	private void foo() {}\n" +
					"	public default void apply() {\n" +
					"		foo();\n" +
					"	}\n" +
					"}\n" +
					"public class X {\n" +
					"	public static void main(String[] args) {\n" +
					"	}\n" +
					"}\n",
			},
			"",
			options
	);

	String IFile = getClassFileContents("pack1/I.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "invokeinterface pack1.I.foo";
	verifyOutputPositive(IFile, partialOutput);
}
//private interface method invoked from a nestmate interface should be invokeinterface
public void testBug535918_005k() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n" +
					"interface I {" +
					"	private void foo() {}" +
					"	" +
					"	interface J {" +
					"		public default void apply() {" +
					"			I i = new X();" +
					"			i.foo();" +
					"		}	" +
					"	}" +
					"}" +
					"public class X implements I{\n" +
					"}\n",
			},
			"",
			options
	);

	String IFile = getClassFileContents("pack1/I$J.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "invokeinterface pack1.I.foo";
	verifyOutputPositive(IFile, partialOutput);
}
//test for SyntheticMethodBinding.SuperField*Access
public void testBug535918_0056a() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n"+
					"public class X {\n"+
					"	private int priv_int;\n"+
					"\n"+
					"	class Y extends X {\n"+
					"		class Z extends Y {\n"+
					"			public void foo() {\n"+
					"				X.Y.super.priv_int = 0;\n"+
					"			}\n"+
					"		}\n"+
					"	}\n"+
					"\n"+
					"	public static void main(String[] args) {\n"+
					"		new X().new Y().new Z().foo();\n"+
					"	}\n"+
					"}\n",
			},
			"",
			options
	);

	String XFile = getClassFileContents("pack1/X.class", ClassFileBytesDisassembler.SYSTEM);
	String XYFile = getClassFileContents("pack1/X$Y.class", ClassFileBytesDisassembler.SYSTEM);
	String XYZFile = getClassFileContents("pack1/X$Y$Z.class", ClassFileBytesDisassembler.SYSTEM);
	String partialOutput = "Nest Members:\n" +
			"   #20 pack1/X$Y,\n" +
			"   #18 pack1/X$Y$Z";
	verifyOutputPositive(XFile, partialOutput);
	verifyOutputPositive(XYFile, "Nest Host: #3 pack1/X");
	verifyOutputPositive(XYZFile, "Nest Host: #22 pack1/X");
	verifyOutputPositive(XYZFile, "putfield pack1.X.priv_int"); //direct access

	verifyOutputNegative(XYFile, "synthetic X$Y");
	verifyOutputNegative(XYZFile, "invokestatic X.access$0(X, int)");
}

public void testBug545387_01() throws Exception {
	Map<String, String> options = getCompilerOptions();
	options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
	options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);

	this.runConformTest(
			new String[] {
					"pack1/X.java",
					"package pack1;\n"+
					"public class X {\n"+
					"	public class Inner1 {\n"+
					"		private void foo() {\n"+
					"			System.out.println(\"hello\");;\n"+
					"		}\n"+
					"	}\n"+
					"	public class Sub1 extends Inner1 {\n"+
					"		public class Sub2 {\n"+
					"			void testFoo() {\n"+
					"				Sub1.super.foo();\n"+
					"			}\n"+
					"		}\n"+
					"		void testFoo() {\n"+
					"			(new Sub2()).testFoo();\n"+
					"		}\n"+
					"	}\n"+
					"	public static void main(String[] args) {\n"+
					"		Sub1 s1 = getS1();\n"+
					"		s1.testFoo();\n"+
					"	}\n"+
					"	public static Sub1 getS1() {\n"+
					"		return new X().new Sub1();\n"+
					"	}\n"+
					"}\n",
			},
			"hello",
			options
	);

	String XSub1Sub2 = getClassFileContents("pack1/X$Sub1$Sub2.class", ClassFileBytesDisassembler.SYSTEM);
	verifyOutputPositive(XSub1Sub2, "Nest Host: #29 pack1/X");
}

public void testBug572190_01() throws Exception {

	this.runConformTest(
			new String[] {
				"X.java",
				"public class X {\n"+
				"       public void foo() {\n"+
				"               new Thread(() -> {\n"+
				"                       new Object() {\n"+
				"                       };\n"+
				"               });\n"+
				"       }\n"+
				"       public static void main(String[] args) {\n"+
				"               System.out.println(0);\n"+
				"       }\n"+
				"}",
			},
			"0"
	);

	String XFile = getClassFileContents("X.class", ClassFileBytesDisassembler.SYSTEM);
	String expected = "Nest Members:\n" +
			"   #41 X$1\n" +
			"Bootstrap methods:\n" ;
	String unexpectedOutput = "Nest Members:\n" +
			 "   #41 X$1,\n" +
			 "   #68 X$2\n" +
			 "Bootstrap methods:\n";
	verifyOutputPositive(XFile, expected);

	verifyOutputNegative(XFile, unexpectedOutput);
}

public void testBug572190_02() throws Exception {

	this.runConformTest(
			new String[] {
				"pack1/X.java",
				"package pack1;\n"+
				"\n"+
				"import pack1.XB.EF;\n"+
				"\n"+
				"public class X {\n"+
				"       private static int foo() {\n"+
				"               return  EF.values().length;\n"+
				"       }\n"+
				"    public static void main(String argv[])   {\n"+
				"       System.out.println(X.foo());\n"+
				"    }\n"+
				"    public enum ch { }\n"+
				"}\n",
				"pack1/XA.java",
				"package pack1;\n"+
				"public class XA {\n"+
				"    public enum EC {}\n"+
				"}",
				"pack1/XB.java",
				"package pack1;\n"+
				"public class XB {\n"+
				"    protected enum EF {}\n"+
				"}",
			},
			"0"
	);

	String XFile = getClassFileContents("pack1/XB.class", ClassFileBytesDisassembler.SYSTEM);
	String expected = "Nest Members:\n" +
			"   #17 pack1/XB$EF\n" +
			"}";
	verifyOutputPositive(XFile, expected);

}

public static Class testClass() {
	return JEP181NestTest.class;
}
}
