/* * $Id$ * * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.javatest; import java.io.File; import java.util.Hashtable; import java.util.Map; import java.util.Vector; import com.sun.javatest.util.DynamicArray; import com.sun.javatest.util.Fifo; import com.sun.javatest.util.I18NResourceBundle; /** * An iterator-based interface to the tests in a test suite, as read by a test finder. */ public class TestFinderQueue { /** * This interface provides a means for TestFinder to report on events that * might be of interest as it executes. */ public static interface Observer { /** * Another file which needs to be read has been found. * @param file the file which was found */ void found(File file); /** * A file is being read. * @param file the file being read */ void reading(File file); /** * A file has been read. * @param file the file which was read */ void done(File file); /** * A test description has been found. * @param td the test description which was found */ void found(TestDescription td); /** * A test description which was previously found, has been rejected by * a test filter, and so has not been put in the queue of tests to be executed. * @param td the test description which was rejected by the filter * @param f the filter which rejected the test */ void ignored(TestDescription td, TestFilter f); /** * A test description that was previously put in the test finder queue * has been taken from the queue and passed back to the client caller. * @param td the test description which was taken from the queue */ void done(TestDescription td); /** * The queue of tests has been flushed. */ void flushed(); /** * An error was reported by the test finder while reading a file. * @param msg a detail message describing the error */ void error(String msg); /** * An error was reported by the test finder while reading a file. * @param td the test description to which the error applies * @param msg a detail message describing the error */ void error(TestDescription td, String msg); } /** * Create a test finder queue. */ public TestFinderQueue() { } /** * Create a test finder queue, using a specified test finder. * @param finder the test finder to be used to read the tests */ public TestFinderQueue(TestFinder finder) { setTestFinder(finder); } /** * Get the test finder being used by this object. * @return the test finder being used by this object * @see #setTestFinder */ public TestFinder getTestFinder() { return testFinder; } /** * Set the test finder to be used by this object. * It may only be set once. * @param finder the test finder to be used by this object * @throws NullPointerException if the finder is null * @throws IllegalStateException if the finder has already been set * @see #getTestFinder */ public void setTestFinder(TestFinder finder) { if (finder == null) throw new NullPointerException(); if (testFinder != null && testFinder != finder) throw new IllegalStateException(); this.testFinder = finder; testFinder.setErrorHandler(new TestFinder.ErrorHandler() { public void error(String msg) { errorCount++; notifier.error(msg); } }); } /** * Set an array of filters that will be used to filter the tests read by the * test finder. Each test must be accepted by all the filters to be put in * the queue. * @param filters the filters to be used. */ public void setFilters(TestFilter[] filters) { this.filters = filters; } /** * Set the initial set of files to be read by the test finder. * Additional files may be read as a result of reading these and subsequent files. * @param initTests the initial set of files to be read by the test finder */ public synchronized void setTests(String[] initTests) { File testSuiteRoot = testFinder.getRoot(); // make canonical copy of tests // really ought not to be using File, since the tests may contain a trailing #xxx File[] files; if (initTests == null) // ensure not null files = new File[] {testSuiteRoot}; else { files = new File[initTests.length]; for (int i = 0; i < initTests.length; i++) { files[i] = new File(initTests[i]); } } rootDir = (testSuiteRoot.isDirectory() ? testSuiteRoot : new File(testSuiteRoot.getParent())); // build up the fifo of tests to be used by readNextFile tests = new Fifo<>(); currInitialFile = null; for (int pass = 0; pass < 2; pass++) { for (int i = 0; i < files.length; i++) { File f = files[i]; String n = f.getName(); // in pass 0, only select initial files without # // in pass 1, only select initial files with # if ((n.indexOf("#") != -1) == (pass == 0)) continue; // ensure all absolute, or if relative, make them relative // to rootDir if (!f.isAbsolute()) f = new File(rootDir, f.getPath()); // ensure no trailing file separator String p = f.getPath(); if (p.endsWith(File.separator)) f = new File(p.substring(0, p.length() - 1)); tests.insert(f); } } filesRemainingCount = filesToRead.size() + tests.size(); } /** * Set a flag indicating whether it is OK to find no tests in the * specified set of files. If set to false, and if no tests have * been found by the time the last file has been read, an error * will be notified to any observers. * @param zeroTestsOK set to true to suppress an error being generated * if no tests are found by the time that all files have been read */ public void setZeroTestsOK(boolean zeroTestsOK) { this.zeroTestsOK = zeroTestsOK; } /** * Set the queue to "repeat" a set of test descriptions by putting * them in the test found queue again. * @param tds the test descriptions to be "found again". * @deprecated retained for historical purposes */ public void repeat(TestDescription[] tds) { if (tests == null) tests = new Fifo<>(); // for now for (int i = 0; i < tds.length; i++) { TestDescription td = tds[i]; testDescsFound.insert(td); testsFoundCount++; notifier.found(td); } } /** * Get the next test description if one is available, or null when all have * been returned. * * @return A test description or null. */ public TestDescription next() { TestDescription td; synchronized (this) { while (needReadAhead() && readNextFile()) /*NO-OP*/; // read files until there is a test description available or there // are no more files. while ((td = testDescsFound.remove()) == null) { boolean ok = readNextFile(); if (!ok) return null; } // note testsDone, for readAhead testsDoneCount++; } notifier.done(td); return td; } //-------------------------------------------------------------------------- /** * Get the root directory for the test finder. * @return the root directory, as set in the test finder */ public File getRoot() { return rootDir; } //-------------------------------------------------------------------------- // // these are all carefully arranges to not need to be synchronized /** * Get the number of files that have been found so far. * @return the number of files that have been found so far */ public int getFilesFoundCount() { return filesFound.size(); } /** * Get the number of files that have been found and read so far. * @return the number of files that have been found and read so far */ public int getFilesDoneCount() { return filesDoneCount; } /** * Get the number of files that have been found but not yet read so far. * @return the number of files that have been found but not yet read so far */ public int getFilesRemainingCount() { return filesRemainingCount; } /** * Get the number of tests that have been found so far. * @return the number of tests that have been found so far */ public int getTestsFoundCount() { return testsFoundCount; } /** * Get the number of tests that have been read from this object so far. * @return the number of tests that have been read from this object so far */ public int getTestsDoneCount() { return testsDoneCount; } /** * Get the number of tests which have been found but not yet from this * object so far. * @return the number of tests which have been found but not yet read * from this object so far */ public int getTestsRemainingCount() { return testDescsFound.size(); } /** * Get the number of errors that have been found so far by the test finder * while reading the tests. * @return the number of errors that have been found so far by the test finder * while reading the tests. */ public int getErrorCount() { return errorCount; } //-------------------------------------------------------------------------- /** * Add an observer to monitor the progress of the TestFinder. * @param o the observer */ public void addObserver(Observer o) { notifier.addObserver(o); } /** * Remove an observer form the set currently monitoring the progress * of the TestFinder. * @param o the observer */ public void removeObserver(Observer o) { notifier.removeObserver(o); } //-------------------------------------------------------------------------- /** * Set the amount of read-ahead done by the finder. * @param mode acceptable values are as follows: *