/*
* Copyright (C) 2011 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.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Issue;
import java.io.File;
import java.util.Arrays;
@SuppressWarnings("javadoc")
public class UnusedResourceDetectorTest extends AbstractCheckTest {
private boolean mEnableIds = false;
@Override
protected Detector getDetector() {
return new UnusedResourceDetector();
}
@Override
protected boolean isEnabled(Issue issue) {
if (issue == UnusedResourceDetector.ISSUE_IDS) {
return mEnableIds;
} else {
return true;
}
}
public void testUnused() throws Exception {
mEnableIds = false;
assertEquals(
"res/layout/accessibility.xml: Warning: The resource R.layout.accessibility appears to be unused [UnusedResources]\n" +
"res/layout/main.xml: Warning: The resource R.layout.main appears to be unused [UnusedResources]\n" +
"res/layout/other.xml: Warning: The resource R.layout.other appears to be unused [UnusedResources]\n" +
"res/values/strings2.xml:3: Warning: The resource R.string.hello appears to be unused [UnusedResources]\n" +
" <string name=\"hello\">Hello</string>\n" +
" ~~~~~~~~~~~~\n" +
"0 errors, 4 warnings\n" +
"",
lintProject(
"res/values/strings2.xml",
"res/layout/layout1.xml=>res/layout/main.xml",
"res/layout/layout1.xml=>res/layout/other.xml",
// Rename .txt files to .java
"src/my/pkg/Test.java.txt=>src/my/pkg/Test.java",
"gen/my/pkg/R.java.txt=>gen/my/pkg/R.java",
"AndroidManifest.xml",
"res/layout/accessibility.xml"));
}
public void testUnusedIds() throws Exception {
mEnableIds = true;
assertEquals(
"res/layout/accessibility.xml: Warning: The resource R.layout.accessibility appears to be unused [UnusedResources]\n" +
"Warning: The resource R.layout.main appears to be unused [UnusedResources]\n" +
"Warning: The resource R.layout.other appears to be unused [UnusedResources]\n" +
"Warning: The resource R.string.hello appears to be unused [UnusedResources]\n" +
"res/layout/accessibility.xml:2: Warning: The resource R.id.newlinear appears to be unused [UnusedIds]\n" +
"<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" android:id=\"@+id/newlinear\" android:orientation=\"vertical\" android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n" +
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
"res/layout/accessibility.xml:3: Warning: The resource R.id.button1 appears to be unused [UnusedIds]\n" +
" <Button android:text=\"Button\" android:id=\"@+id/button1\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"></Button>\n" +
" ~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
"res/layout/accessibility.xml:4: Warning: The resource R.id.android_logo appears to be unused [UnusedIds]\n" +
" <ImageView android:id=\"@+id/android_logo\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n" +
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
"res/layout/accessibility.xml:5: Warning: The resource R.id.android_logo2 appears to be unused [UnusedIds]\n" +
" <ImageButton android:importantForAccessibility=\"yes\" android:id=\"@+id/android_logo2\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n" +
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
"Warning: The resource R.id.imageView1 appears to be unused [UnusedIds]\n" +
"Warning: The resource R.id.include1 appears to be unused [UnusedIds]\n" +
"Warning: The resource R.id.linearLayout2 appears to be unused [UnusedIds]\n" +
"0 errors, 11 warnings\n",
lintProject(
// Rename .txt files to .java
"src/my/pkg/Test.java.txt=>src/my/pkg/Test.java",
"gen/my/pkg/R.java.txt=>gen/my/pkg/R.java",
"AndroidManifest.xml",
"res/layout/accessibility.xml"));
}
public void testArrayReference() throws Exception {
assertEquals(
"res/values/arrayusage.xml:3: Warning: The resource R.array.my_array appears to be unused [UnusedResources]\n" +
"<string-array name=\"my_array\">\n" +
" ~~~~~~~~~~~~~~~\n" +
"0 errors, 1 warnings\n" +
"",
lintProject(
"AndroidManifest.xml",
"res/values/arrayusage.xml"));
}
public void testAttrs() throws Exception {
assertEquals(
"res/layout/customattrlayout.xml: Warning: The resource R.layout.customattrlayout appears to be unused [UnusedResources]\n" +
"0 errors, 1 warnings\n" +
"",
lintProject(
"res/values/customattr.xml",
"res/layout/customattrlayout.xml",
"unusedR.java.txt=>gen/my/pkg/R.java",
"AndroidManifest.xml"));
}
public void testMultiProjectIgnoreLibraries() throws Exception {
assertEquals(
"No warnings.",
lintProject(
// Master project
"multiproject/main-manifest.xml=>AndroidManifest.xml",
"multiproject/main.properties=>project.properties",
"multiproject/MainCode.java.txt=>src/foo/main/MainCode.java",
// Library project
"multiproject/library-manifest.xml=>../LibraryProject/AndroidManifest.xml",
"multiproject/library.properties=>../LibraryProject/project.properties",
"multiproject/LibraryCode.java.txt=>../LibraryProject/src/foo/library/LibraryCode.java",
"multiproject/strings.xml=>../LibraryProject/res/values/strings.xml"
));
}
public void testMultiProject() throws Exception {
File master = getProjectDir("MasterProject",
// Master project
"multiproject/main-manifest.xml=>AndroidManifest.xml",
"multiproject/main.properties=>project.properties",
"multiproject/MainCode.java.txt=>src/foo/main/MainCode.java"
);
File library = getProjectDir("LibraryProject",
// Library project
"multiproject/library-manifest.xml=>AndroidManifest.xml",
"multiproject/library.properties=>project.properties",
"multiproject/LibraryCode.java.txt=>src/foo/library/LibraryCode.java",
"multiproject/strings.xml=>res/values/strings.xml"
);
assertEquals(
// string1 is defined and used in the library project
// string2 is defined in the library project and used in the master project
// string3 is defined in the library project and not used anywhere
"LibraryProject/res/values/strings.xml:7: Warning: The resource R.string.string3 appears to be unused [UnusedResources]\n" +
" <string name=\"string3\">String 3</string>\n" +
" ~~~~~~~~~~~~~~\n" +
"0 errors, 1 warnings\n",
checkLint(Arrays.asList(master, library)).replace("/TESTROOT/", ""));
}
public void testFqcnReference() throws Exception {
assertEquals(
"No warnings.",
lintProject(
"res/layout/layout1.xml=>res/layout/main.xml",
"src/test/pkg/UnusedReference.java.txt=>src/test/pkg/UnusedReference.java",
"AndroidManifest.xml"));
}
public void testIgnoreXmlDrawable() throws Exception {
assertEquals(
"No warnings.",
lintProject(
"res/drawable/ic_menu_help.xml",
"gen/my/pkg/R2.java.txt=>gen/my/pkg/R.java"
));
}
public void testPlurals() throws Exception {
assertEquals(
"res/values/plurals.xml:3: Warning: The resource R.plurals.my_plural appears to be unused [UnusedResources]\n" +
" <plurals name=\"my_plural\">\n" +
" ~~~~~~~~~~~~~~~~\n" +
"0 errors, 1 warnings\n" +
"",
lintProject(
"res/values/strings4.xml",
"res/values/plurals.xml",
"AndroidManifest.xml"));
}
public void testNoMerging() throws Exception {
// http://code.google.com/p/android/issues/detail?id=36952
File master = getProjectDir("MasterProject",
// Master project
"multiproject/main-manifest.xml=>AndroidManifest.xml",
"multiproject/main.properties=>project.properties",
"multiproject/MainCode.java.txt=>src/foo/main/MainCode.java"
);
File library = getProjectDir("LibraryProject",
// Library project
"multiproject/library-manifest.xml=>AndroidManifest.xml",
"multiproject/library.properties=>project.properties",
"multiproject/LibraryCode.java.txt=>src/foo/library/LibraryCode.java",
"multiproject/strings.xml=>res/values/strings.xml"
);
assertEquals(
// The strings are all referenced in the library project's manifest file
// which in this project is merged in
"LibraryProject/res/values/strings.xml:7: Warning: The resource R.string.string3 appears to be unused [UnusedResources]\n" +
" <string name=\"string3\">String 3</string>\n" +
" ~~~~~~~~~~~~~~\n" +
"0 errors, 1 warnings\n",
checkLint(Arrays.asList(master, library)).replace("/TESTROOT/", ""));
}
public void testLibraryMerging() throws Exception {
// http://code.google.com/p/android/issues/detail?id=36952
File master = getProjectDir("MasterProject",
// Master project
"multiproject/main-manifest.xml=>AndroidManifest.xml",
"multiproject/main-merge.properties=>project.properties",
"multiproject/MainCode.java.txt=>src/foo/main/MainCode.java"
);
File library = getProjectDir("LibraryProject",
// Library project
"multiproject/library-manifest.xml=>AndroidManifest.xml",
"multiproject/library.properties=>project.properties",
"multiproject/LibraryCode.java.txt=>src/foo/library/LibraryCode.java",
"multiproject/strings.xml=>res/values/strings.xml"
);
assertEquals(
// The strings are all referenced in the library project's manifest file
// which in this project is merged in
"No warnings.",
checkLint(Arrays.asList(master, library)));
}
public void testCornerCase() throws Exception {
// See http://code.google.com/p/projectlombok/issues/detail?id=415
mEnableIds = true;
assertEquals(
"No warnings.",
lintProject(
"src/test/pkg/Foo.java.txt=>src/test/pkg/Foo.java",
"AndroidManifest.xml"));
}
public void testAnalytics() throws Exception {
// See http://code.google.com/p/android/issues/detail?id=42565
mEnableIds = false;
assertEquals(
"No warnings.",
lintProject(
"res/values/analytics.xml"
));
}
public void testIntegers() throws Exception {
// See https://code.google.com/p/android/issues/detail?id=53995
mEnableIds = true;
assertEquals(
"No warnings.",
lintProject(
"res/values/integers.xml",
"res/anim/slide_in_out.xml"
));
}
public void testIntegerArrays() throws Exception {
// See http://code.google.com/p/android/issues/detail?id=59761
mEnableIds = false;
assertEquals(
"No warnings.",
lintProject("res/values/integer_arrays.xml=>res/values/integer_arrays.xml"));
}
public void testUnitTestReferences() throws Exception {
// Make sure that we pick up references in unit tests as well
// Regression test for
// https://code.google.com/p/android/issues/detail?id=79066
mEnableIds = false;
//noinspection ClassNameDiffersFromFileName
assertEquals("No warnings.",
lintProject(
copy("res/values/strings2.xml"),
copy("res/layout/layout1.xml", "res/layout/main.xml"),
copy("res/layout/layout1.xml", "res/layout/other.xml"),
copy("src/my/pkg/Test.java.txt", "src/my/pkg/Test.java"),
copy("gen/my/pkg/R.java.txt", "gen/my/pkg/R.java"),
copy("AndroidManifest.xml"),
copy("res/layout/accessibility.xml"),
// Add unit test source which references resources which would otherwise
// be marked as unused
java("test/my/pkg/MyTest.java", ""
+ "package my.pkg;\n"
+ "class MyTest {\n"
+ " public void test() {\n"
+ " System.out.println(R.layout.accessibility);\n"
+ " System.out.println(R.layout.main);\n"
+ " System.out.println(R.layout.other);\n"
+ " System.out.println(R.string.hello);\n"
+ " }\n"
+ "}\n")
));
}
}