Merge branch 'master' of git@git.labs.intellij.net:idea/community
[idea/community.git] / platform / testFramework / src / com / intellij / TestCaseLoader.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Created by IntelliJ IDEA.
19  * User: mike
20  * Date: Jun 7, 2002
21  * Time: 8:30:35 PM
22  * To change template for new class use
23  * Code Style | Class Templates options (Tools | IDE Options).
24  */
25 package com.intellij;
26
27 import com.intellij.idea.Bombed;
28 import com.intellij.openapi.util.Comparing;
29 import com.intellij.openapi.util.text.StringUtil;
30 import com.intellij.testFramework.PlatformTestUtil;
31 import com.intellij.testFramework.TestRunnerUtil;
32 import junit.framework.Test;
33 import junit.framework.TestCase;
34 import junit.framework.TestSuite;
35
36 import java.io.*;
37 import java.lang.reflect.Method;
38 import java.lang.reflect.Modifier;
39 import java.util.*;
40
41 @SuppressWarnings({"HardCodedStringLiteral"})
42 public class TestCaseLoader {
43   private final List<Class> myClassList = new ArrayList<Class>();
44   private final TestClassesFilter myTestClassesFilter;
45   private final String myTestGroupName;
46   private final Set<String> blockedTests = new HashSet<String>();
47
48   public TestCaseLoader(String classFilterName) {
49     String preconfiguredTestGroup = System.getProperty("idea.test.group");
50     if (StringUtil.isEmpty(preconfiguredTestGroup)) {
51       myTestGroupName = TestClassesFilter.ALL_EXCLUDE_DEFINED;
52     } else {
53       myTestGroupName = preconfiguredTestGroup.trim();
54     }
55     InputStream excludedStream = getClass().getClassLoader().getResourceAsStream(classFilterName);
56     if (excludedStream != null) {
57       try {
58         myTestClassesFilter = TestClassesFilter.createOn(new InputStreamReader(excludedStream));
59       }
60       finally {
61         try {
62           excludedStream.close();
63         }
64         catch (IOException e) {
65           e.printStackTrace();
66         }
67       }
68     }
69     else {
70       String patterns = System.getProperty("idea.test.patterns");
71       if (patterns != null) {
72         myTestClassesFilter = new TestClassesFilter(StringUtil.split(patterns, ";"));
73       }
74       else {
75         myTestClassesFilter = TestClassesFilter.EMPTY_CLASSES_FILTER;
76       }
77     }
78
79     if (Comparing.equal(System.getProperty("idea.fast.only"), "true")) {
80       BufferedReader reader =
81               new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("tests/slowTests.txt")));
82       try {
83         String testName;
84         while ((testName = reader.readLine()) != null) {
85           blockedTests.add(testName);
86         }
87       }
88       catch (IOException e) {
89         // No luck
90       } finally {
91         try {
92           reader.close();
93         }
94         catch (IOException e) {
95           // ignore
96         }
97       }
98     }
99     System.out.println("Using test group: [" + (myTestGroupName == null ? "" :  myTestGroupName) + "]");
100   }
101
102   /*
103    * Adds <code>testCaseClass</code> to the list of classdes
104    * if the class is a test case we wish to load. Calls
105    * <code>shouldLoadTestCase ()</code> to determine that.
106    */
107   void addClassIfTestCase(final Class testCaseClass) {
108     if (shouldAddTestCase(testCaseClass)) {
109       myClassList.add(testCaseClass);
110     }
111   }
112
113   /**
114    * Determine if we should load this test case.
115    */
116   private boolean shouldAddTestCase(final Class testCaseClass) {
117     if ((testCaseClass.getModifiers() & Modifier.ABSTRACT) != 0) return false;
118     if (shouldExcludeTestClass(testCaseClass)) return false;
119
120     if (TestCase.class.isAssignableFrom(testCaseClass) || TestSuite.class.isAssignableFrom(testCaseClass)) {
121       return true;
122     }
123     try {
124       final Method suiteMethod = testCaseClass.getMethod("suite");
125       if (Test.class.isAssignableFrom(suiteMethod.getReturnType()) && (suiteMethod.getModifiers() & Modifier.STATIC) != 0) {
126         //System.out.println("testCaseClass = " + testCaseClass);
127         return true;
128       }
129     } catch (NoSuchMethodException e) { }
130
131     return TestRunnerUtil.isJUnit4TestClass(testCaseClass);
132   }
133
134   /*
135    * Determine if we should exclude this test case.
136    */
137   private boolean shouldExcludeTestClass(Class testCaseClass) {
138     return !myTestClassesFilter.matches(testCaseClass.getName(), myTestGroupName) || isBombed(testCaseClass) || blockedTests.contains(testCaseClass.getName());
139   }
140
141   public static boolean isBombed(final Method method) {
142     final Bombed bombedAnnotation = method.getAnnotation(Bombed.class);
143     if (bombedAnnotation == null) return false;
144     if (PlatformTestUtil.isRotten(bombedAnnotation)) {
145       String message = "Disarm the stale bomb for '" + method + "' in class '" + method.getDeclaringClass() + "'";
146       System.err.println(message);
147       //Assert.fail(message);
148     }
149     return !PlatformTestUtil.bombExplodes(bombedAnnotation);
150   }
151
152   public static boolean isBombed(final Class<?> testCaseClass) {
153     final Bombed bombedAnnotation = testCaseClass.getAnnotation(Bombed.class);
154     if (bombedAnnotation == null) return false;
155     if (PlatformTestUtil.isRotten(bombedAnnotation)) {
156       String message = "Disarm the stale bomb for '" + testCaseClass + "'";
157       System.err.println(message);
158      // Assert.fail(message);
159     }
160     return !PlatformTestUtil.bombExplodes(bombedAnnotation);
161   }
162
163   public void loadTestCases(final Collection<String> classNamesIterator) {
164     for (String className : classNamesIterator) {
165       try {
166         Class candidateClass = Class.forName(className);
167         addClassIfTestCase(candidateClass);
168       }
169       catch (UnsatisfiedLinkError e) {
170         //ignore
171       }
172       catch (ClassNotFoundException e) {
173         e.printStackTrace();
174         System.err.println("Cannot load class: " + className + " " + e.getMessage());
175       }
176       catch (NoClassDefFoundError e) {
177         e.printStackTrace();
178         System.err.println("Cannot load class that " + className + " is dependant on");
179       }
180       catch (ExceptionInInitializerError e) {
181         e.printStackTrace();
182         e.getException().printStackTrace();
183         System.err.println("Cannot load class: " + className + " " + e.getException().getMessage());
184       }
185     }
186   }
187   
188   private static final List<String> ourRanklist = getTeamCityRankList();
189   private static List<String> getTeamCityRankList() {
190     final String filepath = System.getProperty("teamcity.tests.recentlyFailedTests.file", null);
191     if (filepath == null) {
192       return Collections.emptyList();
193     }
194
195     List<String> result = new ArrayList<String>();
196     try {
197       BufferedReader reader = new BufferedReader(new FileReader(filepath));
198       do {
199         final String classname = reader.readLine();
200         if (classname == null) break;
201         result.add(classname);
202       }
203       while (true);
204       return result;
205     }
206     catch (IOException e) {
207       return Collections.emptyList();
208     }
209   }
210
211   private static int getRank(Class aClass) {
212     final String name = aClass.getName();
213     if (ourRanklist.contains(name)) {
214       return ourRanklist.indexOf(name);
215     }
216     return Integer.MAX_VALUE;
217   }
218
219   public List<Class> getClasses() {
220     List<Class> result = new ArrayList<Class>(myClassList);
221
222     if (!ourRanklist.isEmpty()) {
223       Collections.sort(result, new Comparator<Class>() {
224         public int compare(final Class o1, final Class o2) {
225           return getRank(o1) - getRank(o2);
226         }
227       });
228     }
229
230     return result;
231   }
232
233 }