1 33 34 package edu.rice.cs.drjava.model.junit; 35 36 import java.io.File ; 37 import java.io.IOException ; 38 39 import java.util.List ; 40 import java.util.LinkedList ; 41 import java.util.ArrayList ; 42 import java.util.Arrays ; 43 import java.util.HashMap ; 44 import java.util.HashSet ; 45 import java.util.Set ; 46 47 import javax.swing.JOptionPane ; 48 import javax.swing.SwingUtilities ; 49 50 import edu.rice.cs.drjava.DrJava; 51 import edu.rice.cs.drjava.model.GlobalModel; 52 import edu.rice.cs.drjava.model.FileMovedException; 53 import edu.rice.cs.drjava.model.OpenDefinitionsDocument; 54 import edu.rice.cs.drjava.model.repl.newjvm.MainJVM; 55 import edu.rice.cs.drjava.model.compiler.CompilerModel; 56 import edu.rice.cs.drjava.model.compiler.CompilerListener; 57 import edu.rice.cs.drjava.model.compiler.DummyCompilerListener; 58 import edu.rice.cs.drjava.model.definitions.InvalidPackageException; 59 60 import edu.rice.cs.plt.io.IOUtil; 62 import edu.rice.cs.util.ClassPathVector; 63 import edu.rice.cs.util.UnexpectedException; 64 import edu.rice.cs.util.classloader.ClassFileError; 65 import edu.rice.cs.util.text.SwingDocument; 66 import edu.rice.cs.util.swing.Utilities; 67 68 import org.apache.bcel.classfile.*; 69 70 import static edu.rice.cs.drjava.config.OptionConstants.*; 71 72 75 public class DefaultJUnitModel implements JUnitModel, JUnitModelCallback { 76 77 78 private final JUnitEventNotifier _notifier = new JUnitEventNotifier(); 79 80 83 private final MainJVM _jvm; 84 85 88 private final CompilerModel _compilerModel; 89 90 91 private final GlobalModel _model; 92 93 94 private volatile JUnitErrorModel _junitErrorModel; 95 96 97 private volatile boolean _testInProgress = false; 98 99 100 private boolean _forceTestSuffix = false; 101 102 103 private final SwingDocument _junitDoc = new SwingDocument(); 104 105 110 public DefaultJUnitModel(MainJVM jvm, CompilerModel compilerModel, GlobalModel model) { 111 _jvm = jvm; 112 _compilerModel = compilerModel; 113 _model = model; 114 _junitErrorModel = new JUnitErrorModel(new JUnitError[0], _model, false); 115 } 116 117 119 public void setForceTestSuffix(boolean b) { _forceTestSuffix = b; } 120 121 123 public boolean isTestInProgress() { return _testInProgress; } 124 125 127 130 public void addListener(JUnitListener listener) { _notifier.addListener(listener); } 131 132 136 public void removeListener(JUnitListener listener) { _notifier.removeListener(listener); } 137 138 139 public void removeAllListeners() { _notifier.removeAllListeners(); } 140 141 142 143 145 146 public SwingDocument getJUnitDocument() { return _junitDoc; } 147 148 151 public void junitAll() { junitDocs(_model.getOpenDefinitionsDocuments()); } 152 153 157 public void junitProject() { 158 LinkedList <OpenDefinitionsDocument> lod = new LinkedList <OpenDefinitionsDocument>(); 159 160 for (OpenDefinitionsDocument doc : _model.getOpenDefinitionsDocuments()) { 161 if (doc.inProjectPath()) lod.add(doc); 162 } 163 junitDocs(lod); 164 } 165 166 171 public void junitClasses(List <String > qualifiedClassnames, List <File > files) { 172 Utilities.showDebug("junitClasses(" + qualifiedClassnames + ", " + files); 173 synchronized(_compilerModel.getCompilerLock()) { 174 175 if (_testInProgress) return; 177 178 List <String > testClasses; 179 try { testClasses = _jvm.findTestClasses(qualifiedClassnames, files); } 180 catch(IOException e) { throw new UnexpectedException(e); } 181 182 184 if (testClasses.isEmpty()) { 185 nonTestCase(true); 186 return; 187 } 188 _notifier.junitClassesStarted(); 189 try { _jvm.runTestSuite(); } 190 catch(Throwable t) { 191 _notifier.junitEnded(); 193 _testInProgress = false; 194 throw new UnexpectedException(t); 195 } 196 } 197 } 198 199 public void junitDocs(List <OpenDefinitionsDocument> lod) { junitOpenDefDocs(lod, true); } 200 201 202 public void junit(OpenDefinitionsDocument doc) throws ClassNotFoundException , IOException { 203 File testFile; 205 try { 206 testFile = doc.getFile(); 207 if (testFile == null) { nonTestCase(false); 209 return; 210 } 211 } 212 catch(FileMovedException fme) { } 213 214 LinkedList <OpenDefinitionsDocument> lod = new LinkedList <OpenDefinitionsDocument>(); 215 lod.add(doc); 216 junitOpenDefDocs(lod, false); 217 } 218 219 221 private void junitOpenDefDocs(final List <OpenDefinitionsDocument> lod, final boolean allTests) { 222 224 226 if (_testInProgress) return; 228 229 _junitErrorModel = new JUnitErrorModel(new JUnitError[0], null, false); 231 232 235 237 239 if (_model.hasOutOfSyncDocuments() || _model.hasModifiedDocuments()) { 240 243 245 CompilerListener testAfterCompile = new DummyCompilerListener() { 246 @Override public void compileEnded(File workDir, List <? extends File > excludedFiles) { 247 final CompilerListener listenerThis = this; 248 try { 249 if (_model.hasOutOfSyncDocuments() || _model.getNumCompErrors() > 0) { 250 if (! Utilities.TEST_MODE) 251 JOptionPane.showMessageDialog(null, "All open files must be compiled before running a unit test", 252 "Must Compile All Before Testing", JOptionPane.ERROR_MESSAGE); 253 nonTestCase(allTests); 254 return; 255 } 256 _rawJUnitOpenDefDocs(lod, allTests); 257 } 258 finally { SwingUtilities.invokeLater(new Runnable () { 260 public void run() { _compilerModel.removeListener(listenerThis); } 261 }); 262 } 263 } 264 }; 265 266 _notifier.compileBeforeJUnit(testAfterCompile); 268 } 269 270 else _rawJUnitOpenDefDocs(lod, allTests); 271 } 272 273 275 private void _rawJUnitOpenDefDocs(List <OpenDefinitionsDocument> lod, boolean allTests) { 276 277 File buildDir = _model.getBuildDirectory(); 278 280 281 HashSet <String > openDocFiles = new HashSet <String >(); 282 283 286 HashMap <File , File > classDirsAndRoots = new HashMap <File , File >(); 287 288 291 for (OpenDefinitionsDocument doc: lod) { 292 if (doc.isSourceFile()) { try { 294 File sourceRoot = doc.getSourceRoot(); 296 openDocFiles.add(doc.getCanonicalPath()); 298 299 String packagePath = doc.getPackageName().replace('.', File.separatorChar); 300 301 303 File buildRoot = (buildDir == null) ? sourceRoot: buildDir; 304 305 File classFileDir = new File (IOUtil.attemptCanonicalFile(buildRoot), packagePath); 306 307 File sourceDir = 308 (buildDir == null) ? classFileDir : new File (IOUtil.attemptCanonicalFile(sourceRoot), packagePath); 309 310 if (! classDirsAndRoots.containsKey(classFileDir)) { 311 classDirsAndRoots.put(classFileDir, sourceDir); 312 } 315 } 316 catch (InvalidPackageException e) { } 317 } 318 } 319 320 322 323 Set <File > classDirs = classDirsAndRoots.keySet(); 324 325 327 328 ArrayList <String > classNames = new ArrayList <String >(); 329 330 331 ArrayList <File > files = new ArrayList <File >(); 332 333 334 boolean isProject = _model.isProjectActive(); 335 336 try { 337 for (File dir: classDirs) { 340 File [] listing = dir.listFiles(); 341 342 344 if (listing != null) { for (File entry : listing) { 346 347 349 350 String name = entry.getName(); 351 if (! name.endsWith(".class")) continue; 352 353 354 if (_forceTestSuffix) { 355 String noExtName = name.substring(0, name.length() - 6); int indexOfLastDot = noExtName.lastIndexOf('.'); 357 String simpleClassName = noExtName.substring(indexOfLastDot + 1); 358 if (isProject && ! simpleClassName.endsWith("Test")) continue; 360 } 361 362 364 365 if (! entry.isFile()) continue; 366 367 370 try { 371 JavaClass clazz = new ClassParser(entry.getCanonicalPath()).parse(); 372 String className = clazz.getClassName(); int indexOfDot = className.lastIndexOf('.'); 375 376 File rootDir = classDirsAndRoots.get(dir); 377 378 379 String javaSourceFileName = rootDir.getCanonicalPath() + File.separator + clazz.getSourceFileName(); 380 382 383 int indexOfExtDot = javaSourceFileName.lastIndexOf('.'); 384 if (indexOfExtDot == -1) continue; 388 389 String strippedName = javaSourceFileName.substring(0, indexOfExtDot); 390 392 String sourceFileName; 393 394 if (openDocFiles.contains(javaSourceFileName)) sourceFileName = javaSourceFileName; 395 else if (openDocFiles.contains(strippedName + ".dj0")) sourceFileName = strippedName + ".dj0"; 396 else if (openDocFiles.contains(strippedName + ".dj1")) sourceFileName = strippedName + ".dj1"; 397 else if (openDocFiles.contains(strippedName + ".dj2")) sourceFileName = strippedName + ".dj2"; 398 else continue; 400 File sourceFile = new File (sourceFileName); 401 classNames.add(className); 402 files.add(sourceFile); 403 } 405 catch(IOException e) { } 406 catch(ClassFormatException e) { } 407 } 408 } 409 } 410 } 411 catch(Throwable t) { 412 throw new UnexpectedException(t); 414 } 415 419 422 synchronized(_compilerModel.getCompilerLock()) { 423 424 List <String > tests; 425 try { tests = _jvm.findTestClasses(classNames, files); } 426 catch(IOException e) { throw new UnexpectedException(e); } 427 428 if (tests == null || tests.isEmpty()) { 429 nonTestCase(allTests); 431 return; 432 } 433 434 try { 435 436 _notifier.junitStarted(); _jvm.runTestSuite(); 439 440 } 441 catch(Throwable t) { 442 _notifier.junitEnded(); _testInProgress = false; 446 throw new UnexpectedException(t); 447 } 448 } 449 } 450 451 453 455 456 public JUnitErrorModel getJUnitErrorModel() { return _junitErrorModel; } 457 458 459 public void resetJUnitErrors() { 460 _junitErrorModel = new JUnitErrorModel(new JUnitError[0], _model, false); 461 } 462 463 465 468 public void nonTestCase(final boolean isTestAll) { 469 _notifier.nonTestCase(isTestAll); 473 _testInProgress = false; 474 } 475 476 479 public void classFileError(ClassFileError e) { _notifier.classFileError(e); } 480 481 484 public void testSuiteStarted(final int numTests) { _notifier.junitSuiteStarted(numTests); } 485 486 489 public void testStarted(final String testName) { _notifier.junitTestStarted(testName); } 490 491 497 public void testEnded(final String testName, final boolean wasSuccessful, final boolean causedError) { 498 _notifier.junitTestEnded(testName, wasSuccessful, causedError); 499 } 500 501 504 public void testSuiteEnded(JUnitError[] errors) { 505 _junitErrorModel = new JUnitErrorModel(errors, _model, true); 507 _notifier.junitEnded(); 508 _testInProgress = false; 509 } 511 512 516 public File getFileForClassName(String className) { return _model.getSourceFile(className + ".java"); } 517 518 519 public ClassPathVector getClassPath() { return _jvm.getClassPath(); } 520 521 522 public void junitJVMReady() { 523 524 if (! _testInProgress) return; 525 JUnitError[] errors = new JUnitError[1]; 526 errors[0] = new JUnitError("Previous test suite was interrupted", true, ""); 527 _junitErrorModel = new JUnitErrorModel(errors, _model, true); 528 _notifier.junitEnded(); 529 _testInProgress = false; 530 } 531 } 532 | Popular Tags |