/* * Copyright 2016 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; import static com.google.common.truth.Truth.assertThat; import static com.google.javascript.jscomp.testing.JSErrorSubject.assertError; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import junit.framework.TestCase; public abstract class BaseReplaceScriptTestCase extends TestCase { protected static final Joiner LINE_JOINER = Joiner.on('\n'); protected static final String CLOSURE_BASE = LINE_JOINER.join( "/** @const */ var goog = goog || {};", "goog.require = function(x) {};", "goog.provide = function(x) {};"); protected static final ImmutableList<SourceFile> EXTERNS = ImmutableList.of(SourceFile.fromCode("externs", "var extVar = 3;")); /** * In addition to the passed parameter adds a few options necessary options for * {@code replaceScript} and creates a {@code CompilerOptions}. */ protected CompilerOptions getOptions(DiagnosticGroup... typesOfGuard) { CompilerOptions options = new CompilerOptions(); options.declaredGlobalExternsOnWindow = false; options.setClosurePass(true); // These are the options that are always on in JsDev which is the only // use-case for replaceScript currently. options.setInferTypes(true); options.setAllowHotswapReplaceScript(true); options.setChecksOnly(true); options.setContinueAfterErrors(true); for (DiagnosticGroup group : typesOfGuard) { options.setWarningLevel(group, CheckLevel.ERROR); } return options; } protected void flushResults(Compiler compiler) { // TODO(bashir) Maybe implement error-flush functionality in Compiler? compiler.setErrorManager(new PrintStreamErrorManager(System.err)); } protected void runReplaceScriptNoWarnings( List<String> sources, String newSource, int newSourceInd) { Result result = runReplaceScript(getOptions(), sources, 0, 0, newSource, newSourceInd, true).getResult(); assertNoWarningsOrErrors(result); assertThat(result.success).isTrue(); } protected void runReplaceScriptWithError( List<String> sources, String newSource, int newSourceInd, DiagnosticType errorType) { Result result = runReplaceScript(getOptions(), sources, 0, 0, newSource, newSourceInd, true).getResult(); assertNumWarningsAndErrors(result, 1, 0); assertError(result.errors[0]).hasType(errorType); } /** * For a given set of sources, first runs a full compile, then replaces one source with a given * new version and calls {@code replaceScript}. * * @param options Compiler options. * @param sources The list of sources. * @param expectedCompileErrors Expected number of errors after full compile. * @param expectedCompileWarnings Expected number of warnings of full compile. * @param newSource The source version. * @param newSourceInd Index of the source in {@code sources} to be replaced. * @param flushResults Whether to flush results after full-build or not. * @return The compiler which can be reused for further inc-compiles. */ protected Compiler runReplaceScript( CompilerOptions options, List<String> sources, int expectedCompileErrors, int expectedCompileWarnings, String newSource, int newSourceInd, boolean flushResults) { Preconditions.checkArgument(newSourceInd < sources.size()); // First do a full compile. Compiler compiler = runFullCompile( options, sources, expectedCompileErrors, expectedCompileWarnings, flushResults); // Now replace one of the source files and run replaceScript. doReplaceScript(compiler, newSource, newSourceInd); return compiler; } protected Compiler runAddScript( CompilerOptions options, List<String> sources, int expectedCompileErrors, int expectedCompileWarnings, String newSource, boolean flushResults) { // First do a full compile. Compiler compiler = runFullCompile( options, sources, expectedCompileErrors, expectedCompileWarnings, flushResults); // Now replace one of the source files and run replaceScript. doAddScript(compiler, newSource, sources.size()); return compiler; } protected Compiler runFullCompile( CompilerOptions options, List<String> sources, int expectedCompileErrors, int expectedCompileWarnings, boolean flushResults) { List<SourceFile> inputs = new ArrayList<>(); int i = 0; for (String source : sources) { inputs.add(SourceFile.fromCode("in" + i, source)); i++; } Compiler compiler = new Compiler(); Compiler.setLoggingLevel(Level.INFO); Result result = compiler.compile(EXTERNS, inputs, options); if (expectedCompileErrors == 0) { assertThat(compiler.getErrors()).isEmpty(); assertThat(result.success).isTrue(); } else { assertThat(compiler.getErrors()).hasLength(expectedCompileErrors); assertThat(result.success).isFalse(); } assertThat(compiler.getWarnings()).hasLength(expectedCompileWarnings); if (flushResults) { flushResults(compiler); } return compiler; } protected void doReplaceScript(Compiler compiler, String newSource, int newSourceInd) { SourceFile replacedSource = SourceFile.fromCode("in" + newSourceInd, newSource); JsAst ast = new JsAst(replacedSource); compiler.replaceScript(ast); } protected void doAddScript(Compiler compiler, String newSource, int newSourceInd) { SourceFile replacedSource = SourceFile.fromCode("in" + newSourceInd, newSource); JsAst ast = new JsAst(replacedSource); compiler.addNewScript(ast); } protected void assertNoWarningsOrErrors(Result result) { assertNumWarningsAndErrors(result, 0, 0); } protected void assertNumWarningsAndErrors(Result result, int e, int w) { assertThat(result.warnings).hasLength(w); assertThat(result.errors).hasLength(e); assertThat(result.success).isEqualTo(e == 0); } protected void assertErrorType(JSError e, DiagnosticType type, int lineNumber) { assertError(e).hasType(type); assertEquals(e.lineNumber, lineNumber); } }