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.List;
27  import java.util.Set;
28  
29  import org.apache.maven.surefire.testset.TestSetFailedException;
30  
31  import static java.lang.Math.max;
32  
33  /**
34   * Contains all the tests that have been found according to specified include/exclude
35   * specification for a given surefire run.
36   *
37   * @author Kristian Rosenvold (junit core adaption)
38   */
39  public class TestsToRun implements Iterable<Class<?>>
40  {
41      private final List<Class<?>> locatedClasses;
42  
43      private volatile boolean finished;
44  
45      private int iteratedCount;
46  
47      /**
48       * Constructor
49       *
50       * @param locatedClasses A set of java.lang.Class objects representing tests to run
51       */
52      public TestsToRun( Set<Class<?>> locatedClasses )
53      {
54          this.locatedClasses = new ArrayList<Class<?>>( locatedClasses );
55      }
56  
57      public static TestsToRun fromClass( Class<?> clazz )
58          throws TestSetFailedException
59      {
60          return new TestsToRun( Collections.<Class<?>>singleton( clazz ) );
61      }
62  
63      /**
64       * @return test classes which have been retrieved by {@link TestsToRun#iterator()}.
65       */
66      public Iterator<Class<?>> iterated()
67      {
68          return newWeakIterator();
69      }
70  
71      /**
72       * Returns an iterator over the located java.lang.Class objects
73       *
74       * @return an unmodifiable iterator
75       */
76      public Iterator<Class<?>> iterator()
77      {
78          return new ClassesIterator();
79      }
80  
81      private final class ClassesIterator
82          extends CloseableIterator<Class<?>>
83      {
84          private final Iterator<Class<?>> it = TestsToRun.this.locatedClasses.iterator();
85  
86          private int iteratedCount;
87  
88          @Override
89          protected boolean isClosed()
90          {
91              return TestsToRun.this.isFinished();
92          }
93  
94          @Override
95          protected boolean doHasNext()
96          {
97              return it.hasNext();
98          }
99  
100         @Override
101         protected Class<?> doNext()
102         {
103             Class<?> nextTest = it.next();
104             TestsToRun.this.iteratedCount = max( ++iteratedCount, TestsToRun.this.iteratedCount );
105             return nextTest;
106         }
107 
108         @Override
109         protected void doRemove()
110         {
111         }
112 
113         @Override
114         public void remove()
115         {
116             throw new UnsupportedOperationException( "unsupported remove" );
117         }
118     }
119 
120     public final void markTestSetFinished()
121     {
122         finished = true;
123     }
124 
125     public final boolean isFinished()
126     {
127         return finished;
128     }
129 
130     public String toString()
131     {
132         StringBuilder sb = new StringBuilder( "TestsToRun: [" );
133         for ( Class<?> clazz : this )
134         {
135             sb.append( ' ' )
136                     .append( clazz.getName() );
137         }
138 
139         sb.append( ']' );
140         return sb.toString();
141     }
142 
143     public boolean containsAtLeast( int atLeast )
144     {
145         return containsAtLeast( iterator(), atLeast );
146     }
147 
148     private boolean containsAtLeast( Iterator<Class<?>> it, int atLeast )
149     {
150         for ( int i = 0; i < atLeast; i++ )
151         {
152             if ( !it.hasNext() )
153             {
154                 return false;
155             }
156 
157             it.next();
158         }
159 
160         return true;
161     }
162 
163     public boolean containsExactly( int items )
164     {
165         Iterator<Class<?>> it = iterator();
166         return containsAtLeast( it, items ) && !it.hasNext();
167     }
168 
169     /**
170      * @return {@code true}, if the classes may be read eagerly. {@code false},
171      *         if the classes must only be read lazy.
172      */
173     public boolean allowEagerReading()
174     {
175         return true;
176     }
177 
178     public Class<?>[] getLocatedClasses()
179     {
180         if ( !allowEagerReading() )
181         {
182             throw new IllegalStateException( "Cannot eagerly read" );
183         }
184         Collection<Class<?>> result = new ArrayList<Class<?>>();
185         for ( Class<?> clazz : this )
186         {
187             result.add( clazz );
188         }
189         return result.toArray( new Class<?>[result.size()] );
190     }
191 
192     /**
193      * Get test class which matches className
194      *
195      * @param className string used to find the test class
196      * @return Class object with the matching name, null if could not find a class with the matching name
197      */
198     public Class<?> getClassByName( String className )
199     {
200         for ( Class<?> clazz : this )
201         {
202             if ( clazz.getName().equals( className ) )
203             {
204                 return clazz;
205             }
206         }
207         return null;
208     }
209 
210     /**
211      * @return snapshot of tests upon constructs of internal iterator.
212      * Therefore weakly consistent while {@link TestsToRun#iterator()} is being iterated.
213      */
214     private Iterator<Class<?>> newWeakIterator()
215     {
216         final Iterator<Class<?>> it = locatedClasses.subList( 0, iteratedCount ).iterator();
217         return new CloseableIterator<Class<?>>()
218         {
219             @Override
220             protected boolean isClosed()
221             {
222                 return TestsToRun.this.isFinished();
223             }
224 
225             @Override
226             protected boolean doHasNext()
227             {
228                 return it.hasNext();
229             }
230 
231             @Override
232             protected Class<?> doNext()
233             {
234                 return it.next();
235             }
236 
237             @Override
238             protected void doRemove()
239             {
240             }
241 
242             @Override
243             public void remove()
244             {
245                 throw new UnsupportedOperationException( "unsupported remove" );
246             }
247         };
248     }
249 }