1 /*******************************************************************************
2  * Copyright (c) 2012, 2014 IBM Corporation GK Software AG and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     Stephan Herrmann - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.core.tests.compiler.regression;
15 
16 import java.io.File;
17 import java.io.PrintWriter;
18 import java.util.Map;
19 
20 import junit.framework.Test;
21 
22 import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable;
23 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
24 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
25 
26 @SuppressWarnings({ "unchecked", "rawtypes" })
27 public class ConcurrentBatchCompilerTest extends BatchCompilerTest {
28 
suite()29 	public static Test suite() {
30 		return buildUniqueComplianceTestSuite(testClass(), ClassFileConstants.JDK1_6);
31 	}
testClass()32 	public static Class testClass() {
33 		return ConcurrentBatchCompilerTest.class;
34 	}
ConcurrentBatchCompilerTest(String name)35 	public ConcurrentBatchCompilerTest(String name) {
36 		super(name);
37 	}
38 
39 	Thread runner1;
40 	Thread runner2;
41 
42 	static int COUNT = 100;
43 
44 	/* Invoke the compiler COUNT times to increase bug probabililty. */
45 	@Override
invokeCompiler(PrintWriter out, PrintWriter err, Object extraArguments, TestCompilationProgress compilationProgress)46 	protected boolean invokeCompiler(PrintWriter out, PrintWriter err, Object extraArguments, TestCompilationProgress compilationProgress) {
47 		boolean success = true;
48 		for (int j=0; j<COUNT; j++) {
49 			success &= super.invokeCompiler(out, err, extraArguments, compilationProgress);
50 		}
51 		return success;
52 	}
53 
54 	/* Disambiguate file names for concurrent tests in the same directory. */
55 	@Override
testName()56 	protected String testName() {
57 		Thread current = Thread.currentThread();
58 		String baseName = super.testName();
59 		if (current == this.runner1)
60 			return baseName+"-Thread1";
61 		if (current == this.runner2)
62 			return baseName+"-Thread2";
63 		return baseName;
64 	}
65 
testBug372319()66 	public void testBug372319() throws Throwable {
67 		try {
68 			FakedTrackingVariable.TEST_372319 = true;
69 
70 			// expected error output for runner2 times COUNT:
71 			final StringBuffer errorOutput = new StringBuffer();
72 			for (int j=0; j<COUNT; j++)
73 				errorOutput.append("----------\n" +
74 						"1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/test01/X.java (at line 12)\n" +
75 						"	FileReader reader = getReader(\"somefile\");\n" +
76 						"	           ^^^^^^\n" +
77 						"Potential resource leak: \'reader\' may not be closed\n" +
78 						"----------\n" +
79 						"1 problem (1 error)\n");
80 
81 			// collect exceptions indicating a failure:
82 			final Throwable[] thrown = new Throwable[2];
83 
84 			this.runner1 = new Thread(new Runnable() {
85 					@Override
86 					public void run() {
87 						try {
88 							runConformTest(new String[] {
89 								"org/eclipse/jdt/internal/launching/CompositeId.java",
90 								"/*******************************************************************************\n" +
91 								" * Copyright (c) 2000, 2014 IBM Corporation and others.\n" +
92 								" * All rights reserved. This program and the accompanying materials\n" +
93 								" * are made available under the terms of the Eclipse Public License v1.0\n" +
94 								" * which accompanies this distribution, and is available at\n" +
95 								" * http://www.eclipse.org/legal/epl-v10.html\n" +
96 								" * \n" +
97 								" * Contributors:\n" +
98 								" *     IBM Corporation - initial API and implementation\n" +
99 								" *******************************************************************************/\n" +
100 								"package org.eclipse.jdt.internal.launching;\n" +
101 								"\n" +
102 								"import java.util.ArrayList;\n" +
103 								"\n" +
104 								"/**\n" +
105 								" * Utility class for id's made of multiple Strings\n" +
106 								" */\n" +
107 								"public class CompositeId {\n" +
108 								"	private String[] fParts;\n" +
109 								"	\n" +
110 								"	public CompositeId(String[] parts) {\n" +
111 								"		fParts= parts;\n" +
112 								"	}\n" +
113 								"	\n" +
114 								"	public static CompositeId fromString(String idString) {\n" +
115 								"		ArrayList<String> parts= new ArrayList<String>();\n" +
116 								"		int commaIndex= idString.indexOf(',');\n" +
117 								"		while (commaIndex > 0) {\n" +
118 								"			int length= Integer.valueOf(idString.substring(0, commaIndex)).intValue();\n" +
119 								"			String part= idString.substring(commaIndex+1, commaIndex+1+length);\n" +
120 								"			parts.add(part);\n" +
121 								"			idString= idString.substring(commaIndex+1+length);\n" +
122 								"			commaIndex= idString.indexOf(',');\n" +
123 								"		}\n" +
124 								"		String[] result= parts.toArray(new String[parts.size()]);\n" +
125 								"		return new CompositeId(result);\n" +
126 								"	}\n" +
127 								"	\n" +
128 								"	@Override\n" +
129 								"	public String toString() {\n" +
130 								"		StringBuffer buf= new StringBuffer();\n" +
131 								"		for (int i= 0; i < fParts.length; i++) {\n" +
132 								"			buf.append(fParts[i].length());\n" +
133 								"			buf.append(',');\n" +
134 								"			buf.append(fParts[i]);\n" +
135 								"		}\n" +
136 								"		return buf.toString();\n" +
137 								"	}\n" +
138 								"	\n" +
139 								"	public String get(int index) {\n" +
140 								"		return fParts[index];\n" +
141 								"	}\n" +
142 								"	\n" +
143 								"	public int getPartCount() {\n" +
144 								"		return fParts.length;\n" +
145 								"	}\n" +
146 								"}\n" +
147 								""
148 							},
149 					        "\"" + OUTPUT_DIR +  File.separator + "org/eclipse/jdt/internal/launching/CompositeId.java\""
150 				            + " -1.5 -g -preserveAllLocals"
151 				            + " -proceedOnError -d \"" + OUTPUT_DIR + "\"",
152 							"",
153 							"",
154 							false);
155 						} catch (Throwable t) {
156 							thrown[0] = t;
157 						}
158 					}
159 			});
160 			this.runner2 = new Thread(new Runnable() {
161 				@Override
162 				public void run() {
163 					try {
164 						// from ResourceLeakTests.test056e():
165 						Map options = getCompilerOptions();
166 						options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
167 						options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
168 						runNegativeTest(
169 							new String[] {
170 								"test01/X.java",
171 								"package test01;\n" +
172 								"import java.io.File;\n" +
173 								"import java.io.FileReader;\n" +
174 								"import java.io.IOException;\n" +
175 								"public class X {\n" +
176 								"    FileReader getReader(String filename) throws IOException {\n" +
177 								"        File file = new File(\"somefile\");\n" +
178 								"        FileReader fileReader = new FileReader(file);\n" +
179 								"        return fileReader;\n" + 		// don't complain here, pass responsibility to caller
180 								"    }\n" +
181 								"    void foo() throws IOException {\n" +
182 								"        FileReader reader = getReader(\"somefile\");\n" +
183 								"        char[] in = new char[50];\n" +
184 								"        reader.read(in);\n" +
185 								"    }\n" +
186 								"    public static void main(String[] args) throws IOException {\n" +
187 								"        new X().foo();\n" +
188 								"    }\n" +
189 								"}\n"
190 							},
191 					        "\"" + OUTPUT_DIR +  File.separator + "test01/X.java\""
192 				            + " -1.5 -g -preserveAllLocals -err:+resource"
193 				            + " -proceedOnError -d \"" + OUTPUT_DIR + "\"",
194 				            "",
195 							errorOutput.toString(),
196 							false);
197 					} catch (Throwable t) {
198 						thrown[1] = t;
199 					}
200 				}
201 			});
202 
203 			this.runner2.start();
204 			this.runner1.start();
205 			this.runner1.join();
206 			this.runner2.join();
207 			if (thrown[0] != null) throw thrown[0];
208 			if (thrown[1] != null) throw thrown[1];
209 		} finally {
210 			FakedTrackingVariable.TEST_372319 = false;
211 		}
212 	}
213 }
214