e44c9650d9eb5060374c662fbf02d0ae33b5c0e1
[idea/community.git] / platform / testFramework / src / com / intellij / testFramework / InspectionTestUtil.java
1 /*
2  * Copyright 2000-2016 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 package com.intellij.testFramework;
17
18 import com.intellij.analysis.AnalysisScope;
19 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
20 import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
21 import com.intellij.codeInspection.ex.InspectionToolWrapper;
22 import com.intellij.codeInspection.ui.InspectionToolPresentation;
23 import com.intellij.openapi.util.Comparing;
24 import com.intellij.openapi.util.JDOMUtil;
25 import com.intellij.testFramework.fixtures.impl.GlobalInspectionContextForTests;
26 import com.intellij.util.ui.UIUtil;
27 import org.jdom.Document;
28 import org.jdom.Element;
29 import org.jetbrains.annotations.NotNull;
30 import org.junit.Assert;
31
32 import java.io.CharArrayReader;
33 import java.io.File;
34 import java.io.StreamTokenizer;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38
39 public class InspectionTestUtil {
40   private InspectionTestUtil() {
41   }
42
43   protected static void compareWithExpected(Document expectedDoc, Document doc, boolean checkRange) throws Exception {
44     List<Element> expectedProblems = new ArrayList<Element>(expectedDoc.getRootElement().getChildren("problem"));
45     List<Element> reportedProblems = new ArrayList<Element>(doc.getRootElement().getChildren("problem"));
46
47     Element[] expectedArray = expectedProblems.toArray(new Element[expectedProblems.size()]);
48     boolean failed = false;
49
50 expected:
51     for (Element expectedProblem : expectedArray) {
52       Element[] reportedArrayed = reportedProblems.toArray(new Element[reportedProblems.size()]);
53       for (Element reportedProblem : reportedArrayed) {
54         if (compareProblemWithExpected(reportedProblem, expectedProblem, checkRange)) {
55           expectedProblems.remove(expectedProblem);
56           reportedProblems.remove(reportedProblem);
57           continue expected;
58         }
59       }
60
61       Document missing = new Document(expectedProblem.clone());
62       System.out.println("The following haven't been reported as expected: " + new String(JDOMUtil.printDocument(missing, "\n")));
63       failed = true;
64     }
65
66     for (Element reportedProblem : reportedProblems) {
67       Document extra = new Document(reportedProblem.clone());
68       System.out.println("The following has been unexpectedly reported: " + new String(JDOMUtil.printDocument(extra, "\n")));
69       failed = true;
70     }
71
72     Assert.assertFalse(failed);
73   }
74
75   static boolean compareProblemWithExpected(Element reportedProblem, Element expectedProblem, boolean checkRange) throws Exception {
76     if (!compareFiles(reportedProblem, expectedProblem)) return false;
77     if (!compareLines(reportedProblem, expectedProblem)) return false;
78     if (!compareDescriptions(reportedProblem, expectedProblem)) return false;
79     if (checkRange && !compareTextRange(reportedProblem, expectedProblem)) return false;
80     return true;
81   }
82
83   static boolean compareTextRange(final Element reportedProblem, final Element expectedProblem) {
84     Element reportedTextRange = reportedProblem.getChild("entry_point");
85     if (reportedTextRange == null) return false;
86     Element expectedTextRange = expectedProblem.getChild("entry_point");
87     return Comparing.equal(reportedTextRange.getAttributeValue("TYPE"), expectedTextRange.getAttributeValue("TYPE")) &&
88            Comparing.equal(reportedTextRange.getAttributeValue("FQNAME"), expectedTextRange.getAttributeValue("FQNAME"));
89   }
90
91   static boolean compareDescriptions(Element reportedProblem, Element expectedProblem) throws Exception {
92     String expectedDescription = expectedProblem.getChildText("description");
93     String reportedDescription = reportedProblem.getChildText("description");
94     if (expectedDescription.equals(reportedDescription)) return true;
95
96     StreamTokenizer tokenizer = new StreamTokenizer(new CharArrayReader(expectedDescription.toCharArray()));
97     tokenizer.quoteChar('\'');
98
99     int idx = 0;
100     while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
101       String word;
102       if (tokenizer.sval != null) {
103         word = tokenizer.sval;
104       } else if (tokenizer.ttype == StreamTokenizer.TT_NUMBER) {
105         word = Double.toString(tokenizer.nval);
106       }
107       else {
108         continue;
109       }
110
111       idx = reportedDescription.indexOf(word, idx);
112       if (idx == -1) return false;
113       idx += word.length();
114     }
115
116     return true;
117   }
118
119   static boolean compareLines(Element reportedProblem, Element expectedProblem) {
120     return Comparing.equal(reportedProblem.getChildText("line"), expectedProblem.getChildText("line"));
121   }
122
123   static boolean compareFiles(Element reportedProblem, Element expectedProblem) {
124     String reportedFileName = reportedProblem.getChildText("file");
125     if (reportedFileName == null) {
126       return true;
127     }
128     File reportedFile = new File(reportedFileName);
129
130     return Comparing.equal(reportedFile.getName(), expectedProblem.getChildText("file"));
131   }
132
133   public static void compareToolResults(@NotNull GlobalInspectionContextImpl context,
134                                         @NotNull InspectionToolWrapper toolWrapper,
135                                         boolean checkRange,
136                                         String testDir) {
137     final Element root = new Element("problems");
138     final Document doc = new Document(root);
139     InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
140
141     presentation.updateContent();  //e.g. dead code need check for reachables
142     presentation.exportResults(root, Collections.emptySet(), Collections.emptySet());
143
144     File file = new File(testDir + "/expected.xml");
145     try {
146       compareWithExpected(JDOMUtil.loadDocument(file), doc, checkRange);
147     }
148     catch (Exception e) {
149       throw new RuntimeException(e);
150     }
151   }
152
153   public static void runTool(@NotNull InspectionToolWrapper toolWrapper,
154                              @NotNull final AnalysisScope scope,
155                              @NotNull final GlobalInspectionContextForTests globalContext) {
156     final String shortName = toolWrapper.getShortName();
157     final HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
158     if (key == null){
159       HighlightDisplayKey.register(shortName);
160     }
161
162     globalContext.doInspections(scope);
163     do {
164       UIUtil.dispatchAllInvocationEvents();
165     }
166     while (!globalContext.isFinished());
167   }
168 }