Recent Tests: refactored test order calculation

This commit is contained in:
Yaroslav Lepenkin
2016-01-27 14:07:33 +03:00
parent 082e5655e7
commit 594398f81f
4 changed files with 240 additions and 74 deletions
@@ -0,0 +1,222 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* 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.intellij.testIntegration;
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.*;
import static com.intellij.testIntegration.TestInfo.select;
import static com.intellij.testIntegration.TestInfo.selectNot;
public class RecentTestsData {
private static Comparator<SuiteInfo> TEST_BY_PATH_COMPARATOR = new Comparator<SuiteInfo>() {
@Override
public int compare(SuiteInfo o1, SuiteInfo o2) {
String path1 = VirtualFileManager.extractPath(o1.getUrl());
String path2 = VirtualFileManager.extractPath(o2.getUrl());
return path1.compareTo(path2);
}
};
private final RecentTestRunner myRunner;
private final Map<String, SuiteInfo> mySuites = ContainerUtil.newHashMap();
private List<TestInfo> myTestsWithoutSuites = ContainerUtil.newArrayList();
public RecentTestsData(RecentTestRunner runner) {
myRunner = runner;
}
public void addTest(String url, TestStateInfo.Magnitude magnitude) {
if (myRunner.isSuite(url)) {
mySuites.put(url, new SuiteInfo(url, magnitude));
return;
}
TestInfo testInfo = new TestInfo(url, magnitude);
SuiteInfo suite = getSuite(url);
if (suite != null) {
suite.addTest(testInfo);
return;
}
myTestsWithoutSuites.add(testInfo);
}
@Nullable
private SuiteInfo getSuite(String url) {
String testName = VirtualFileManager.extractPath(url);
for (SuiteInfo info : mySuites.values()) {
String suiteName = info.getSuiteName();
if (testName.startsWith(suiteName)) {
return info;
}
}
return null;
}
public List<String> calculateTestList() {
distributeUnmatchedTests();
List<SuiteInfo> suites = ContainerUtil.newArrayList(mySuites.values());
Collections.sort(suites, TEST_BY_PATH_COMPARATOR);
List<String> result = ContainerUtil.newArrayList();
fillWithSuites(result, select(suites, ERROR_INDEX));
fillWithTests(result, select(myTestsWithoutSuites, ERROR_INDEX));
fillWithSuites(result, selectNot(suites, ERROR_INDEX, COMPLETE_INDEX, PASSED_INDEX));
fillWithTests(result, selectNot(myTestsWithoutSuites, COMPLETE_INDEX, PASSED_INDEX));
fillWithSuites(result, select(suites, COMPLETE_INDEX, PASSED_INDEX));
fillWithTests(result, select(myTestsWithoutSuites, COMPLETE_INDEX, PASSED_INDEX));
return result;
}
private static void fillWithTests(List<String> result, List<TestInfo> tests) {
for (TestInfo info : tests) {
result.add(info.getUrl());
}
}
private static void fillWithSuites(List<String> result, List<SuiteInfo> suites) {
for (SuiteInfo suite : suites) {
result.addAll(suiteToTestList(suite));
}
}
private static List<String> suiteToTestList(SuiteInfo suite) {
List<String> result = ContainerUtil.newArrayList();
TestStateInfo.Magnitude suiteMagnitude = suite.getMagnitude();
Set<TestInfo> allTests = suite.getTests();
List<TestInfo> sameMagnitudeTests = suite.getTests(suiteMagnitude);
if (sameMagnitudeTests.size() == allTests.size()) {
result.add(suite.getUrl());
}
else {
result.add(suite.getUrl());
for (TestInfo test : sameMagnitudeTests) {
result.add(test.getUrl());
}
}
return result;
}
private void distributeUnmatchedTests() {
List<TestInfo> noSuites = ContainerUtil.newSmartList();
for (TestInfo test : myTestsWithoutSuites) {
String url = test.getUrl();
SuiteInfo suite = getSuite(url);
if (suite != null) {
suite.addTest(test);
}
else {
noSuites.add(test);
}
}
myTestsWithoutSuites = noSuites;
}
}
class SuiteInfo extends TestInfo {
private final String mySuiteName;
private Set<TestInfo> tests = ContainerUtil.newHashSet();
public SuiteInfo(String url, TestStateInfo.Magnitude magnitude) {
super(url, magnitude);
mySuiteName = VirtualFileManager.extractPath(url);
}
public String getSuiteName() {
return mySuiteName;
}
public void addTest(TestInfo info) {
tests.add(info);
}
public Set<TestInfo> getTests() {
return tests;
}
public List<TestInfo> getTests(TestStateInfo.Magnitude magnitude) {
return select(tests, magnitude);
}
}
class TestInfo {
private String url;
private TestStateInfo.Magnitude magnitude;
public TestInfo(String url, TestStateInfo.Magnitude magnitude) {
this.url = url;
this.magnitude = magnitude;
}
public String getUrl() {
return url;
}
public TestStateInfo.Magnitude getMagnitude() {
return magnitude;
}
public static <T extends TestInfo> List<T> select(Collection<T> infos, final TestStateInfo.Magnitude... magnitudes) {
return ContainerUtil.filter(infos, new Condition<T>() {
@Override
public boolean value(T t) {
for (TestStateInfo.Magnitude magnitude : magnitudes) {
if (t.getMagnitude() == magnitude) {
return true;
}
}
return false;
}
});
}
public static <T extends TestInfo> List<T> selectNot(Collection<T> infos, final TestStateInfo.Magnitude... magnitudes) {
return ContainerUtil.filter(infos, new Condition<T>() {
@Override
public boolean value(T t) {
for (TestStateInfo.Magnitude magnitude : magnitudes) {
if (t.getMagnitude() == magnitude) {
return false;
}
}
return true;
}
});
}
}
@@ -22,11 +22,13 @@ import com.intellij.execution.testframework.sm.runner.states.TestStateInfo;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.*;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SelectTestStep extends BaseListPopupStep<String> {
private static Comparator<String> TEST_BY_PATH_COMPARATOR = new Comparator<String>() {
@@ -48,66 +50,15 @@ public class SelectTestStep extends BaseListPopupStep<String> {
}
private static List<String> getUrls(Map<String, TestStateStorage.Record> records, RecentTestRunner runner) {
TestGroup groups = toTestGroups(records, runner);
List<String> failed = ContainerUtil.newArrayList(groups.failedTests);
Collections.sort(failed, TEST_BY_PATH_COMPARATOR);
List<String> other = ContainerUtil.newArrayList(groups.otherTests);
Collections.sort(other, TEST_BY_PATH_COMPARATOR);
List<String> passed = ContainerUtil.newArrayList(groups.passedTests);
Collections.sort(passed, TEST_BY_PATH_COMPARATOR);
failed.addAll(other);
failed.addAll(passed);
return failed;
}
RecentTestsData data = new RecentTestsData(runner);
private static TestGroup toTestGroups(Map<String, TestStateStorage.Record> records, RecentTestRunner runner) {
Set<String> failedTests = ContainerUtil.newHashSet();
Set<String> passedSuites = ContainerUtil.newHashSet();
Set<String> otherSuites = ContainerUtil.newHashSet();
List<TestInfo> infos = getTestInfos(records.entrySet(), runner);
for (TestInfo info : infos) {
String url = info.url;
TestStateInfo.Magnitude magnitude = info.magnitude;
if (magnitude == null) continue;
switch (magnitude) {
case COMPLETE_INDEX:
if (info.isSuite) {
passedSuites.add(url);
}
break;
case PASSED_INDEX:
if (info.isSuite) {
passedSuites.add(url);
}
break;
case ERROR_INDEX:
failedTests.add(url);
break;
default:
otherSuites.add(url);
break;
}
}
return new TestGroup(failedTests, passedSuites, otherSuites);
}
private static List<TestInfo> getTestInfos(Set<Map.Entry<String, TestStateStorage.Record>> entries, RecentTestRunner runner) {
List<TestInfo> list = ContainerUtil.newSmartList();
for (Map.Entry<String, TestStateStorage.Record> item : entries) {
String url = item.getKey();
TestStateStorage.Record record = item.getValue();
TestStateInfo.Magnitude magnitude = getMagnitude(record.magnitude);
list.add(new TestInfo(url, magnitude, runner.isSuite(url)));
for (Map.Entry<String, TestStateStorage.Record> entry : records.entrySet()) {
String url = entry.getKey();
TestStateStorage.Record record = entry.getValue();
data.addTest(url, getMagnitude(record.magnitude));
}
return list;
return data.calculateTestList();
}
private static TestStateInfo.Magnitude getMagnitude(int magnitude) {
@@ -155,17 +106,4 @@ public class SelectTestStep extends BaseListPopupStep<String> {
this.otherTests = otherTests;
}
}
private static class TestInfo {
private final boolean isSuite;
public String url;
public TestStateInfo.Magnitude magnitude;
public TestInfo(String url, TestStateInfo.Magnitude magnitude, boolean isSuite) {
this.url = url;
this.magnitude = magnitude;
this.isSuite = isSuite;
}
}
}
@@ -19,12 +19,12 @@ import com.intellij.execution.Location;
import com.intellij.execution.TestStateStorage;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ListPopupStep;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.util.PsiNavigateUtil;
import com.intellij.util.Time;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionEvent;
@@ -39,9 +39,14 @@ public class ShowRecentTests extends AnAction {
return new Date(System.currentTimeMillis() - Time.DAY);
}
@Override
public void update(@NotNull AnActionEvent e) {
e.getPresentation().setEnabled(e.getProject() != null);
}
@Override
public void actionPerformed(AnActionEvent e) {
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
final Project project = e.getProject();
if (project == null) return;
Map<String, TestStateStorage.Record> records = TestStateStorage.getInstance(project).getRecentTests(TEST_LIMIT, getSinceDate());