001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.js.translate.general;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.util.Function;
021    import com.intellij.util.containers.ContainerUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
024    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
025    import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
026    import org.jetbrains.kotlin.descriptors.Modality;
027    import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
028    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
029    import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
030    import org.jetbrains.kotlin.psi.KtClass;
031    import org.jetbrains.kotlin.psi.KtDeclaration;
032    import org.jetbrains.kotlin.psi.KtFile;
033    import org.jetbrains.kotlin.resolve.BindingContext;
034    import org.jetbrains.kotlin.resolve.DescriptorUtils;
035    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
036    import org.jetbrains.kotlin.types.KotlinType;
037    
038    import java.util.Collection;
039    import java.util.List;
040    
041    /**
042     * Helps find functions which are annotated with a @Test annotation from junit
043     */
044    public class JetTestFunctionDetector {
045        private JetTestFunctionDetector() {
046        }
047    
048        private static boolean isTest(@NotNull FunctionDescriptor functionDescriptor) {
049            Annotations annotations = functionDescriptor.getAnnotations();
050            for (AnnotationDescriptor annotation : annotations) {
051                // TODO ideally we should find the fully qualified name here...
052                KotlinType type = annotation.getType();
053                String name = type.toString();
054                if (name.equals("Test")) {
055                    return true;
056                }
057            }
058    
059            /*
060            if (function.getName().startsWith("test")) {
061                List<JetParameter> parameters = function.getValueParameters();
062                return parameters.size() == 0;
063            }
064            */
065            return false;
066        }
067    
068        @NotNull
069        public static List<FunctionDescriptor> getTestFunctionDescriptors(
070                @NotNull BindingContext bindingContext,
071                @NotNull Collection<KtFile> files
072        ) {
073            List<FunctionDescriptor> answer = Lists.newArrayList();
074            for (KtFile file : files) {
075                answer.addAll(getTestFunctions(bindingContext, file.getDeclarations()));
076            }
077            return answer;
078        }
079    
080        @NotNull
081        private static List<FunctionDescriptor> getTestFunctions(
082                @NotNull BindingContext bindingContext,
083                @NotNull List<KtDeclaration> declarations
084        ) {
085            List<FunctionDescriptor> answer = Lists.newArrayList();
086            for (KtDeclaration declaration : declarations) {
087                MemberScope scope = null;
088    
089                if (declaration instanceof KtClass) {
090                    KtClass klass = (KtClass) declaration;
091                    ClassDescriptor classDescriptor = BindingUtils.getClassDescriptor(bindingContext, klass);
092    
093                    if (classDescriptor.getModality() != Modality.ABSTRACT) {
094                        scope = classDescriptor.getDefaultType().getMemberScope();
095                    }
096                }
097    
098                if (scope != null) {
099                    Collection<DeclarationDescriptor> allDescriptors = DescriptorUtils.getAllDescriptors(scope);
100                    List<FunctionDescriptor> testFunctions = ContainerUtil.mapNotNull(
101                            allDescriptors,
102                            new Function<DeclarationDescriptor, FunctionDescriptor>() {
103                                @Override
104                                public FunctionDescriptor fun(DeclarationDescriptor descriptor) {
105                                    if (descriptor instanceof FunctionDescriptor) {
106                                        FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
107                                        if (isTest(functionDescriptor)) return functionDescriptor;
108                                    }
109    
110                                    return null;
111                                }
112                            });
113    
114                    answer.addAll(testFunctions);
115                }
116            }
117            return answer;
118        }
119    }