Logo Search packages:      
Sourcecode: cacao-oj6 version File versions

ExcludeList.java

/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  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.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Vector;

import com.sun.javatest.util.DynamicArray;
import com.sun.javatest.util.I18NResourceBundle;

/**
 * A set of tests to be excluded from a test run.
 */

00054 public class ExcludeList
{
    /**
     * This exception is used to report problems manipulating an exclude list.
     */
00059     public static class Fault extends Exception
    {
      Fault(I18NResourceBundle i18n, String s, Object o) {
          super(i18n.getString(s, o));
      }
    }

    /**
     * Test if a file appears to be for an exclude list, by checking the extension.
     * @param f The file to be tested.
     * @return <code>true</code if the file appears to be an exclude list.
     */
00071     public static boolean isExcludeFile(File f) {
      return f.getPath().endsWith(EXCLUDEFILE_EXTN);
    }

    /**
     * Create a new exclude list.
     */
00078     public ExcludeList() {
    }

    /**
     * Create an ExcludeList from the data contained in a file.
     * @param f The file to be read.
     * @throws FileNotFoundException if the file cannot be found
     * @throws IOException if any problems occur while reading the file
     * @throws ExcludeList.Fault if the data in the file is ionconsistent
     * @see #ExcludeList(File[])
     */
00089     public ExcludeList(File f) 
      throws FileNotFoundException, IOException, Fault 
    {
      this(f, false);
    }

    /**
     * Create an ExcludeList from the data contained in a file.
     * @param f The file to be read.
     * @param strict Indicate if strict data checking rules should be used.
     * @throws FileNotFoundException if the file cannot be found
     * @throws IOException if any problems occur while reading the file
     * @throws ExcludeList.Fault if the data in the file is ionconsistent
     * @see #ExcludeList(File[])
     * @see #setStrictModeEnabled(boolean)
     */
00105     public ExcludeList(File f, boolean strict) 
      throws FileNotFoundException, IOException, Fault 
    {
      setStrictModeEnabled(strict);
      if (f != null) {
          BufferedReader in = new BufferedReader(new FileReader(f));
          Parser p = new Parser(in);
          try {
            Entry e;
            while ((e = p.readEntry()) != null)
                addEntry(e);
          }
          finally {
            in.close();
          }
          
          title = p.getTitle();
      }
    }


    /**
     * Create an ExcludeList from the data contained in a series of files.
     * @param files The file to be read.
     * @throws FileNotFoundException if any of the files cannot be found
     * @throws IOException if any problems occur while reading the files.
     * @throws ExcludeList.Fault if the data in the files is ionconsistent
     * @see #ExcludeList(File)
     */
00134     public ExcludeList(File[] files) 
      throws FileNotFoundException, IOException, Fault 
    {
      this(files, false);
    }

    /**
     * Create an ExcludeList from the data contained in a series of files.
     * @param files The file to be read.
     * @param strict Indicate if strict data checking rules should be used.
     * @throws FileNotFoundException if any of the files cannot be found
     * @throws IOException if any problems occur while reading the files.
     * @throws ExcludeList.Fault if the data in the files is ionconsistent
     * @see #ExcludeList(File)
     * @see #setStrictModeEnabled(boolean)
     */
00150     public ExcludeList(File[] files, boolean strict) 
      throws FileNotFoundException, IOException, Fault 
    {
      setStrictModeEnabled(strict);
      for (int i = 0; i < files.length; i++) {
          ExcludeList et = new ExcludeList(files[i], strict);
          merge(et);
      }
    }

    /**
     * Specify whether strict mode is on or not. In strict mode, calls to addEntry
     * may generate an exception in the case of conflicts, such as adding an entry
     * to exclude a specifc test case when the entire test is already excluded.
     * @param on true if strict mode should be enabled, and false otherwise
     * @see #isStrictModeEnabled
     */
00167     public void setStrictModeEnabled(boolean on) {
      //System.err.println("EL.setStrictModeEnabled " + on);
      strict = on;
    }

    /**
     * Check whether strict mode is enabled or not. In strict mode, calls to addEntry
     * may generate an exception in the case of conflicts, such as adding an entry
     * to exclude a specifc test case when the entire test is already excluded.
     * @return true if strict mode is enabled, and false otherwise
     * @see #setStrictModeEnabled
     */
00179     public boolean isStrictModeEnabled() {
      return strict;
    }

    /**
     * Test if a specific test is completely excluded according to the table.
     * It is completely excluded if there is an entry, and the test case field is null.
     * @param td A test description for the test being checked.
     * @return <code>true</code> if the table contains an entry for this test.
     */
00189     public boolean excludesAllOf(TestDescription td) {
      return excludesAllOf(td.getRootRelativeURL());
    }

    /**
     * Test if a specific test is completely excluded according to the table.
     * It is completely excluded if there is an entry, and the test case field is null.
     * @param url The test-suite root-relative URL for the test.
     * @return <code>true</code> if the table contains an entry for this test.
     */
00199     public boolean excludesAllOf(String url) {
      Object o = table.get(new Key(url));
      return (o != null && o instanceof Entry && ((Entry)o).testCase == null);
    }

    /**
     * Test if a specific test is partially or completely excluded according to the table.
     * It is so excluded if there is any entry in the table for the test.
     * @param td A test description for the test being checked.
     * @return <code>true</code> if the table contains an entry for this test.
     */
00210     public boolean excludesAnyOf(TestDescription td) {
      return excludesAnyOf(td.getRootRelativeURL());
    }

    /**
     * Test if a specific test is partially or completely excluded according to the table.
     * It is so excluded if there is any entry in the table for the test.
     * @param url The test-suite root-relative URL for the test.
     * @return <code>true</code> if the table contains an entry for this test.
     */
00220     public boolean excludesAnyOf(String url) {
      Object o = table.get(new Key(url));
      return (o != null);
    }

    /**
     * Get the test cases to be excluded for a test.
     *
     * @param td A test description for the test being checked.
     * @return an array of test case names if any test cases are to
     * be excluded. The result is null if the test is not found or is
     * completely excluded without specifying test cases.  This may be
     * a mix of single TC strings or a comma separated list of them.
     */
00234     public String[] getTestCases(TestDescription td) {
      Key key = new Key(td.getRootRelativeURL());
      synchronized (table) {
          Object o = table.get(key);
          if (o == null)
            // not found
            return null;
          else if (o instanceof Entry) {
            Entry e = (Entry)o;
            if (e.testCase == null)
                // entire test excluded
                return null;
            else
                return (new String[] {e.testCase});
          }
          else {
            Entry[] ee = (Entry[])o;
            String[] testCases = new String[ee.length];
            for (int i = 0; i < ee.length; i++)
                testCases[i] = ee[i].testCase;
            return testCases;
          }
      }
    }

    /**
     * Add an entry to the table. 
     * @param e The entry to be added; if an entry already exists for this test
     *      description, it will be replaced.
     * @throws ExcludeList.Fault if the entry is for the entire test and 
     *   there is already an entry for a test case for this test, or vice versa.
     */
00266     public void addEntry(Entry e) throws Fault {
      synchronized (table) {
          Key key = new Key(e.relativeURL);
          Object o = table.get(key);
          if (o == null) {
            // easy case: nothing already exists in the table, so just
            // add this one
            table.put(key, e);
          }
          else if (o instanceof Entry) {
            // a single entry exists in the table, so need to check for
            // invalid combinations of test cases and tests
            Entry curr = (Entry)o;
            if (curr.testCase == null) {
                if (e.testCase == null) 
                  // overwrite existing entry for entire test
                  table.put(key, e);
                else {
                  if (strict) {
                      // can't exclude test case when entire test already excluded
                      throw new Fault(i18n, "excl.cantExcludeCase", e.relativeURL);
                  }
                  // else ignore new entry since entire test is already excluded
                }
            }
            else {
                if (e.testCase == null) {
                  if (strict) {
                      // can't exclude entire test when test case already excluded
                      throw new Fault(i18n, "excl.cantExcludeTest", e.relativeURL);
                  }
                  else {
                      // overwrite existing entry for a test case with
                      // new entry for entire test
                      table.put(key, e);
                  }
                }
                else if (curr.testCase.equals(e.testCase)) {
                  // overwrite existing entry for the same test case
                  table.put(key, e);
                }
                else {
                  // already excluded one test case, now we need to exclude
                  // another; make an array to hold both entries against the
                  // one key
                  table.put(key, new Entry[] {curr, e});
                }
            }
          }
          else {
            // if there is an array, it must be for unique test cases
            if (e.testCase == null) {
                if (strict) {
                  // can't exclude entire test when selected test cases already excluded
                  throw new Fault(i18n, "excl.cantExcludeTest", e.relativeURL);
                }
                else {
                  // overwrite existing entry for list of test cases with
                  // new entry for entire test
                  table.put(key, e);
                }
            }
            else {
                Entry[] curr = (Entry[])o;
                for (int i = 0; i < curr.length; i++) {
                  if (curr[i].testCase.equals(e.testCase)) {
                      curr[i] = e;
                      return;
                  }
                }
                // must be a new test case, add it into the array
                table.put(key, DynamicArray.append(curr, e));
            }
          }
          
      }
    }

    /**
     * Locate an entry for a test.
     * @param url The root relative URL for the test; the URL may include
     * a test case if necessary included in square brackets after the URL proper.
     * @return The entry for the test, or null if there is none.
     */
00350     public Entry getEntry(String url) {
      String testCase = null;
      if (url.endsWith("]")) {
          int i = url.lastIndexOf("[");
          if (i != -1) {
            testCase = url.substring(i+1, url.length()-1);
            url = url.substring(0, i);
          }
      }
      return getEntry(url, testCase);
    }

    /**
     * Locate an entry for a test.
     *
     * @param url The root relative URL for the test.
     * @param testCase An optional test case to be taken into account.  This cannot
     *  be a comma separated list.  A value of null will match any entry with the given
     *  url.
     * @return The entry for the test, or null if the URL cannot be found.
     */
00371     public Entry getEntry(String url, String testCase) {
      // XXX what if multiple entries?
      Key key = new Key(url);
      Object o = table.get(key);
      if (o == null)
          return null;
      else if (o instanceof Entry) {
          Entry e = (Entry)o;
          if (testCase == null)
            return e;
          else
            return (isInList(e.testCase, testCase) ? e : null);
      }
      else {
          Entry[] entries = (Entry[])o;
          for (int i = 0; i < entries.length; i++) {
            Entry e = entries[i];
            if (isInList(e.testCase, testCase))
                return e;
          }
          return null;
      }
    }

    /**
     * Merge the contents of another exclude list into this one.
     * The individual entries are merged;  The title of the exclude list
     * being merged is ignored.
     * @param other the exclude list to be merged with this one.
     * 
     */
00402     public void merge(ExcludeList other) {
      synchronized (table) {
          for (Iterator iter = other.getIterator(false); iter.hasNext(); ) {
            Entry otherEntry = (Entry) (iter.next());
            Key key = new Key(otherEntry.relativeURL);
            Object o = table.get(key);
            if (o == null) {
                // Easy case: nothing already exists in the table, so just
                // add this one
                table.put(key, otherEntry);
            }
            else if (o instanceof Entry) {
                // A single entry exists in the table
                Entry curr = (Entry)o;
                if (curr.testCase == null || otherEntry.testCase == null) {
                  table.put(key, new Entry(curr.relativeURL, null, 
                                  mergeBugIds(curr.bugIdStrings, otherEntry.bugIdStrings),
                                  mergePlatforms(curr.platforms, otherEntry.platforms),
                                  mergeSynopsis(curr.synopsis, otherEntry.synopsis)));
                }
                else 
                  table.put(key, new Entry[] {curr, otherEntry});
            }
            else if (otherEntry.testCase == null) {
                // An array of test cases exist in the table, but we're merging
                // an entry for the complete test, so flatten down to a single entry
                // for the whole test
                String[] bugIdStrings = otherEntry.bugIdStrings;
                String[] platforms = otherEntry.platforms;
                String synopsis = otherEntry.synopsis;
                Entry[] curr = (Entry[])o;
                for (int i = 0; i < curr.length; i++) {
                  bugIdStrings = mergeBugIds(bugIdStrings, curr[i].bugIdStrings);
                  platforms = mergePlatforms(platforms, curr[i].platforms);
                  synopsis = mergeSynopsis(synopsis, curr[i].synopsis);
                }
                table.put(key, new Entry(otherEntry.relativeURL, null,
                                   bugIdStrings, platforms, synopsis));
            }
            else {
                // An array of test cases exist in the table, and we're merging
                // an entry with another set of test cases.
                // For now, concatenate the arrays.
                // RFE: Replace Entry[] with Set and merge the sets.
                table.put(key, (Entry[]) DynamicArray.append((Entry[]) o, otherEntry));
            }
          }
      }
    }

    private static String[] mergeBugIds(String[] a, String[] b) {
      return merge(a, b);
    }

    private static String[] mergePlatforms(String[] a, String[] b) {
      return merge(a, b);
    }

    private static String[] merge(String[] a, String[] b) {
      SortedSet s = new TreeSet();
      s.addAll(Arrays.asList(a));
      s.addAll(Arrays.asList(b));
      return (String[]) (s.toArray(new String[s.size()]));
    }

    private static String mergeSynopsis(String a, String b) {
      if (a == null || a.trim().length() == 0)
          return b;
      else if (b == null || b.trim().length() == 0)
          return a;
      else if (a.indexOf(b) != -1)
          return a;
      else if (b.indexOf(a) != -1)
          return b;
      else
          return a + "; " + b;
    }


    /**
     * Remove an entry from the table.  
     * @param e the entry to be removed
     */
00485     public void removeEntry(Entry e) {
      synchronized (table) {
          Key key = new Key(e.relativeURL);
          Object o = table.get(key);
          if (o == null)
            // no such entry
            return;
          else if (o instanceof Entry) {
            if (o == e)
                table.remove(key);
          }
          else {
            Entry[] o2 = (Entry[])DynamicArray.remove((Entry[])o, e);
            if (o2 == o)
                // not found
                return;
            else {
                if (o2.length == 1)
                  table.put(key, o2[0]);
                else
                  table.put(key, o2);
            }
          }
      }
    }

    /**
     * Check whether an exclude list has any entries or not.
     * @return true if this exclude list has no entries
     * @see #size
     */
00516     public boolean isEmpty() {
      return table.isEmpty();
    }

    /**
     * Get the number of entries in the table.
     * @return the number of entries in the table
     * @see #isEmpty
     */
00525     public int size() {
      // ouch, this is now expensive to compute
      int n = 0;
      for (Iterator i = table.values().iterator(); i.hasNext(); ) {
          Object o = i.next();
          if (o instanceof Entry[])
            n += ((Entry[])o).length;
          else
            n++;
      }
      return n;
    }

    /**
     * Iterate over the contents of the table.
     * @param group if <code>true</code>, entries for the same relative
     * URL are grouped together, and if more than one, returned in an
     * array; if <code>false</code>, the iterator always returns
     * separate entries.
     * @see Entry
     * @return an iterator for the table: the entries are either
     * single instances of @link(Entry) or a mixture of @link(Entry)
     * and @link(Entry)[], depending on the <code>group</code>
     * parameter.
     */
00550     public Iterator getIterator(boolean group) {
      if (group)
          return table.values().iterator();
      else {
          // flatten the enumeration into a vector, then
          // enumerate that
          Vector v = new Vector(table.size());
          for (Iterator iter = table.values().iterator(); iter.hasNext(); ) {
            Object o = iter.next();
            if (o instanceof Entry) 
                v.addElement(o);
            else {
                Entry[] entries = (Entry[])o;
                for (int i = 0; i < entries.length; i++)
                  v.addElement(entries[i]);
            }
          }
          return v.iterator();
      }

    }

    /**
     * Get the title for this exclude list.
     * @return the title for this exclude list
     * @see #setTitle
     */
00577     public String getTitle() {
      return title;
    }

    /**
     * Set the title for this exclude list.
     * @param title the title for this exclude list
     * @see #getTitle
     */
00586     public void setTitle(String title) {
      this.title = title;
    }

    /**
     * Write the table out to a file.
     * @param f The file to which the table should be written.
     * @throws IOException is thrown if any problems occur while the
     * file is being written.
     */
00596     public void write(File f) throws IOException {
      // sort the entries for convenience, and measure col widths
      int maxURLWidth = 0;
      int maxBugIdWidth = 0;
      int maxPlatformWidth = 0;
      SortedSet entries = new TreeSet();
      for (Iterator iter = getIterator(false); iter.hasNext(); ) {
          Entry entry = (Entry) (iter.next());
          entries.add(entry);
          if (entry.testCase == null)
            maxURLWidth = Math.max(entry.relativeURL.length(), maxURLWidth);
          else
            maxURLWidth = Math.max(entry.relativeURL.length() + entry.testCase.length() + 2, maxURLWidth);
          maxBugIdWidth = Math.max(bugIdsToString(entry).length(), maxBugIdWidth);
          maxPlatformWidth = Math.max(platformsToString(entry).length(), maxPlatformWidth);
      }

      BufferedWriter out = new BufferedWriter(new FileWriter(f));
      out.write("# Exclude List");
      out.newLine();
      out.write("# SCCS %" + 'W' + "% %" + 'E' + "%"); // TAKE CARE WITH SCCS HEADERS
      out.newLine();
      if (title != null) {
          out.write("### title " + title);
          out.newLine();
      }
      for (Iterator iter = entries.iterator(); iter.hasNext(); ) {
          Entry e = (Entry) (iter.next());
          if (e.testCase == null)
            write(out, e.relativeURL, maxURLWidth + 2);
          else
            write(out, e.relativeURL + "[" + e.testCase + "]", maxURLWidth + 2);
          write(out, bugIdsToString(e), maxBugIdWidth + 2);
          write(out, platformsToString(e), maxPlatformWidth + 2);
          out.write(e.synopsis);
          out.newLine();
      }
      out.close();
    }

    private void write(Writer out, String s, int width) throws IOException {
      out.write(s);
      for (int i = s.length(); i < width; i++)
          out.write(' ');
    }

    private String bugIdsToString(Entry e) {
      StringBuffer sb = new StringBuffer(e.bugIdStrings.length*10);
      sb.append(e.bugIdStrings[0]);
      for (int i = 1; i < e.bugIdStrings.length; i++) {
          sb.append(',');
          sb.append(e.bugIdStrings[i]);
      }
      return sb.toString();
    }

    private String platformsToString(Entry e) {
      StringBuffer sb = new StringBuffer(e.platforms.length*10);
      sb.append(e.platforms[0]);
      for (int i = 1; i < e.platforms.length; i++) {
          sb.append(',');
          sb.append(e.platforms[i]);
      }
      return sb.toString();
    }

    private static boolean equals(String s1, String s2) {
      return (s1 == null && s2 == null
            || s1 != null && s2 != null && s1.equals(s2));
    }

    /**
     * Is val in the comma separated list.
     *
     * @param list Comma separated list or a single value.
     * @return Null if either parameter is null.
     */
00673     private static boolean isInList(String list, String val) {
      // check for invalid args  
      if (list == null || val == null)                   
          return false;
      
      // loop through possible matches
      for (int pos = list.indexOf(val); pos != -1; pos = list.indexOf(val, pos + 1) ) {
          // check beginning of string
          if (!(pos == 0 || list.charAt(pos -1) == ','))
            continue;
      
          // check end of string
          if (!(pos + val.length() == list.length()  || list.charAt(pos + val.length()) == ','))
            continue;
      
          // beginning and end are OK; got a match
          return true;
      }
      
      // no good matches found  
      return false; 
    }

    private Map table = new HashMap();
    private String title;
    private boolean strict;

    private static final class Parser {
      Parser(Reader in) throws IOException {
          this.in = in;
          ch = in.read();
      }

      String getTitle() {
          return title;
      }

      Entry readEntry() throws IOException, Fault {
          String url = readURL(); // includes optional test case
          if (url == null)
            return null;
          String testCase = null; // for now
          if (url.endsWith("]")) {
            int i = url.lastIndexOf("[");
            if (i != -1) {
                testCase = url.substring(i+1, url.length()-1);
                url = url.substring(0, i);
            }
          }
          String[] bugIdStrings = readBugIds();
          String[] platforms = readPlatforms();
          String synopsis = readRest();
          return new Entry(url, testCase, bugIdStrings, platforms, synopsis);
      }

      private boolean isEndOfLine(int ch) {
          return (ch == -1 || ch == '\n' || ch == '\r');
      }

      private boolean isWhitespace(int ch) {
          return (ch == ' ' || ch == '\t');
      }

      private String readURL() throws IOException, Fault {
          // skip white space, comments and blank lines until a word is found
          for (;;) {
            skipWhite();
            switch (ch) {
            case -1:
                // end of file
                return null;
            case '#':
                // comment
                skipComment();
                break;
            case '\r':
            case '\n':
                // blank line (or end of comment)
                ch = in.read();
                break;
            default:
                return readWord();
            }
          }
      }

      private String[] readBugIds() throws IOException {
          // skip white space, then read and sort a list of comma-separated
          // numbers with no embedded white-space
          skipWhite();
          TreeSet s = new TreeSet();
          StringBuffer sb = new StringBuffer();
          for ( ; !isEndOfLine(ch) && !isWhitespace(ch); ch = in.read()) {
            if (ch == ',') {
                if (sb.length() > 0) {
                  s.add(sb.toString());
                  sb.setLength(0);
                }
            }
            else 
                sb.append((char) ch);
          }

          if (sb.length() > 0) 
              s.add(sb.toString());

          if (s.size() == 0)
              s.add("0");  // backwards compatibility

          return (String[]) (s.toArray(new String[s.size()]));
      }

      private String[] readPlatforms() throws IOException {
          // skip white space, then read and sort a list of comma-separated
          // platform names with no embedded white space. Since the
          // set of platforms (and their combinations) is small,
          // share the result amongst all equivalent entries.
          skipWhite();
          String s = readWord();
          String[] platforms = (String[])platformCache.get(s);
          if (platforms == null) {
            // split string into sorted comma separated pieces
            int n = 0;
            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == ',')
                  n++;
            }
            TreeSet ts = new TreeSet();
            int start = 0;
            int end = s.indexOf(',');
            while (end != -1) {
                ts.add(s.substring(start, end));
                start = end + 1;
                end = s.indexOf(',', start);
            }
            ts.add(s.substring(start));
            platforms = (String[]) (ts.toArray(new String[ts.size()]));
            platformCache.put(s, platforms);
          }
          return platforms;
      }

      private String readRest() throws IOException {
          // skip white space, then read up to the end of the line
          skipWhite();
          StringBuffer word = new StringBuffer(80);
          for ( ; !isEndOfLine(ch); ch = in.read())
            word.append((char)ch);
          // skip over terminating character
          ch = in.read();
          return word.toString();
      }

      private String readWord() throws IOException {
          // read characters up to the next white space
          StringBuffer word = new StringBuffer(32);
          for ( ; !isEndOfLine(ch) && !isWhitespace(ch); ch = in.read())
            word.append((char)ch);
          return word.toString();
      }

      private void skipComment() throws IOException, Fault {
          ch = in.read();
          // first # has already been read
          if (ch == '#') {
            ch = in.read();
            if (ch == '#') {
                ch = in.read();
                skipWhite();
                String s = readWord();
                if (s.equals("title")) {
                  skipWhite();
                  title = readRest();
                  return;
                }
            }
          }
          while (!isEndOfLine(ch))
            ch = in.read();
      }

      private void skipWhite() throws IOException {
          // skip horizontal white space
          // input is line-oriented, so do not skip over end of line
          while (ch != -1 && isWhitespace(ch))
            ch = in.read();
      }

      private Reader in;      // source stream being read
      private int ch;         // current character
      private Map platformCache = new HashMap();
                        // cache of results for readPlatforms
      private String title;
    };

    private static class Key {
      Key(String url) {
          relativeURL = url;
      }

      public int hashCode() {
          // the hashCode for a key is the hashcode of the normalized URL.
          // The normalized URL is url.replace(File.separatorChar, '/').toLowerCase();
          int h = hash;
          if (h == 0) {
            int len = relativeURL.length();
            
            for (int i = 0; i < len; i++) {
                char c = Character.toLowerCase(relativeURL.charAt(i));
                if (c == sep)
                  c = '/';
                h = 31*h + c;
            }
            hash = h;
          }
          return h;
      }

      public boolean equals(Object o) {
          // Two keys are equal if their normalized URLs are equal.
          // The normalized URL is url.replace(File.separatorChar, '/').toLowerCase();
          if (o == null || !(o instanceof Key))
            return false;
          String u1 = relativeURL;
          String u2 = ((Key) o).relativeURL;
          int len = u1.length();
          if (len != u2.length())
            return false;
          for (int i = 0; i < len; i++) {
            char c1 = Character.toLowerCase(u1.charAt(i));
            if (c1 == sep)
                c1 = '/';
            char c2 = Character.toLowerCase(u2.charAt(i));
            if (c2 == sep)
                c2 = '/';
            if (c1 != c2)
                return false;
          }
          return true;
      }

      private static final char sep = File.separatorChar;
      private String relativeURL;
      private int hash;
    }

    /**
     * An entry in the exclude list.
     */
