summaryrefslogtreecommitdiff
path: root/plugins/junit/src/com/intellij/execution/junit2/TestProxy.java
blob: 1d306493b081dec774a269eb492fa1f257e533bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*
 * Copyright 2000-2013 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.execution.junit2;

import com.intellij.execution.Location;
import com.intellij.execution.junit2.events.*;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.junit2.info.TestInfo;
import com.intellij.execution.junit2.states.IgnoredState;
import com.intellij.execution.junit2.states.Statistics;
import com.intellij.execution.junit2.states.TestState;
import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.execution.testframework.Filter;
import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.rt.execution.junit.states.PoolOfTestStates;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class TestProxy extends AbstractTestProxy {
  private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.TestProxy");

  private final TestInfo myInfo;
  private TestState myState = TestState.DEFAULT;
  private final TestProxyListenersNotifier myNotifier = new TestProxyListenersNotifier();
  private Statistics myStatistics = new Statistics();
  private TestEventsConsumer myEventsConsumer;
  private int myPreviousMagnitude = -1;
  private int myStateTimestamp = 0;

  //  private ArrayList myChildren = new ArrayList();
  private final FilterCache myChildren = new FilterCache();
  private TestProxy myParent = null;
  public static final Filter NOT_LEAF = Filter.LEAF.not();

  public TestProxy(@NotNull final TestInfo info) {
    myInfo = info;
  }

  public String toString() {
    return getInfo().getComment() + "." + getInfo().getName();
  }

  public TestState getState() {
    return myState;
  }

  public void setState(final TestState state) {
    if (myState != state) {
      if (state.isFinal()) {
        addLast(state);
      } else {
        fireOnNewPrintable(state);
      }
      if (myState != null) {
        state.merge(myState, getParent());
      }

      myState = state;
      fireStateChanged();
    }
  }

  public void fireStateChanged() {
    myStateTimestamp++;
    pullEvent(new StateChangedEvent(this));
    if (myParent != null)
      myParent.onChanged(this);
    myNotifier.onChanged(this);
  }

  public int getStateTimestamp() {
    return myStateTimestamp;
  }

  public int getChildCount() {
    return myChildren.getList().size();
  }

  public List<TestProxy> getChildren() {
    return myChildren.getUnmodifiableList();
  }

  public TestProxy getParent() {
    return myParent;
  }

  public Navigatable getDescriptor(final Location location, final TestConsoleProperties testConsoleProperties) {
    return getState().getDescriptor(location);
  }

  public String getName() {
    return getInfo().getName();
  }

  public boolean isInProgress() {
    return getState().isInProgress();
  }

  public boolean isDefect() {
    return getState().isDefect();
  }

  public boolean shouldRun() {
    return getInfo().shouldRun();
  }

  public int getMagnitude() {
    return getState().getMagnitude();
  }

  public Location getLocation(final Project project, GlobalSearchScope searchScope) {
    final Location location = getInfo().getLocation(project, searchScope);
    if (location == null) {
      return checkParentParameterized(project, searchScope);
    } else {
      Location parentLocation = getParent().getLocation(project, searchScope);
      if (parentLocation instanceof PsiMemberParameterizedLocation) {
        return new PsiMemberParameterizedLocation(project, 
                                                  location.getPsiElement(),
                                                  location instanceof MethodLocation ? ((MethodLocation)location).getContainingClass() : null,
                                                  ((PsiMemberParameterizedLocation)parentLocation).getParamSetName());
      }
    }
    return location;
  }

  private Location checkParentParameterized(Project project, GlobalSearchScope searchScope) {
    final TestProxy parent = getParent();
    if (parent != null) {
      final Location parentLocation = parent.getLocation(project, searchScope);
      if (parentLocation != null) {
        final PsiElement parentElement = parentLocation.getPsiElement();
        if (parentElement instanceof PsiClass) {
          return PsiMemberParameterizedLocation.getParameterizedLocation((PsiClass)parentElement, getInfo().getName());
        }
      }
    }
    return null;
  }

  public boolean isLeaf() {
    return getChildCount() == 0;
  }

  @Override
  public boolean isInterrupted() {
    return getMagnitude() == PoolOfTestStates.TERMINATED_INDEX;
  }

  @Override
  public boolean isIgnored() {
    return myState instanceof IgnoredState;
  }

  public boolean isPassed() {
    return getMagnitude() <= PoolOfTestStates.PASSED_INDEX;
  }

  public void addChild(final TestProxy child) {
    addChild(child, -1);
  }

  public void addChild(final TestProxy child, final int idx) {
    if (myChildren.contains(child))
      return;
    if (child.getParent() != null)
      return;//todo throw new RuntimeException("Test: "+child + " already has parent: " + child.getParent());
    myChildren.insert(child, idx);
    child.myParent = this;
    addLast(child);
    child.setPrinter(myPrinter);
    pullEvent(new NewChildEvent(this, child));
    getState().changeStateAfterAddingChildTo(this, child);
    myNotifier.onChildAdded(this, child);
  }

  public void insertNextRunningChild(final TestProxy child) {
    int idx = -1;
    List<TestProxy> list = myChildren.getList();
    for (int i = 0; i < list.size(); i++) {
      TestProxy proxy = list.get(i);
      if (!proxy.getState().isFinal()) {
        idx = i;
        break;
      }
    }
    addChild(child, idx);
  }


  public TestInfo getInfo() {
    return myInfo;
  }


  public void onChanged(final AbstractTestProxy test) {
    myChildren.resetCache();
    final int magnitude = test.getMagnitude();
    getState().update();
    if (myPreviousMagnitude < magnitude || getState().getMagnitude() <= magnitude) {
      fireStateChanged();
      myPreviousMagnitude = getState().getMagnitude();
    }
  }

  public void onStatisticsChanged() {
    myChildren.resetCache();
    if (myParent != null)
      myParent.onStatisticsChanged();
    pullEvent(new StatisticsChanged(this));
    myNotifier.onStatisticsChanged(this);
  }

  public void addListener(final TestProxyListener listener) {
    myNotifier.addListener(listener);
  }

  public void setStatistics(final Statistics statistics) {
    if (!myState.isFinal()) {
      LOG.error(String.valueOf(myState.getMagnitude()));
    }
    myStatistics = statistics;
    onStatisticsChanged();
  }

  public Statistics getStatisticsImpl() {
    return myStatistics;
  }

  public boolean hasChildSuites() {
    return myChildren.detect(NOT_LEAF) != null;
  }

  public Statistics getStatistics() {
    return myState.getStatisticsFor(this);
  }

  public TestProxy[] selectChildren(final Filter filter) {
    return myChildren.select(filter);
  }

  public void setEventsConsumer(final TestEventsConsumer eventsConsumer) {
    myEventsConsumer = eventsConsumer;
  }

  private void pullEvent(final TestEvent event) {
    if (myEventsConsumer != null) {
      myEventsConsumer.onEvent(event);
      return;
    }
    if (myParent != null)
      myParent.pullEvent(event);
  }

  public List<TestProxy> getAllTests() {
    return myState.getAllTestsOf(this);
  }

  public void collectAllTestsTo(final ArrayList<TestProxy> allTests) {
    allTests.add(this);
    for (Iterator iterator = myChildren.iterator(); iterator.hasNext();) {
      final TestProxy testProxy = (TestProxy) iterator.next();
      testProxy.collectAllTestsTo(allTests);
    }
  }

  public TestProxy getCommonAncestor(final TestProxy test) {
    if (test == null) return this;
    if (test.isAncestorOf(this)) return test;
    for (TestProxy parent = this; parent != null; parent = parent.getParent())
      if (parent.isAncestorOf(test)) return parent;
    return null;
  }

  public boolean isAncestorOf(final TestProxy test) {
    if (test == null) return false;
    for (TestProxy parent = test; parent != null; parent = parent.getParent())
      if (parent == this) return true;
    return false;
  }

  public AbstractTestProxy[] getPathFromRoot() {
    final ArrayList<TestProxy> parents = new ArrayList<TestProxy>();
    TestProxy test = this;
    do {
      parents.add(test);
    } while ((test = test.getParent()) != null);
    Collections.reverse(parents);
    return parents.toArray(new TestProxy[parents.size()]);
  }

  @Override
  public Long getDuration() {
    return (long) getStatistics().getTime();
  }

  @Override
  public boolean shouldSkipRootNodeForExport() {
    return false;
  }

  @Override
  @Nullable
  public AssertEqualsDiffViewerProvider getDiffViewerProvider() {
    if (myState instanceof AssertEqualsDiffViewerProvider) {
      return (AssertEqualsDiffViewerProvider)myState;
    }
    return null;
  }
}