/*
* Copyright 2012 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.junit.result;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import org.gradle.api.Action;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.testing.TestOutputEvent;
import org.gradle.internal.concurrent.CompositeStoppable;
import java.io.IOException;
import java.io.Writer;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import static org.gradle.util.CollectionUtils.any;
public class AggregateTestResultsProvider implements TestResultsProvider {
private final Iterable<TestResultsProvider> providers;
private Multimap<Long, DelegateProvider> classOutputProviders;
public AggregateTestResultsProvider(Iterable<TestResultsProvider> providers) {
this.providers = providers;
}
@Override
public void visitClasses(final Action<? super TestClassResult> visitor) {
final Map<String, OverlayedIdProxyingTestClassResult> aggregatedTestResults = new LinkedHashMap<String, OverlayedIdProxyingTestClassResult>();
classOutputProviders = ArrayListMultimap.create();
final AtomicLong newIdCounter = new AtomicLong(0L);
for (final TestResultsProvider provider : providers) {
provider.visitClasses(new Action<TestClassResult>() {
public void execute(final TestClassResult classResult) {
OverlayedIdProxyingTestClassResult newTestResult = aggregatedTestResults.get(classResult.getClassName());
if (newTestResult != null) {
newTestResult.addTestClassResult(classResult);
} else {
long newId = newIdCounter.incrementAndGet();
newTestResult = new OverlayedIdProxyingTestClassResult(newId, classResult);
aggregatedTestResults.put(classResult.getClassName(), newTestResult);
}
classOutputProviders.put(newTestResult.getId(), new DelegateProvider(classResult.getId(), provider));
}
});
}
for (OverlayedIdProxyingTestClassResult classResult : aggregatedTestResults.values()) {
visitor.execute(classResult);
}
}
private static class DelegateProvider {
private final long id;
private final TestResultsProvider provider;
private DelegateProvider(long id, TestResultsProvider provider) {
this.id = id;
this.provider = provider;
}
}
private static class OverlayedIdProxyingTestClassResult extends TestClassResult {
private final Map<Long, TestClassResult> delegates = new LinkedHashMap<Long, TestClassResult>();
public OverlayedIdProxyingTestClassResult(long id, TestClassResult delegate) {
super(id, delegate.getClassName(), delegate.getStartTime());
addTestClassResult(delegate);
}
void addTestClassResult(TestClassResult delegate) {
Preconditions.checkArgument(delegates.isEmpty() || delegates.values().iterator().next().getClassName().equals(delegate.getClassName()));
delegates.put(delegate.getId(), delegate);
for (TestMethodResult result : delegate.getResults()) {
add(result);
}
if (delegate.getStartTime() < getStartTime()) {
setStartTime(delegate.getStartTime());
}
}
}
@Override
public boolean hasOutput(long id, final TestOutputEvent.Destination destination) {
return Iterables.any(
classOutputProviders.get(id),
new Predicate<DelegateProvider>() {
public boolean apply(DelegateProvider delegateProvider) {
return delegateProvider.provider.hasOutput(delegateProvider.id, destination);
}
});
}
@Override
public void writeAllOutput(long id, TestOutputEvent.Destination destination, Writer writer) {
for (DelegateProvider delegateProvider : classOutputProviders.get(id)) {
delegateProvider.provider.writeAllOutput(delegateProvider.id, destination, writer);
}
}
@Override
public boolean isHasResults() {
return any(providers, new Spec<TestResultsProvider>() {
public boolean isSatisfiedBy(TestResultsProvider element) {
return element.isHasResults();
}
});
}
@Override
public void writeNonTestOutput(long id, TestOutputEvent.Destination destination, Writer writer) {
for (DelegateProvider delegateProvider : classOutputProviders.get(id)) {
delegateProvider.provider.writeNonTestOutput(delegateProvider.id, destination, writer);
}
}
@Override
public void writeTestOutput(long classId, long testId, TestOutputEvent.Destination destination, Writer writer) {
for (DelegateProvider delegateProvider : classOutputProviders.get(classId)) {
delegateProvider.provider.writeTestOutput(delegateProvider.id, testId, destination, writer);
}
}
@Override
public void close() throws IOException {
CompositeStoppable.stoppable(providers).stop();
}
}