00922     public static final class Entry implements Comparable {
      /**
       * Create an ExcludeList entry.
       * @param u The URL for the test, specified relative to the test suite root.
       * @param tc One or more test cases within the test to be excluded.
       * @param b An array of bug identifiers, justifying why the test is excluded.
       * @param p An array of platform identifiers, on which the faults are
       *          known to occur
       * @param s A short synopsis of the reasons why the test is excluded.
       */
00932       public Entry(String u, String tc, String[] b, String[] p, String s) {
          if (b == null || p == null)
            throw new NullPointerException();

          // The file format cannot support platforms but no bugids, 
          // so fault that; other combinations (bugs, no platforms;
          // no bugs, no platforms etc) are acceptable.
          if (b.length == 0 &&  p.length > 0)
            throw new IllegalArgumentException();

          relativeURL = u;
          testCase = tc;
          bugIdStrings = b;
          platforms = p;
          synopsis = s;
      }
      /**
       * Create an ExcludeList entry.
       * @param u The URL for the test, specified relative to the test suite root.
       * @param tc One or more test cases within the test to be excluded.
       * @param b An array of bug numbers, justifying why the test is excluded.
       * @param p An array of platform identifiers, on which the faults are
       *          known to occur
       * @param s A short synopsis of the reasons why the test is excluded.
       */
00957       public Entry(String u, String tc, int[] b, String[] p, String s) {
          if (b == null || p == null)
            throw new NullPointerException();

          // The file format cannot support platforms but no bugids, 
          // so fault that; other combinations (bugs, no platforms;
          // no bugs, no platforms etc) are acceptable.
          if (b.length == 0 &&  p.length > 0)
            throw new IllegalArgumentException();

          relativeURL = u;
          testCase = tc;

          bugIdStrings = new String[b.length];
          for (int i = 0; i < b.length; i++)
            bugIdStrings[i] = String.valueOf(b[i]);
          bugIds = b;

          platforms = p;
          synopsis = s;
      }

      public int compareTo(Object o) {
          Entry e = (Entry) o;
          int n = relativeURL.compareTo(e.relativeURL);
          if (n == 0) {
            if (testCase == null && e.testCase == null)
                return 0;
            else if (testCase == null)
                return -1;
            else if (e.testCase == null)
                return +1;
            else 
                return testCase.compareTo(e.testCase);
          }
          else
            return n;
      }

      /**
       * Get the relative URL identifying the test referenced by this entry.
       * @return the relative URL identifying the test referenced by this entry
       */
01000       public String getRelativeURL() {
          return relativeURL;
      }

      /**
       * Get the (possibly empty) list of test cases for this entry.
       * An entry can have zero, one, or a comma separated list of TCs.
       *
       * @return List, or null if there are no test cases.
       */
01010       public String getTestCases() {
          return testCase;
      }

      /** 
       * Get the same data as getTestCases(), but split into many Strings
       * This method is costly, so use with care.
       *
       * @return The parsed comma list, or null if there are no test cases.
       */
01020       public String[] getTestCaseList() {
          // code borrowed from StringArray
          // it is a little wasteful to recalc everytime but saves space
          if (testCase == null)
            return null;

          Vector v = new Vector();
          int start = -1;
          for (int i = 0; i < testCase.length(); i++) {
            if (testCase.charAt(i) == ',') {
                if (start != -1)
                  v.addElement(testCase.substring(start, i));
                start = -1;
            } else
                if (start == -1)
                  start = i;
          }
          if (start != -1)
            v.addElement(testCase.substring(start));

          if (v.size() == 0)
            return null;

          String[] a = new String[v.size()];
          v.copyInto(a);
          return a;
      }

      /**
       * Get the set of bug IDs referenced by this entry.
       * @return the bugs referenced by the entry
       */
01052       public int[] getBugIds() {
          if (bugIds == null) {
            bugIds = new int[bugIdStrings.length];
            for (int i = 0; i < bugIds.length; i++) {
                try {
                  bugIds[i] = Integer.parseInt(bugIdStrings[i]);
                }
                catch (NumberFormatException e) {
                  bugIds[i] = -1;
                }
            }
          }

          return bugIds;
      }

      /**
       * Get the set of bug IDs referenced by this entry.
       * @return the bugs referenced by the entry
       */
01072       public String[] getBugIdStrings() {
          return bugIdStrings;
      }

      /**
       * Get the set of platforms or keywords associated with this entry.
       * These should normally give details about why the test has been
       * excluded.
       * @return the set of platforms or keywords associated with this entry
       */
01082       public String[] getPlatforms() {
          return platforms;
      }

      /**
       * Get a short description associated with this entry.
       * This should normally give details about why the test has been
       * excluded.
       * @return a short description associated with this entry
       */
01092       public String getSynopsis() {
          return synopsis;
      }

      /**
       * Create an entry from a string. The string should be formatted
       * as though it were a line of text in an exclude file.
       * @param text The text to be read 
       * @return the first entry read from the supplied text
       * @throws ExcludeList.Fault if there is a problem reading the entry.
       */
01103       public static Entry read(String text) throws Fault {
          try {
            return new Parser(new StringReader(text)).readEntry();
          }
          catch (IOException e) {
            throw new Fault(i18n, "excl.badEntry", e);
          }
      }

      /**
       * Compare this entry against another.
       * @param o the object to compare against
       * @return true is the objects are bothe ExcludeList.Entries containing
       *    the same details
       */
01118       public boolean equals(Object o) {
          if (o instanceof Entry) {
            Entry e = (Entry)o;
            return equals(relativeURL, e.relativeURL)
                && equals(testCase, e.testCase)
                && equals(bugIdStrings, e.bugIdStrings)
                && equals(platforms, e.platforms)
                && equals(synopsis, e.synopsis);
          }
          else
            return false;
      }

      public int hashCode() {
          return relativeURL.hashCode();
      }

      public String toString() {
          StringBuffer sb = new StringBuffer(64);
          sb.append(relativeURL);
          if (testCase != null) {
            sb.append('[');
            sb.append(testCase);
            sb.append(']');
          }
          if (bugIdStrings != null) {
            for (int i = 0; i<bugIdStrings.length; i++) {
                sb.append(i == 0 ? ' ' : ',');
                sb.append(bugIdStrings[i]);
            }
          }
          if (platforms != null) {
            for (int i = 0; i<platforms.length; i++) {
                sb.append(i == 0 ? ' ' : ',');
                sb.append(platforms[i]);
            }
          }
          if (synopsis != null) {
            sb.append(' ');
            sb.append(synopsis);
          }
          return new String(sb);
      }

      private static boolean equals(int[] i1, int[] i2) {
          if (i1 == null || i2 == null)
            return (i1 == null && i2 == null);

          if (i1.length != i2.length)
            return false;

          for (int x = 0; x < i1.length; x++)
            if (i1[x] != i2[x])
                return false;

          return true;
      }

      private static boolean equals(String[] s1, String[] s2) {
          if (s1 == null || s2 == null)
            return (s1 == null && s2 == null);

          if (s1.length != s2.length)
            return false;

          for (int x = 0; x < s1.length; x++) {
            if (!equals(s1[x], s2[x]))
                return false;
          }

          return true;
      }

      private static boolean equals(String s1, String s2) {
          return (s1 == null && s2 == null
                || s1 != null && s2 != null && s1.equals(s2));
      }


      private String relativeURL;
      private String testCase;
      private String[] bugIdStrings;
      private int[] bugIds; // null, unless required
      private String[] platforms;
      private String synopsis;
    }

    private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(ExcludeList.class);

    /**
     * The standard extension for exclude-list files. (".jtx")
     */
01210     public static final String EXCLUDEFILE_EXTN = ".jtx";

}

Generated by  Doxygen 1.6.0   Back to index