| /* |
| * Copyright 2017 The Bazel Authors. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.google.idea.blaze.clwb.run.test; |
| |
| import com.google.idea.blaze.base.command.BlazeFlags; |
| import com.google.idea.sdkcompat.cidr.CidrGoogleTestUtilAdapter; |
| import com.intellij.execution.Location; |
| import com.intellij.execution.PsiLocation; |
| import com.intellij.openapi.util.Couple; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.jetbrains.cidr.lang.psi.OCFile; |
| import com.jetbrains.cidr.lang.psi.OCFunctionDefinition; |
| import com.jetbrains.cidr.lang.psi.OCMacroCall; |
| import com.jetbrains.cidr.lang.psi.OCMacroCallArgument; |
| import com.jetbrains.cidr.lang.psi.OCStruct; |
| import com.jetbrains.cidr.lang.symbols.OCSymbol; |
| import com.jetbrains.cidr.lang.symbols.cpp.OCFunctionSymbol; |
| import com.jetbrains.cidr.lang.symbols.cpp.OCStructSymbol; |
| import com.jetbrains.cidr.lang.symbols.cpp.OCSymbolWithQualifiedName; |
| import java.util.Collection; |
| import java.util.List; |
| import javax.annotation.Nullable; |
| |
| /** A {@link PsiLocation} with corresponding gtest specification */ |
| public class GoogleTestLocation extends PsiLocation<PsiElement> { |
| |
| public final GoogleTestSpecification gtest; |
| @Nullable public final String testFilter; |
| |
| GoogleTestLocation(PsiElement psi, GoogleTestSpecification gtest) { |
| super(psi); |
| this.gtest = gtest; |
| this.testFilter = gtest.testFilter(); |
| } |
| |
| /** The raw test filter string with '--test_filter=' prepended, or null if there is no filter. */ |
| @Nullable |
| public String getTestFilterFlag() { |
| return testFilter != null ? BlazeFlags.TEST_FILTER + "=" + testFilter : null; |
| } |
| |
| @Nullable |
| public static GoogleTestLocation findGoogleTest(Location<?> location) { |
| if (location instanceof GoogleTestLocation) { |
| return (GoogleTestLocation) location; |
| } |
| return findGoogleTest(location.getPsiElement()); |
| } |
| |
| @Nullable |
| public static GoogleTestLocation findGoogleTest(PsiElement element) { |
| // Copied from on CidrGoogleTestRunConfigurationProducer::findTestObject. |
| // Precedence order (decreasing): class/function, macro, file |
| PsiElement parent = |
| PsiTreeUtil.getNonStrictParentOfType(element, OCFunctionDefinition.class, OCStruct.class); |
| |
| OCStructSymbol parentSymbol; |
| if (parent instanceof OCStruct |
| && ((parentSymbol = ((OCStruct) parent).getSymbol()) != null) |
| && CidrGoogleTestUtilAdapter.isGoogleTestClass(parentSymbol)) { |
| Couple<String> name = CidrGoogleTestUtilAdapter.extractGoogleTestName(parentSymbol); |
| if (name != null) { |
| return createFromClassAndMethod(parent, name.first, name.second); |
| } |
| String className = parentSymbol.getQualifiedName().getName(); |
| return createFromClass(parent, className); |
| } else if (parent instanceof OCFunctionDefinition) { |
| OCFunctionSymbol symbol = ((OCFunctionDefinition) parent).getSymbol(); |
| if (symbol != null) { |
| OCSymbolWithQualifiedName<?> resolvedOwner = symbol.getResolvedOwner(); |
| if (resolvedOwner != null) { |
| OCSymbol<?> owner = resolvedOwner.getDefinitionSymbol(); |
| if (owner instanceof OCStructSymbol |
| && CidrGoogleTestUtilAdapter.isGoogleTestClass((OCStructSymbol) owner)) { |
| OCStruct struct = (OCStruct) owner.locateDefinition(); |
| Couple<String> name = |
| CidrGoogleTestUtilAdapter.extractGoogleTestName((OCStructSymbol) owner); |
| if (name != null) { |
| return createFromClassAndMethod(struct, name.first, name.second); |
| } |
| return createFromClass(struct, ((OCStructSymbol) owner).getQualifiedName().getName()); |
| } |
| } |
| } |
| } |
| |
| // if we're still here, let's test for a macro and, as a last resort, a file. |
| parent = PsiTreeUtil.getNonStrictParentOfType(element, OCMacroCall.class, OCFile.class); |
| if (parent instanceof OCMacroCall) { |
| OCMacroCall gtestMacro = CidrGoogleTestUtilAdapter.findGoogleTestMacros(parent); |
| if (gtestMacro != null) { |
| List<OCMacroCallArgument> arguments = gtestMacro.getArguments(); |
| if (arguments.size() >= 2) { |
| OCMacroCallArgument suiteArg = arguments.get(0); |
| OCMacroCallArgument testArg = arguments.get(1); |
| |
| // if the element is the first argument of macro call, |
| // then running entire suite, otherwise only a current test |
| boolean isSuite = |
| isFirstArgument(PsiTreeUtil.getParentOfType(element, OCMacroCallArgument.class)) |
| || isFirstArgument(element.getPrevSibling()); |
| String suiteName = CidrGoogleTestUtilAdapter.extractArgumentValue(suiteArg); |
| String testName = CidrGoogleTestUtilAdapter.extractArgumentValue(testArg); |
| OCStructSymbol symbol = |
| CidrGoogleTestUtilAdapter.findGoogleTestSymbol( |
| element.getProject(), suiteName, testName); |
| if (symbol != null) { |
| OCStruct targetElement = (OCStruct) symbol.locateDefinition(); |
| return createFromClassAndMethod(targetElement, suiteName, isSuite ? null : testName); |
| } |
| } |
| } |
| Couple<String> suite = CidrGoogleTestUtilAdapter.extractFullSuiteNameFromMacro(parent); |
| if (suite != null) { |
| Collection<OCStructSymbol> res = |
| CidrGoogleTestUtilAdapter.findGoogleTestSymbolsForSuiteRandomly( |
| element.getProject(), suite.first, true); |
| if (res.size() != 0) { |
| OCStruct struct = (OCStruct) res.iterator().next().locateDefinition(); |
| GoogleTestSpecification gtest = |
| new GoogleTestSpecification.FromPsiElement(suite.first, null, suite.second, null); |
| return new GoogleTestLocation(struct, gtest); |
| } |
| } |
| } else if (parent instanceof OCFile) { |
| return createFromFile(parent); |
| } |
| return null; |
| } |
| |
| private static boolean isFirstArgument(@Nullable PsiElement element) { |
| OCMacroCall macroCall = PsiTreeUtil.getParentOfType(element, OCMacroCall.class); |
| if (macroCall != null) { |
| List<OCMacroCallArgument> arguments = macroCall.getArguments(); |
| return arguments.size() > 0 && arguments.get(0).equals(element); |
| } |
| return false; |
| } |
| |
| @Nullable |
| private static GoogleTestLocation createFromFile(@Nullable PsiElement element) { |
| return createFromClassAndMethod(element, null, null); |
| } |
| |
| @Nullable |
| private static GoogleTestLocation createFromClass( |
| @Nullable PsiElement element, @Nullable String className) { |
| return createFromClassAndMethod(element, className, null); |
| } |
| |
| @Nullable |
| private static GoogleTestLocation createFromClassAndMethod( |
| @Nullable PsiElement element, @Nullable String classOrSuiteName, @Nullable String testName) { |
| if (element == null) { |
| return null; |
| } |
| GoogleTestSpecification gtest = |
| new GoogleTestSpecification.FromPsiElement(classOrSuiteName, testName, null, null); |
| return new GoogleTestLocation(element, gtest); |
| } |
| } |