/*
* Copyright 2009 Google Inc.
*
* 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.google.jstestdriver.coverage;
import com.google.common.collect.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Named;
import com.google.jstestdriver.ResponseStreamFactory;
import com.google.jstestdriver.config.ConfigurationSource;
import com.google.jstestdriver.guice.BrowserActionProvider;
import com.google.jstestdriver.hooks.ActionListProcessor;
import com.google.jstestdriver.hooks.FileLoadPostProcessor;
import com.google.jstestdriver.hooks.ResourcePreProcessor;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;
/**
* Configure the code coverage plugin.
* @author corysmith@google.com (Cory Smith)
*
*/
public class CoverageModule extends AbstractModule {
private final List<String> excludes;
public CoverageModule(List<String> excludes) {
this.excludes = excludes;
}
@Override
protected void configure() {
Multibinder.newSetBinder(binder(), FileLoadPostProcessor.class)
.addBinding().to(CoverageInstrumentingProcessor.class);
Multibinder.newSetBinder(binder(), ResourcePreProcessor.class)
.addBinding().to(CoverageJsAdder.class);
Multibinder.newSetBinder(binder(), ResponseStreamFactory.class)
.addBinding().to(CoverageResponseStreamFactory.class);
Multibinder.newSetBinder(binder(), ActionListProcessor.class)
.addBinding().to(CoverageActionDecorator.class);
bind(new TypeLiteral<Set<String>>(){})
.annotatedWith(new CoverageImpl("coverageExcludes")).toInstance(Sets.newHashSet(excludes));
// TODO(corysmith): Remove this when there is a correct separation of phases.
bind(BrowserActionProvider.class).to(CoverageThreadedActionProvider.class);
}
/** Lets me bind to annotations with arguments, namespaced to the Coverage plugin.*/
public static class CoverageImpl implements Coverage {
private final String value;
@Override
public int hashCode() {
// This is specified in java.lang.Annotation.
return (127 * "value".hashCode()) ^ value.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Coverage))
return false;
Coverage other = (Coverage) obj;
if (value == null) {
if (other.value() != null)
return false;
} else if (!value.equals(other.value()))
return false;
return true;
}
public CoverageImpl(String name) {
this.value = name;
}
public String value() {
return value;
}
public Class<? extends Annotation> annotationType() {
return Coverage.class;
}
}
// TODO(corysmith): figure out if there is a better way for plugins to configure themselves.
// no point in requiring bad practice to integrate. (unlike some frameworks...)
@Provides @Inject
public CoverageWriter createCoverageWriter(@Named("testOutput") String testOut,
@Named("config") ConfigurationSource source,
@Named("outputStream") PrintStream out,
CoverageNameMapper mapper) {
if (testOut.length() > 0) {
try {
File testOutDir = new File(testOut);
if (!testOutDir.exists()) {
testOutDir.mkdirs();
}
// this should probably be configurable
File coverageFile = new File(testOutDir, String.format("%s-coverage.dat", source.getName()));
if (coverageFile.exists()) {
coverageFile.delete();
}
coverageFile.createNewFile();
return new LcovWriter(new FileWriter(coverageFile), mapper);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return new SummaryCoverageWriter(out, mapper);
}
}