Skip to content

Commit

Permalink
Extend CompilerBasedTransformer to CoverageInstrumenter
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=170706158
  • Loading branch information
johnjbarton authored and dimvar committed Oct 2, 2017
1 parent 66262ea commit de10f16
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 1 deletion.
Expand Up @@ -106,11 +106,15 @@ public CompileResult compile(Path path, String code) {
// impossible, and not a big deal even if it did happen.
}
}
boolean transformed = !result.transpiledFiles.isEmpty();
boolean transformed = transformed(result);
return new CompileResult(
source, result.errors, transformed, transformed ? sourceMap.toString() : "");
}

public boolean transformed(Result result) {
return !result.transpiledFiles.isEmpty();
}

public String runtime(String library) {
Compiler compiler = compiler();
CompilerOptions options = options();
Expand Down
79 changes: 79 additions & 0 deletions src/com/google/javascript/jscomp/bundle/CoverageInstrumenter.java
@@ -0,0 +1,79 @@
/*
* Copyright 2017 The Closure Compiler 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 com.google.javascript.jscomp.bundle;

import com.google.common.annotations.GwtIncompatible;
import com.google.errorprone.annotations.Immutable;
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.Result;
import com.google.javascript.jscomp.VariableRenamingPolicy;
import java.util.Optional;

/**
* A source transformer for instrmenting code for coverage data collection.
*/
@GwtIncompatible
@Immutable
public class CoverageInstrumenter extends CompilerBasedTransformer {

public CoverageInstrumenter(CompilerBasedTransformer.CompilerSupplier compilerSupplier) {
super(compilerSupplier);
}
/**
* Supply options for coverage.
*/
public static class CompilerSupplier extends CompilerBasedTransformer.CompilerSupplier {
@Override
protected void setOptions(CompilerOptions options) {
options.coalesceVariableNames = false;
options.setLanguageOut(CompilerOptions.LanguageMode.ECMASCRIPT5);
// The next two options together sum to the deprecated ECMASCRIPT6, and
// mimic historical behavior of this class.
options.setLanguageIn(CompilerOptions.LanguageMode.ECMASCRIPT_2015);
options.setStrictModeInput(false);
options.setShadowVariables(false);
// Setting the path to any non-null value will trigger source map generation.
// CompilerBasedTransformer attachs the sourcemap to the result.
options.setSourceMapOutputPath("/dev/null");
options.setVariableRenaming(VariableRenamingPolicy.OFF);
options.instrumentForCoverage = true;
options.setInstrumentForCoverageOnly(true);
}

@Override
public boolean transformed(Result result) {
return true;
}
}

@Override
public Optional<String> getRuntime() {
return Optional.empty();
}

@Override
public String getTranformationName() {
return "Coverage Instrumentation";
}

public static CoverageInstrumenter.CompilerSupplier compilerSupplier() {
return new CoverageInstrumenter.CompilerSupplier();
}

public static final CoverageInstrumenter INSTRUMENTER =
new CoverageInstrumenter(CoverageInstrumenter.compilerSupplier());
}
100 changes: 100 additions & 0 deletions test/com/google/javascript/jscomp/bundle/CoverageInstrumenterTest.java
@@ -0,0 +1,100 @@
/*
* Copyright 2017 The Closure Compiler 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 com.google.javascript.jscomp.bundle;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_SMART_NULLS;
import static org.mockito.Mockito.when;

import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Joiner;
import com.google.javascript.jscomp.JSError;
import java.nio.file.Path;
import java.nio.file.Paths;
import junit.framework.TestCase;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/** Tests for {@link CoverageInstrumenter}. */
@GwtIncompatible

public final class CoverageInstrumenterTest extends TestCase {

private Source.Transformer instrumenter;
private CoverageInstrumenter.CompilerSupplier compiler;

@Mock(answer = RETURNS_SMART_NULLS)
CoverageInstrumenter.CompilerSupplier mockCompiler;

private static final Path FOO_JS = Paths.get("foo.js");
private static final Path SOURCE_JS = Paths.get("source.js");
private static final JSError[] NO_ERRORS = new JSError[] {};

@Override
public void setUp() {
MockitoAnnotations.initMocks(this);
instrumenter = new CoverageInstrumenter(mockCompiler);
compiler = CoverageInstrumenter.compilerSupplier();
}

// Tests for CoverageInstrumenter

public void testCoverageInstrumenter_instrument() {
when(mockCompiler.compile(FOO_JS, "bar"))
.thenReturn(new CoverageInstrumenter.CompileResult("result", NO_ERRORS, true, "srcmap"));
assertThat(instrumenter.transform(source(FOO_JS, "bar")))
.isEqualTo(
Source.builder()
.setPath(FOO_JS)
.setOriginalCode("bar")
.setCode("result")
.setSourceMap("srcmap")
.build());
}

public void testCoverageInstrumenter_noInstrumentation() {
when(mockCompiler.compile(FOO_JS, "bar"))
.thenReturn(new CoverageInstrumenter.CompileResult("result", NO_ERRORS, false, "srcmap"));
assertThat(instrumenter.transform(source(FOO_JS, "bar"))).isEqualTo(source(FOO_JS, "bar"));
}

private static Source source(Path path, String code) {
return Source.builder().setPath(path).setCode(code).build();
}

// Tests for CompilerSupplier

public void testCompilerSupplier_instruments() {
CoverageInstrumenter.CompileResult result = compiler.compile(SOURCE_JS, "var x = 42;");
String[] expected = new String[]{
"if(!self.window){self.window=self;self.window.top=self}",
"var __jscov=window.top.__jscov||",
"(window.top.__jscov={fileNames:[],instrumentedLines:[],executedLines:[]});",
"var JSCompiler_lcov_data_source_js=[];",
"__jscov.executedLines.push(JSCompiler_lcov_data_source_js);",
"__jscov.instrumentedLines.push(\"01\");",
"__jscov.fileNames.push(\"source.js\");",
"JSCompiler_lcov_data_source_js[0]=true;var x=42;"};

assertThat(result.source).isEqualTo(Joiner.on("").join(expected));
assertThat(result.errors).isEmpty();
assertThat(result.transformed).isTrue();
assertThat(result.sourceMap)
.contains("\"mappings\":\"AAAA,GAAI,CAAC,IAAA,OAAL,CAAkB,CAAE,IAAA,OAAA,CAAc,IAAM,");
}

}

0 comments on commit de10f16

Please sign in to comment.