/* * Copyright 2010 the original author or authors. * * 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 org.gradle.api.internal.tasks.testing.results; import org.gradle.api.internal.tasks.testing.*; import org.gradle.api.tasks.testing.TestOutputEvent; import java.util.HashMap; import java.util.Map; public class StateTrackingTestResultProcessor implements TestResultProcessor { private final Map<Object, TestState> executing = new HashMap<Object, TestState>(); private TestDescriptorInternal currentParent; private final TestListenerInternal delegate; public StateTrackingTestResultProcessor(TestListenerInternal delegate) { this.delegate = delegate; } @Override public final void started(TestDescriptorInternal test, TestStartEvent event) { TestDescriptorInternal parent = null; if (event.getParentId() != null) { parent = executing.get(event.getParentId()).test; } TestState state = new TestState(new DecoratingTestDescriptor(test, parent), event, executing); TestState oldState = executing.put(test.getId(), state); if (oldState != null) { throw new IllegalArgumentException(String.format("Received a start event for %s with duplicate id '%s'.", test, test.getId())); } delegate.started(state.test, event); } @Override public final void completed(Object testId, TestCompleteEvent event) { TestState testState = executing.remove(testId); if (testState == null) { throw new IllegalArgumentException(String.format( "Received a completed event for test with unknown id '%s'. Registered test ids: '%s'", testId, executing.keySet())); } //In case the output event arrives after completion of the test //and we need to have a matching descriptor to inform the user which test this output belongs to //we will use the current parent //(SF) This approach should generally work because at the moment we reset capturing output per suite //(see CaptureTestOutputTestResultProcessor) and that reset happens earlier in the chain. //So in theory when suite is completed, the output redirector has been already stopped //and there shouldn't be any output events passed //See also GRADLE-2035 currentParent = testState.test.getParent(); testState.completed(event); delegate.completed(testState.test, new DefaultTestResult(testState), event); } @Override public final void failure(Object testId, Throwable result) { TestState testState = executing.get(testId); if (testState == null) { throw new IllegalArgumentException(String.format( "Received a failure event for test with unknown id '%s'. Registered test ids: '%s'", testId, executing.keySet())); } testState.failures.add(result); } @Override public final void output(Object testId, TestOutputEvent event) { delegate.output(findDescriptor(testId), event); } private TestDescriptorInternal findDescriptor(Object testId) { TestState state = executing.get(testId); if (state != null) { return state.test; } if (currentParent != null) { return currentParent; } //in theory this should not happen return new UnknownTestDescriptor(); } }