/* * Copyright (C) 2014 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.manifmerger; import com.android.sdklib.mock.MockLog; import com.google.common.base.Optional; import com.google.common.base.Strings; import junit.framework.TestCase; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; /** * Tests for the {@link com.android.manifmerger.ToolsInstructionsCleaner} class. */ public class ToolsInstructionsCleanerTest extends TestCase { public void testNodeRemoveOperation() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\">\n" + "\n" + " <application android:label=\"@string/lib_name\">\n" + "\n" + " <activity android:name=\"activityOne\" tools:node=\"remove\"/>\n" + " </application>" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testNodeRemoveOperation"), main); Element rootElement = mainDocument.getRootNode().getXml(); ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog); Optional<Element> application = getChildElementByName(rootElement, "application"); assertTrue(application.isPresent()); Optional<Element> activity = getChildElementByName(application.get(), "activity"); // ensure the activity did get deleted. assertFalse(activity.isPresent()); } public void testNodeWithChildrenRemoveOperation() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\" >\n" + "\n" + " <application>\n" + " <activity android:name=\"com.example.lib3.activityOne\" >\n" + " <intent-filter tools:node=\"remove\" >\n" + " <action android:name=\"android.intent.action.VIEW\" />\n" + " <category android:name=\"android.intent.category.DEFAULT\" />\n" + " <category android:name=\"android.intent.category.BROWSABLE\" />\n" + " </intent-filter>\n" + " </activity>\n" + " </application>\n" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testNodeRemoveWithChildrenOperation"), main); Element rootElement = mainDocument.getRootNode().getXml(); ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog); Optional<Element> application = getChildElementByName(rootElement, "application"); assertTrue(application.isPresent()); Optional<Element> activity = getChildElementByName(application.get(), "activity"); assertTrue(activity.isPresent()); Optional<Element> intentFilter = getChildElementByName(application.get(), "intent-filter"); // ensure the intent-filter did get deleted. assertFalse(intentFilter.isPresent()); } public void testInvalidToolsRemoveOperation() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\"" + " tools:node=\"remove\">\n" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testNodeRemoveOperation"), main); assertNull(ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog)); } public void testInvalidToolsRemoveAllOperation() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\"" + " tools:node=\"removeAll\">\n" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testNodeRemoveOperation"), main); assertNull(ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog)); } public void testNodeReplaceOperation() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\">\n" + "\n" + " <application android:label=\"@string/lib_name\">\n" + " <activity android:name=\"activityOne\" tools:node=\"replace\"/>\n" + " </application>\n" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testNodeReplaceOperation"), main); Element rootElement = mainDocument.getRootNode().getXml(); ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog); Optional<Element> application = getChildElementByName(rootElement, "application"); assertTrue(application.isPresent()); Optional<Element> activity = getChildElementByName(application.get(), "activity"); // ensure the activity did not get deleted. assertTrue(activity.isPresent()); } public void testAttributeRemoveOperation() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\">\n" + "\n" + " <application android:label=\"@string/lib_name\">\n" + " <activity android:name=\"activityOne\" tools:remove=\"exported\"/>\n" + " </application>\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testAttributeRemoveOperation"), main); Element rootElement = mainDocument.getRootNode().getXml(); ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog); Optional<Element> application = getChildElementByName(rootElement, "application"); assertTrue(application.isPresent()); Optional<Element> activity = getChildElementByName(application.get(), "activity"); // ensure the activity did not get deleted. assertTrue(activity.isPresent()); assertEquals(1, activity.get().getAttributes().getLength()); assertNotNull(activity.get().getAttribute("android:name")); } public void testSelectorRemoval() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\">\n" + "\n" + " <application android:label=\"@string/lib_name\">\n" + " <activity android:name=\"activityOne\" " + " tools:node=\"remove\" tools:selector=\"foo\"/>\n" + " </application>\n" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testSelectorRemoval"), main); Element rootElement = mainDocument.getRootNode().getXml(); ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog); Optional<Element> application = getChildElementByName(rootElement, "application"); assertTrue(application.isPresent()); Optional<Element> activity = getChildElementByName(application.get(), "activity"); // ensure the activity did not get deleted since it has a selector assertTrue(activity.isPresent()); assertTrue(Strings.isNullOrEmpty(activity.get().getAttribute("tools:selector"))); } public void testOtherToolInstructionRemoval() throws ParserConfigurationException, SAXException, IOException { MockLog mockLog = new MockLog(); String main = "" + "<manifest\n" + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " package=\"com.example.lib3\">\n" + "\n" + " <application android:label=\"@string/lib_name\">\n" + " <activity android:name=\"activityOne\" tools:ignore=\"value\"/>\n" + " </application>\n" + "\n" + "</manifest>"; XmlDocument mainDocument = TestUtils.xmlDocumentFromString( TestUtils.sourceFile(getClass(), "testNodeReplaceOperation"), main); Element rootElement = mainDocument.getRootNode().getXml(); ToolsInstructionsCleaner.cleanToolsReferences(mainDocument, mockLog); Optional<Element> application = getChildElementByName(rootElement, "application"); assertTrue(application.isPresent()); Optional<Element> activity = getChildElementByName(application.get(), "activity"); // ensure the activity did not get deleted. assertTrue(activity.isPresent()); // ensure tools:ignore got deleted. assertNull(activity.get().getAttributeNodeNS("http://schemas.android.com/tools", "ignore")); } private static Optional<Element> getChildElementByName(Element parent, String name) { NodeList childNodes = parent.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node item = childNodes.item(i); if (item.getNodeType() == Node.ELEMENT_NODE && item.getNodeName().equals(name)) { return Optional.of((Element) item); } } return Optional.absent(); } }