View Javadoc
1   package org.apache.maven.surefire.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.Iterator;
26  import java.util.NoSuchElementException;
27  import java.util.Set;
28  import org.apache.maven.surefire.testset.TestSetFailedException;
29  
30  /**
31   * Contains all the tests that have been found according to specified include/exclude
32   * specification for a given surefire run.
33   *
34   * @author Kristian Rosenvold (junit core adaption)
35   */
36  public class TestsToRun implements Iterable<Class<?>>
37  {
38      private final Set<Class<?>> locatedClasses;
39  
40      private volatile boolean finished;
41  
42      /**
43       * Constructor
44       *
45       * @param locatedClasses A set of java.lang.Class objects representing tests to run
46       */
47      public TestsToRun( Set<Class<?>> locatedClasses )
48      {
49          this.locatedClasses = Collections.unmodifiableSet( locatedClasses );
50      }
51  
52      public static TestsToRun fromClass( Class<?> clazz )
53          throws TestSetFailedException
54      {
55          return new TestsToRun( Collections.<Class<?>>singleton( clazz ) );
56      }
57  
58      /**
59       * Returns an iterator over the located java.lang.Class objects
60       *
61       * @return an unmodifiable iterator
62       */
63      public Iterator<Class<?>> iterator()
64      {
65          return new ClassesIterator();
66      }
67  
68      private final class ClassesIterator
69          implements Iterator<Class<?>>
70      {
71          private final Iterator<Class<?>> it = TestsToRun.this.locatedClasses.iterator();
72  
73          private Boolean finishCurrentIteration;
74  
75          public boolean hasNext()
76          {
77              popMarker();
78              return !finishCurrentIteration && it.hasNext();
79          }
80  
81          public Class<?> next()
82          {
83              try
84              {
85                  if ( popMarker() && finishCurrentIteration )
86                  {
87                      throw new NoSuchElementException();
88                  }
89                  return it.next();
90              }
91              finally
92              {
93                  finishCurrentIteration = null;
94              }
95          }
96  
97          public void remove()
98          {
99              throw new UnsupportedOperationException();
100         }
101 
102         /**
103          * @return {@code true} if marker changed from NULL to anything
104          */
105         private boolean popMarker()
106         {
107             if ( finishCurrentIteration == null )
108             {
109                 finishCurrentIteration = TestsToRun.this.finished;
110                 return true;
111             }
112             return false;
113         }
114     }
115 
116     public final void markTestSetFinished()
117     {
118         finished = true;
119     }
120 
121     public String toString()
122     {
123         StringBuilder sb = new StringBuilder();
124         sb.append( "TestsToRun: [" );
125         for ( Class<?> clazz : this )
126         {
127             sb.append( " " ).append( clazz.getName() );
128         }
129 
130         sb.append( ']' );
131         return sb.toString();
132     }
133 
134     public boolean containsAtLeast( int atLeast )
135     {
136         return containsAtLeast( iterator(), atLeast );
137     }
138 
139     private boolean containsAtLeast( Iterator<Class<?>> it, int atLeast )
140     {
141         for ( int i = 0; i < atLeast; i++ )
142         {
143             if ( !it.hasNext() )
144             {
145                 return false;
146             }
147 
148             it.next();
149         }
150 
151         return true;
152     }
153 
154     public boolean containsExactly( int items )
155     {
156         Iterator<Class<?>> it = iterator();
157         return containsAtLeast( it, items ) && !it.hasNext();
158     }
159 
160     /**
161      * @return {@code true}, if the classes may be read eagerly. {@code false},
162      *         if the classes must only be read lazy.
163      */
164     public boolean allowEagerReading()
165     {
166         return true;
167     }
168 
169     public Class<?>[] getLocatedClasses()
170     {
171         if ( !allowEagerReading() )
172         {
173             throw new IllegalStateException( "Cannot eagerly read" );
174         }
175         Collection<Class<?>> result = new ArrayList<Class<?>>();
176         for ( Class<?> clazz : this )
177         {
178             result.add( clazz );
179         }
180         return result.toArray( new Class<?>[result.size()] );
181     }
182 
183     /**
184      * Get test class which matches className
185      *
186      * @param className string used to find the test class
187      * @return Class object with the matching name, null if could not find a class with the matching name
188      */
189     public Class<?> getClassByName( String className )
190     {
191         for ( Class<?> clazz : this )
192         {
193             if ( clazz.getName().equals( className ) )
194             {
195                 return clazz;
196             }
197         }
198         return null;
199     }
200 }