blob: 7a7fa28954a3b0128b119431264a47137101ad05 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.android.tools.lint.checks;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Severity;
import java.io.File;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.StringWriter;
@SuppressWarnings("javadoc")
public class ApiLookupTest extends AbstractCheckTest {
private final ApiLookup mDb = ApiLookup.get(new TestLintClient());
public void test1() {
assertEquals(5, mDb.getFieldVersion("android/Manifest$permission", "AUTHENTICATE_ACCOUNTS"));
assertTrue(mDb.getFieldVersion("android/R$attr", "absListViewStyle") <= 1);
assertEquals(11, mDb.getFieldVersion("android/R$attr", "actionMenuTextAppearance"));
assertEquals(5, mDb.getCallVersion("android/graphics/drawable/BitmapDrawable",
"<init>", "(Landroid/content/res/Resources;Ljava/lang/String;)V"));
assertEquals(4, mDb.getCallVersion("android/graphics/drawable/BitmapDrawable",
"setTargetDensity", "(Landroid/util/DisplayMetrics;)V"));
assertEquals(7, mDb.getClassVersion("android/app/WallpaperInfo"));
assertEquals(11, mDb.getClassVersion("android/widget/StackView"));
assertTrue(mDb.getClassVersion("ava/text/ChoiceFormat") <= 1);
// Class lookup: Unknown class
assertEquals(-1, mDb.getClassVersion("foo/Bar"));
// Field lookup: Unknown class
assertEquals(-1, mDb.getFieldVersion("foo/Bar", "FOOBAR"));
// Field lookup: Unknown field
assertEquals(-1, mDb.getFieldVersion("android/Manifest$permission", "FOOBAR"));
// Method lookup: Unknown class
assertEquals(-1, mDb.getCallVersion("foo/Bar",
"<init>", "(Landroid/content/res/Resources;Ljava/lang/String;)V"));
// Method lookup: Unknown name
assertEquals(-1, mDb.getCallVersion("android/graphics/drawable/BitmapDrawable",
"foo", "(Landroid/content/res/Resources;Ljava/lang/String;)V"));
// Method lookup: Unknown argument list
assertEquals(-1, mDb.getCallVersion("android/graphics/drawable/BitmapDrawable",
"<init>", "(I)V"));
}
public void test2() {
// Regression test:
// This used to return 11 because of some wildcard syntax in the signature
assertTrue(mDb.getCallVersion("java/lang/Object", "getClass", "()") <= 1);
}
public void testIssue26467() {
assertTrue(mDb.getCallVersion("java/nio/ByteBuffer", "array", "()") <= 1);
assertEquals(9, mDb.getCallVersion("java/nio/Buffer", "array", "()"));
}
public void testNoInheritedConstructors() {
assertTrue(mDb.getCallVersion("java/util/zip/ZipOutputStream", "<init>", "()") <= 1);
assertTrue(mDb.getCallVersion("android/app/AliasActivity", "<init>", "(Landroid/content/Context;I)") <= 1);
}
public void testIssue35190() {
assertEquals(9, mDb.getCallVersion("java/io/IOException", "<init>",
"(Ljava/lang/Throwable;)V"));
}
public void testInheritInterfaces() {
// The onPreferenceStartFragment is inherited via the
// android/preference/PreferenceFragment$OnPreferenceStartFragmentCallback
// interface
assertEquals(11, mDb.getCallVersion("android/preference/PreferenceActivity",
"onPreferenceStartFragment",
"(Landroid/preference/PreferenceFragment;Landroid/preference/Preference;)"));
}
public void testIsValidPackage() {
assertTrue(mDb.isValidJavaPackage("java/lang/Integer"));
assertTrue(mDb.isValidJavaPackage("javax/crypto/Cipher"));
assertTrue(mDb.isValidJavaPackage("java/awt/font/NumericShaper"));
assertFalse(mDb.isValidJavaPackage("javax/swing/JButton"));
assertFalse(mDb.isValidJavaPackage("java/rmi/Naming"));
assertFalse(mDb.isValidJavaPackage("java/lang/instrument/Instrumentation"));
}
@Override
protected Detector getDetector() {
fail("This is not used in the ApiDatabase test");
return null;
}
private File mCacheDir;
@SuppressWarnings("StringBufferField")
private StringBuilder mLogBuffer = new StringBuilder();
@SuppressWarnings({"ConstantConditions", "IOResourceOpenedButNotSafelyClosed",
"ResultOfMethodCallIgnored"})
public void testCorruptedCacheHandling() throws Exception {
ApiLookup lookup;
// Real cache:
mCacheDir = new TestLintClient().getCacheDir(true);
mLogBuffer.setLength(0);
lookup = ApiLookup.get(new LookupTestClient());
assertEquals(11, lookup.getFieldVersion("android/R$attr", "actionMenuTextAppearance"));
assertNotNull(lookup);
assertEquals("", mLogBuffer.toString()); // No warnings
ApiLookup.dispose();
// Custom cache dir: should also work
mCacheDir = new File(getTempDir(), "test-cache");
mCacheDir.mkdirs();
mLogBuffer.setLength(0);
lookup = ApiLookup.get(new LookupTestClient());
assertEquals(11, lookup.getFieldVersion("android/R$attr", "actionMenuTextAppearance"));
assertNotNull(lookup);
assertEquals("", mLogBuffer.toString()); // No warnings
ApiLookup.dispose();
// Now truncate cache file
File cacheFile = new File(mCacheDir,
ApiLookup.getCacheFileName("api-versions.xml",
ApiLookup.getPlatformVersion(new LookupTestClient()))); //$NON-NLS-1$
mLogBuffer.setLength(0);
assertTrue(cacheFile.exists());
RandomAccessFile raf = new RandomAccessFile(cacheFile, "rw");
// Truncate file in half
raf.setLength(100); // Broken header
raf.close();
lookup = ApiLookup.get(new LookupTestClient());
String message = mLogBuffer.toString();
// NOTE: This test is incompatible with the DEBUG_FORCE_REGENERATE_BINARY and WRITE_STATS
// flags in the ApiLookup class, so if the test fails during development and those are
// set, clear them.
assertTrue(message.contains("Please delete the file and restart the IDE/lint:"));
assertTrue(message.contains(mCacheDir.getPath()));
ApiLookup.dispose();
mLogBuffer.setLength(0);
assertTrue(cacheFile.exists());
raf = new RandomAccessFile(cacheFile, "rw");
// Truncate file in half in the data portion
raf.setLength(raf.length() / 2);
raf.close();
lookup = ApiLookup.get(new LookupTestClient());
// This data is now truncated: lookup returns the wrong size.
try {
assertNotNull(lookup);
lookup.getFieldVersion("android/R$attr", "actionMenuTextAppearance");
fail("Can't look up bogus data");
} catch (Throwable t) {
// Expected this: the database is corrupted.
}
assertTrue(message.contains("Please delete the file and restart the IDE/lint:"));
assertTrue(message.contains(mCacheDir.getPath()));
ApiLookup.dispose();
mLogBuffer.setLength(0);
assertTrue(cacheFile.exists());
raf = new RandomAccessFile(cacheFile, "rw");
// Truncate file to 0 bytes
raf.setLength(0);
raf.close();
lookup = ApiLookup.get(new LookupTestClient());
assertEquals(11, lookup.getFieldVersion("android/R$attr", "actionMenuTextAppearance"));
assertNotNull(lookup);
assertEquals("", mLogBuffer.toString()); // No warnings
ApiLookup.dispose();
}
private final class LookupTestClient extends TestLintClient {
@SuppressWarnings("ResultOfMethodCallIgnored")
@Override
public File getCacheDir(boolean create) {
assertNotNull(mCacheDir);
if (create && !mCacheDir.exists()) {
mCacheDir.mkdirs();
}
return mCacheDir;
}
@Override
public void log(
@NonNull Severity severity,
@Nullable Throwable exception,
@Nullable String format,
@Nullable Object... args) {
if (format != null) {
mLogBuffer.append(String.format(format, args));
mLogBuffer.append('\n');
}
if (exception != null) {
StringWriter writer = new StringWriter();
exception.printStackTrace(new PrintWriter(writer));
mLogBuffer.append(writer.toString());
mLogBuffer.append('\n');
}
}
@Override
public void log(Throwable exception, String format, Object... args) {
log(Severity.WARNING, exception, format, args);
}
}
}