mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
Recent tests collapses tests executed from the same run configuration.
- provided simple versioning of TestStateStorage.Record - run configuration name hash is saved into TestStateStorage.Record - lots of refactorings
This commit is contained in:
@@ -136,6 +136,8 @@ public abstract class JavaTestFrameworkRunnableState<T extends
|
||||
Disposer.register(getConfiguration().getProject(), consoleView);
|
||||
|
||||
final OSProcessHandler handler = createHandler(executor);
|
||||
handler.putUserData(TestStateStorage.RUN_CONFIGURATION_NAME_KEY, getConfiguration().getName());
|
||||
|
||||
consoleView.attachToProcess(handler);
|
||||
final AbstractTestProxy root = viewer.getRoot();
|
||||
if (root instanceof TestProxyRoot) {
|
||||
|
||||
@@ -15,12 +15,19 @@
|
||||
*/
|
||||
package com.intellij.testIntegration;
|
||||
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.Location;
|
||||
import com.intellij.execution.ProgramRunnerUtil;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.executors.DefaultDebugExecutor;
|
||||
import com.intellij.execution.executors.DefaultRunExecutor;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface RecentTestRunner {
|
||||
@@ -30,12 +37,16 @@ public interface RecentTestRunner {
|
||||
}
|
||||
|
||||
void setMode(Mode mode);
|
||||
void run(Location location);
|
||||
void run(String url);
|
||||
void run(RunnerAndConfigurationSettings configuration);
|
||||
}
|
||||
|
||||
class RecentTestRunnerImpl implements RecentTestRunner {
|
||||
private static AnAction RUN = ActionManager.getInstance().getAction("RunClass");
|
||||
private static AnAction DEBUG = ActionManager.getInstance().getAction("DebugClass");
|
||||
|
||||
private final Project myProject;
|
||||
private final TestLocator myTestLocator;
|
||||
|
||||
protected AnAction myCurrentAction = RUN;
|
||||
|
||||
@@ -50,7 +61,25 @@ class RecentTestRunnerImpl implements RecentTestRunner {
|
||||
}
|
||||
}
|
||||
|
||||
public void run(final Location location) {
|
||||
public RecentTestRunnerImpl(Project project, TestLocator testLocator) {
|
||||
myProject = project;
|
||||
myTestLocator = testLocator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(RunnerAndConfigurationSettings configuration) {
|
||||
Executor executor = myCurrentAction == RUN ? DefaultRunExecutor.getRunExecutorInstance()
|
||||
: DefaultDebugExecutor.getDebugExecutorInstance();
|
||||
|
||||
ProgramRunnerUtil.executeConfiguration(myProject, configuration, executor);
|
||||
}
|
||||
|
||||
public void run(@NotNull String url) {
|
||||
Location location = myTestLocator.getLocation(url);
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataContext data = new DataContext() {
|
||||
@Nullable
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.RunnerAndConfigurationSettings
|
||||
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import java.util.*
|
||||
|
||||
class RecentTestsData {
|
||||
|
||||
private val suitePacks = hashMapOf<String, SuitePackInfo>()
|
||||
private var testsWithoutSuites: MutableList<TestInfo> = ContainerUtil.newArrayList<TestInfo>()
|
||||
|
||||
fun addSuite(url: String,
|
||||
magnitude: TestStateInfo.Magnitude,
|
||||
runDate: Date,
|
||||
runConfiguration: RunnerAndConfigurationSettings)
|
||||
{
|
||||
|
||||
val suiteInfo = SuiteInfo(url, magnitude, runDate, runConfiguration)
|
||||
|
||||
val suitePack = suitePacks[runConfiguration.uniqueID]
|
||||
if (suitePack != null) {
|
||||
suitePack.addSuite(suiteInfo)
|
||||
return
|
||||
}
|
||||
|
||||
suitePacks[runConfiguration.uniqueID] = SuitePackInfo(runConfiguration, suiteInfo)
|
||||
}
|
||||
|
||||
|
||||
fun addTest(url: String,
|
||||
magnitude: TestStateInfo.Magnitude,
|
||||
runDate: Date,
|
||||
runConfiguration: RunnerAndConfigurationSettings) {
|
||||
|
||||
val testInfo = TestInfo(url, magnitude, runDate, runConfiguration)
|
||||
|
||||
val suite = findSuite(url, runConfiguration)
|
||||
if (suite != null) {
|
||||
suite.addTest(testInfo)
|
||||
return
|
||||
}
|
||||
|
||||
testsWithoutSuites.add(testInfo)
|
||||
}
|
||||
|
||||
private fun findSuite(url: String, runConfiguration: RunnerAndConfigurationSettings): SuiteInfo? {
|
||||
val pack: SuitePackInfo = suitePacks[runConfiguration.uniqueID] ?: return null
|
||||
val testName = VirtualFileManager.extractPath(url)
|
||||
|
||||
pack.suites.forEach {
|
||||
if (testName.startsWith(it.suiteName)) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun getTestsToShow(): List<RecentTestsPopupEntry> {
|
||||
testsWithoutSuites.forEach {
|
||||
val url = it.url
|
||||
findSuite(url, it.runConfiguration)?.addTest(it)
|
||||
}
|
||||
|
||||
val packsByDate = suitePacks.values.sortedByDescending { it.runDate }
|
||||
return packsByDate.fold(listOf(), { list, pack -> list + pack.entriesToShow() })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun SuitePackInfo.entriesToShow(): List<RecentTestsPopupEntry> {
|
||||
if (suites.size == 1) {
|
||||
return suites[0].entriesToShow()
|
||||
}
|
||||
|
||||
val failedSuites = suites.filter { it.failedTests.size > 0 }
|
||||
if (failedSuites.size == 0) {
|
||||
return listOf(this)
|
||||
}
|
||||
return failedSuites + this
|
||||
}
|
||||
|
||||
fun SuiteInfo.entriesToShow(): List<RecentTestsPopupEntry> {
|
||||
val failed = failedTests
|
||||
if (failed.size > 0) {
|
||||
return failed.sortedByDescending { it.runDate } + this
|
||||
}
|
||||
return listOf(this)
|
||||
}
|
||||
+73
-256
@@ -15,42 +15,99 @@
|
||||
*/
|
||||
package com.intellij.testIntegration;
|
||||
|
||||
import com.intellij.execution.RunManagerEx;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.TestStateStorage;
|
||||
import com.intellij.execution.configurations.ConfigurationType;
|
||||
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.Function;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.*;
|
||||
import static com.intellij.testIntegration.TestInfo.select;
|
||||
import static com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.values;
|
||||
|
||||
|
||||
interface ConfigurationByRecordProvider {
|
||||
RunnerAndConfigurationSettings getConfiguration(TestStateStorage.Record record);
|
||||
}
|
||||
|
||||
|
||||
class RunConfigurationByRecordProvider implements ConfigurationByRecordProvider {
|
||||
private final Project myProject;
|
||||
private final Map<Integer, RunnerAndConfigurationSettings> myConfigurationsMap = ContainerUtil.newHashMap();
|
||||
|
||||
public RunConfigurationByRecordProvider(Project project) {
|
||||
myProject = project;
|
||||
initRunConfigurationsMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunnerAndConfigurationSettings getConfiguration(TestStateStorage.Record record) {
|
||||
Integer runConfigurationHash = new Integer((int)record.configurationHash);
|
||||
return myConfigurationsMap.get(runConfigurationHash);
|
||||
}
|
||||
|
||||
private void initRunConfigurationsMap() {
|
||||
RunManagerEx manager = RunManagerEx.getInstanceEx(myProject);
|
||||
ConfigurationType[] types = manager.getConfigurationFactories();
|
||||
|
||||
for (ConfigurationType type : types) {
|
||||
Map<String, List<RunnerAndConfigurationSettings>> structure = manager.getStructure(type);
|
||||
for (Map.Entry<String, List<RunnerAndConfigurationSettings>> e : structure.entrySet()) {
|
||||
for (RunnerAndConfigurationSettings settings : e.getValue()) {
|
||||
myConfigurationsMap.put(settings.getName().hashCode(), settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class RecentTestsListProvider {
|
||||
private final Map<String, TestStateStorage.Record> myRecords;
|
||||
private final ConfigurationByRecordProvider myConfigurationProvider;
|
||||
|
||||
public RecentTestsListProvider(Map<String, TestStateStorage.Record> records) {
|
||||
myRecords = records;
|
||||
public RecentTestsListProvider(ConfigurationByRecordProvider configurationProvider, Map<String, TestStateStorage.Record> records) {
|
||||
myRecords = records;
|
||||
myConfigurationProvider = configurationProvider;
|
||||
}
|
||||
|
||||
public List<String> getUrlsToShowFromHistory() {
|
||||
|
||||
public List<RecentTestsPopupEntry> getTestsToShow() {
|
||||
if (myRecords == null) return ContainerUtil.emptyList();
|
||||
|
||||
|
||||
RecentTestsData data = new RecentTestsData();
|
||||
for (Map.Entry<String, TestStateStorage.Record> entry : myRecords.entrySet()) {
|
||||
String url = entry.getKey();
|
||||
TestStateStorage.Record record = entry.getValue();
|
||||
|
||||
if (TestLocator.canLocate(url)) {
|
||||
data.addTest(url, getMagnitude(record.magnitude), record.date);
|
||||
handleUrl(data, url, record);
|
||||
}
|
||||
}
|
||||
|
||||
return data.getSortedTestsList();
|
||||
return data.getTestsToShow();
|
||||
}
|
||||
|
||||
|
||||
private void handleUrl(RecentTestsData data, String url, TestStateStorage.Record record) {
|
||||
TestStateInfo.Magnitude magnitude = getMagnitude(record.magnitude);
|
||||
if (magnitude == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RunnerAndConfigurationSettings runConfiguration = myConfigurationProvider.getConfiguration(record);
|
||||
if (TestLocator.isSuite(url)) {
|
||||
if (runConfiguration != null) {
|
||||
data.addSuite(url, magnitude, record.date, runConfiguration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
data.addTest(url, magnitude, record.date, runConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
private static TestStateInfo.Magnitude getMagnitude(int magnitude) {
|
||||
for (TestStateInfo.Magnitude m : values()) {
|
||||
if (m.getValue() == magnitude) {
|
||||
@@ -59,244 +116,4 @@ public class RecentTestsListProvider {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class RecentTestsData {
|
||||
private static Comparator<TestInfo> BY_PATH_COMPARATOR = (o1, o2) -> {
|
||||
String path1 = VirtualFileManager.extractPath(o1.getUrl());
|
||||
String path2 = VirtualFileManager.extractPath(o2.getUrl());
|
||||
return path1.compareTo(path2);
|
||||
};
|
||||
|
||||
private static Comparator<SuiteInfo> SUITE_BY_RECENT_COMPARATOR =
|
||||
(o1, o2) -> -o1.getMostRecentRunDate().compareTo(o2.getMostRecentRunDate());
|
||||
|
||||
private static Comparator<TestInfo> TEST_BY_RECENT_COMPARATOR = (o1, o2) -> -o1.getRunDate().compareTo(o2.getRunDate());
|
||||
|
||||
private final Map<String, SuiteInfo> mySuites = ContainerUtil.newHashMap();
|
||||
|
||||
private List<TestInfo> myTestsWithoutSuites = ContainerUtil.newArrayList();
|
||||
|
||||
public void addTest(String url, TestStateInfo.Magnitude magnitude, Date runDate) {
|
||||
if (TestLocator.isSuite(url)) {
|
||||
mySuites.put(url, new SuiteInfo(url, magnitude, runDate));
|
||||
return;
|
||||
}
|
||||
|
||||
TestInfo testInfo = new TestInfo(url, magnitude, runDate);
|
||||
|
||||
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> getSortedTestsList() {
|
||||
distributeUnmatchedTests();
|
||||
List<String> result = ContainerUtil.newArrayList();
|
||||
fillWithTests(result, ERROR_INDEX, FAILED_INDEX);
|
||||
fillWithTests(result, COMPLETE_INDEX, PASSED_INDEX, IGNORED_INDEX);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fillWithTests(List<String> result, TestStateInfo.Magnitude... magnitudes) {
|
||||
List<SuiteInfo> suites = ContainerUtil.newArrayList(mySuites.values());
|
||||
|
||||
List<SuiteInfo> failedSuites = select(suites, magnitudes);
|
||||
List<TestInfo> failedTests = select(myTestsWithoutSuites, magnitudes);
|
||||
|
||||
sortByPath(failedSuites);
|
||||
sortByPath(failedTests);
|
||||
|
||||
sortSuitesByRecent(failedSuites);
|
||||
sortTestsByRecent(failedTests);
|
||||
|
||||
fillWithSuites(result, failedSuites);
|
||||
fillWithTests(result, failedTests);
|
||||
}
|
||||
|
||||
private static void sortSuitesByRecent(List<SuiteInfo> suites) {
|
||||
Collections.sort(suites, SUITE_BY_RECENT_COMPARATOR);
|
||||
}
|
||||
|
||||
private static void sortTestsByRecent(List<TestInfo> tests) {
|
||||
Collections.sort(tests, TEST_BY_RECENT_COMPARATOR);
|
||||
}
|
||||
|
||||
private static void sortByPath(List<? extends TestInfo> list) {
|
||||
Collections.sort(list, BY_PATH_COMPARATOR);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (suite.canTrustSuiteMagnitude() && suite.isPassed()) {
|
||||
result.add(suite.getUrl());
|
||||
return result;
|
||||
}
|
||||
|
||||
List<TestInfo> failedTests = suite.getFailedTests();
|
||||
sortTestsByRecent(failedTests);
|
||||
|
||||
if (failedTests.size() == suite.getTotalTestsCount()) {
|
||||
result.add(suite.getUrl());
|
||||
}
|
||||
else if (failedTests.size() < 3) {
|
||||
result.addAll(ContainerUtil.map(failedTests, testInfo -> {
|
||||
return testInfo.getUrl();
|
||||
}));
|
||||
result.add(suite.getUrl());
|
||||
}
|
||||
else {
|
||||
result.add(suite.getUrl());
|
||||
result.addAll(ContainerUtil.map(failedTests, testInfo -> {
|
||||
return testInfo.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, Date runDate) {
|
||||
super(url, magnitude, runDate);
|
||||
mySuiteName = VirtualFileManager.extractPath(url);
|
||||
}
|
||||
|
||||
public Date getMostRecentRunDate() {
|
||||
Date mostRecent = getRunDate();
|
||||
for (TestInfo test : tests) {
|
||||
Date testDate = test.getRunDate();
|
||||
if (testDate.compareTo(mostRecent) > 0) {
|
||||
mostRecent = testDate;
|
||||
}
|
||||
}
|
||||
return mostRecent;
|
||||
}
|
||||
|
||||
public boolean canTrustSuiteMagnitude() {
|
||||
Date suiteRunDate = getRunDate();
|
||||
for (TestInfo test : tests) {
|
||||
if (test.getRunDate().getTime() > suiteRunDate.getTime()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isPassed() {
|
||||
return getMagnitude() == IGNORED_INDEX || getMagnitude() == PASSED_INDEX || getMagnitude() == COMPLETE_INDEX;
|
||||
}
|
||||
|
||||
public List<TestInfo> getFailedTests() {
|
||||
List<TestInfo> failed = ContainerUtil.newSmartList();
|
||||
for (TestInfo test : tests) {
|
||||
if (test.getMagnitude() == FAILED_INDEX || test.getMagnitude() == ERROR_INDEX) {
|
||||
failed.add(test);
|
||||
}
|
||||
}
|
||||
return failed;
|
||||
}
|
||||
|
||||
public String getSuiteName() {
|
||||
return mySuiteName;
|
||||
}
|
||||
|
||||
public void addTest(TestInfo info) {
|
||||
tests.add(info);
|
||||
}
|
||||
|
||||
public int getTotalTestsCount() {
|
||||
return tests.size();
|
||||
}
|
||||
}
|
||||
|
||||
class TestInfo {
|
||||
private final Date runDate;
|
||||
private final String url;
|
||||
private final TestStateInfo.Magnitude magnitude;
|
||||
|
||||
public TestInfo(String url, TestStateInfo.Magnitude magnitude, Date runDate) {
|
||||
this.url = url;
|
||||
this.magnitude = magnitude;
|
||||
this.runDate = runDate;
|
||||
}
|
||||
|
||||
public Date getRunDate() {
|
||||
return runDate;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.Location;
|
||||
import com.intellij.openapi.ui.popup.PopupStep;
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SelectTestStep extends BaseListPopupStep<String> {
|
||||
private final RecentTestRunner myRunner;
|
||||
private final TestLocator myTestLocator;
|
||||
private final Map<String, Icon> myIcons;
|
||||
|
||||
public SelectTestStep(List<String> urls, Map<String, Icon> icons, RecentTestRunner runner, TestLocator locator) {
|
||||
super("Debug Recent Tests", urls);
|
||||
myRunner = runner;
|
||||
myIcons = icons;
|
||||
myTestLocator = locator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIconFor(String value) {
|
||||
return myIcons.get(value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getTextFor(String value) {
|
||||
return VirtualFileManager.extractPath(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpeedSearchEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PopupStep onChosen(String url, boolean finalChoice) {
|
||||
Location location = myTestLocator.getLocation(url);
|
||||
myRunner.run(location);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.TestIconMapper
|
||||
import com.intellij.openapi.keymap.MacKeymapUtil
|
||||
import com.intellij.openapi.ui.popup.ListPopupStep
|
||||
import com.intellij.openapi.ui.popup.PopupStep
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.ui.popup.list.ListPopupImpl
|
||||
import com.intellij.util.PsiNavigateUtil
|
||||
import java.awt.event.ActionEvent
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.AbstractAction
|
||||
import javax.swing.Icon
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
class RecentTestsListPopup(popupStep: ListPopupStep<RecentTestsPopupEntry>,
|
||||
private val testRunner: RecentTestRunner,
|
||||
private val locator: TestLocator)
|
||||
: ListPopupImpl(popupStep)
|
||||
{
|
||||
|
||||
init {
|
||||
shiftReleased()
|
||||
registerActions(this)
|
||||
|
||||
val shift = if (SystemInfo.isMac) MacKeymapUtil.SHIFT else "Shift"
|
||||
setAdText("Debug with $shift, navigate with F4")
|
||||
}
|
||||
|
||||
private fun registerActions(popup: ListPopupImpl) {
|
||||
popup.registerAction("alternate", KeyStroke.getKeyStroke("shift pressed SHIFT"), object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) = shiftPressed()
|
||||
})
|
||||
popup.registerAction("restoreDefault", KeyStroke.getKeyStroke("released SHIFT"), object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) = shiftReleased()
|
||||
})
|
||||
popup.registerAction("invokeAction", KeyStroke.getKeyStroke("shift ENTER"), object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) = handleSelect(true)
|
||||
})
|
||||
|
||||
popup.registerAction("navigate", KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0), object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) {
|
||||
val values = selectedValues
|
||||
if (values.size == 1) {
|
||||
val element = (values[0] as RecentTestsPopupEntry).navigatableElement(locator)
|
||||
if (element != null) {
|
||||
cancel()
|
||||
PsiNavigateUtil.navigate(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun shiftPressed() {
|
||||
setCaption("Debug Recent Tests")
|
||||
testRunner.setMode(RecentTestRunner.Mode.DEBUG)
|
||||
}
|
||||
|
||||
private fun shiftReleased() {
|
||||
setCaption("Run Recent Tests")
|
||||
testRunner.setMode(RecentTestRunner.Mode.RUN)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SelectTestStep(tests: List<RecentTestsPopupEntry>,
|
||||
private val runner: RecentTestRunner)
|
||||
: BaseListPopupStep<RecentTestsPopupEntry>("Debug Recent Tests", tests)
|
||||
{
|
||||
|
||||
override fun getIconFor(value: RecentTestsPopupEntry): Icon? {
|
||||
return TestIconMapper.getIcon(value.magnitude)
|
||||
}
|
||||
|
||||
override fun getTextFor(value: RecentTestsPopupEntry) = value.presentation
|
||||
|
||||
override fun isSpeedSearchEnabled() = true
|
||||
|
||||
override fun onChosen(entry: RecentTestsPopupEntry, finalChoice: Boolean): PopupStep<RecentTestsPopupEntry>? {
|
||||
entry.run(runner)
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,28 +15,15 @@
|
||||
*/
|
||||
package com.intellij.testIntegration;
|
||||
|
||||
import com.intellij.execution.Location;
|
||||
import com.intellij.execution.TestStateStorage;
|
||||
import com.intellij.execution.testframework.TestIconMapper;
|
||||
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.keymap.MacKeymapUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.ListPopupStep;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.ui.popup.list.ListPopupImpl;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.PsiNavigateUtil;
|
||||
import com.intellij.util.Time;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -60,88 +47,29 @@ public class ShowRecentTests extends AnAction {
|
||||
|
||||
final TestStateStorage testStorage = TestStateStorage.getInstance(project);
|
||||
final TestLocator testLocator = new TestLocator(project);
|
||||
final RecentTestRunnerImpl testRunner = new RecentTestRunnerImpl();
|
||||
final RecentTestRunnerImpl testRunner = new RecentTestRunnerImpl(project, testLocator);
|
||||
|
||||
final Map<String, TestStateStorage.Record> records = testStorage.getRecentTests(TEST_LIMIT, getSinceDate());
|
||||
RecentTestsListProvider listProvider = new RecentTestsListProvider(records);
|
||||
List<String> urls = listProvider.getUrlsToShowFromHistory();
|
||||
Map<String, Icon> icons = ContainerUtil.map2Map(urls, url -> {
|
||||
return Pair.create(url, getIconFor(url, records));
|
||||
});
|
||||
SelectTestStep selectStepTest = new SelectTestStep(urls, icons, testRunner, testLocator);
|
||||
|
||||
RunConfigurationByRecordProvider configurationProvider = new RunConfigurationByRecordProvider(project);
|
||||
RecentTestsListProvider listProvider = new RecentTestsListProvider(configurationProvider, records);
|
||||
|
||||
List<RecentTestsPopupEntry> entries = listProvider.getTestsToShow();
|
||||
|
||||
SelectTestStep selectStepTest = new SelectTestStep(entries, testRunner);
|
||||
|
||||
RecentTestsListPopup popup = new RecentTestsListPopup(selectStepTest, testRunner, testLocator);
|
||||
popup.showCenteredInCurrentWindow(project);
|
||||
|
||||
|
||||
cleanDeadTests(entries, testLocator, testStorage);
|
||||
}
|
||||
|
||||
private static void cleanDeadTests(List<RecentTestsPopupEntry> entries, TestLocator testLocator, TestStateStorage testStorage) {
|
||||
List<String> urls = ContainerUtil.newArrayList();
|
||||
entries.forEach((entry) -> urls.addAll(entry.getTestsUrls()));
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new DeadTestsCleaner(testStorage, urls, testLocator));
|
||||
}
|
||||
|
||||
private static Icon getIconFor(String value, Map<String, TestStateStorage.Record> records) {
|
||||
TestStateStorage.Record record = records.get(value);
|
||||
TestStateInfo.Magnitude magnitude = TestIconMapper.getMagnitude(record.magnitude);
|
||||
return TestIconMapper.getIcon(magnitude);
|
||||
}
|
||||
}
|
||||
|
||||
class RecentTestsListPopup extends ListPopupImpl {
|
||||
private final RecentTestRunner myTestRunner;
|
||||
private final TestLocator myLocator;
|
||||
|
||||
public RecentTestsListPopup(ListPopupStep<String> popupStep, RecentTestRunner testRunner, TestLocator locator) {
|
||||
super(popupStep);
|
||||
myTestRunner = testRunner;
|
||||
myLocator = locator;
|
||||
|
||||
shiftReleased();
|
||||
registerActions(this);
|
||||
|
||||
String shift = SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift";
|
||||
setAdText("Debug with " + shift + ", navigate with F4");
|
||||
}
|
||||
|
||||
private void registerActions(ListPopupImpl popup) {
|
||||
popup.registerAction("alternate", KeyStroke.getKeyStroke("shift pressed SHIFT"), new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
shiftPressed();
|
||||
}
|
||||
});
|
||||
popup.registerAction("restoreDefault", KeyStroke.getKeyStroke("released SHIFT"), new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
shiftReleased();
|
||||
}
|
||||
});
|
||||
popup.registerAction("invokeAction", KeyStroke.getKeyStroke("shift ENTER"), new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
handleSelect(true);
|
||||
}
|
||||
});
|
||||
popup.registerAction("navigate", KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0), new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Object[] values = getSelectedValues();
|
||||
if (values.length == 1) {
|
||||
Location location = myLocator.getLocation(values[0].toString());
|
||||
if (location != null) {
|
||||
cancel();
|
||||
PsiNavigateUtil.navigate(location.getPsiElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void shiftPressed() {
|
||||
setCaption("Debug Recent Tests");
|
||||
myTestRunner.setMode(RecentTestRunner.Mode.DEBUG);
|
||||
}
|
||||
|
||||
private void shiftReleased() {
|
||||
setCaption("Run Recent Tests");
|
||||
myTestRunner.setMode(RecentTestRunner.Mode.RUN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.RunnerAndConfigurationSettings
|
||||
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo
|
||||
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.*
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import java.util.*
|
||||
|
||||
interface RecentTestsPopupEntry {
|
||||
val runDate: Date
|
||||
val magnitude: TestStateInfo.Magnitude
|
||||
val presentation: String
|
||||
|
||||
val testsUrls: List<String>
|
||||
|
||||
fun run(runner: RecentTestRunner)
|
||||
|
||||
open fun navigatableElement(locator: TestLocator): PsiElement? = null
|
||||
}
|
||||
|
||||
open class TestInfo(val url: String,
|
||||
override val magnitude: TestStateInfo.Magnitude,
|
||||
override val runDate: Date,
|
||||
val runConfiguration: RunnerAndConfigurationSettings) : RecentTestsPopupEntry
|
||||
{
|
||||
|
||||
override val presentation = VirtualFileManager.extractPath(url)
|
||||
override val testsUrls = listOf(url)
|
||||
|
||||
override fun run(runner: RecentTestRunner) {
|
||||
runner.run(url)
|
||||
}
|
||||
|
||||
override fun navigatableElement(locator: TestLocator) = locator.getLocation(url)?.psiElement
|
||||
|
||||
}
|
||||
|
||||
class SuiteInfo(url: String, magnitude: TestStateInfo.Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings)
|
||||
: TestInfo(url, magnitude, runDate, runConfiguration)
|
||||
{
|
||||
|
||||
private val tests = hashSetOf<TestInfo>()
|
||||
|
||||
override val testsUrls: List<String>
|
||||
get() = tests.fold(listOf<String>(), { acc, testEntry -> acc + testEntry.testsUrls })
|
||||
|
||||
val suiteName = VirtualFileManager.extractPath(url)
|
||||
|
||||
val failedTests: List<TestInfo>
|
||||
get() = tests.filter { it.magnitude == FAILED_INDEX || it.magnitude == ERROR_INDEX }
|
||||
|
||||
fun addTest(info: TestInfo) = tests.add(info)
|
||||
|
||||
override val presentation = suiteName
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SuitePackInfo(val runSettings: RunnerAndConfigurationSettings, initial: SuiteInfo) : RecentTestsPopupEntry {
|
||||
|
||||
val suites = ContainerUtil.newArrayList<SuiteInfo>()
|
||||
|
||||
init {
|
||||
addSuite(initial)
|
||||
}
|
||||
|
||||
fun addSuite(s: SuiteInfo) = suites.add(s)
|
||||
|
||||
override val runDate = suites.map { it.runDate }.min()!!
|
||||
|
||||
override val magnitude = COMPLETE_INDEX
|
||||
|
||||
override val presentation = runSettings.name
|
||||
|
||||
override val testsUrls: List<String>
|
||||
get() = suites.fold(listOf<String>(), { list, suite -> list + suite.testsUrls })
|
||||
|
||||
override fun run(runner: RecentTestRunner) {
|
||||
runner.run(runSettings)
|
||||
}
|
||||
}
|
||||
@@ -15,290 +15,73 @@
|
||||
*/
|
||||
package com.intellij.testIntergration
|
||||
|
||||
import com.intellij.execution.Location
|
||||
import com.intellij.execution.TestStateStorage
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings
|
||||
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.testFramework.LightIdeaTestCase
|
||||
import com.intellij.testIntegration.*
|
||||
import com.intellij.testIntegration.RecentTestsData
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.mockito.Matchers
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.mock
|
||||
import java.util.*
|
||||
|
||||
fun passed(date: Date) = TestStateStorage.Record(TestStateInfo.Magnitude.PASSED_INDEX.value, date)
|
||||
fun failed(date: Date) = TestStateStorage.Record(TestStateInfo.Magnitude.FAILED_INDEX.value, date)
|
||||
|
||||
class RecentTestsStepTest: LightIdeaTestCase() {
|
||||
val runner = mock(RecentTestRunner::class.java)
|
||||
|
||||
val passed = passed(Date(0))
|
||||
val failed = failed(Date(0))
|
||||
|
||||
class TestStorage {
|
||||
private val map: MutableMap<String, TestStateStorage.Record> = hashMapOf()
|
||||
|
||||
fun addSuite(name: String, pass: Boolean, date: Date = Date(0), language: String = "java") {
|
||||
val magnitude = if (pass) TestStateInfo.Magnitude.PASSED_INDEX else TestStateInfo.Magnitude.FAILED_INDEX
|
||||
addSuite(name, magnitude, date, language)
|
||||
}
|
||||
|
||||
fun addSuite(name: String, magnitude: TestStateInfo.Magnitude, date: Date = Date(0), language: String = "java") {
|
||||
val record = TestStateStorage.Record(magnitude.value, date)
|
||||
map.put("$language:suite://$name", record)
|
||||
}
|
||||
|
||||
fun addTest(name: String, magnitude: TestStateInfo.Magnitude, date: Date = Date(0)) {
|
||||
val record = TestStateStorage.Record(magnitude.value, date)
|
||||
map.put("java:test://$name", record)
|
||||
}
|
||||
lateinit var data: RecentTestsData
|
||||
lateinit var allTests: RunnerAndConfigurationSettings
|
||||
lateinit var now: Date
|
||||
|
||||
fun addTest(name: String, pass: Boolean, date: Date = Date(0)) {
|
||||
val magnitude = if (pass) TestStateInfo.Magnitude.PASSED_INDEX else TestStateInfo.Magnitude.FAILED_INDEX
|
||||
addTest(name, magnitude, date)
|
||||
}
|
||||
|
||||
fun getMap() = map
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
data = RecentTestsData()
|
||||
allTests = mock(RunnerAndConfigurationSettings::class.java)
|
||||
`when`(allTests.uniqueID).thenAnswer { "JUnit.all tests" }
|
||||
`when`(allTests.name).thenAnswer { "all tests" }
|
||||
now = Date()
|
||||
}
|
||||
|
||||
fun getSuite(name: String, language: String = "java") = map["$language:suite://$name"]
|
||||
fun `test all tests passed`() {
|
||||
data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addTest("java:test://Test.textYYY", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addTest("java:test://Test.textZZZ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addTest("java:test://Test.textQQQ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
|
||||
val tests = data.getTestsToShow()
|
||||
assertThat(tests).hasSize(1)
|
||||
assertThat(tests[0].presentation).isEqualTo("all tests")
|
||||
}
|
||||
|
||||
|
||||
fun `test if one failed in run configuration show failed suite`() {
|
||||
data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests)
|
||||
data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
|
||||
data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests)
|
||||
data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
|
||||
fun removeUrl(url: String) {
|
||||
map.remove(url)
|
||||
}
|
||||
data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
|
||||
val tests = data.getTestsToShow()
|
||||
|
||||
assertThat(tests).hasSize(2)
|
||||
assertThat(tests[0].presentation).isEqualTo("JavaFormatterSuperDuperTest")
|
||||
assertThat(tests[1].presentation).isEqualTo("all tests")
|
||||
}
|
||||
|
||||
fun `test show sorted by date`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
fun `test if configuration with single test show failed test`() {
|
||||
data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests)
|
||||
data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests)
|
||||
data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests)
|
||||
|
||||
storage.addSuite("ASTest", true, Date(1000))
|
||||
storage.addSuite("JSTest", true, Date(1200))
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf("JSTest", "ASTest"))
|
||||
val tests = data.getTestsToShow()
|
||||
assertThat(tests).hasSize(2)
|
||||
assertThat(tests[0].presentation).isEqualTo("JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt")
|
||||
assertThat(tests[1].presentation).isEqualTo("JavaFormatterSuperDuperTest")
|
||||
}
|
||||
|
||||
fun `test show tests sorted by date`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
storage.addSuite("ASTest", false, Date(0))
|
||||
storage.addTest("ASTest.xxxx", true, Date(99999))
|
||||
|
||||
storage.addTest("ASTest.aaaa", false, Date(10000))
|
||||
storage.addTest("ASTest.cccc", false, Date(20000))
|
||||
storage.addTest("ASTest.bbbb", false, Date(30000))
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf("ASTest", "ASTest.bbbb", "ASTest.cccc", "ASTest.aaaa"))
|
||||
}
|
||||
|
||||
fun `test show ignored`() {
|
||||
val storage = TestStorage()
|
||||
storage.addSuite("ASTest", TestStateInfo.Magnitude.IGNORED_INDEX)
|
||||
storage.addTest("ASTest.ignored", TestStateInfo.Magnitude.IGNORED_INDEX)
|
||||
storage.addTest("ASTest.passed", pass = true)
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf("ASTest"))
|
||||
}
|
||||
|
||||
fun `test when suite passed - show only suite`() {
|
||||
val map: MutableMap<String, TestStateStorage.Record> = hashMapOf()
|
||||
|
||||
map.put("java:suite://JavaFormatterSuperDuperTest", passed)
|
||||
map.put("java:test://Test.textXXX", passed)
|
||||
map.put("java:suite://Test", passed)
|
||||
map.put("java:test://Test.textYYY", passed)
|
||||
map.put("java:test://Test.textZZZ", passed)
|
||||
map.put("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", passed)
|
||||
map.put("java:test://Test.textQQQ", passed)
|
||||
map.put("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", passed)
|
||||
|
||||
val expected = listOf(
|
||||
"java:suite://JavaFormatterSuperDuperTest",
|
||||
"java:suite://Test"
|
||||
)
|
||||
|
||||
val list = getSortedList(map)
|
||||
assertThat(list).isEqualTo(expected)
|
||||
}
|
||||
|
||||
private fun getSortedList(map: MutableMap<String, TestStateStorage.Record>): List<String> {
|
||||
val provider = RecentTestsListProvider(map)
|
||||
return provider.urlsToShowFromHistory
|
||||
}
|
||||
|
||||
|
||||
fun `test show only java tests`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
storage.addSuite("JavaTest1", true)
|
||||
storage.addSuite("JavaTest2", true)
|
||||
|
||||
storage.addSuite("JsSuite1", true, Date(0), "js")
|
||||
storage.addSuite("JsSuite2", true, Date(0), "js")
|
||||
storage.addSuite("JsSuite3", true, Date(0), "js")
|
||||
|
||||
val values = getSortedList(storage.getMap())
|
||||
assertThat(values.map { VirtualFileManager.extractPath(it) }).isEqualTo(listOf("JavaTest1", "JavaTest2"))
|
||||
}
|
||||
|
||||
fun `test show failed first`() {
|
||||
val map: MutableMap<String, TestStateStorage.Record> = hashMapOf()
|
||||
|
||||
map.put("java:suite://JavaFormatterSuperDuperTest", failed)
|
||||
map.put("java:test://Test.textXXX", passed)
|
||||
map.put("java:suite://Test", passed)
|
||||
map.put("java:suite://JavaFormatterFailed", failed)
|
||||
map.put("java:test://JavaFormatterFailed.fail", failed)
|
||||
map.put("java:test://JavaFormatterFailed.notFail", passed)
|
||||
map.put("java:test://Test.textYYY", passed)
|
||||
map.put("java:test://Test.textZZZ", passed)
|
||||
map.put("java:test://JavaFormatterSuperDuperTest.testFail", failed)
|
||||
map.put("java:test://Test.textQQQ", passed)
|
||||
map.put("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", passed)
|
||||
|
||||
val values = getSortedList(map)
|
||||
|
||||
val expected = listOf(
|
||||
"java:test://JavaFormatterFailed.fail",
|
||||
"java:suite://JavaFormatterFailed",
|
||||
"java:test://JavaFormatterSuperDuperTest.testFail",
|
||||
"java:suite://JavaFormatterSuperDuperTest",
|
||||
"java:suite://Test"
|
||||
)
|
||||
|
||||
assertThat(values).isEqualTo(expected)
|
||||
}
|
||||
|
||||
fun `test if failed more than 2 tests show suite first`() {
|
||||
val storage = TestStorage()
|
||||
storage.addSuite("ASTest", false)
|
||||
storage.addTest("ASTest.failed1", false, Date(3000))
|
||||
storage.addTest("ASTest.failed2", false, Date(2000))
|
||||
storage.addTest("ASTest.failed3", false, Date(1000))
|
||||
storage.addTest("ASTest.passed1", true)
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf(
|
||||
"ASTest",
|
||||
"ASTest.failed1",
|
||||
"ASTest.failed2",
|
||||
"ASTest.failed3"
|
||||
))
|
||||
}
|
||||
|
||||
fun `test if failed less than 3 tests, show tests first`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
storage.addSuite("ASTest", false)
|
||||
storage.addTest("ASTest.failed1", false, Date(3000))
|
||||
storage.addTest("ASTest.failed2", false, Date(2000))
|
||||
storage.addTest("ASTest.passed1", true)
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf(
|
||||
"ASTest.failed1",
|
||||
"ASTest.failed2",
|
||||
"ASTest"
|
||||
))
|
||||
}
|
||||
|
||||
fun `test if all failed show only suite`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
storage.addSuite("ASTest", false)
|
||||
storage.addTest("ASTest.failed1", false)
|
||||
storage.addTest("ASTest.failed2", false)
|
||||
storage.addTest("ASTest.failed3", false)
|
||||
storage.addTest("ASTest.failed4", false)
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf("ASTest"))
|
||||
}
|
||||
|
||||
private fun locatorReturningNullIfContains(substring: String): TestLocator {
|
||||
val locator = mock(TestLocator::class.java)
|
||||
`when`(locator.getLocation(Matchers.anyString())).thenAnswer {
|
||||
val url = it.arguments[0] as String
|
||||
if (url.contains(substring)) null else mock(Location::class.java)
|
||||
}
|
||||
return locator
|
||||
}
|
||||
|
||||
fun `test shown value without protocol`() {
|
||||
val step = SelectTestStep(emptyList(), emptyMap(), runner, mock(TestLocator::class.java))
|
||||
var shownValue = step.getTextFor("java:suite://JavaFormatterSuperDuperTest")
|
||||
assertThat(shownValue).isEqualTo("JavaFormatterSuperDuperTest")
|
||||
|
||||
shownValue = step.getTextFor("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt")
|
||||
assertThat(shownValue).isEqualTo("JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt")
|
||||
}
|
||||
|
||||
fun `test do not show urls which we can locate without location`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
storage.addSuite("ASTest", true)
|
||||
storage.addSuite("BSTest", false)
|
||||
storage.addTest("BSTest.fff", false)
|
||||
storage.addTest("BSTest.ppp", true)
|
||||
|
||||
storage.addTest("<default package>", false)
|
||||
storage.addSuite("<default package>", false)
|
||||
|
||||
val testStorageMock = createMockStorage(storage)
|
||||
|
||||
val map = storage.getMap()
|
||||
|
||||
val cleaner = DeadTestsCleaner(testStorageMock, map.keys.toList(), locatorReturningNullIfContains("<"))
|
||||
cleaner.run()
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
val values = sortedUrlList.map { VirtualFileManager.extractPath(it) }
|
||||
|
||||
assertThat(values).isEqualTo(listOf("BSTest.fff", "BSTest", "ASTest"))
|
||||
assertThat(storage.getSuite("<default package>")).isEqualTo(null)
|
||||
}
|
||||
|
||||
fun `test do not remove tests if we are unable to locate them`() {
|
||||
val storage = TestStorage()
|
||||
|
||||
storage.addSuite("ASTest", true)
|
||||
|
||||
storage.addSuite("JsSuite1", true, Date(), "js")
|
||||
storage.addSuite("JsSuite2", true, Date(), "js")
|
||||
|
||||
val testStorageMock = createMockStorage(storage)
|
||||
|
||||
val sortedUrlList = getSortedList(storage.getMap())
|
||||
|
||||
val cleaner = DeadTestsCleaner(testStorageMock, sortedUrlList, locatorReturningNullIfContains("JsSuite"))
|
||||
cleaner.run()
|
||||
|
||||
assertThat(storage.getSuite("JsSuite1", "js")).isNotEqualTo(null)
|
||||
assertThat(storage.getSuite("JsSuite2", "js")).isNotEqualTo(null)
|
||||
}
|
||||
|
||||
private fun createMockStorage(storage: TestStorage): TestStateStorage? {
|
||||
val testStorageMock = mock(TestStateStorage::class.java)
|
||||
`when`(testStorageMock.removeState(Matchers.anyString())).then {
|
||||
val url = it.arguments[0]as String
|
||||
storage.removeUrl(url)
|
||||
}
|
||||
return testStorageMock
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -20,7 +20,9 @@ import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -44,7 +46,12 @@ import java.util.concurrent.ScheduledFuture;
|
||||
*/
|
||||
public class TestStateStorage implements Disposable {
|
||||
|
||||
public static Key<String> RUN_CONFIGURATION_NAME_KEY = Key.create("run.configuration.name");
|
||||
|
||||
private static final File TEST_HISTORY_PATH = new File(PathManager.getSystemPath(), "testHistory");
|
||||
|
||||
private static final int CURRENT_VERSION = 1;
|
||||
|
||||
private final File myFile;
|
||||
|
||||
public static File getTestHistoryRoot(Project project) {
|
||||
@@ -53,11 +60,13 @@ public class TestStateStorage implements Disposable {
|
||||
|
||||
public static class Record {
|
||||
public final int magnitude;
|
||||
public final long configurationHash;
|
||||
public final Date date;
|
||||
|
||||
public Record(int magnitude, Date date) {
|
||||
public Record(int magnitude, Date date, long configurationHash) {
|
||||
this.magnitude = magnitude;
|
||||
this.date = date;
|
||||
this.configurationHash = configurationHash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,18 +80,47 @@ public class TestStateStorage implements Disposable {
|
||||
}
|
||||
|
||||
public TestStateStorage(Project project) {
|
||||
String directoryPath = getTestHistoryRoot(project).getPath();
|
||||
|
||||
myFile = new File(getTestHistoryRoot(project).getPath() + "/testStateMap");
|
||||
myFile = new File(directoryPath + "/testStateMap");
|
||||
FileUtilRt.createParentDirs(myFile);
|
||||
|
||||
File versionFile = new File(directoryPath + "/version");
|
||||
dropMapFileIfOutdated(versionFile);
|
||||
|
||||
try {
|
||||
myMap = initializeMap();
|
||||
} catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
myMapFlusher = FlushingDaemon.everyFiveSeconds(() -> flushMap());
|
||||
|
||||
myMapFlusher = FlushingDaemon.everyFiveSeconds(this::flushMap);
|
||||
}
|
||||
|
||||
private void dropMapFileIfOutdated(File versionFile) {
|
||||
if (myFile.exists() && myFile.length() > 0
|
||||
&& readVersion(versionFile) != CURRENT_VERSION) {
|
||||
myFile.delete();
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtil.writeToFile(versionFile, Integer.toString(CURRENT_VERSION));
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static int readVersion(File versionFile) {
|
||||
if (!versionFile.exists()) return 0;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(FileUtil.loadFile(versionFile));
|
||||
}
|
||||
catch (NumberFormatException | IOException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private PersistentHashMap<String, Record> initializeMap() throws IOException {
|
||||
return IOUtil.openCleanOrResetBroken(getComputable(myFile), myFile);
|
||||
}
|
||||
@@ -97,16 +135,17 @@ public class TestStateStorage implements Disposable {
|
||||
return new ThrowableComputable<PersistentHashMap<String, Record>, IOException>() {
|
||||
@Override
|
||||
public PersistentHashMap<String, Record> compute() throws IOException {
|
||||
return new PersistentHashMap<String, Record>(file, EnumeratorStringDescriptor.INSTANCE, new DataExternalizer<Record>() {
|
||||
return new PersistentHashMap<>(file, EnumeratorStringDescriptor.INSTANCE, new DataExternalizer<Record>() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, Record value) throws IOException {
|
||||
out.writeInt(value.magnitude);
|
||||
out.writeLong(value.date.getTime());
|
||||
out.writeLong(value.configurationHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Record read(@NotNull DataInput in) throws IOException {
|
||||
return new Record(in.readInt(), new Date(in.readLong()));
|
||||
return new Record(in.readInt(), new Date(in.readLong()), in.readLong());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+8
-1
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.execution.TestStateStorage;
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.configurations.RunProfile;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.testframework.*;
|
||||
import com.intellij.execution.testframework.actions.ScrollToTestSourceAction;
|
||||
import com.intellij.execution.testframework.export.TestResultsXmlFormatter;
|
||||
@@ -847,7 +848,13 @@ public class SMTestRunnerResultsForm extends TestResultsPanel
|
||||
for (SMTestProxy proxy : tests) {
|
||||
String url = proxy instanceof SMTestProxy.SMRootTestProxy ? ((SMTestProxy.SMRootTestProxy)proxy).getRootLocation() : proxy.getLocationUrl();
|
||||
if (url != null) {
|
||||
storage.writeState(url, new TestStateStorage.Record(proxy.getMagnitude(), new Date()));
|
||||
ProcessHandler handler = myRoot.getHandler();
|
||||
String configurationName = null;
|
||||
if (handler != null) {
|
||||
configurationName = handler.getUserData(TestStateStorage.RUN_CONFIGURATION_NAME_KEY);
|
||||
}
|
||||
storage.writeState(url, new TestStateStorage.Record(proxy.getMagnitude(), new Date(),
|
||||
configurationName == null ? 0 : configurationName.hashCode()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user