/* * 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.gwt.dev.javac; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.javac.testing.impl.MockJavaResource; import com.google.gwt.dev.javac.testing.impl.StaticJavaResource; import com.google.gwt.dev.resource.Resource; import com.google.gwt.dev.util.UnitTestTreeLogger; import com.google.gwt.thirdparty.guava.common.base.Joiner; import com.google.gwt.thirdparty.guava.common.collect.Sets; import junit.framework.TestCase; import java.util.Set; /** * A base type for testing the code checkers. */ public abstract class CheckerTestCase extends TestCase { /** * Pass represents passes to be run by the checker test cases. */ public interface Pass { /** * Run the pass. Returns true if pass completes successfully. */ boolean run(TreeLogger logger, MockJavaResource buggyResource, MockJavaResource extraResource); boolean classAvailable(String className); String getTopErrorMessage(Type logLevel, MockJavaResource resource); } /** * A warning or error message. */ protected static class Message { private int line; private Type logLevel; private String message; private Message(int line, Type logLevel, String message) { this.line = line; this.logLevel = logLevel; this.message = message; } } /** * Provide a pass to be checked by default runs only passes required to build TypeOracle. */ protected Pass providePass() { return new Pass() { private TypeOracle oracle = null; @Override public boolean run(TreeLogger logger, MockJavaResource buggyResource, MockJavaResource extraResource) { Set<Resource> resources = Sets.newHashSet(); addLongCheckingCups(resources); Set<GeneratedUnit> generatedUnits = CompilationStateTestBase.getGeneratedUnits(buggyResource); if (extraResource != null) { generatedUnits.addAll(CompilationStateTestBase.getGeneratedUnits(extraResource)); } CompilationState state = TypeOracleTestingUtils.buildCompilationStateWith(logger, resources, generatedUnits); oracle = state.getTypeOracle(); return !state.hasErrors(); } @Override public boolean classAvailable(String className) { return oracle.findType(className) != null; } @Override public String getTopErrorMessage(Type logLevel, MockJavaResource resource) { return (logLevel == Type.WARN ? "Warnings" : "Errors") + " in '" + resource.getLocation() + "'"; } }; } protected Message warning(int line, String message) { return new Message(line, Type.WARN, message); } protected Message error(int line, String message) { return new Message(line, Type.ERROR, message); } protected void shouldGenerate(MockJavaResource buggyCode, MockJavaResource extraCode, Type logLevel, Message... messages) { UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder(); b.setLowestLogLevel(logLevel); Pass pass = providePass(); String topLevelMessage = pass.getTopErrorMessage(logLevel, buggyCode); if (messages.length != 0 && topLevelMessage != null) { b.expect(logLevel, topLevelMessage, null); } for (Message message : messages) { final String fullMessage = "Line " + message.line + ": " + message.message; b.expect(message.logLevel, fullMessage, null); } UnitTestTreeLogger logger = b.createLogger(); boolean result = pass.run(logger, buggyCode, extraCode); logger.assertCorrectLogEntries(); String className = buggyCode.getTypeName(); if (messages.length != 0 && logLevel == TreeLogger.ERROR) { assertFalse("Compilation unit " + className + " not removed" + " but should have been removed.", pass.classAvailable(className)); } else { assertTrue("Compilation unit " + className + " was removed but shouldnt have.", pass.classAvailable(className)); } boolean expectingErrors = messages.length != 0 && logLevel == Type.ERROR; assertEquals(!expectingErrors, result); } protected void shouldGenerateError(MockJavaResource buggyCode, MockJavaResource extraCode, int line, String message) { shouldGenerate(buggyCode, extraCode, TreeLogger.ERROR, error(line, message)); } protected void shouldGenerateError(MockJavaResource buggyCode, int line, String message) { shouldGenerateError(buggyCode, null, line, message); } protected void shouldGenerateNoError(MockJavaResource code) { shouldGenerateNoError(code, null); } protected void shouldGenerateNoError(MockJavaResource code, MockJavaResource extraCode) { shouldGenerate(code, extraCode, TreeLogger.ERROR); } protected void shouldGenerateNoWarning(MockJavaResource code) { shouldGenerateNoWarning(code, null); } protected void shouldGenerateNoWarning(MockJavaResource code, MockJavaResource extraCode) { shouldGenerate(code, extraCode, TreeLogger.WARN); } protected void shouldGenerateWarning(MockJavaResource buggyCode, MockJavaResource extraCode, int line, String message) { shouldGenerate(buggyCode, extraCode, TreeLogger.WARN, warning(line, message)); } protected void shouldGenerateWarning(MockJavaResource buggyCode, int line, String message) { shouldGenerateWarning(buggyCode, null, line, message); } protected void shouldGenerateWarnings(MockJavaResource buggyCode, Message... messages) { shouldGenerateWarnings(buggyCode, null, messages); } protected void shouldGenerateWarnings(MockJavaResource buggyCode, MockJavaResource extraCode, Message... messages) { shouldGenerate(buggyCode, extraCode, TreeLogger.WARN, messages); } private void addLongCheckingCups(Set<Resource> resources) { String code = Joiner.on('\n').join( "package com.google.gwt.core.client;", "public @interface UnsafeNativeLong {", "}"); resources.add(new StaticJavaResource( "com.google.gwt.core.client.UnsafeNativeLong", code.toString())); } }