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
44   /** Holds name of JVM property that is assumed to define target test group name. */
45   private static final String TARGET_TEST_GROUP = "idea.test.group";
46
47   /** Holds name of JVM property that is assumed to define filtering rules for test classes. */
48   private static final String TARGET_TEST_PATTERNS = "idea.test.patterns";
49
50   /** Holds name of JVM property that is assumed to determine if only 'fast' tests should be executed. */
51   private static final String FAST_TESTS_ONLY_FLAG = "idea.fast.only";
52
53   private final List<Class> myClassList = new ArrayList<Class>();
54   private final TestClassesFilter myTestClassesFilter;
55   private final String myTestGroupName;
56   private final Set<String> blockedTests = new HashSet<String>();
57
58   public TestCaseLoader(String classFilterName) {
59     InputStream excludedStream = getClass().getClassLoader().getResourceAsStream(classFilterName);
60     myTestGroupName = System.getProperty(TARGET_TEST_GROUP);
61     if (excludedStream != null) {
62       try {
63         myTestClassesFilter = TestClassesFilter.createOn(new InputStreamReader(excludedStream));
64       }
65       finally {
66         try {
67           excludedStream.close();
68         }
69         catch (IOException e) {
70           e.printStackTrace();
71         }
72       }
73     }
74     else {
75       String patterns = System.getProperty(TARGET_TEST_PATTERNS);
76       if (patterns != null) {
77         myTestClassesFilter = new TestClassesFilter(StringUtil.split(patterns, ";"));
78       }
79       else {
80         myTestClassesFilter = TestClassesFilter.EMPTY_CLASSES_FILTER;
81       }
82     }
83
84     if (Comparing.equal(System.getProperty(FAST_TESTS_ONLY_FLAG), "true")) {
85       BufferedReader reader =
86               new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("tests/slowTests.txt")));
87       try {
88         String testName;
89         while ((testName = reader.readLine()) != null) {
90           blockedTests.add(testName);
91         }
92       }
93       catch (IOException e) {
94         // No luck
95       } finally {
96         try {
97           reader.close();
98         }
99         catch (IOException e) {
100           // ignore
101         }
102       }
103     }
104     System.out.println("Using test group: [" + (myTestGroupName == null ? "" :  myTestGroupName) + "]");
105   }
106
107   /*
108    * Adds <code>testCaseClass</code> to the list of classdes
109    * if the class is a test case we wish to load. Calls
110    * <code>shouldLoadTestCase ()</code> to determine that.
111    */
112   void addClassIfTestCase(final Class testCaseClass) {
113     if (shouldAddTestCase(testCaseClass)) {
114       myClassList.add(testCaseClass);
115     }
116   }
117
118   /**
119    * Determine if we should load this test case.
120    */
121   private boolean shouldAddTestCase(final Class testCaseClass) {
122     if ((testCaseClass.getModifiers() & Modifier.ABSTRACT) != 0) return false;
123     if (shouldExcludeTestClass(testCaseClass)) return false;
124
125     if (TestCase.class.isAssignableFrom(testCaseClass) || TestSuite.class.isAssignableFrom(testCaseClass)) {
126       return true;
127     }
128     try {
129       final Method suiteMethod = testCaseClass.getMethod("suite");
130       if (Test.class.isAssignableFrom(suiteMethod.getReturnType()) && (suiteMethod.getModifiers() & Modifier.STATIC) != 0) {
131         //System.out.println("testCaseClass = " + testCaseClass);
132         return true;
133       }
134     } catch (NoSuchMethodException e) { }
135
136     return TestRunnerUtil.isJUnit4TestClass(testCaseClass);
137   }
138
139   /*
140    * Determine if we should exclude this test case.
141    */
142   private boolean shouldExcludeTestClass(Class testCaseClass) {
143     if (myTestGroupName != null && !myTestClassesFilter.matches(testCaseClass.getName(), myTestGroupName)) {
144       return true;
145     }
146     return isBombed(testCaseClass) || blockedTests.contains(testCaseClass.getName());
147   }
148
149   public static boolean isBombed(final Method method) {
150     final Bombed bombedAnnotation = method.getAnnotation(Bombed.class);
151     if (bombedAnnotation == null) return false;
152     if (PlatformTestUtil.isRotten(bombedAnnotation)) {
153       String message = "Disarm the stale bomb for '" + method + "' in class '" + method.getDeclaringClass() + "'";
154       System.err.println(message);
155       //Assert.fail(message);
156     }
157     return !PlatformTestUtil.bombExplodes(bombedAnnotation);
158   }
159
160   public static boolean isBombed(final Class<?> testCaseClass) {
161     final Bombed bombedAnnotation = testCaseClass.getAnnotation(Bombed.class);
162     if (bombedAnnotation == null) return false;
163     if (PlatformTestUtil.isRotten(bombedAnnotation)) {
164       String message = "Disarm the stale bomb for '" + testCaseClass + "'";
165       System.err.println(message);
166      // Assert.fail(message);
167     }
168     return !PlatformTestUtil.bombExplodes(bombedAnnotation);
169   }
170
171   public void loadTestCases(final Collection<String> classNamesIterator) {
172     for (String className : classNamesIterator) {
173       try {
174         Class candidateClass = Class.forName(className);
175         addClassIfTestCase(candidateClass);
176       }
177       catch (UnsatisfiedLinkError e) {
178         //ignore
179       }
180       catch (ClassNotFoundException e) {
181         e.printStackTrace();
182         System.err.println("Cannot load class: " + className + " " + e.getMessage());
183       }
184       catch (NoClassDefFoundError e) {
185         e.printStackTrace();
186         System.err.println("Cannot load class that " + className + " is dependant on");
187       }
188       catch (ExceptionInInitializerError e) {
189         e.printStackTrace();
190         e.getException().printStackTrace();
191         System.err.println("Cannot load class: " + className + " " + e.getException().getMessage());
192       }
193     }
194   }
195   
196   private static final List<String> ourRanklist = getTeamCityRankList();
197   private static List<String> getTeamCityRankList() {
198     final String filepath = System.getProperty("teamcity.tests.recentlyFailedTests.file", null);
199     if (filepath == null) {
200       return Collections.emptyList();
201     }
202
203     List<String> result = new ArrayList<String>();
204     try {
205       BufferedReader reader = new BufferedReader(new FileReader(filepath));
206       do {
207         final String classname = reader.readLine();
208         if (classname == null) break;
209         result.add(classname);
210       }
211       while (true);
212       return result;
213     }
214     catch (IOException e) {
215       return Collections.emptyList();
216     }
217   }
218
219   private static int getRank(Class aClass) {
220     final String name = aClass.getName();
221     if (ourRanklist.contains(name)) {
222       return ourRanklist.indexOf(name);
223     }
224     return Integer.MAX_VALUE;
225   }
226
227   public List<Class> getClasses() {
228     List<Class> result = new ArrayList<Class>(myClassList);
229
230     if (!ourRanklist.isEmpty()) {
231       Collections.sort(result, new Comparator<Class>() {
232         public int compare(final Class o1, final Class o2) {
233           return getRank(o1) - getRank(o2);
234         }
235       });
236     }
237
238     return result;
239   }
240
241 }