diff --git a/.travis.yml b/.travis.yml index 8b37156..7ccf9e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ sudo: false language: java -dist: precise +dist: trusty jdk: - oraclejdk8 diff --git a/src/org/atoum/intellij/plugin/atoum/AtoumIconProvider.java b/src/org/atoum/intellij/plugin/atoum/AtoumIconProvider.java index 949a644..58516ce 100644 --- a/src/org/atoum/intellij/plugin/atoum/AtoumIconProvider.java +++ b/src/org/atoum/intellij/plugin/atoum/AtoumIconProvider.java @@ -7,15 +7,13 @@ import com.jetbrains.php.lang.psi.PhpFile; import javax.swing.Icon; -import com.jetbrains.php.lang.psi.elements.PhpClass; import org.jetbrains.annotations.NotNull; public class AtoumIconProvider extends IconProvider { public Icon getIcon(@NotNull PsiElement element, @IconFlags int flags) { if (element instanceof PhpFile) { - PhpClass firstClass = Utils.getFirstClassFromFile((PhpFile) element); - if (firstClass != null && Utils.isClassAtoumTest(firstClass)) { + if (Utils.getFirstTestClassFromFile((PhpFile) element) != null) { return Icons.ATOUM_FILE; } } diff --git a/src/org/atoum/intellij/plugin/atoum/Utils.java b/src/org/atoum/intellij/plugin/atoum/Utils.java index 1333e8d..d4bbbf6 100644 --- a/src/org/atoum/intellij/plugin/atoum/Utils.java +++ b/src/org/atoum/intellij/plugin/atoum/Utils.java @@ -5,6 +5,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.php.PhpIndex; import com.jetbrains.php.lang.psi.PhpFile; +import com.jetbrains.php.lang.psi.elements.ClassReference; import com.jetbrains.php.lang.psi.elements.PhpClass; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; @@ -17,7 +18,38 @@ public class Utils { public static Boolean isClassAtoumTest(PhpClass checkedClass) { - return checkedClass.getNamespaceName().toLowerCase().contains(getTestsNamespaceSuffix().toLowerCase()); + // First, we check if the class is in the units tests namespace + if (!checkedClass.getNamespaceName().toLowerCase().contains(getTestsNamespaceSuffix().toLowerCase())) { + return false; + } + + if (checkedClass.isAbstract() || checkedClass.isInterface()) { + return false; + } + + // We also check if the class extends atoum + PhpClass loopCheckedClass = checkedClass; + while (loopCheckedClass.getSuperClass() != null) { + PhpClass parent = loopCheckedClass.getSuperClass(); + if (parent.getFQN().equals("\\atoum")) { + return true; + } + loopCheckedClass = parent; + } + + // We try with another method to check, if the project does not have atoum/stubs + do { + List extendsList = checkedClass.getExtendsList().getReferenceElements(); + if (extendsList.iterator().hasNext()) { + ClassReference ref = extendsList.iterator().next(); + if (ref.getFQN() != null && ref.getFQN().equals("\\atoum")) { + return true; + } + } + checkedClass = checkedClass.getSuperClass(); + } while (checkedClass != null); + + return false; } @Nullable @@ -98,4 +130,17 @@ public static PhpClass getFirstClassFromFile(PhpFile phpFile) { Collection phpClasses = PsiTreeUtil.collectElementsOfType(phpFile, PhpClass.class); return phpClasses.size() == 0 ? null : phpClasses.iterator().next(); } + + @Nullable + public static PhpClass getFirstTestClassFromFile(PhpFile phpFile) { + Collection phpClasses = PsiTreeUtil.collectElementsOfType(phpFile, PhpClass.class); + + for (PhpClass phpClass:phpClasses) { + if (isClassAtoumTest(phpClass)) { + return phpClass; + } + } + + return null; + } } diff --git a/src/org/atoum/intellij/plugin/atoum/actions/Run.java b/src/org/atoum/intellij/plugin/atoum/actions/Run.java index 2104e29..1401eea 100644 --- a/src/org/atoum/intellij/plugin/atoum/actions/Run.java +++ b/src/org/atoum/intellij/plugin/atoum/actions/Run.java @@ -126,16 +126,21 @@ protected PhpClass getCurrentTestClass(AnActionEvent e) { } PhpFile phpFile = ((PhpFile) psiFile); - PhpClass currentClass = Utils.getFirstClassFromFile(phpFile); - if (null == currentClass) { - return null; + PhpClass currentClass = Utils.getFirstTestClassFromFile(phpFile); + + if (currentClass != null) { + // The file contains a test class, use it + return currentClass; } - if (!Utils.isClassAtoumTest(currentClass)) { - return Utils.locateTestClass(e.getProject(), currentClass); + // There is no tests in this file, maybe this is a php class + currentClass = Utils.getFirstClassFromFile(phpFile); + if (null == currentClass) { + return null; } - return currentClass; + // This is a PHP class, find its test + return Utils.locateTestClass(e.getProject(), currentClass); } @Nullable diff --git a/src/org/atoum/intellij/plugin/atoum/actions/SwitchContext.java b/src/org/atoum/intellij/plugin/atoum/actions/SwitchContext.java index f0324fd..f6f76b7 100644 --- a/src/org/atoum/intellij/plugin/atoum/actions/SwitchContext.java +++ b/src/org/atoum/intellij/plugin/atoum/actions/SwitchContext.java @@ -57,15 +57,18 @@ protected PhpClass getSwitchClass(final AnActionEvent e) { @Nullable protected PhpClass getSwitchClass(Project project, PhpFile phpFile) { - PhpClass currentClass = Utils.getFirstClassFromFile(phpFile); - if (null == currentClass) { - return null; + PhpClass currentClass = Utils.getFirstTestClassFromFile(phpFile); + if (currentClass != null) { + // The file contains a test class, switch to the tested class + return Utils.locateTestedClass(project, currentClass); } - if (Utils.isClassAtoumTest(currentClass)) { - return Utils.locateTestedClass(project, currentClass); + currentClass = Utils.getFirstClassFromFile(phpFile); + if (currentClass != null) { + // The file contains a class, switch to the test class if it exists + return Utils.locateTestClass(project, currentClass); } - return Utils.locateTestClass(project, currentClass); + return null; } } diff --git a/tests/org/atoum/intellij/plugin/atoum/tests/UtilsTest.java b/tests/org/atoum/intellij/plugin/atoum/tests/UtilsTest.java index 32c52c1..2d03747 100644 --- a/tests/org/atoum/intellij/plugin/atoum/tests/UtilsTest.java +++ b/tests/org/atoum/intellij/plugin/atoum/tests/UtilsTest.java @@ -1,6 +1,5 @@ package org.atoum.intellij.plugin.atoum.tests; -import com.intellij.psi.PsiFile; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.jetbrains.php.lang.psi.PhpFile; import com.jetbrains.php.lang.psi.elements.PhpClass; @@ -9,25 +8,96 @@ import java.io.File; public class UtilsTest extends LightCodeInsightFixtureTestCase { - @Override - public void setUp() throws Exception { - super.setUp(); - - // Add Fixtures - myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("TestA.php")); - } - protected String getTestDataPath() { return new File(this.getClass().getResource("fixtures").getFile()).getAbsolutePath(); } - public void testGetFirstClassFromFile() throws Exception { - PsiFile psiElement = myFixture.getFile(); - PhpClass phpClass = Utils.getFirstClassFromFile((PhpFile) psiElement); + public void testGetFirstClassFromFile() { + PhpClass phpClass = Utils.getFirstClassFromFile((PhpFile) myFixture.configureByFile( + "TestSimpleClass.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestSimpleClass", phpClass.getFQN()); + phpClass = Utils.getFirstClassFromFile((PhpFile) myFixture.configureByFile( + "TestMultipleClassNotFirst.php" + )); assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\AnotherClassDefinedBeforeTheTest", phpClass.getFQN()); + } + + public void testGetFirstTestClassFromFile() { + // Include stubs + myFixture.copyFileToProject("atoum.php"); - assertEquals("\\PhpStormPlugin\\tests\\units\\TestA", phpClass.getFQN()); + PhpClass phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestSimpleClass.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestSimpleClass", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestMultipleClassNotFirst.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestMultipleClassNotFirst", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestSimpleClassWithoutUse.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestSimpleClassWithoutUse", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestWithParentClass.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestWithParentClass", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestWrongExtends.php" + )); + assertNull(phpClass); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestWrongNamespace.php" + )); + assertNull(phpClass); } + public void testGetFirstTestClassFromFileWithoutStubs() { + PhpClass phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestSimpleClass.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestSimpleClass", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestMultipleClassNotFirst.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestMultipleClassNotFirst", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestSimpleClassWithoutUse.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestSimpleClassWithoutUse", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestWithParentClass.php" + )); + assertNotNull(phpClass); + assertEquals("\\PhpStormPlugin\\tests\\units\\TestWithParentClass", phpClass.getFQN()); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestWrongExtends.php" + )); + assertNull(phpClass); + + phpClass = Utils.getFirstTestClassFromFile((PhpFile) myFixture.configureByFile( + "TestWrongNamespace.php" + )); + assertNull(phpClass); + } } diff --git a/tests/org/atoum/intellij/plugin/atoum/tests/fixtures/TestMultipleClassNotFirst.php b/tests/org/atoum/intellij/plugin/atoum/tests/fixtures/TestMultipleClassNotFirst.php new file mode 100644 index 0000000..69536c5 --- /dev/null +++ b/tests/org/atoum/intellij/plugin/atoum/tests/fixtures/TestMultipleClassNotFirst.php @@ -0,0 +1,15 @@ +