001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.api.java.source;
043:
044: import java.io.ByteArrayInputStream;
045: import java.io.EOFException;
046: import java.io.File;
047: import java.io.FileInputStream;
048: import java.io.FileOutputStream;
049: import java.io.IOException;
050: import java.io.InputStream;
051: import java.io.OutputStream;
052: import java.net.URL;
053: import java.util.ArrayList;
054: import java.util.List;
055: import java.util.concurrent.CountDownLatch;
056: import java.util.concurrent.ExecutionException;
057: import java.util.concurrent.Future;
058: import java.util.concurrent.TimeUnit;
059: import java.util.concurrent.TimeoutException;
060: import java.util.zip.GZIPInputStream;
061:
062: import org.netbeans.api.java.classpath.ClassPath;
063: import org.netbeans.modules.java.source.classpath.GlobalSourcePathTestUtil;
064: import org.netbeans.modules.java.source.usages.IndexUtil;
065: import org.netbeans.modules.java.source.usages.RepositoryUpdater;
066: import org.netbeans.spi.java.classpath.support.ClassPathSupport;
067: import org.openide.filesystems.FileObject;
068: import org.openide.filesystems.FileUtil;
069:
070: /**
071: * Utilities to aid unit testing java.source module.
072: *
073: * @author Jaroslav Tulach
074: * @author Tom Ball
075: * @author Tomas Zezula
076: */
077: public final class TestUtilities {
078:
079: // do not instantiate
080: private TestUtilities() {
081: }
082:
083: /**
084: * Waits for the end of the background scan, this helper method
085: * is designed for tests which require to wait for the end of initial scan.
086: * The method can be used as a barrier but it is not garanted that the
087: * backgoud scan will not start again after return from this method, the
088: * test is responsible for it itself. In general it's safer to use {@link JavaSource#runWhenScanFinished}
089: * method and do the critical action inside the run methed.
090: * @param timeout the maximum time to wait
091: * @param unit the time unit of the timeout argument
092: * @return true if the scan finished, false when the timeout elapsed before the end of the scan.
093: * @throws InterruptedException is thrown when the waiting thread is interrupted.
094: */
095: public static boolean waitScanFinished(final long timeout,
096: final TimeUnit unit) throws InterruptedException {
097: assert unit != null;
098: final ClasspathInfo cpInfo = ClasspathInfo.create(
099: ClassPathSupport.createClassPath(new URL[0]),
100: ClassPathSupport.createClassPath(new URL[0]), null);
101: assert cpInfo != null;
102: final JavaSource js = JavaSource.create(cpInfo);
103: assert js != null;
104: try {
105: Future<Void> future = js.runWhenScanFinished(
106: new Task<CompilationController>() {
107: public void run(CompilationController parameter)
108: throws Exception {
109: }
110: }, true);
111: future.get(timeout, unit);
112: return true;
113: } catch (IOException ioe) {
114: //Actually never thrown
115: } catch (ExecutionException ee) {
116: //Actually never thrown
117: } catch (TimeoutException timeoutEx) {
118: }
119: return false;
120: }
121:
122: /**
123: * Schedules compilation of the folder inside the source root. May be used by tests
124: * which need to fill data into {@link ClassIndex} or need to work on the group of java files.
125: * @param folder to be compiled, has to be either the root itself or must be subfolder of the root.
126: * @param root owning the folder. There must be boot, compile and source ClassPath for it
127: * available by {@link ClassPath#getClassPah} method - there must be {@link ClassPathProvider} handling
128: * the root registered in the global {@link Lookup}. There must be also source level provided for the root -
129: * {@link SourceLevelImplementation} registered in the global {@link Lookup}.
130: * @return CountDownLatch which may be used to wait to the end of asynchronous compilation, {@see CountDownLatch#await}
131: * @throws java.io.IOException when folder or root is not valid
132: */
133: public static CountDownLatch scheduleCompilation(
134: final FileObject folder, final FileObject root)
135: throws IOException {
136: assert folder != null;
137: assert root != null;
138: assert folder.equals(root) || FileUtil.isParentOf(root, folder);
139: return RepositoryUpdater.getDefault()
140: .scheduleCompilationAndWait(folder, root);
141: }
142:
143: /**
144: * Schedules compilation of the folder inside the source root. May be used by tests
145: * which need to fill data into {@link ClassIndex} or need to work on the group of java files.
146: * @param folder to be compiled, has to be either the root itself or must be subfolder of the root.
147: * @param root owning the folder. There must be boot, compile and source ClassPath for it
148: * available by {@link ClassPath#getClassPah} method - there must be {@link ClassPathProvider} handling
149: * the root registered in the global {@link Lookup}. There must be also source level provided for the root -
150: * {@link SourceLevelImplementation} registered in the global {@link Lookup}.
151: * @return CountDownLatch which may be used to wait to the end of asynchronous compilation, {@see CountDownLatch#await}
152: * @throws java.io.IOException when folder or root is not valid
153: */
154: public static CountDownLatch scheduleCompilation(final File folder,
155: final File root) throws IOException {
156: assert folder != null;
157: assert root != null;
158: final FileObject rootFo = FileUtil.toFileObject(root);
159: final FileObject folderFo = FileUtil.toFileObject(folder);
160: return RepositoryUpdater.getDefault()
161: .scheduleCompilationAndWait(folderFo, rootFo);
162: }
163:
164: /**
165: * Schedules compilation of the folder inside the source root and blocks until it finishes. May be used by tests
166: * which need to fill data into {@link ClassIndex} or need to work on the group of java files.
167: * @param folder to be compiled, has to be either the root itself or must be subfolder of the root.
168: * @param root owning the folder. There must be boot, compile and source ClassPath for it
169: * available by {@link ClassPath#getClassPah} method - there must be {@link ClassPathProvider} handling
170: * the root registered in the global {@link Lookup}. There must be also source level provided for the root -
171: * a {@link SourceLevelImplementation} registered in the global {@link Lookup}.
172: * @param timeout the maximum time to wait
173: * @param unit the time unit of the timeout argument
174: * @return false if the timeout elapsed before the end of compilation
175: * @throws java.io.IOException when folder or root is not valid
176: * @throws InterruptedException when the thread is interrupted
177: */
178: public static boolean scheduleCompilationAndWait(
179: final FileObject folder, final FileObject root,
180: final long timeout, final TimeUnit unit)
181: throws IOException, InterruptedException {
182: assert unit != null;
183: final CountDownLatch latch = scheduleCompilation(folder, root);
184: return latch.await(timeout, unit);
185: }
186:
187: /**
188: * Schedules compilation of the folder inside the source root and blocks until it finishes. May be used by tests
189: * which need to fill data into {@link ClassIndex} or need to work on the group of java files.
190: * @param folder to be compiled, has to be either the root itself or must be subfolder of the root.
191: * @param root owning the folder. There must be boot, compile and source ClassPath for it
192: * available by {@link ClassPath#getClassPah} method - there must be {@link ClassPathProvider} handling
193: * the root registered in the global {@link Lookup}. There must be also source level provided for the root -
194: * a {@link SourceLevelImplementation} registered in the global {@link Lookup}.
195: * @param timeout the maximum time to wait
196: * @param unit the time unit of the timeout argument
197: * @return false if the timeout elapsed before the end of compilation
198: * @throws java.io.IOException when folder or root is not valid
199: * @throws InterruptedException when the thread is interrupted
200: */
201: public static boolean scheduleCompilationAndWait(final File folder,
202: final File root, final long timeout, final TimeUnit unit)
203: throws IOException, InterruptedException {
204: assert unit != null;
205: final CountDownLatch latch = scheduleCompilation(folder, root);
206: return latch.await(timeout, unit);
207: }
208:
209: /**
210: * Disables use of {@link LibraryManager} in the {@link GlobalSourcePath}. The tests
211: * which don't register {@link LibraryProvider} or {@link LibraryTypeProvider} may
212: * use this method to disable use of {@link LibraryManager} in the {@link GlobalSourcePath}.
213: * @param use false value disables use of {@link LibraryManager}
214: */
215: public static void setUseLibraries(final boolean use) {
216: GlobalSourcePathTestUtil.setUseLibraries(use);
217: }
218:
219: /**
220: * Sets a root folder of the java source caches. This method may be used by tests
221: * which need to do an initial compilation, they require either {@link ClassIndex} or
222: * need to work with a group of related java files.
223: * @param cacheFolder the folder used by java infrastructure as a cache,
224: * has to exist and must be a folder.
225: */
226: public static void setCacheFolder(final File cacheFolder) {
227: IndexUtil.setCacheFolder(cacheFolder);
228: }
229:
230: /**
231: * Creates boot {@link ClassPath} for platform the test is running on,
232: * it uses the sun.boot.class.path property to find out the boot path roots.
233: * @return ClassPath
234: * @throws java.io.IOException when boot path property conatins non valid path
235: */
236: public static ClassPath createBootClassPath() throws IOException {
237: String bootPath = System.getProperty("sun.boot.class.path");
238: String[] paths = bootPath.split(File.pathSeparator);
239: List<URL> roots = new ArrayList<URL>(paths.length);
240: for (String path : paths) {
241: File f = new File(path);
242: if (!f.exists()) {
243: continue;
244: }
245: URL url = f.toURI().toURL();
246: if (FileUtil.isArchiveFile(url)) {
247: url = FileUtil.getArchiveRoot(url);
248: }
249: roots.add(url);
250: }
251: return ClassPathSupport.createClassPath(roots
252: .toArray(new URL[roots.size()]));
253: }
254:
255: /**
256: * Returns a string which contains the contents of a file.
257: *
258: * @param f the file to be read
259: * @return the contents of the file(s).
260: */
261: public final static String copyFileToString(java.io.File f)
262: throws java.io.IOException {
263: int s = (int) f.length();
264: byte[] data = new byte[s];
265: int len = new FileInputStream(f).read(data);
266: if (len != s)
267: throw new EOFException("truncated file");
268: return new String(data);
269: }
270:
271: /**
272: * Returns a string which contains the contents of a GZIP compressed file.
273: *
274: * @param f the file to be read
275: * @return the contents of the file(s).
276: */
277: public final static String copyGZipFileToString(java.io.File f)
278: throws java.io.IOException {
279: GZIPInputStream is = new GZIPInputStream(new FileInputStream(f));
280: byte[] arr = new byte[256 * 256];
281: int first = 0;
282: for (;;) {
283: int len = is.read(arr, first, arr.length - first);
284: if (first + len < arr.length) {
285: return new String(arr, 0, first + len);
286: }
287: }
288: }
289:
290: /**
291: * Copies a string to a specified file.
292: *
293: * @param f the file to use.
294: * @param content the contents of the returned file.
295: * @return the created file
296: */
297: public final static File copyStringToFile(File f, String content)
298: throws Exception {
299: FileOutputStream os = new FileOutputStream(f);
300: InputStream is = new ByteArrayInputStream(content
301: .getBytes("UTF-8"));
302: FileUtil.copy(is, os);
303: os.close();
304: is.close();
305:
306: return f;
307: }
308:
309: /**
310: * Copies a string to a specified file.
311: *
312: * @param f the {@link FilObject} to use.
313: * @param content the contents of the returned file.
314: * @return the created file
315: */
316: public final static FileObject copyStringToFile(FileObject f,
317: String content) throws Exception {
318: OutputStream os = f.getOutputStream();
319: InputStream is = new ByteArrayInputStream(content
320: .getBytes("UTF-8"));
321: FileUtil.copy(is, os);
322: os.close();
323: is.close();
324:
325: return f;
326: }
327: }
|