/* * 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.client.api.LintClient; import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.Project; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; @SuppressWarnings("javadoc") public class ManifestOrderDetectorTest extends AbstractCheckTest { @Override protected Detector getDetector() { return new ManifestOrderDetector(); } private Set<Issue> mEnabled = new HashSet<Issue>(); @Override protected TestConfiguration getConfiguration(LintClient client, Project project) { return new TestConfiguration(client, project, null) { @Override public boolean isEnabled(Issue issue) { return super.isEnabled(issue) && mEnabled.contains(issue); } }; } public void testOrderOk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.ORDER); assertEquals( "No warnings.", lintProject( "AndroidManifest.xml", "res/values/strings.xml")); } public void testBrokenOrder() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.ORDER); assertEquals( "AndroidManifest.xml:16: Warning: <uses-sdk> tag appears after <application> tag [ManifestOrder]\n" + " <uses-sdk android:minSdkVersion=\"Froyo\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "0 errors, 1 warnings\n" + "", lintProject( "broken-manifest.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testMissingUsesSdk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.USES_SDK); assertEquals( "AndroidManifest.xml: Warning: Manifest should specify a minimum API level with <uses-sdk android:minSdkVersion=\"?\" />; if it really supports all versions of Android set it to 1. [UsesMinSdkAttributes]\n" + "0 errors, 1 warnings\n", lintProject( "missingusessdk.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testMissingMinSdk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.USES_SDK); assertEquals( "AndroidManifest.xml:7: Warning: <uses-sdk> tag should specify a minimum API level with android:minSdkVersion=\"?\" [UsesMinSdkAttributes]\n" + " <uses-sdk android:targetSdkVersion=\"10\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "0 errors, 1 warnings\n" + "", lintProject( "missingmin.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testMissingTargetSdk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.USES_SDK); assertEquals( "AndroidManifest.xml:7: Warning: <uses-sdk> tag should specify a target API level (the highest verified version; when running on later versions, compatibility behaviors may be enabled) with android:targetSdkVersion=\"?\" [UsesMinSdkAttributes]\n" + " <uses-sdk android:minSdkVersion=\"10\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "0 errors, 1 warnings\n", lintProject( "missingtarget.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testOldTargetSdk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.TARGET_NEWER); assertEquals( "AndroidManifest.xml:7: Warning: Not targeting the latest versions of Android; compatibility modes apply. Consider testing and updating this version. Consult the android.os.Build.VERSION_CODES javadoc for details. [OldTargetApi]\n" + " <uses-sdk android:minSdkVersion=\"10\" android:targetSdkVersion=\"14\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "0 errors, 1 warnings\n", lintProject( "oldtarget.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testMultipleSdk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.MULTIPLE_USES_SDK); assertEquals( "AndroidManifest.xml:8: Error: There should only be a single <uses-sdk> element in the manifest: merge these together [MultipleUsesSdk]\n" + " <uses-sdk android:targetSdkVersion=\"14\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " AndroidManifest.xml:7: Also appears here\n" + " AndroidManifest.xml:9: Also appears here\n" + "1 errors, 0 warnings\n", lintProject( "multiplesdk.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testWrongLocation() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.WRONG_PARENT); assertEquals( "AndroidManifest.xml:8: Error: The <uses-sdk> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <uses-sdk android:minSdkVersion=\"Froyo\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:9: Error: The <uses-permission> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <uses-permission />\n" + " ~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:10: Error: The <permission> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <permission />\n" + " ~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:11: Error: The <permission-tree> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <permission-tree />\n" + " ~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:12: Error: The <permission-group> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <permission-group />\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:14: Error: The <uses-sdk> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <uses-sdk />\n" + " ~~~~~~~~~~~~\n" + "AndroidManifest.xml:15: Error: The <uses-configuration> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <uses-configuration />\n" + " ~~~~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:16: Error: The <uses-feature> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <uses-feature />\n" + " ~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:17: Error: The <supports-screens> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <supports-screens />\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:18: Error: The <compatible-screens> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <compatible-screens />\n" + " ~~~~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:19: Error: The <supports-gl-texture> element must be a direct child of the <manifest> root element [WrongManifestParent]\n" + " <supports-gl-texture />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:24: Error: The <uses-library> element must be a direct child of the <application> element [WrongManifestParent]\n" + " <uses-library />\n" + " ~~~~~~~~~~~~~~~~\n" + "AndroidManifest.xml:25: Error: The <activity> element must be a direct child of the <application> element [WrongManifestParent]\n" + " <activity android:name=\".HelloWorld\"\n" + " ^\n" + "13 errors, 0 warnings\n" + "", lintProject("broken-manifest2.xml=>AndroidManifest.xml")); } public void testDuplicateActivity() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.DUPLICATE_ACTIVITY); assertEquals( "AndroidManifest.xml:16: Error: Duplicate registration for activity com.example.helloworld.HelloWorld [DuplicateActivity]\n" + " <activity android:name=\"com.example.helloworld.HelloWorld\"\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n" + "", lintProject( "duplicate-manifest.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testIgnoreDuplicateActivity() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.DUPLICATE_ACTIVITY); assertEquals( "No warnings.", lintProject( "duplicate-manifest-ignore.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testAllowBackup() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.ALLOW_BACKUP); assertEquals( "AndroidManifest.xml:9: Warning: Should explicitly set android:allowBackup to " + "true or false (it's true by default, and that can have some security " + "implications for the application's data) [AllowBackup]\n" + " <application\n" + " ^\n" + "0 errors, 1 warnings\n", lintProject( "AndroidManifest.xml", "res/values/strings.xml")); } public void testAllowBackupOk() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.ALLOW_BACKUP); assertEquals( "No warnings.", lintProject( "allowbackup.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testAllowIgnore() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.ALLOW_BACKUP); assertEquals( "No warnings.", lintProject( "allowbackup_ignore.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testDuplicatePermissions() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.UNIQUE_PERMISSION); assertEquals( "AndroidManifest.xml:12: Error: Permission name SEND_SMS is not unique (appears in both foo.permission.SEND_SMS and bar.permission.SEND_SMS) [UniquePermission]\n" + " <permission android:name=\"bar.permission.SEND_SMS\"\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " AndroidManifest.xml:9: Previous permission here\n" + "1 errors, 0 warnings\n", lintProject( "duplicate_permissions1.xml=>AndroidManifest.xml", "res/values/strings.xml")); } public void testDuplicatePermissionsMultiProject() throws Exception { mEnabled = Collections.singleton(ManifestOrderDetector.UNIQUE_PERMISSION); File master = getProjectDir("MasterProject", // Master project "duplicate_permissions2.xml=>AndroidManifest.xml", "multiproject/main-merge.properties=>project.properties", "multiproject/MainCode.java.txt=>src/foo/main/MainCode.java" ); File library = getProjectDir("LibraryProject", // Library project "duplicate_permissions3.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( "LibraryProject/AndroidManifest.xml:9: Error: Permission name SEND_SMS is not unique (appears in both foo.permission.SEND_SMS and bar.permission.SEND_SMS) [UniquePermission]\n" + " <permission android:name=\"bar.permission.SEND_SMS\"\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", checkLint(Arrays.asList(master, library))); } }